Change Label Color in GTK Game Tutorial

How to change label color in GTK using the gtk_label_set_markup function. Demonstrates changing text color in a simple heads or tails game programmed with C, GTK and Glade.

Part 14 of GTK 3 Programming with C and Glade Tutorial

See the full GTK3 tutorial index

About this Tutorial

This tutorial improves the world’s simplest game from part 7 of this tutorial series. In part 7, a GUI window for a coin toss game was built in the video for that tutorial part.

In this new version of the coin toss game the user can place a bet on either heads or tails before flipping the coin.

Improved Coin Toss Game Created with C, GTK and Glade. Demonstrates how to change label color in GTK for game result.
Improved Coin Toss Game Created with C, GTK and Glade
Demonstrates how to Change Label Color in GTK

How to Change Label Color in GTK and More

This tutorial demonstrates more than how to change label color in GTK. It includes the following.

  • How to make a GTK window a fixed size and stop the user from resizing it.
  • Hide and show a widget, such as a button.
  • Disable and enable a widget, demonstrated with a button.
  • Lay out widgets in a window by nesting widgets.
  • Show a radio button group with no default selected.
  • Change label color in GTK as well as other label attributes.
  • Change label attributes in Glade.

Heads or Tails GTK Coin Game Tutorial Steps

Follow the tutorial steps below to build the simple GTK heads or tails coin game.

1. Create a New Project

Start a new project using the template files.

1.1 Copy and Rename Template Folder

Copy the template folder from part 4 of this tutorial series. Rename the folder to heads_tails.

1.2 Change Name in Make File

Open the make file and change the TARGET name to heads_tails. The complete make file follows.

makefile

# change application name here (executable output name)
TARGET=heads_tails

# compiler
CC=gcc
# debug
DEBUG=-g
# optimisation
OPT=-O0
# warnings
WARN=-Wall

PTHREAD=-pthread

CCFLAGS=$(DEBUG) $(OPT) $(WARN) $(PTHREAD) -pipe

GTKLIB=`pkg-config --cflags --libs gtk+-3.0`

# linker
LD=gcc
LDFLAGS=$(PTHREAD) $(GTKLIB) -export-dynamic

OBJS=    main.o

all: $(OBJS)
	$(LD) -o $(TARGET) $(OBJS) $(LDFLAGS)
    
main.o: src/main.c
	$(CC) -c $(CCFLAGS) src/main.c $(GTKLIB) -o main.o
    
clean:
	rm -f *.o $(TARGET)

2. Modify the Glade File

Open the Glade file for editing from the project glade folder.

2.1 Edit the Main GtkWindow Window

Click the main GtkWindow in Glade to select it (window_main). Change the title of the window to Heads or Tails.

Enable the Default Width and change its value to 500.

How to Fix the Window Size and Stop the User from Changing It

Under the General tab, find Window Flags at the bottom of the pane. Uncheck Resizable to keep the window at a fixed size and stop the user from resizing the window.

Main Window Settings in Glade
Main Window Settings in Glade

2.2 Place the Main GtkBox

In Glade, click the Containers button and then GtkBox on the menu that drops down. Click the main window to place the GtkBox in it. Change the GtkBox settings as follows.

General Tab Settings
Orientation: Vertical
Number of Item: 3
Spacing: 20

Common Tab Settings
All Margins: 10

Place a GtkBox in Glade
Place a GtkBox in Glade

The top slot of the box holds all of the labels and the radio buttons for this application. Because each slot can contain only one widget, additional containers are placed in each slot where needed.

A win/lose result label goes into the middle slot of the main GtkBox.

Two buttons go into the bottom slot of the box, but another GtkBox must be placed in the slot first.

2.3 Place a GtkGrid

Place a GtkGrid in the top slot of the GtkBox that was just placed. Find the GtkGrid under the Containers button.

Under the General tab, change Rows Count to 2 and Rows Spacing to 10.

Change the Columns Spacing to 30. Check the Columns Homogeneous box.

GtkGrid Settings
GtkGrid Settings

2.4 Place Top Labels and Edit Attributes

Place 3 labels in the top 3 slots of the GtkGrid using the Display button and then selecting GtkLabel. The text for these labels are as follows from left to right.

  • Place Bet, Then Toss Coin
  • Your Bet:
  • Coin Toss Result:
Place the Top Labels then Change Alignment and Font to Bold
Place the Top Labels then Change Alignment and Font to Bold
2.4.1 Align Labels to the Left

For each label, click the label then click the Common tab at the top right of Glade. Under the Alignment heading, select Start for both Horizontal and Vertical.

Label Alignment in Glade for Top Labels
Label Alignment in Glade for Top Labels
2.4.2 Make Label Text Bold

