信号在插入的飞行小部件中不起作用

Signals doesnt work in inserted on fly widgets

我有一个自定义小部件,例如按钮,它具有下一个结构

GtkWidget* button_new(ServerEntity *server)
{
    GtkWidget *fixed;
    GtkWidget *favoriteEventBox;
    GtkWidget *eventBox;

    fixed=  gtk_fixed_new();
    eventBox = gtk_event_box_new();
    favoriteEventBox = gtk_event_box_new();

    gtk_fixed_put(GTK_FIXED(fixed), eventBox, 0,0);
    gtk_fixed_put(GTK_FIXED(fixed), favoriteEventBox, 183,8);

    g_signal_connect (G_OBJECT (eventBox),
                    "button_press_event",
                    G_CALLBACK (on_event_box_button_press),
                    server);

    g_signal_connect (G_OBJECT (favoriteEventBox),
                    "button_press_event",
                    G_CALLBACK (on_favorite_box_button_press),
                    server);

    g_signal_connect (G_OBJECT (fixed),
                    "draw",
                    G_CALLBACK (on_fixed_draw),
                    server);

    return fixed;
}

我把它放到vbox里,然后放到scrollable里window:

    GtkWidget *scroll_window;
    scroll_window = gtk_scrolled_window_new(NULL, NULL);
    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll_window), box);
return scroll_window;

box 在 c 文件中仍然可见,稍后我用它来动态添加小部件。主机小部件是单一的,所以我可以做到。

然后我把它放入gtk_fixed、gtk_fixed和window

当我在所有小部件构建过程中添加我的自定义按钮时,它会在两个嵌套框上收到按钮按下和绘制信号。但是当我稍后添加按钮时,只有当我拉动滚动条时才会调用绘制信号。

这就是我在构造和执行期间添加按钮的方式。

void server_list_set_servers(SERVER_ENTITY_CONTAINER* servers)
{
    int servers_count = server_entity_container_get_items_count(servers);

    int j = 0;
    int i = 0;
    for (i = 0; i < servers_count; i++)
    {
          GtkWidget* button;
          ServerEntity* server = server_entity_container_get_item_at(servers, i);
          button = button_new(server);
          // gtk_table_attach_defaults (GTK_TABLE (table), button, j, j + 1, i, i  + 1);
          gtk_box_pack_end(GTK_BOX(box), button, TRUE, TRUE, 5);
          gtk_widget_show (button);
    }
}

并且在构建期间按钮仍然接收所有信号,但在它旁边,即时添加 - 没有。

尝试将 "event" 信号连接到所有设备,已删除 scrollable_window,将框更改为 table - 不起作用。为什么会这样?

主循环启动后,GTK 系统无法将委托函数连接到信号。 因此,将整个视图重新创建为 window 是一个很好的做法。

在我的例子中,我从登录 GtkWindow 的用户那里获取凭据,调用 gtk_quit,向服务器发出两次请求 - 首先验证凭据,然后获取数据,然后才创建包含所有数据的 Main GtkWindow手,并根据需要用任意数量的按钮填充它。

我不明白你说的一半,所以也许我没有理解你真正的问题,但我知道你可以动态更改 GUI,连接或不连接信号,没有任何问题。

#include <gtk/gtk.h>

static void
child_button(GtkButton *button)
{
    GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
                                               GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
                                               "A child button has been clicked");
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
}

static void
main_button(GtkButton *button, GtkContainer *vbox)
{
    GtkWidget *widget = gtk_button_new_with_label("New button");
    g_signal_connect(widget, "clicked", G_CALLBACK(child_button), NULL);
    gtk_container_add(vbox, widget);
    gtk_widget_show(widget);
}

int main(int argc, char **argv)
{
    GtkWidget *window, *vbox, *button;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    button = gtk_button_new_with_label("Add button");
    g_signal_connect(button, "clicked", G_CALLBACK(main_button), vbox);
    gtk_container_add(GTK_CONTAINER(vbox), button);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}

您也可以准备小部件(连接或未连接到信号)并稍后添加,只需重新排列上面代码段中的代码即可。信号毕竟只是 C 回调。

附录

我更新了上面的代码以使用 GtkEventBoxbutton-press-event 信号只是为了表明改变小部件或信号不会改变最终结果。

#include <gtk/gtk.h>

static gboolean
child_event_box(GtkEventBox *event_box)
{
    GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
                                               GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
                                               "A button has been pressed inside a child event box");
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
    return FALSE;
}

static gboolean
main_event_box(GtkEventBox *event_box, GdkEvent *event, GtkContainer *vbox)
{
    GtkWidget *label = gtk_label_new("Dynamic event box");
    GtkWidget *widget = gtk_event_box_new();
    gtk_container_add(GTK_CONTAINER(widget), label);
    g_signal_connect(widget, "button-press-event", G_CALLBACK(child_event_box), NULL);
    gtk_container_add(vbox, widget);
    gtk_widget_show_all(widget);
    return FALSE;
}

int main(int argc, char **argv)
{
    GtkWidget *window, *vbox, *label, *event_box;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
    event_box = gtk_event_box_new();
    label = gtk_label_new("Add event box");

    gtk_container_add(GTK_CONTAINER(window), vbox);

    /* The default event mask for GtkEventBox already includes
     * GDK_BUTTON_PRESS_MASK but it is not documented.
     * Better to be safe than sorry...
     */
    gtk_widget_add_events(event_box, GDK_BUTTON_PRESS_MASK);

    g_signal_connect(event_box, "button-press-event", G_CALLBACK(main_event_box), vbox);
    gtk_container_add(GTK_CONTAINER(event_box), label);

    gtk_container_add(GTK_CONTAINER(vbox), event_box);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}