Create a Simple Stopwatch App Using GTK

CCBeginner
Practice Now

Introduction

In this project, we will create a simple stopwatch application using the GTK library in C. This stopwatch will have a start/pause button and a reset button to control the stopwatch timer. We will break down the process into several steps, starting with setting up the project files and ending with running the stopwatch application.

👀 Preview

Stopwatch

🎯 Tasks

In this project, you will learn:

  • How to install the GTK library
  • How to create the project files
  • How to include GTK headers and define variables
  • How to create the timer callback function
  • How to implement button click callbacks
  • How to create the main function and UI elements
  • How to compile and run the project

🏆 Achievements

After completing this project, you will be able to:

  • Use the GTK library to create a graphical user interface in C
  • Handle button click events in GTK
  • Work with timers in GTK
  • Update labels dynamically in GTK

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL c(("`C`")) -.-> c/UserInteractionGroup(["`User Interaction`"]) c(("`C`")) -.-> c/BasicsGroup(["`Basics`"]) c(("`C`")) -.-> c/ControlFlowGroup(["`Control Flow`"]) c(("`C`")) -.-> c/CompoundTypesGroup(["`Compound Types`"]) c(("`C`")) -.-> c/PointersandMemoryGroup(["`Pointers and Memory`"]) c(("`C`")) -.-> c/FunctionsGroup(["`Functions`"]) c/UserInteractionGroup -.-> c/output("`Output`") c/BasicsGroup -.-> c/comments("`Comments`") c/BasicsGroup -.-> c/variables("`Variables`") c/BasicsGroup -.-> c/data_types("`Data Types`") c/BasicsGroup -.-> c/operators("`Operators`") c/ControlFlowGroup -.-> c/if_else("`If...Else`") c/ControlFlowGroup -.-> c/break_continue("`Break/Continue`") c/CompoundTypesGroup -.-> c/arrays("`Arrays`") c/CompoundTypesGroup -.-> c/strings("`Strings`") c/PointersandMemoryGroup -.-> c/memory_address("`Memory Address`") c/PointersandMemoryGroup -.-> c/pointers("`Pointers`") c/FunctionsGroup -.-> c/function_parameters("`Function Parameters`") c/FunctionsGroup -.-> c/function_declaration("`Function Declaration`") subgraph Lab Skills c/output -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/comments -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/variables -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/data_types -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/operators -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/if_else -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/break_continue -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/arrays -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/strings -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/memory_address -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/pointers -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/function_parameters -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} c/function_declaration -.-> lab-298824{{"`Create a Simple Stopwatch App Using GTK`"}} end

Create the Project Files

First, make sure you have the GTK library installed on your system, if not, you can use the following command to install it:

sudo apt-get install libgtk-3-dev

Next, create a new file named stopwatch.c and open it in your preferred code editor.

cd ~/project
touch stopwatch.c

Include GTK Headers and Define Variables

In this step, we will include the necessary GTK headers and define variables for our stopwatch application.

#include <gtk/gtk.h>

static guint timer_id = 0;
static gboolean running = FALSE;
static int elapsed_seconds = 0;

static GtkWidget *label;
  • #include <gtk/gtk.h>: This contains the GTK library header files for using GTK functions and data structures in your program.
  • static guint timer_id = 0;: This is a variable used to store the ID of the GTK timer. The timer ID is used in the following code to control the start and stop of the timer.
  • static gboolean running = FALSE;: This is a Boolean variable used to track whether the stopwatch is running. running is TRUE when the stopwatch is running and FALSE when the stopwatch is paused.
  • static int elapsed_seconds = 0;: This is an integer variable used to track the number of seconds passed. It is used to calculate the elapsed time and displays the stopwatch time on the label.
  • static GtkWidget *label;: This is a pointer to store the GTK tag widget. This TAB displays the time of the stopwatch.

Create the Timer Callback Function

Next, we'll create a callback function that updates the stopwatch timer every second.

static gboolean timer_callback(gpointer data) {
    if (running) {
        elapsed_seconds++;
        int minutes = elapsed_seconds / 60;
        int seconds = elapsed_seconds % 60;
        char time_str[10];
        snprintf(time_str, sizeof(time_str), "%02d:%02d", minutes, seconds);
        gtk_label_set_text(GTK_LABEL(label), time_str);
    }
    return G_SOURCE_CONTINUE;
}
  • elapsed_seconds++: If the stopwatch is running, the value of the elapsed_seconds variable is increased, indicating that the number of seconds passed has increased by 1 second.
  • Since one minute is equal to 60 seconds, we divide elapsed_seconds by 60 to get the number of minutes. The number of seconds less than one minute can be obtained by using the redundant operator %.
  • Use the snprintf function to format the minutes and seconds as a string in the format mm:ss, where %02d means two digits for minutes and seconds, and any less than two digits are filled with leading zeros.
  • gtk_label_set_text sets the just-generated time string to the text of the label part to update the stopwatch display.
  • return G_SOURCE_CONTINUEtells the GTK timer to continue the timer after the callback completes so that the next timer event is triggered again. If the callback returns G_SOURCE_REMOVE, the timer stops.