For each label, select the label and then click the Edit Attributes button under the General tab.

In the dialog box that pops up, click Weight to select it. Now click the Enter Value text next to Weight and select bold on the menu that pops out. Click OK to close the dialog box.

Make Label Text Bold in Glade and Change Label Color in GTK
Make Label Text Bold in Glade

2.5 Place a GtkBox for the Radio Buttons

In the open GtkGrid slot below the Place Bet, Then Toss Coin label, place a GtkBox. This will hold the three radio buttons. Leave it with default values of vertical and 3 items. Change the spacing to 5.

Place the Box for the Radio Buttons Below the First Text Label
Place the Box for the Radio Buttons Below the First Text Label

2.6 Place Radio Buttons

Although we only want two radio buttons, we need to place three radio buttons in order to have the two radio buttons appear to both be deselected.

Place a radio button in each of the 3 slots of the previously placed GtkBox under the Place Bet, Then Toss Coin text.

Change the radio button IDs and label text from top to bottom as follows.

IDrb_noneLabelnone
IDrb_headsLabelHeads
IDrb_tailsLabelTails
2.6.1 Group Radio Buttons

Select the Heads radio button. Click the pencil icon at the end of the Group box under Button Attributes of the General tab. In the dialog box that pops up, select the button at the left of rb_none to make this radio button part of the rb_none group. Click the OK button to close the dialog box.

Do the same for the Tails radio button, also making it part of the rb_none group.

2.6.2 Hide the Unused Radio Button

In order to have two deselected radio buttons, we make a group of three radio buttons and then hide one that is selected by default. In our application this is the none button.

Click the none button to select it. Click the Common tab at the top right of Glade. Under the Widget Flags heading, uncheck the Visible item.

The none radio button will not be invisible in Glade. It will only be invisible if previewing in Glade and when the application is run.

2.6.2 Add a Handler Function to the Heads and Tails Radio Buttons

Either the Heads or Tails radio button is selected by the player to place a bet. When this is done, the Toss Coin button must be enabled and the bet label updated. This requires a handler function for the ratio buttons.

Do the following for both the Heads and Tails radio buttons. Click the radio button to select it. Click the Signals tab at the top right of Glade. Expand the GtkToggleButton item by clicking the arrow at the left of it.

Find the toggled signal under GtkToggleButton. Add a handler called on_rb_heads_tails_toggled under the Handler heading. Use the same handler name for both radio buttons. No handler is attached to the “none” button.

2.7 Place Three Labels for Selected Bet and Results

Three labels must now be placed, each with an ID. They need IDs so that we can write to them in our C code. Place a label below the Your Bet text and one below Coin Toss Result. Place the third label in the next available open slot from the top.

2.7.1 Change ID and Text of Labels

These labels have the following IDs and label text from left to right, top to bottom.

IDlbl_your_betLabelHeads or Tails?
IDlbl_resultLabelHeads or Tails?
IDlbl_win_loseLabelWill You Win or Lose?
2.7.2 Change Label Alignment

For both lbl_your_bet and lbl_result, click the Common tab. Change both Horizontal and Vertical Alignment to Start.

2.7.3 Change Label Width and Height

Select the lbl_win_lose label. Click the Common tab. At the bottom of the right pane in Glade enable Width request and Height request by clicking the checkbox next to them. Change their values as follows.

Width request:200
Height request:40

These values are changed because in the C code we will change the font size. Without a preset width and height, the change in font size will also change the window size.

At this stage the window in Glade should look as follows.

Coin Toss Game in Glade as it Appears at this Stage in the Tutorial
Coin Toss Game in Glade as it Appears at this Stage in the Tutorial

2.8 Place a GtkBox for the Buttons

There is now only one open slot at the bottom of the window in Glade. This slot holds the two buttons, but has place for only one widget, so a GtkBox with two slots must first be placed in this open slot.

Place a GtkBox in the open slot and make the following changes.

OrientationHorizontal
Spacing50
HomogeneousChecked
Number of items2

2.9 Place Two Buttons

Place a GtkButton in each of the open slots of the GtkBox just placed. Change the IDs and labels of the two buttons as follows.

IDbtn_tossLabelToss Coin
IDbtn_play_againLabelPlay Again
2.9.1 Change Button Width and Alignment

Change the width of both buttons. Under the Common tab, change Width request to 200.

Now change Horizontal under the Alignment heading from Fill to Center for both buttons.

2.9.2 Add Button Signal Handlers

Do the following for both buttons. Select a button. Click the Signals tab at the right of Glade. Add a handler for the clicked signal as follows for each button.

Button IDHandler Name
btn_tosson_btn_toss_clicked
btn_play_againon_btn_play_again_clicked
2.9.3 Disable one Button and Hide the Other

