使用 GTK3 的虚拟 LED

Virtual LED using GTK3

我正在尝试使用 GTK3 制作虚拟 LED。 我不熟悉 GUI 编程。 不知道我的做法对不对。 无论如何,这是我到目前为止所做的:

// gcc ledgui.c `pkg-config --cflags gtk+-3.0 pkg-config --libs gtk+-3.0`

#include <stdint.h>
#include <stdbool.h>
#include <gtk/gtk.h>


#define LED_COLOR_RED       0
#define LED_COLOR_GREEN     1
#define LED_COLOR_YELLOW    2
#define LED_COLOR_OFF       3
#define LED_COLOR_COUNT     4

static GtkTextBuffer *buffer;
GtkTextTag *tagLed[LED_COLOR_COUNT];
uint8_t ledColorData[] = {0,0};

static void activate (GtkApplication* app, gpointer user_data);
static void SetGuiLedColor(int id, GtkTextTag *tag);
static void SetLedColorTags();
void Task_sleep_ms(int ms);

int main()
{
    GtkApplication *app;
    int status;

    app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    SetGuiLedColor(0, tagLed[LED_COLOR_RED]);
    // Task_sleep_ms(500);
    // SetGuiLedColor(0, tagLed[LED_COLOR_GREEN]);
    // Task_sleep_ms(500);
    status = g_application_run(G_APPLICATION(app), 0, NULL);

    g_object_unref(app);
}

static void activate (GtkApplication* app, gpointer user_data)
{
    GtkWidget *window;

    window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "LED");
    gtk_window_set_default_size(GTK_WINDOW(window), 200, 50);

    GtkWidget *view;
    GtkCssProvider *provider;
    GtkStyleContext *context;

    view = gtk_text_view_new();
    gtk_container_add (GTK_CONTAINER (window), view);
    gtk_widget_set_name (view, "led1");

    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
    gtk_text_buffer_set_text(buffer, "1 2 3 4\no o o o", -1);

    /* Change default font and color throughout the widget */
    provider = gtk_css_provider_new();
    gtk_css_provider_load_from_data(provider,
                                    "* {"
                                    " color: white;"
                                    " background-color: black;"
                                    " font: 20 monospace;"
                                    "}",
                                    -1,
                                    NULL);

    context = gtk_widget_get_style_context(view);
    gtk_style_context_add_provider(context,
                                   GTK_STYLE_PROVIDER(provider),
                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    /* Change left margin throughout the widget */
    gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 40);
    gtk_text_view_set_top_margin (GTK_TEXT_VIEW (view), 2);

    SetLedColorTags();
    // g_print ("Hello World\n");
    SetGuiLedColor(0, tagLed[LED_COLOR_YELLOW]);
    gtk_widget_show_all(window);
}

static void SetLedColorTags()
{
    int i;
    char *color[] = {"red", "green", "yellow", "black"};
    /* Use a tag to change the color for just one part of the widget */

    if (buffer == NULL)
    {
        printf("Error!! buffer is NULL\n");
        return;
    }
    for (i=0; i<LED_COLOR_COUNT; i++)
    {
        tagLed[i] = gtk_text_buffer_create_tag (buffer, color[i] /*tag name*/,
                            "foreground", color[i], NULL);  
    }
}

static void SetGuiLedColor(int id, GtkTextTag *tag)
{
    GtkTextIter start, end;
    int idStart, idEnd;
    idStart = id*2+8;
    idEnd = idStart+1;
    g_print ("LED color %p\n", tag);
    gtk_text_buffer_get_iter_at_offset (buffer, &start, idStart);
    gtk_text_buffer_get_iter_at_offset (buffer, &end, idEnd);
    gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
}

void Task_sleep_ms(int ms)
{
    printf("sleep %d ms\n", ms);
    usleep(ms * 1000);
}

我调用了 SetGuiLedColor 函数 3 次。 当我 运行 代码时,它只显示黄色。但我希望它依次显示黄色、红色和绿色。 我该怎么做?

谢谢亚历山大, 在您的帮助下,我编写了这段工作代码。如果有什么不对,你能告诉我吗?

