Virtuelle LED mit GTK3

Sep 16 2020

Ich versuche mit GTK3 eine virtuelle LED zu erstellen. Ich bin nicht mit der GUI-Programmierung vertraut. Ich weiß nicht, ob mein Ansatz richtig ist. Jedenfalls habe ich das bisher getan:

// 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);
}

Ich rufe die SetGuiLedColorFunktion 3 mal auf. Wenn ich den Code ausführe, wird nur GELB angezeigt. Aber ich hoffe, es wird nacheinander GELB, ROT und dann GRÜN angezeigt. Wie kann ich es tun?

Antworten

YoungminKim Sep 17 2020 at 10:17

Danke Alexander, mit deiner Hilfe habe ich diesen Arbeitscode geschrieben. Könnten Sie mir raten, wenn etwas nicht stimmt?

// https://stackoverflow.com/questions/26429173/getting-a-gtk-label-to-dislay-an-int-in-c

#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);
}

YoungminKim Sep 23 2020 at 06:09

Nach dem Rat von Alexander habe ich den Code auf thread-safe aktualisiert.

// 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);
}

Danke David!. Ich habe den Code aktualisiert. Es sieht viel besser aus.

// 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);
}