By default, when the game is started, we want to hide the Play Again button. This is because we only want to see this button after tossing a coin for the first time.

Select the Play Again button in Glade. Hide the button by clicking the Common tab and then unchecking the Visible check box under Widget Flags.

We also want to disable the Toss Coin button in order to let the user first select either heads or tails.

Select the Toss Coin button in Glade. Disable the button by clicking the Common tab and then unchecking the Sensitive check box under Widget Flags.

3. Write the C Code

Open main.c from the src folder for editing. Add the code shown in the following listing.

main.c

#include <gtk/gtk.h>

typedef struct {
    // Radio Buttons
    GtkWidget *w_rb_none;
    GtkWidget *w_rb_heads;
    GtkWidget *w_rb_tails;
    // Labels
    GtkWidget *w_lbl_result;
    GtkWidget *w_lbl_win_lose;
    GtkWidget *w_lbl_your_bet;
    // Buttons
    GtkWidget *w_btn_toss;
    GtkWidget *w_btn_play_again;
} app_widgets;

int main(int argc, char *argv[])
{
    GtkBuilder      *builder; 
    GtkWidget       *window;
    app_widgets     *widgets = g_slice_new(app_widgets);

    gtk_init(&argc, &argv);

    builder = gtk_builder_new_from_file("glade/window_main.glade");

    // Get pointer to main window
    window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
    
    // Get pointers to widgets
    widgets->w_rb_none          = GTK_WIDGET(gtk_builder_get_object(builder, "rb_none"));
    widgets->w_rb_heads         = GTK_WIDGET(gtk_builder_get_object(builder, "rb_heads"));
    widgets->w_rb_tails         = GTK_WIDGET(gtk_builder_get_object(builder, "rb_tails"));
    widgets->w_lbl_result       = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_result"));
    widgets->w_lbl_win_lose     = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_win_lose"));
    widgets->w_lbl_your_bet     = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_your_bet"));
    widgets->w_btn_toss         = GTK_WIDGET(gtk_builder_get_object(builder, "btn_toss"));
    widgets->w_btn_play_again   = GTK_WIDGET(gtk_builder_get_object(builder, "btn_play_again"));
    
    gtk_builder_connect_signals(builder, widgets);
    g_object_unref(builder);
    gtk_widget_show(window);
    
    gtk_main();
    g_slice_free(app_widgets, widgets);

    return 0;
}

// Either "Heads" or "Tails" radio button clicked
void on_rb_heads_tails_toggled (GtkToggleButton *togglebutton, app_widgets *wdgts)
{
    // A radio button was selected, so enable the "Toss Coin" button
    gtk_widget_set_sensitive(wdgts->w_btn_toss, TRUE);
    
    // Find the selected radio button and update the selection in the text under "Your Bet:"
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wdgts->w_rb_heads))) {
        gtk_label_set_text(GTK_LABEL(wdgts->w_lbl_your_bet), "Heads");
    }
    else {
        gtk_label_set_text(GTK_LABEL(wdgts->w_lbl_your_bet), "Tails");
    }
}

// "Toss Coin" button clicked
void on_btn_toss_clicked(GtkButton *button, app_widgets *wdgts)
{
    gboolean result;    // Result of coin toss
    // Win and Lose text strings and settings
    // Win and Lose text strings and settings, change label color in GTK here
    gchar str_win[] = "<span foreground='green' weight='bold' font='14'>You Win!</span>";
    gchar str_lose[] = "<span foreground='red' weight='bold' font='14'>You Lose!</span>";
    
    // Toss the coin
    result = g_random_boolean();
    // Set the text to either "Heads" or "Tails" under the "Coin Toss Result:" heading
    if (result == TRUE) {
        gtk_label_set_text(GTK_LABEL(wdgts->w_lbl_result), "Heads");
    }
    else {
        gtk_label_set_text(GTK_LABEL(wdgts->w_lbl_result), "Tails");
    }
    
    // Determine if player won or lost the game, depending on bet placed
    if ((result == TRUE) && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wdgts->w_rb_heads))) {
        // Player bet on heads and coin toss resulted in heads
        gtk_label_set_markup (GTK_LABEL (wdgts->w_lbl_win_lose), str_win);
    }
    else if ((result == FALSE) && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wdgts->w_rb_tails))) {
        // Player bet on tails and coin toss resulted in tails
        gtk_label_set_markup (GTK_LABEL (wdgts->w_lbl_win_lose), str_win);
    }
    else {
        // Player lost the game
        gtk_label_set_markup (GTK_LABEL (wdgts->w_lbl_win_lose), str_lose);
    }
    
    // Show "Play Again" button
    gtk_widget_set_visible(wdgts->w_btn_play_again, TRUE);
    // Hide "Toss Coin" button
    gtk_widget_set_visible(wdgts->w_btn_toss, FALSE);
    // Disable "Toss Coin" buttons and radio buttons
    gtk_widget_set_sensitive(wdgts->w_btn_toss, FALSE);
    gtk_widget_set_sensitive(wdgts->w_rb_heads, FALSE);
    gtk_widget_set_sensitive(wdgts->w_rb_tails, FALSE);
}

