Как избежать использования глобальной переменной указателя в моем приложении GTK3
Я создаю GTK3
ЧАТ приложение с C
В Linux ( Linux Mint 19 прямо сейчас) и я не могу понять, как избежать использования глобального (Label) указателя в том, как я проектировал всю программу.
Есть окно, в котором есть кнопка, запись и метка. Когда пользователь что-то набирает и нажимает клавишу Enter или нажимает кнопку, сообщение должно быть напечатано в разделе "Метка".
Все в порядке, за исключением того факта, что я использую глобальный указатель, чтобы обновить метку здесь, где я хотел бы ее избежать, и использую ее в функции сигнала.
Вот рабочий пример, который прекрасно компилируется и может быть протестирован:
#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 ответ
Отказ от ответственности: я никогда не использовал 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 );
...
}