2013-07-31 2 views
3

Я заметил, что Glade позволяет вам устанавливать объект, который должен быть передан в пользовательской части данных обратного вызова GTK.GTK передает пользовательские данные для обратного вызова с использованием Glade

Можно ли каким-либо образом передать целочисленное значение?

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

Примечание: Все мои сигналы настраиваются автоматически с помощью glade_xml_signal_autoconnect, и я бы просил сохранить его таким образом.

ответ

4

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

Я привык передать структуру с именем App ко всем обратным вызовам, содержащим указатель на каждый элемент ui, который загружается из файла определений ui и уже создан экземпляром GtkBuilder. Это также останавливает утомительную задачу в glade щелчка назад и вперед между виджетами только для настройки пользовательских данных обратных вызовов. В дополнение к элементам ui большую часть времени эта структура содержит дополнительные элементы, которые важны во время выполнения на уровне приложения.

Преимущество такого подхода заключается в том, что у вас не возникает соблазнов подумать о том, как реализовать индивидуальный обратный вызов, который должен действовать более чем на один элемент, что часто бывает. Некоторые люди занимаются этим, группируя интересующие виджеты в контейнер. Чтобы передать все виджеты на обратный вызов, они просто передают контейнер. Затем в обратном вызове они получают виджетов, вызывая gtk_container_get_children или аналогичные функции. Такой подход делает обратные вызовы неразборчивыми и уменьшает удовольствие при редактировании кода.

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

Далее я создал вспомогательный макрос, который определяет указатель на уже созданный элемент с именем его идентификатора поляризации. Таким образом, определения элементов в коде всегда синхронизируются с теми, которые отображаются на поляне. Это упрощает переименование виджетов (замените имя во всех источниках + файл glade).

Для иллюстрации этого подхода у меня есть прилагаемые файлы примерной программы. Не бойтесь количества файлов. Разделение программы на логические единицы/модули упрощает программирование. Чтобы получить быстрый просмотр всего проекта я создал репозиторий на GitHub:

https://github.com/o8i12398z12h9h/gtk-sample-app

Просто сравните мой callbacks.c с файлом (ами) обратного вызова. Мне было бы интересно узнать, как они сравниваются с разборчивостью и структурой и с учетом того, что у вас могут быть элементы-идентификаторы от glade.


callbacks.c:

#include "app.h" 

void 
button1_clicked_cb (GtkButton * button, App * app) 
{ 
    GET_UI_ELEMENT (GtkEntry, entry1); 

    if (gtk_entry_get_text_length (entry1) == 0) 
     gtk_entry_set_text (entry1, "test"); 
    else 
     gtk_entry_set_text (entry1, ""); 
} 

void 
button2_clicked_cb (GtkButton * button, App * app) 
{ 
    gboolean active; 

    GET_UI_ELEMENT (GtkSpinner, spinner1); 
    GET_UI_ELEMENT (GtkWidget, eventbox1); 

    g_object_get (G_OBJECT (spinner1), "active", &active, 
        NULL); 

    if (active) { 
     gtk_spinner_stop (spinner1); 
     gtk_widget_override_background_color (eventbox1, 
               GTK_STATE_FLAG_NORMAL, 
               app-> 
               active_color); 
    } 
    else { 
     gtk_spinner_start (spinner1); 
     gtk_widget_override_background_color (eventbox1, 
               GTK_STATE_FLAG_NORMAL, 
               app-> 
               inactive_color); 
    } 
} 

void 
button3_clicked_cb (GtkButton * button, App * app) 
{ 
    GdkRGBA bg = { 0, 0, 1, 1 }; 

    GET_UI_ELEMENT (GtkWidget, eventbox1); 

    gtk_widget_override_background_color (eventbox1, 
              GTK_STATE_FLAG_NORMAL, 
              &bg); 
} 

void 
button4_clicked_cb (GtkButton * button, App * app) 
{ 
    const gchar *str; 

    GET_UI_ELEMENT (GtkLabel, label1); 

    str = gtk_label_get_text (label1); 

    if (strcmp (str, "label") == 0) { 
     gtk_label_set_text (label1, "NewText"); 
    } 
    else { 
     gtk_label_set_text (label1, "label"); 
    } 
} 

void 
button5_clicked_cb (GtkButton * button, App * app) 
{ 
    GET_UI_ELEMENT (GtkWidget, button1); 
    GET_UI_ELEMENT (GtkWidget, button2); 
    GET_UI_ELEMENT (GtkWidget, button4); 

    g_signal_emit_by_name (button1, "clicked", app); 
    g_signal_emit_by_name (button2, "clicked", app); 
    g_signal_emit_by_name (button4, "clicked", app); 
} 

main.c:

