How to refresh, redraw a window (widget) in gtk?

最后都变了- 提交于 2019-12-11 03:53:29

问题


I am using Opensuse 13.1 Linux Os. I am new to gtk2 and c. I am trying to create a application that can place a button on a table which is attached as per the values typed by the user. My program code is as following

#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;
}

Now whenever i open my application from terminal and enter some values and hit submit button, values are printed on terminal, but the problem is window did not draw the button2 with newly assigned values. I dont know any function which can refresh or redraw the whole window, though i tried the

while (gtk_events_pending())
  gtk_main_iteration();

above the button2 table attachment still i window do nothing. Do i need another callback function to resize window? Please help me with this problem.

EDIT : If my question is unclear i want to show it graphical way as follows

 ----------------------------
| 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 |               |
|   ---------                |
 ----------------------------

回答1:


You never changed the label of the button2.

You should have some callback calling gtk_button_set_label on button2 ; if you want to resize the widget you may need to send the size-request signal and/or size-allocate and/or the check-resize signal on the container. See also this thread.

BTW, you really should use GTK3 in new code (since GTK3 improved a lot on widget layout w.r.t. GTK2). And you'll better first code something simpler, to understand the event loop of GTK. You'll need to use the gdb debugger (and valgrind should be useful too).

Don't forget to enable all warnings & debug info when compiling (with e.g. gcc -Wall -Wextra -Wstring-prototypes -g)

As you guessed, you need much more callbacks (and signals and slots) functions. Understanding what continuations are and what CPS is should be useful (because callbacks are related to continuations).




回答2:


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.



来源:https://stackoverflow.com/questions/32308231/how-to-refresh-redraw-a-window-widget-in-gtk

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!