【问题标题】:How to refresh, redraw a window (widget) in gtk?如何在 gtk 中刷新、重绘窗口(小部件)?
【发布时间】:2015-08-31 09:40:37
【问题描述】:

我正在使用 Opensuse 13.1 Linux 操作系统。我是 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 |               |
|   ---------                |
 ----------------------------

【问题讨论】:

  • 你有很多问题尝试解决它们。使用“-Wall -Wextra -Werror -Wstrict-prototypes -Wconversion --std=c11 -Og pkg-config --cflags gtk+-3.0”进行编译以查看它们。
  • 感谢 Michi 的评论,但我目前正在 gtk2 上使用此应用程序。很抱歉 gtk3 标签。
  • 你想做什么还不清楚。是否要根据在eg 中输入的数字 x、y、w、h 值调整 button2 的大小?请编辑您的问题以改进它。
  • 为什么不使用 GTK3 编写新代码?已知改进了小部件布局代码...
  • 您确实需要阅读更多关于 C 编程和 GTK 的内容。那将需要你几个星期的工作。不要指望我们为您的程序编写代码(您应该使用 GTK3)。

标签: c user-interface gtk gtk2


【解决方案1】:

您从未更改过button2 的标签。

您应该在 button2 上有一些回调调用 gtk_button_set_label ;如果您想调整小部件的大小,您可能需要在容器上发送size-request 信号和/或size-allocate 和/或check-resize 信号。另请参阅this 线程。

顺便说一句,您真的应该在新代码中使用GTK3(因为 GTK3 在小部件布局方面与 GTK2 相比有了很大改进)。您最好先编写一些更简单的代码,以了解 GTK 的event loop。您需要使用gdb debuggervalgrind 也应该很有用)。

编译时不要忘记启用所有警告和调试信息(例如gcc -Wall -Wextra -Wstring-prototypes -g

如您所料,您需要更多callbacks(以及signals 和槽)函数。了解continuations 是什么以及CPS 是什么应该很有用(因为回调与延续有关)。

【讨论】:

  • 感谢重播,但我不想更改按钮 2 的标签,我想定位按钮 2 并在输入值后更新或刷新所有窗口。
  • 请改进您的问题,不要添加 cmets。
  • 你需要使用size-request信号
【解决方案2】:

经过大量阅读和挫折后,我终于能够解决我的答案,我的应用程序的目的是了解表格附件的工作原理。

  1. 因此我为问题做了简单的解决方案。即为对话框附加新按钮,在“点击”事件后调用,回调如下
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);

虽然此功能符合我的目的,但上述解决方案与本文的问题无关,因此它没有重用或重绘小部件。

  1. 因此这里是我的程序的最终代码如下
#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;
}

所以我做了以下区别:-

  1. gtk_box_pack_start(); 函数的第二个和第三个参数与扩展和填充属性相关,在我之前的程序中设置为 0,这意味着我没有为它分配任何额外的空间。
  2. button2 仅对 main() 可用。因此,我声明 main() 上面的函数可供所有函数访问。
  3. 将 button2 附加到 downtable 小部件后,当我下次尝试将 button2 重新附加到表时,它给了我一个 gtk_table_attach 断言 child->parent == NULL failed 错误。所以之前的引用需要是空闲的,因此在 showid 回调函数中添加了函数gtk_container_remove(),以将引用计数减少1。我再次通过g_object_ref引用它以将引用计数器增加1以再次引用小部件.

我要感谢 Basile 和 Michi 的帮助,这对我很有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多