Gtk стиль программирования: определение виджетов

#c #callback #gtk #widget

#c #обратный вызов #gtk #виджет

Вопрос:

Практически в каждом примере кода GTK , который я видел до сих пор, все виджеты графического интерфейса определены внутри функции main. Сначала я принял это, но затем обнаружил, что это очень неудобно, например, при управлении несколькими виджетами из одной функции обратного вызова. Конечно, я мог бы просто использовать для этого gpointer ‘data’, но разве мне не нужно было бы сначала обернуть каждый виджет, которым я хочу манипулировать, в какую-то структуру, чтобы передать его в качестве аргумента ‘data’?

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

Ответ №1:

Недостатки те же, что и при использовании любой глобальной переменной. На этой странице представлен хороший обзор ситуаций, когда не следует (и когда следует) использовать глобальные переменные. Если вы посмотрите ближе к низу, вы увидите раздел «Действительно плохие причины для использования глобальных переменных»:

Я не хочу постоянно передавать его.

Боюсь, это похоже на то, как звучит ваше возражение. Однако, как также упоминается на странице, на которую я ссылался, если вы просто пишете короткие или одноразовые программы, то простота использования глобальных переменных, вероятно, перевешивает недостатки.

Обычный способ в программах среднего размера — создать структуру, заполнить ее main() и передать обратным вызовам:

 typedef struct {
    GtkWidget *window, *button, *textfield;
} Widgets;

int main(int argc, char **argv) {
    gtk_init(amp;argc, amp;argv);
    Widgets *w = g_slice_new0(Widgets);
    w->window = gtk_window_new(... etc...
    ...
    g_signal_connect(w->button, "clicked", G_CALLBACK(on_clicked), w);
    ...etc...
    gtk_main();
    g_slice_free(Widgets, w);
    return 0;
}
  

В больших программах лучшим способом является создание собственных классов, представляющих основные окна, диалоговые окна настроек и т. Д., И передача этих классов различным обратным вызовам.

Комментарии:

1. Спасибо за ответ! Я думаю, в конце концов, самый простой способ сделать обе стороны счастливыми — это, как вы и предлагали, поместить каждый виджет с самого начала в одну большую структуру, а затем передавать ее каждый раз. (Хотя, что делать, если мне нужны как виджеты, так и идентификатор обработчика сигналов? Похоже, что виджеты всегда будут блокировать ‘gpointer userdata’)

2. Ничто не мешает вам также ввести идентификатор обработчика сигналов в структуру.