// "Play Again" button clicked, so reset the game
void on_btn_play_again_clicked(GtkButton *button, app_widgets *wdgts)
{
    // Enable radio buttons
    gtk_widget_set_sensitive(wdgts->w_rb_heads, TRUE);
    gtk_widget_set_sensitive(wdgts->w_rb_tails, TRUE);
    // Select "none" radio button
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wdgts->w_rb_none), TRUE);
    // Hide "Play Again" button
    gtk_widget_set_visible(wdgts->w_btn_play_again, FALSE);
    // Reset labels
    gtk_label_set_text(GTK_LABEL(wdgts->w_lbl_your_bet), "Heads or Tails?");
    gtk_label_set_text(GTK_LABEL(wdgts->w_lbl_result), "Heads or Tails?");
    gtk_label_set_text(GTK_LABEL(wdgts->w_lbl_win_lose), "Will You Win or Lose?");
    // Show "Toss Coin" button
    gtk_widget_set_visible(wdgts->w_btn_toss, TRUE);
    // Disable "Toss Coin" buton
    gtk_widget_set_sensitive(wdgts->w_btn_toss, FALSE);
    
}

// Called when window is closed
void on_window_main_destroy()
{
    gtk_main_quit();
}

If you have been following the tutorial series, the code should mostly be self explanatory. Read the comments for the details. The only things expounded on are how to change label color in GTK, and how to show/hide and enable/disable widgets.

3.1 How to Change Label Color in GTK

Before we look at how to change label color in GTK C code, I would like to point out that this can also be done in Glade. If the label text color is changed in Glade, it can not be overwritten in the C code using the method shown in this tutorial. Because of this reason, be sure not to alter any of the label attributes in Glade.

3.1.1 How to Change Label Color in Glade

To change label text attributes in Glade, including label color, start by selecting the label and then clicking the General tab. Click the Edit Attributes button under the General tab. A dialog box pops up allowing the label color to be changed next to Foreground Color. Other font attributes can also be changed here. This is where we changed the font weight for the top three labels to bold.

3.1.2 How to Change Label Color in GTK C Code

Here we look at how to change label color in GTK C code, as well as other label attributes such as font weight and size. As already mentioned, attributes must not be changed in Glade if they must be changed programmatically in the C code.

The function gtk_label_set_markup can be used to set the color and other font attributes of a label. The most basic use of this function is to apply a HTML <span> tag to the label and then apply attributes inline CSS style. The following line of code demonstrates basic use of this function.

gtk_label_set_markup (GTK_LABEL (wdgts->w_lbl_win_lose), "<span foreground='green'>You Win!</span>");

In this code, our win/lose label is placed in a span tag and the foreground color changed to green.

Hexadecimal colors can be used instead, as follows.

gtk_label_set_markup (GTK_LABEL (wdgts->w_lbl_win_lose), "<span foreground='#00FF00'>You Win!</span>");

Other attributes such a font weight and size can also be changed by adding them to the span tag as shown in the next line of code.

gtk_label_set_markup (GTK_LABEL (wdgts->w_lbl_win_lose), "<span foreground='green' weight='bold' font='14'>You Win!</span>");

In the main.c code listing of this tutorial, the text and attributes were separated into strings and placed at the beginning of the Toss Coin button handler function. This was to make the code more readable and so that the “Win” string did not have to be repeated twice in the code. It is accessed in the “if” and “if else” constructs of the handler.

3.2 How to Enable and Disable Widgets in GTK

As can be seen in the main code listing, gtk_widget_set_sensitive is called to enable and disable widgets in the C code. Passing TRUE as the second parameter to this function enables a widget. Passing FALSE as the second parameter disables a widget. When a widget is disabled, it appears greyed out and won’t respond to mouse clicks.

As we already saw, a widget can be disabled by unchecking its Sensitive flag in Glade.

3.3 How to Show and Hide Widgets in GTK

Passing FALSE as the second parameter to gtk_widget_set_visible hides a widget. Passing TRUE as the second parameter to this function shows a widget.

A widget can be hidden by default in Glade by unchecking its Visible flag.

Development Tools

This project was developed using the following tools.

  • Linux Mint 19.2 Cinnamon 64-bit
  • Glade 3.22.1
  • GTK+ 3 library, version 3.22.30
  • gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0

Leave a Reply

Your email address will not be published. Required fields are marked *