cgtkglade

Changing background color of GtkEntry


I have written a C language program with many GtkEntry's for data input. I have created the UI using Glade and the GtkEntrys emit an on_entry#_changed() signal when modified. My program checks the validity of the input, which has certain requirements. e.g., must be valid hexadecimal.

I would like the background of a GtkEntry to go red while it is invalid, and turn back to the original color when acceptable. The original color is dependent upon the desktop style set by the user. For example, on Ubuntu, I'm using a "Dark" style, so the box is dark gray.

What is the best way to implement this background color switching so that it applies to an individual GtkEntry and renders the user's chosen style color when the data is ok? I see a lot of discussion out there but it is often using deprecated functions.


Solution

  • You can use the error style class to mark the entry as having error. The following is a minimal example that checks if an entry has a valid hex digit and updates the entry style:

    /* main.c
     *
     * Compile: cc -ggdb main.c -o main $(pkg-config --cflags --libs gtk+-3.0) -o main
     * Run: ./main
     *
     * Author: Mohammed Sadiq <www.sadiqpk.org>
     *
     * SPDX-License-Identifier: LGPL-2.1-or-later OR CC0-1.0
     */
    
    #include <gtk/gtk.h>
    
    static void
    entry_changed_cb (GtkEntry *entry)
    {
      GtkStyleContext *style;
      const char *text;
      gboolean empty;
    
      g_assert (GTK_IS_ENTRY (entry));
    
      style = gtk_widget_get_style_context (GTK_WIDGET (entry));
      text = gtk_entry_get_text (entry);
      empty = !*text;
    
      /* Loop until we reach an invalid hex digit or the end of the string */
      while (g_ascii_isxdigit (*text))
        text++;
    
      if (empty || *text)
        gtk_style_context_add_class (style, "error");
      else
        gtk_style_context_remove_class (style, "error");
    }
    
    static void
    app_activated_cb (GtkApplication *app)
    {
      GtkWindow *window;
      GtkWidget *entry;
    
      window = GTK_WINDOW (gtk_application_window_new (app));
    
      entry = gtk_entry_new ();
      gtk_widget_set_halign (entry, GTK_ALIGN_CENTER);
      gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
      gtk_widget_show (entry);
      gtk_container_add (GTK_CONTAINER (window), entry);
    
      g_signal_connect_object (entry, "changed",
                               G_CALLBACK (entry_changed_cb),
                               app, G_CONNECT_AFTER);
      entry_changed_cb (GTK_ENTRY (entry));
    
      gtk_window_present (window);
    }
    
    int
    main (int   argc,
          char *argv[])
    {
      g_autoptr(GtkApplication) app = gtk_application_new (NULL, 0);
    
      g_signal_connect (app, "activate", G_CALLBACK (app_activated_cb), NULL);
    
      return g_application_run (G_APPLICATION (app), argc, argv);
    }