如何在gtk中刷新,重绘窗口(小部件)?

时间:2015-08-31 09:40:37

标签: c user-interface gtk gtk2

我正在使用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 个答案:

答案 0 :(得分:0)

您从未更改button2的标签。

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

顺便说一下,你真的应该在新代码中使用GTK3(因为GTK3在小部件布局w.r.t. GTK2上有很大改进)。并且你最好先编写更简单的代码,以便理解GTK的event loop。您需要使用gdb debugger(而且valgrind也应该有用。)

别忘了启用所有警告&amp;编译时调试信息(例如gcc -Wall -Wextra -Wstring-prototypes -g

正如您所猜测的,您需要更多callbacks(以及signals和插槽)功能。了解continuations是什么以及CPS是什么应该是有用的(因为回调与延续相关)。

答案 1 :(得分:0)

After lots reading and frustration i finally able to solve my answer, The purpose of my application is to know how the table attachment works.

  1. Thus i did simple solution for problem. Which is attaching new button to a dialog box, Which is invoked after "clicked" event, the callback is as follows
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);
}

where the callback function statement in main() is

g_signal_connect (G_OBJECT(button), "clicked", G_CALLBACK(fundia), (gpointer) window);

Though this function serves my purpose but above solution is irrelevant to this post's question hence it did not reuse or redraw the widget.

  1. Thus here is the final code of my program is as follows
#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;
}

So I made following differences :-

  1. The gtk_box_pack_start(); functions second and third arguments is related to expand and fill properties was set to 0 in my previous program that means i don't have allocated any extra space for it.
  2. The button2 is only available to main(). Thus i declared the function above main() to accessible to all function.
  3. After attaching the button2 to downtable widget, when next time i am trying to reattach button2 to the table it was giving me a gtk_table_attach assertion child->parent == NULL failed error. So the previous reference needed to be free, thus the function gtk_container_remove()is added in showid callback function to decrease the reference count by 1. And i reference it again by g_object_ref to increase the reference counter by 1 to reference the widget again.

I want to thank Basile and Michi for there help, it was so helpful for me.