Можно ли избежать использования глобальной переменной в этой ситуации? - PullRequest
3 голосов
/ 10 августа 2010

Я пишу GTK + приложение на C (хотя этот принцип широко применим), которое содержит GtkComboBox.GtkComboBox является частью большей структуры, возвращаемой другой функцией и упакованной в главное окно.

Я не вижу, как я могу получить значение того, что выбрано в GtkComboBox, кроме как путем установки глобальной переменнойот его функции обратного вызова.Или все же есть какой-то способ ссылки на GtkComboBox позже в программе, вне функции, которая объявила его?

Или я не должен объявлять его внутри функции (кроме main ()) в первомместо

Ответы [ 3 ]

5 голосов
/ 11 августа 2010

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

gtk_combo_box_new() использует malloc() для внутренних целейвыделить указатель, который он возвращает.(Ну, строго говоря, это не так, но давайте не будем путать здесь.) Таким образом, ваш GtkComboBox будет жив, пока его родительский виджет не будет уничтожен, или он не будет удален из родительского виджета, или пока вы не уничтожите его вручную (с помощьюgtk_widget_destroy(), а не free()).Таким образом, виджет живет в фоновом режиме, но проблема в том, что указатель на него доступен там, где он вам нужен.

Обычно вы хотите манипулировать полем со списком в ответ на сигнал, так как большая частьРабота в программе GTK выполняется в обработчиках сигналов.Если это один из собственных сигналов поля со списком, такой как сигнал changed, то обратный вызов будет такой функцией:

void on_combo_box_changed(GtkComboBox *combo_box, gpointer user_data)

и combo_box будет указателем на ваше поле со списком.

Если вы хотите манипулировать полем со списком в ответ на сигнал другого виджета, скажем, сигнал кнопки clicked, то обратный вызов будет такой функцией:

void on_button_clicked(GtkButton *button, gpointer user_data)

Когда выКак видите, здесь нет указателя на поле со списком.Вот где приходит параметр user_data. Я предполагаю, что вы подключаете свои сигналы в функции, где вы создаете свои виджеты и упаковываете их в главное окно.(Если это не так, вам следует.) В этой функции у вас будут указатели как на кнопку, так и на поле со списком.Подключите ваш сигнал следующим образом ...

g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), combo_box);

..., передав combo_box в качестве параметра user_data к g_signal_connect().Затем указатель на поле со списком будет передан обратному вызову on_button_clicked(), замаскированному как параметр user_data.Затем вы можете получить к нему доступ следующим образом:

void on_button_clicked(GtkButton *button, gpointer user_data)
{
    GtkComboBox *combo_box = GTK_COMBO_BOX(user_data);
    gint item = gtk_combo_box_get_active(combo_box);
    etc.

или, в зависимости от способа работы стека вызовов в C, даже объявив свой обратный вызов следующим образом:

void on_button_clicked(GtkButton *button, GtkComboBox *combo_box)

...хотя в этом случае вы теряете проверочный тип, который дает GTK_COMBO_BOX().

2 голосов
/ 10 августа 2010

Если функция, которая объявляет переменную стека в C, вернулась, этой переменной больше нет.Если вам нужен GtkComboBox (или другой объект) для сохранения, у вас есть несколько вариантов:

  • Используйте malloc, чтобы выделить для него место и передать указатель (который должен быть освобожден, когда он вам больше не нужен)).
  • Используйте глобальную переменную
  • Не используйте обратные вызовы, не объявляйте их во внешней функции и не передавайте.

Я бы, наверное, пошел сmalloc / обходить указатель, но не может быть уверен, не зная вашей ситуации.

0 голосов
/ 11 августа 2010

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

GtkComboBox *getComboBox()
{
  static GtkComboBox gcb = NULL;

  if (NULL != gcb)
    return gcb;

  // Initialise gcb
  return gcb;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...