Как обновить, перерисовать окно (виджет) в gtk?
Я использую Opensuse 13.1 Linux Os. Я новичок в gtk2 и c. Я пытаюсь создать приложение, которое может поместить кнопку в таблицу, которая прикреплена в соответствии со значениями, введенными пользователем. Мой программный код выглядит следующим образом
#include <stdlib.h>
#include <gtk/gtk.h>
typedef struct {
GtkWidget *value1, *value2, *value3, *value4;
} entrygrouped;
guint ival1, ival2, ival3, ival4;
void button_clicked(entrygrouped *widget)
{
const gchar *value1, *value2, *value3, *value4;
value1 = gtk_entry_get_text (GTK_ENTRY(widget->value1));
value2 = gtk_entry_get_text (GTK_ENTRY(widget->value2));
value3 = gtk_entry_get_text (GTK_ENTRY(widget->value3));
value4 = gtk_entry_get_text (GTK_ENTRY(widget->value4));
ival1 = (guint)atoi(value1);
ival2 = (guint)atoi(value2);
ival3 = (guint)atoi(value3);
ival4 = (guint)atoi(value4);
g_print("ENTRY VALUES = %s %s %s %s\n", value1, value2, value3, value4);
g_print("ENTRY NUMS = %d %d %d %d\n", ival1, ival2, ival3, ival4);
}
int main (int argc, char *args[])
{
GtkWidget *window, *vbox, *uptable, *downtable, *label;
GtkWidget *button, *button2;
gtk_init(&argc, &args);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_get_resizable(GTK_WINDOW(window));
entrygrouped *eg;
eg = g_slice_new(entrygrouped);
vbox = gtk_vbox_new(FALSE, 2);
uptable = gtk_table_new (3, 4, FALSE);
downtable = gtk_table_new (3, 3, TRUE);
label = gtk_label_new (" Enter the values to position the widget ");
eg->value1 = gtk_entry_new();
eg->value2 = gtk_entry_new();
eg->value3 = gtk_entry_new();
eg->value4 = gtk_entry_new();
button = gtk_button_new_with_label ("Submit");
button2 = gtk_button_new_with_label("BUTTON");
gtk_table_attach_defaults (GTK_TABLE(uptable), label, 0, 3, 0, 1);
gtk_table_attach_defaults (GTK_TABLE(uptable), eg->value1, 0, 1, 1, 2);
gtk_table_attach_defaults (GTK_TABLE(uptable), eg->value2, 1, 2, 1, 2);
gtk_table_attach_defaults (GTK_TABLE(uptable), eg->value3, 0, 1, 2, 3);
gtk_table_attach_defaults (GTK_TABLE(uptable), eg->value4, 1, 2, 2, 3);
gtk_table_attach_defaults (GTK_TABLE(uptable), button, 1, 2, 3, 4);
gtk_widget_queue_draw(GTK_WIDGET(window));
gtk_table_attach_defaults (GTK_TABLE(downtable), button2, ival1, ival2,
ival3, ival4);
gtk_box_pack_start(GTK_BOX(vbox), uptable, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), downtable, 0, 0, 0);
g_signal_connect_swapped(G_OBJECT(button), "clicked",
G_CALLBACK(button_clicked), eg);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add (GTK_CONTAINER(window), vbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Теперь всякий раз, когда я открываю свое приложение из терминала, вводю некоторые значения и нажимаю кнопку "Отправить", значения печатаются на терминале, но проблема в том, что окно не отображало button2 с новыми назначенными значениями. Я не знаю ни одной функции, которая может обновить или перерисовать все окно, хотя я попробовал
while (gtk_events_pending())
gtk_main_iteration();
над вложением таблицы button2 все еще я ничего не делаю. Нужна ли мне другая функция обратного вызова для изменения размера окна? Пожалуйста, помогите мне с этой проблемой.
РЕДАКТИРОВАТЬ: Если мой вопрос неясен, я хочу показать это графически следующим образом
----------------------------
| a.out _ [ ] x |
---------------------------- before entering the
| -------------------------- | values
|| | ||
| -------------------------- |
|| | ||
| -------------------------- |
| ________ |
| | Submit ||
| -------- |
----------------------------
----------------------------
| a.out _ [ ] x |
---------------------------- after entering the
| -------------------------- | values
|| 0 | 1 ||
| -------------------------- | button2 widget should be
|| 0 | 1 || redrawn according to the
| -------------------------- | values entered and window
| ________ | widget should be updated
| | Submit ||
| -------- |
| _________ |
| | Button | |
| --------- |
----------------------------
2 ответа
После долгих чтений и разочарований я наконец-то смог решить свой ответ. Цель моего приложения - узнать, как работает приложение к таблице.
- Таким образом, я сделал простое решение проблемы. Который прикрепляет новую кнопку к диалоговому окну, Который вызывается после события "нажал", обратный вызов выглядит следующим образом
static void fundia(GtkButton *button, GtkWindow *parent)
{
GtkWidget *dialog, *table, *button2;
dialog = gtk_dialog_new_with_buttons ("Information", parent,
GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
button2 = gtk_button_new_with_label("BUTTON");
table = gtk_table_new (3, 3, TRUE);
gtk_table_attach_defaults (GTK_TABLE(table), button2, ival1, ival2,
ival3, ival4);
gtk_box_pack_start_defaults (GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
gtk_widget_show_all(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
где оператор функции обратного вызова в main()
g_signal_connect (G_OBJECT(button), "clicked", G_CALLBACK(fundia), (gpointer) window);
Хотя эта функция служит моей цели, но решение, приведенное выше, не имеет отношения к вопросу этого поста, следовательно, оно не использовало и не перерисовывало виджет.
- Таким образом, вот окончательный код моей программы выглядит следующим образом
#include <stdlib.h>
#include <gtk/gtk.h>
gboolean buttonbool = FALSE;
typedef struct {
GtkWidget *value1, *value2, *value3, *value4;
} entrygrouped;
static GtkWidget *button2 = 0;
guint ival1, ival2, ival3, ival4;
void button_clicked (gpointer data, entrygrouped *widget)
{
const gchar *cvalue1, *cvalue2, *cvalue3, *cvalue4;
cvalue1 = gtk_entry_get_text (GTK_ENTRY(widget->value1));
cvalue2 = gtk_entry_get_text (GTK_ENTRY(widget->value2));
cvalue3 = gtk_entry_get_text (GTK_ENTRY(widget->value3));
cvalue4 = gtk_entry_get_text (GTK_ENTRY(widget->value4));
ival1 = (guint)atoi(cvalue1);
ival2 = (guint)atoi(cvalue2);
ival3 = (guint)atoi(cvalue3);
ival4 = (guint)atoi(cvalue4);
g_print("ENTRY VALUES = %s %s %s %s\n", cvalue1, cvalue2, cvalue3, cvalue4);
g_print("ENTRY NUMS = %d %d %d %d\n", ival1, ival2, ival3, ival4);
}
void showid(gpointer data, GtkWidget *widget)
{
if (buttonbool == TRUE)
{
/* Here reference count of the widget is decreased by 1. */
gtk_container_remove(GTK_CONTAINER(widget), GTK_WIDGET(button2));
/* In below statement reference count of widget increased by 1 */
g_object_ref(button2);
button2 = gtk_button_new_with_label("BUTTON");
gtk_table_attach_defaults (GTK_TABLE(widget), button2, ival1, ival2,
ival3, ival4);
} else {
gtk_table_attach_defaults (GTK_TABLE(widget), button2, ival1, ival2,
ival3, ival4);
buttonbool = TRUE;
}
gtk_widget_show(button2);
}
int main (int argc, char *args[])
{
GtkWidget *window, *uptable, *downtable, *button, *vbox, *instr;
gtk_init(&argc, &args);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_title (GTK_WINDOW(window), "TABLEAPP");
entrygrouped *eg;
eg = g_slice_new(entrygrouped);
instr = gtk_label_new (" Enter the values to position the widget ");
uptable = gtk_table_new (2, 4, FALSE);
downtable = gtk_table_new (3, 3, TRUE);
button = gtk_button_new_with_label("Submit"); // Button with label
button2 = gtk_button_new_with_label("SAME");
// Button with label
vbox = gtk_vbox_new(FALSE, 2); // GTK vbox
eg->value1 = gtk_entry_new();
eg->value2 = gtk_entry_new();
eg->value3 = gtk_entry_new();
eg->value4 = gtk_entry_new();
gtk_table_attach_defaults (GTK_TABLE(uptable), instr, 0, 3, 0, 1);
gtk_table_attach_defaults (GTK_TABLE(uptable), eg->value1, 0, 1, 1, 2);
gtk_table_attach_defaults (GTK_TABLE(uptable), eg->value2, 1, 2, 1, 2);
gtk_table_attach_defaults (GTK_TABLE(uptable), eg->value3, 0, 1, 2, 3);
gtk_table_attach_defaults (GTK_TABLE(uptable), eg->value4, 1, 2, 2, 3);
gtk_table_attach_defaults (GTK_TABLE(uptable), button, 1, 2, 3, 4);
/* The second arguments gtk_box_pack_start(); is about expand properties of
widget which was set 0 and third is about allocation fill properties is also
set 0 in my previous program. */
gtk_box_pack_start (GTK_BOX(vbox), uptable, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX(vbox), downtable, TRUE, TRUE, 0);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(button_clicked), eg);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(showid), downtable);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Таким образом, я сделал следующие различия:
gtk_box_pack_start();
Второй и третий аргументы функции связаны с расширением, а свойства заполнения были установлены в 0 в моей предыдущей программе, что означает, что я не выделил для этого дополнительного пространства.- Кнопка2 доступна только для main(). Таким образом, я объявил функцию выше main() доступной для всех функций.
- После прикрепления button2 к виджету, который можно отключить, когда в следующий раз я пытаюсь снова прикрепить button2 к таблице, он выдал мне ошибку gtk_table_attach child->parent == NULL. Ошибка не удалась. Таким образом, предыдущая ссылка должна быть бесплатной, таким образом, функция
gtk_container_remove()
добавлен в функцию обратного вызова showid, чтобы уменьшить количество ссылок на 1. И я ссылаюсь на него сноваg_object_ref
увеличить счетчик ссылок на 1, чтобы снова ссылаться на виджет.
Я хочу поблагодарить Васили и Мичи за помощь, это было очень полезно для меня.
Вы никогда не меняли ярлык button2
,
Вы должны иметь некоторый обратный вызов, вызывающий gtk_button_set_label на button2
; если вы хотите изменить размер виджета, вам может потребоваться отправить сигнал запроса размера и / или выделения размера и / или сигнал проверки изменения размера на контейнере. Смотрите также эту тему.
Кстати, вам действительно следует использовать GTK3 в новом коде (поскольку GTK3 значительно улучшил компоновку виджетов по сравнению с GTK2). И вам лучше сначала написать что-то более простое, чтобы понять цикл событий GTK. Вам нужно будет использовать gdb
отладчик (и valgrind тоже должен быть полезен).
Не забудьте включить все предупреждения и отладочную информацию при компиляции (например, gcc -Wall -Wextra -Wstring-prototypes -g
)
Как вы уже догадались, вам нужно гораздо больше функций обратного вызова (и сигналов, и слотов). Понимание того, что такое продолжения и что такое CPS, должно быть полезным (поскольку обратные вызовы связаны с продолжениями).