Как избежать использования глобальной переменной указателя в моем приложении GTK3 - PullRequest
2 голосов
/ 07 июня 2019

Я создаю GTK3 приложение ЧАТ с C В Linux (Linux mint 19 прямо сейчас), и я не могу понять, как избежать использования глобального (Label) указателя в том, как я проектировалвся программа.

Есть окно, в котором есть кнопка, запись и метка.Когда пользователь что-то набирает и нажимает клавишу Enter или нажимает кнопку, сообщение должно быть напечатано в разделе «Метка».

Все в порядке, кроме того факта, что я использую глобальный указатель для обновления метки здесь, гдеЯ хотел бы избежать этого и использовать его в функции Signal.

Вот рабочий пример, который прекрасно компилируется и может быть протестирован:

#include <gtk/gtk.h>

GtkWidget *label;

static void display ( GtkWidget *widget, GtkWidget *data )
{
    (void)widget;
    const gchar *const buffer = gtk_entry_get_text ( GTK_ENTRY ( data ) );

    if ( strlen ( buffer ) > 0 )
    {
        g_print ( "%s\n", buffer );
        gtk_label_set_text ( GTK_LABEL ( label ), buffer );
    }

    gtk_entry_set_text          ( GTK_ENTRY ( data ), "" );
    gtk_editable_select_region  ( GTK_EDITABLE ( data ), 0, -1 );
    gtk_editable_copy_clipboard ( GTK_EDITABLE ( data ) );
}

GtkWidget *createWind   ( void );
GtkWidget *createGrid   ( GtkWidget *window );
GtkWidget *createButton ( GtkWidget *grid, const gint left, const gint top, const gint width, const gint height );
GtkWidget *createEntry  ( GtkWidget *grid, const gint left, const gint top, const gint width, const gint height );
GtkWidget *createLabel  ( GtkWidget *grid, const gint left, const gint top, const gint width, const gint height );

int main ( void )
{
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *entry;

    GtkWidget *button;
    gtk_init ( NULL, NULL );

    window = createWind ();
    gtk_widget_show ( window );

    grid = createGrid ( window );
    gtk_widget_show ( grid );

    entry = createEntry ( grid, 0, 1, 1, 1 );
    gtk_widget_show ( entry );

    button = createButton ( grid, 1, 1, 1, 1 );
    gtk_widget_show ( button );

    label = createLabel ( grid, 0, 0, 1, 1 );
    gtk_widget_show ( label );

    g_signal_connect ( button, "clicked",  G_CALLBACK ( display ), entry );
    g_signal_connect ( entry,  "activate", G_CALLBACK ( display ), entry );
    //gtk_widget_show_all ( window );
    gtk_main();
}

GtkWidget *createWind ( void )
{
    GdkRectangle display = { 0 };
    GtkWidget *window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
    gdk_monitor_get_workarea ( gdk_display_get_primary_monitor ( gdk_display_get_default() ), &display );
    gtk_window_move ( GTK_WINDOW ( window ), display.width, display.height );
    gtk_window_set_title ( GTK_WINDOW ( window ), "MyApp" );
    gtk_window_set_default_size ( GTK_WINDOW ( window ), 850, 100 );
    gtk_window_set_resizable ( GTK_WINDOW ( window ), FALSE );
    gtk_container_set_border_width ( GTK_CONTAINER ( window ), 5 );
    g_signal_connect ( window, "destroy", G_CALLBACK ( gtk_main_quit ), NULL );
    return window;
}

GtkWidget *createGrid ( GtkWidget *window )
{
    GtkWidget *grid = gtk_grid_new();
    gtk_widget_set_name ( grid, "Grid" );
    gtk_container_add ( GTK_CONTAINER ( window ), grid );
    return grid;
}

GtkWidget *createEntry ( GtkWidget *grid, const gint left, const gint top, const gint width, const gint height )
{
    GtkWidget *entry = gtk_entry_new();
    gtk_widget_set_name ( grid, "Entry" );
    gtk_widget_set_size_request ( entry, 800, 50 );
    g_object_set ( entry, "margin", 22, NULL );
    gtk_grid_attach ( GTK_GRID ( grid ), entry, left, top, width, height );
    return entry;
}

GtkWidget *createLabel ( GtkWidget *grid, const gint left, const gint top, const gint width, const gint height )
{
    GtkWidget *ret = gtk_label_new ( "Type a Message" );
    gtk_widget_set_name ( ret, "Label" );
    gtk_widget_set_size_request ( ret, 850, 250 );
    gtk_label_set_justify ( GTK_LABEL ( ret ), GTK_JUSTIFY_CENTER );
    gtk_grid_attach ( GTK_GRID ( grid ), ret, left, top, width, height );
    return ret;
}

GtkWidget *createButton ( GtkWidget *grid, const gint left, const gint top, const gint width, const gint height )
{
    GtkWidget *button = gtk_button_new_with_mnemonic ( "Send" );
    gtk_widget_set_name ( button, "Button" );
    gtk_widget_set_size_request ( button, 50, 50 );
    g_object_set ( button, "margin", 22, NULL );
    gtk_grid_attach ( GTK_GRID ( grid ), button, left, top, width, height );
    return button;
}

1 Ответ

2 голосов
/ 07 июня 2019

Отказ от ответственности: я никогда не использовал GTK и не могу на самом деле проверить свой код. Нижеследующее основано на кратком прочтении документации.

Последним аргументом вашего обратного вызова сигнала может быть что угодно (если это указатель).

Следовательно, вы должны быть в состоянии передать как запись, так и метку через этот параметр, например, объединяя все данные в пользовательскую структуру.

Сама структура может быть локальной переменной в main, адрес которой передается обратному вызову, который затем может восстановить содержимое по мере необходимости.

Например:

struct EntryLabelPair {
    GtkWidget *entry;
    GtkWidget *label;
};

static void display ( GtkWidget *widget, gpointer *data )
{
    (void)widget;
    struct EntryLabelPair *pair = data;
    const gchar *const buffer = gtk_entry_get_text ( GTK_ENTRY ( pair->entry ) );

    if ( strlen ( buffer ) > 0 )
    {
        g_print ( "%s\n", buffer );
        gtk_label_set_text ( GTK_LABEL ( pair->label ), buffer );
    }

    gtk_entry_set_text          ( GTK_ENTRY ( pair->entry ), "" );
    gtk_editable_select_region  ( GTK_EDITABLE ( pair->entry ), 0, -1 );
    gtk_editable_copy_clipboard ( GTK_EDITABLE ( pair->entry ) );
}

...

int main ( void )
{
    GtkWidget *window;
    GtkWidget *grid;
    struct EntryLabelPair pair;

    ...

    pair.entry = createEntry ( grid, 0, 1, 1, 1 );
    gtk_widget_show ( pair.entry );

    pair.label = createLabel ( grid, 0, 0, 1, 1 );
    gtk_widget_show ( pair.label );

    g_signal_connect ( button, "clicked",  G_CALLBACK ( display ), &pair );
    g_signal_connect ( entry,  "activate", G_CALLBACK ( display ), &pair );

    ...
}
...