// 

#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>

#define LED_COLOR_RED       0
#define LED_COLOR_GREEN     1
#define LED_COLOR_YELLOW    2
#define LED_COLOR_OFF       3
#define LED_COLOR_COUNT     4

char *color[] = {"red", "green", "yellow", "black"};
GtkWidget *ledLight;

void *LedControllerTask (void *vargp);
void *LedGuiThread (void *vargp);
void SetFontColors(GtkWidget *grid);
void updateLabel(GtkLabel *led, char* fcolor);
void Task_sleep_ms(int ms);

int main() 
{ 
    pthread_t thread_id; 
    pthread_t thread_id2; 

    // InitSemaphore();

    pthread_create(&thread_id2, NULL, LedControllerTask, NULL); 
    pthread_create(&thread_id, NULL, LedGuiThread, NULL); 
    pthread_join(thread_id2, NULL); 
    pthread_join(thread_id, NULL); 
    exit(0); 
}

void *LedControllerTask (void *vargp)
{
    Task_sleep_ms(1000);
    updateLabel(GTK_LABEL(ledLight), color[LED_COLOR_RED]);
    Task_sleep_ms(1000);
    updateLabel(GTK_LABEL(ledLight), color[LED_COLOR_GREEN]);
    Task_sleep_ms(1000);
    updateLabel(GTK_LABEL(ledLight), color[LED_COLOR_YELLOW]);

}

void *LedGuiThread (void *vargp)
{
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *ledLabel;
    int argc=0;
    char **argv=NULL;
    gtk_init (&argc,&argv);

    //Declarations
    window    = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "LED");
    grid      = gtk_grid_new ();

    SetFontColors(grid);

    ledLabel  = gtk_label_new ("1");
    ledLight  = gtk_label_new ("O");

    //Set Properties
    gtk_container_set_border_width (GTK_CONTAINER(window), 20);
    gtk_widget_set_size_request    (GTK_WIDGET(window), 200, 50);
    gtk_grid_set_row_spacing       (GTK_GRID(grid), 4);
    gtk_grid_set_column_spacing    (GTK_GRID(grid), 4);
    gtk_container_add              (GTK_CONTAINER(window), grid);

    //Fill the grid with shit                  (x, y, h, v)
    gtk_grid_attach (GTK_GRID(grid), ledLabel,       2, 2, 2, 1);
    gtk_grid_attach (GTK_GRID(grid), ledLight,       2, 3, 2, 1);

    gtk_widget_show_all (window);
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_main();
}