In summary, the timer_callback function is responsible for dynamically updating the stopwatch time by incrementing the number of seconds passed while the stopwatch is running, formatting the minutes and seconds as a string, and then setting it to the text of the tag widget.

Implement Button Click Callbacks

We need callback functions for the Start/Pause and Reset buttons.

static void start_stop_button_clicked(GtkButton *button, gpointer data) {
    running = !running;
    if (running) {
        gtk_button_set_label(button, "Pause");
    } else {
        gtk_button_set_label(button, "Start");
    }
}

static void reset_button_clicked(GtkButton *button, gpointer data) {
    elapsed_seconds = 0;
    gtk_label_set_text(GTK_LABEL(label), "00:00");
}
  • start_stop_button_clicked toggles the stopwatch state between running and paused.
  • reset_button_clicked resets the stopwatch timer.

Create the Main Function and UI Elements

Now, let's create the main function and set up the user interface.

int main(int argc, char *argv[]) {
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *start_stop_button;
    GtkWidget *reset_button;

    gtk_init(&argc, &argv); // Initialize GTK

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Stopwatch"); // Set the window title
    gtk_window_set_default_size(GTK_WINDOW(window), 200, 200); // Set the default window size
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); // Connect the window close event

    grid = gtk_grid_new(); // Create a grid layout
    gtk_container_add(GTK_CONTAINER(window), grid); // Add the grid to the window

    label = gtk_label_new("00:00"); // Create a GTK label initially displaying "00:00"
    gtk_widget_set_hexpand(label, TRUE); // Allow the label to expand horizontally
    gtk_widget_set_vexpand(label, TRUE); // Allow the label to expand vertically
    gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1); // Add the label to the grid

    start_stop_button = gtk_button_new_with_label("Start"); // Create a button with the label "Start"
    gtk_widget_set_hexpand(start_stop_button, TRUE); // Allow the button to expand horizontally
    gtk_widget_set_vexpand(start_stop_button, TRUE); // Allow the button to expand vertically
    g_signal_connect(G_OBJECT(start_stop_button), "clicked", G_CALLBACK(start_stop_button_clicked), NULL); // Connect the button click event
    gtk_grid_attach(GTK_GRID(grid), start_stop_button, 0, 1, 1, 1); // Add the button to the grid

    reset_button = gtk_button_new_with_label("Reset"); // Create a button with the label "Reset"
    gtk_widget_set_hexpand(reset_button, TRUE); // Allow the button to expand horizontally
    gtk_widget_set_vexpand(reset_button, TRUE); // Allow the button to expand vertically
    g_signal_connect(G_OBJECT(reset_button), "clicked", G_CALLBACK(reset_button_clicked), NULL); // Connect the button click event
    gtk_grid_attach(GTK_GRID(grid), reset_button, 0, 2, 1, 1); // Add the button to the grid

    gtk_widget_show_all(window); // Show the window and all its child widgets

    timer_id = g_timeout_add(1000, timer_callback, NULL); // Create a timer that triggers every 1000 ms (1 second) and calls timer_callback

    gtk_main(); // Start the GTK main event loop

    return 0;
}
  • The main function sets up the GTK window, labels, buttons, and their click event handlers.

Compile and Run the Project

Now that we've created the stopwatch application, let's compile and run it.

  1. Open your terminal and navigate to the project directory.
cd ~/project
  1. Compile the code using the following command:
gcc -o stopwatch stopwatch.c $(pkg-config --cflags --libs gtk+-3.0)
  1. Run the application:
./stopwatch

You should see a window with the stopwatch. Click the Start button to begin the timer, Pause to pause it, and Reset to reset the timer.

Stopwatch

Summary

In this project, we created a simple stopwatch application using the GTK library in C. We set up project files, defined variables, implemented a timer callback function, and created button click callbacks. The application allows you to start, pause, and reset the stopwatch timer, and you can run it by compiling the code and executing the resulting program.

Other C Tutorials you may like