#include "app.h" 

int 
main (int argc, char *argv[]) 
{ 
    App *app; 

    app = (App *) g_new (App, 1); 

    gtk_init (&argc, &argv); 

    app_init (app); 

    GET_UI_ELEMENT (GtkWidget, window1); 

    gtk_widget_show_all (window1); 

    gtk_main(); 

    return 0; 
} 

app.c:

#include "app.h" 

GObject * 
app_get_ui_element (App * app, const gchar * name) 
{ 
    const gchar *s; 
    GSList *list; 

    list = app->objects; 

    do { 
     s = gtk_buildable_get_name (list->data); 

     if (strcmp (s, name) == 0) { 
      return list->data; 
     } 

    } while (list = g_slist_next (list)); 

    return NULL; 
} 

void 
app_init_colors (App * app) 
{ 
    GdkRGBA active_color = { 1, 0, 0, 1 }; 
    GdkRGBA inactive_color = { 0, 1, 0, 1 }; 

    app->active_color = g_new0 (GdkRGBA, 1); 
    app->inactive_color = g_new0 (GdkRGBA, 1); 

    app->active_color = gdk_rgba_copy (&active_color); 
    app->inactive_color = gdk_rgba_copy (&inactive_color); 
} 


void 
app_init (App * app) 
{ 
    GError *err = NULL; 

    app->definitions = gtk_builder_new(); 

    gtk_builder_add_from_file (app->definitions, 
           UI_DEFINITIONS_FILE, &err); 

    if (err != NULL) { 
     g_printerr 
      ("Error while loading app definitions file: %s\n", 
      err->message); 
     g_error_free (err); 
     gtk_main_quit(); 
    } 

    gtk_builder_connect_signals (app->definitions, app); 

    app->objects = gtk_builder_get_objects (app->definitions); 

    app_init_colors (app); 
} 

app.h:

#ifndef __APP__ 
#define __APP__ 

#include <gtk/gtk.h> 

#define UI_DEFINITIONS_FILE "ui.glade" 