void SetFontColors(GtkWidget *grid)
{
    GtkCssProvider *provider;
    GtkStyleContext *context;

    /* Change default font and color throughout the widget */
    provider = gtk_css_provider_new();
    gtk_css_provider_load_from_data(provider,
                                    "* {"
                                    " color: white;"
                                    " background-color: black;"
                                    " font: 20px monospace;"
                                    "}",
                                    -1,
                                    NULL);

    context = gtk_widget_get_style_context(grid);
    gtk_style_context_add_provider(context,
                                   GTK_STYLE_PROVIDER(provider),
                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

}

void updateLabel(GtkLabel *led, char* fcolor)
{
    char text[256];
    // https://unix.stackexchange.com/questions/457584/gtk3-change-text-color-in-a-label-raspberry-pi
    snprintf(text, 256, "<span background=\"black\" foreground=\"%s\">O</span>", fcolor);
    gtk_label_set_markup (GTK_LABEL (led), text);
}

void Task_sleep_ms(int ms)
{
    printf("sleep %d ms\n", ms);
    usleep(ms * 1000);
}

根据 Alexander 的建议,我已将代码更新为 thread-safe。

// gcc ledgui.c `pkg-config --cflags gtk+-3.0 pkg-config --libs gtk+-3.0`

#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>

#define LED_COLOR_RED       0
#define LED_COLOR_GREEN     1
#define LED_COLOR_YELLOW    2
#define LED_COLOR_OFF       3
#define LED_COLOR_COUNT     4

char *color[] = {"red", "green", "yellow", "black"};
GtkWidget *ledLight;
GMutex mutex;
gchar ledText[256];

void *LedControllerTask (void *vargp);
void *LedGuiThread (void *vargp);
void SetFontColors(GtkWidget *grid);
gboolean updateLabel(gpointer data);
void Task_sleep_ms(int ms);
void SetTextColor(char* fcolor);

int main() 
{ 
    pthread_t thread_id; 
    pthread_t thread_id2; 

    pthread_create(&thread_id2, NULL, LedControllerTask, NULL); 
    pthread_create(&thread_id, NULL, LedGuiThread, NULL);

    {
        Task_sleep_ms(1000);
        while (1)
        {
            Task_sleep_ms(100);
            SetTextColor(color[LED_COLOR_GREEN]);
            g_idle_add(updateLabel, ledLight);
            Task_sleep_ms(100);
            SetTextColor(color[LED_COLOR_OFF]);
            g_idle_add(updateLabel, ledLight);
        }
    }
    pthread_join(thread_id2, NULL); 
    pthread_join(thread_id, NULL); 
    exit(0); 
}

void *LedControllerTask (void *vargp)
{
    Task_sleep_ms(1000);
    while (1)
    {
        Task_sleep_ms(100);
        SetTextColor(color[LED_COLOR_RED]);
        g_idle_add(updateLabel, ledLight);
        Task_sleep_ms(100);
        SetTextColor(color[LED_COLOR_OFF]);
        g_idle_add(updateLabel, ledLight);
    }
}

void *LedGuiThread (void *vargp)
{
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *ledLabel;
    int argc=0;
    char **argv=NULL;
    gtk_init (&argc,&argv);

    //Declarations
    window    = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "LED");
    grid      = gtk_grid_new ();

    SetFontColors(grid);

    ledLabel  = gtk_label_new ("1");
    ledLight  = gtk_label_new ("O");

    //Set Properties
    gtk_container_set_border_width (GTK_CONTAINER(window), 20);
    gtk_widget_set_size_request    (GTK_WIDGET(window), 200, 50);
    gtk_grid_set_row_spacing       (GTK_GRID(grid), 4);
    gtk_grid_set_column_spacing    (GTK_GRID(grid), 4);
    gtk_container_add              (GTK_CONTAINER(window), grid);

    //Fill the grid with shit                  (x, y, h, v)
    gtk_grid_attach (GTK_GRID(grid), ledLabel,       2, 2, 2, 1);
    gtk_grid_attach (GTK_GRID(grid), ledLight,       2, 3, 2, 1);

    gtk_widget_show_all (window);
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_main();
}

void SetFontColors(GtkWidget *grid)
{
    GtkCssProvider *provider;
    GtkStyleContext *context;

    /* Change default font and color throughout the widget */
    provider = gtk_css_provider_new();
    gtk_css_provider_load_from_data(provider,
                                    "* {"
                                    " color: white;"
                                    " background-color: black;"
                                    " font: 20px monospace;"
                                    "}",
                                    -1,
                                    NULL);

    context = gtk_widget_get_style_context(grid);
    gtk_style_context_add_provider(context,
                                   GTK_STYLE_PROVIDER(provider),
                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

}

gboolean updateLabel(gpointer data)
{
    char text[256];
    GtkLabel *led = data;
    g_mutex_lock (&mutex);
    strncpy(text, ledText, sizeof(text));
    g_mutex_unlock (&mutex);
    gtk_label_set_markup (GTK_LABEL (led), text);
}

void Task_sleep_ms(int ms)
{
    // printf("sleep %d ms\n", ms);
    usleep(ms * 1000);
}

void SetTextColor(char* fcolor)
{
    g_mutex_lock(&mutex);
    snprintf(ledText, 256, "<span background=\"black\" foreground=\"%s\">O</span>", fcolor);
    g_mutex_unlock(&mutex);
}

谢谢大卫!我已经更新了代码。看起来好多了。

// gcc ledgui.c `pkg-config --cflags gtk+-3.0 pkg-config --libs gtk+-3.0`

#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>

#define LED_COLOR_RED       0
#define LED_COLOR_GREEN     1
#define LED_COLOR_YELLOW    2
#define LED_COLOR_OFF       3
#define LED_COLOR_COUNT     4

char *color[] = {"red", "green", "yellow", "black"};
GtkWidget *ledLight;
GMutex mutex;
gchar ledText[256];

void *LedTask1 (void *vargp);
void *LedTask2 (void *vargp);
void LedGuiThread ();
void SetFontColors(GtkWidget *grid);
gboolean updateLabel(gpointer data);
void Task_sleep_ms(int ms);
void SetTextColor(char* fcolor);

int main() 
{ 
    pthread_t thread_id; 
    pthread_t thread_id2; 

    LedGuiThread();
    pthread_create(&thread_id2, NULL, LedTask1, NULL); 
    pthread_create(&thread_id, NULL, LedTask2, NULL);

    gtk_main();
    // pthread_join(thread_id2, NULL); 
    // pthread_join(thread_id, NULL); 
    exit(0); 
}

void *LedTask1 (void *vargp)
{
    while (1)
    {
        Task_sleep_ms(100);
        SetTextColor(color[LED_COLOR_RED]);
        g_idle_add(updateLabel, ledLight);
        Task_sleep_ms(100);
        SetTextColor(color[LED_COLOR_OFF]);
        g_idle_add(updateLabel, ledLight);
    }
}

void *LedTask2 (void *vargp)
{
    while (1)
    {
        Task_sleep_ms(100);
        SetTextColor(color[LED_COLOR_GREEN]);
        g_idle_add(updateLabel, ledLight);
        Task_sleep_ms(100);
        SetTextColor(color[LED_COLOR_OFF]);
        g_idle_add(updateLabel, ledLight);
    }
}

void LedGuiThread()
{
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *ledLabel;
    int argc=0;
    char **argv=NULL;
    gtk_init (&argc,&argv);

    //Declarations
    window    = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "LED");
    grid      = gtk_grid_new ();

    SetFontColors(grid);

    ledLabel  = gtk_label_new ("1");
    ledLight  = gtk_label_new ("O");

    //Set Properties
    gtk_container_set_border_width (GTK_CONTAINER(window), 20);
    gtk_widget_set_size_request    (GTK_WIDGET(window), 200, 50);
    gtk_grid_set_row_spacing       (GTK_GRID(grid), 4);
    gtk_grid_set_column_spacing    (GTK_GRID(grid), 4);
    gtk_container_add              (GTK_CONTAINER(window), grid);

    //Fill the grid with shit                  (x, y, h, v)
    gtk_grid_attach (GTK_GRID(grid), ledLabel,       2, 2, 2, 1);
    gtk_grid_attach (GTK_GRID(grid), ledLight,       2, 3, 2, 1);

    gtk_widget_show_all (window);
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
}

void SetFontColors(GtkWidget *grid)
{
    GtkCssProvider *provider;
    GtkStyleContext *context;

    /* Change default font and color throughout the widget */
    provider = gtk_css_provider_new();
    gtk_css_provider_load_from_data(provider,
                                    "* {"
                                    " color: white;"
                                    " background-color: black;"
                                    " font: 20px monospace;"
                                    "}",
                                    -1,
                                    NULL);

    context = gtk_widget_get_style_context(grid);
    gtk_style_context_add_provider(context,
                                   GTK_STYLE_PROVIDER(provider),
                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

}

gboolean updateLabel(gpointer data)
{
    char text[256];
    GtkLabel *led = data;
    g_mutex_lock (&mutex);
    strncpy(text, ledText, sizeof(text));
    g_mutex_unlock (&mutex);
    gtk_label_set_markup (GTK_LABEL (led), text);
}

void Task_sleep_ms(int ms)
{
    // printf("sleep %d ms\n", ms);
    usleep(ms * 1000);
}

void SetTextColor(char* fcolor)
{
    g_mutex_lock(&mutex);
    snprintf(ledText, 256, "<span background=\"black\" foreground=\"%s\">O</span>", fcolor);
    g_mutex_unlock(&mutex);
}