#define GET_UI_ELEMENT(TYPE, ELEMENT) TYPE *ELEMENT = (TYPE *) \ 
              app_get_ui_element(app, #ELEMENT); 

typedef struct app_ 
{ 
    GtkBuilder *definitions; 
    GSList *objects; 

    GdkRGBA *active_color; 
    GdkRGBA *inactive_color; 

} App; 

void app_init (App *); 
GObject * app_get_ui_element (App * , const gchar *); 

#endif 

ui.glade:

<?xml version="1.0" encoding="UTF-8"?> 
<interface> 
    <!-- interface-requires gtk+ 3.0 --> 
    <object class="GtkWindow" id="window1"> 
    <property name="can_focus">False</property> 
    <property name="border_width">20</property> 
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/> 
    <child> 
     <object class="GtkGrid" id="grid1"> 
     <property name="visible">True</property> 
     <property name="can_focus">False</property> 
     <property name="row_spacing">10</property> 
     <property name="column_spacing">20</property> 
     <child> 
      <object class="GtkSpinner" id="spinner1"> 
      <property name="visible">True</property> 
      <property name="can_focus">False</property> 
      </object> 
      <packing> 
      <property name="left_attach">1</property> 
      <property name="top_attach">1</property> 
      <property name="width">2</property> 
      <property name="height">1</property> 
      </packing> 
     </child> 
     <child> 
      <object class="GtkEventBox" id="eventbox1"> 
      <property name="height_request">50</property> 
      <property name="visible">True</property> 
      <property name="can_focus">False</property> 
      <child> 
       <placeholder/> 
      </child> 
      </object> 
      <packing> 
      <property name="left_attach">1</property> 
      <property name="top_attach">2</property> 
      <property name="width">2</property> 
      <property name="height">1</property> 
      </packing> 
     </child> 
     <child> 
      <object class="GtkEntry" id="entry1"> 
      <property name="visible">True</property> 
      <property name="can_focus">True</property> 
      <property name="invisible_char">•</property> 
      <property name="invisible_char_set">True</property> 
      </object> 
      <packing> 
      <property name="left_attach">1</property> 
      <property name="top_attach">0</property> 
      <property name="width">2</property> 
      <property name="height">1</property> 
      </packing> 
     </child> 
     <child> 
      <object class="GtkLabel" id="label1"> 
      <property name="visible">True</property> 
      <property name="can_focus">False</property> 
      <property name="label" translatable="yes">label</property> 
      </object> 
      <packing> 
      <property name="left_attach">1</property> 
      <property name="top_attach">3</property> 
      <property name="width">2</property> 
      <property name="height">1</property> 
      </packing> 
     </child> 
     <child> 
      <object class="GtkButtonBox" id="buttonbox1"> 
      <property name="visible">True</property> 
      <property name="can_focus">False</property> 
      <property name="spacing">10</property> 
      <property name="layout_style">center</property> 
      <child> 
       <object class="GtkButton" id="button1"> 
       <property name="label" translatable="yes">toggle entry</property> 
       <property name="use_action_appearance">False</property> 
       <property name="visible">True</property> 
       <property name="can_focus">True</property> 
       <property name="receives_default">True</property> 
       <property name="use_action_appearance">False</property> 
       <signal name="clicked" handler="button1_clicked_cb" swapped="no"/> 
       </object> 
       <packing> 
       <property name="expand">False</property> 
       <property name="fill">True</property> 
       <property name="position">0</property> 
       </packing> 
      </child> 
      <child> 
       <object class="GtkButton" id="button2"> 
       <property name="label" translatable="yes">toggle spinner + bg</property> 
       <property name="use_action_appearance">False</property> 
       <property name="visible">True</property> 
       <property name="can_focus">True</property> 
       <property name="receives_default">True</property> 
       <property name="use_action_appearance">False</property> 
       <signal name="clicked" handler="button2_clicked_cb" swapped="no"/> 
       </object> 
       <packing> 
       <property name="expand">False</property> 
       <property name="fill">True</property> 
       <property name="position">1</property> 
       </packing> 
      </child> 
      <child> 
       <object class="GtkButton" id="button3"> 
       <property name="label" translatable="yes">set bg</property> 
       <property name="use_action_appearance">False</property> 
       <property name="visible">True</property> 
       <property name="can_focus">True</property> 
       <property name="receives_default">True</property> 
       <property name="use_action_appearance">False</property> 
       <signal name="clicked" handler="button3_clicked_cb" swapped="no"/> 
       </object> 
       <packing> 
       <property name="expand">False</property> 
       <property name="fill">True</property> 
       <property name="position">2</property> 
       </packing> 
      </child> 
      <child> 
       <object class="GtkButton" id="button4"> 
       <property name="label" translatable="yes">toggle label</property> 
       <property name="use_action_appearance">False</property> 
       <property name="visible">True</property> 
       <property name="can_focus">True</property> 
       <property name="receives_default">True</property> 
       <property name="use_action_appearance">False</property> 
       <signal name="clicked" handler="button4_clicked_cb" swapped="no"/> 
       </object> 
       <packing> 
       <property name="expand">False</property> 
       <property name="fill">True</property> 
       <property name="position">3</property> 
       </packing> 
      </child> 
      <child> 
       <object class="GtkButton" id="button5"> 
       <property name="label" translatable="yes">toggle everything</property> 
       <property name="use_action_appearance">False</property> 
       <property name="visible">True</property> 
       <property name="can_focus">True</property> 
       <property name="receives_default">True</property> 
       <property name="use_action_appearance">False</property> 
       <signal name="clicked" handler="button5_clicked_cb" swapped="no"/> 
       </object> 
       <packing> 
       <property name="expand">False</property> 
       <property name="fill">True</property> 
       <property name="position">4</property> 
       </packing> 
      </child> 
      </object> 
      <packing> 
      <property name="left_attach">0</property> 
      <property name="top_attach">5</property> 
      <property name="width">4</property> 
      <property name="height">1</property> 
      </packing> 
     </child> 
     <child> 
      <object class="GtkSeparator" id="separator1"> 
      <property name="visible">True</property> 
      <property name="can_focus">False</property> 
      </object> 
      <packing> 
      <property name="left_attach">0</property> 
      <property name="top_attach">4</property> 
      <property name="width">4</property> 
      <property name="height">1</property> 
      </packing> 
     </child> 
     <child> 
      <placeholder/> 
     </child> 
     <child> 
      <placeholder/> 
     </child> 
     <child> 
      <placeholder/> 
     </child> 
     <child> 
      <placeholder/> 
     </child> 
     <child> 
      <placeholder/> 
     </child> 
     <child> 
      <placeholder/> 
     </child> 
     <child> 
      <placeholder/> 
     </child> 
     <child> 
      <placeholder/> 
     </child> 
     </object> 
    </child> 
    </object> 
</interface> 
+1

Спасибо за такой полный ответ. Я даже не думал об этом так, как вы правильно сказали, по сравнению с вашим, мой файл callback.c - беспорядок. Я загрузил код, который вы предоставили, и я собираюсь использовать его в качестве основы для написания более чистого кода и переосмысления моих обратных вызовов. Еще раз большое спасибо. – Scott

+0

Ваш ответ настолько сложный, хотя, и я не вижу, как это лучше простого 'gtk_builder_connect_signals()'. – TechZilla

Смежные вопросы