gtk在对话框中显示一个对话框

时间:2021-07-08 18:52:19

I'm writing a gtk program, at some point in my application, I call a gtkdialog to obtain input from the user. what I want to do is close the current dialog and open another dialog when the OK button is clicked, I already have a function doing some other work, starting the dialog in that function would be great. here's the parent dialog code:

我正在编写一个gtk程序,在我的应用程序中的某个时刻,我调用gtkdialog来获取用户的输入。我想要做的是关闭当前对话框并在单击确定按钮时打开另一个对话框,我已经有一个功能做其他工作,在该功能中启动对话框会很棒。这是父对话框代码:

GtkWidget * new_button_dialog = gtk_dialog_new_with_buttons("new button",(GtkWindow *)container,GTK_DIALOG_DESTROY_WITH_PARENT,"OK", GTK_RESPONSE_OK,NULL);
       GtkWidget * content_area = gtk_dialog_get_content_area (GTK_DIALOG (new_button_dialog));
       GtkWidget * button_name_label = gtk_label_new ("Press escape at any time to cancel.\ntype in the button name");
       gtk_container_add (GTK_CONTAINER (content_area) , button_name_label);
       GtkWidget * button_name_entry = gtk_entry_new();
       gtk_entry_set_activates_default((GtkEntry*)button_name_entry,TRUE);
       gtk_container_add(GTK_CONTAINER(content_area), button_name_entry);
       GtkWidget * button_text_dialog = gtk_dialog_new_with_buttons("new button",(GtkWindow *)container,GTK_DIALOG_DESTROY_WITH_PARENT,"OK", GTK_RESPONSE_OK,NULL);
      gtk_container_add (GTK_CONTAINER (container), button);
       g_signal_connect(new_button_dialog,"response",G_CALLBACK (add_new_button),NULL);
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",GTK_SIGNAL_FUNC (gtk_widget_show_all),(GtkWidget*)new_button_dialog);
       gtk_widget_show_all((GtkWidget *)container);

1 个解决方案

#1


2  

The response of a dialog cannot be handled in the same function that the dialog is created. It means that in one function you cannot create a dialog, handle its input, close that dialog and open a new dialog. It cannot be done since when that function exits the dialog entry is empty and the first dialog is just shown.

无法在创建对话框的同一函数中处理对话框的响应。这意味着在一个函数中,您无法创建对话框,处理其输入,关闭该对话框并打开新对话框。当该函数退出对话框条目为空并且仅显示第一个对话框时,无法完成。

It should be done as a chain of separate event handlers. All needed variables (data context) should be transferred between those separate handlers using a pointer to structure that holds that context.

它应该作为一系列独立的事件处理程序来完成。应使用指向保存该上下文的结构的指针在这些单独的处理程序之间传输所有需要的变量(数据上下文)。

The below full runnable example demonstrates such flow.

以下完整的可运行示例演示了此类流程。

In the fist dialog handler we want to do something with the main window and some container object and maybe we want some other data that is shared between widgets of that main window. The structure window_ctx_t is declared for such context. There is a boolean flag in that context to lock creation on new dialog chains before closing active dialogs.

在第一个对话框处理程序中,我们想要对主窗口和一些容器对象做一些事情,也许我们想要在该主窗口的窗口小部件之间共享一些其他数据。为此类上下文声明了结构window_ctx_t。在关闭活动对话框之前,该上下文中有一个布尔标志用于锁定新对话链上的创建。

The function first_dialog_create creates the first dialog with text entry field. It receives window_ctx_t, where the main window pointer is stored that is used for the dialog creation. Now we need to attach to that dialog response handler and provide to the handler enough data for its functionality. In that example we provide pointer to text entry that is used to read text.

函数first_dialog_create创建带有文本输入字段的第一个对话框。它接收window_ctx_t,其中存储用于对话创建的主窗口指针。现在我们需要附加到该对话框响应处理程序,并为处理程序提供足够的数据以实现其功能。在该示例中,我们提供指向用于读取文本的文本条目的指针。

Using provided data the response handler add_new_button is able to read text entry, to create a new dialog attached to the main window and also to do something with provided container.

使用提供的数据,响应处理程序add_new_button能够读取文本条目,创建一个附加到主窗口的新对话框,还可以使用提供的容器执行某些操作。

When the first dialog data context is not needed it is freed by calling g_free() in the dialog destroyed handler.

当不需要第一个对话框数据上下文时,通过在对话框销毁的处理程序中调用g_free()来释放它。

Build the example:

建立示例:

gcc -Wall -g dialogs.c -o dialogs `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`

Example "dialogs.c"

#include <gtk/gtk.h>

typedef struct {
    GtkWidget *container;
    GtkWindow *window;
    gboolean dialogs_created;
} window_ctx_t;

typedef struct {
    GtkEntry *entry;
    window_ctx_t *window_ctx;
} first_dialog_data_t;

static void first_dialog_create(gpointer context);

static void another_dialog_response(GtkWidget *dialog, gint response_id,
    gpointer ctx)
{
    window_ctx_t *win_ctx = ctx;

    gtk_widget_destroy(dialog);
    win_ctx->dialogs_created = FALSE;
}

static void cleanup_first_dialog(GtkWidget *widget, gpointer data)
{
    g_free(data);
}

/* response callback of the first dialog */
static void add_new_button(GtkWidget *dialog, gint response_id,
    gpointer ctx)
{
    GtkWidget *button;
    GtkWidget *button_text_dialog;
    first_dialog_data_t *data = ctx;

    if (response_id != GTK_RESPONSE_OK) {
        data->window_ctx->dialogs_created = FALSE;
        goto Exit;
    }

    /* Create a new button with the label from text entry */
    button = gtk_button_new_with_label(gtk_entry_get_text(data->entry));
    /* When the button receives the "clicked" signal, it will again open
     * "new button" dialog */
    g_signal_connect_swapped(button, "clicked", G_CALLBACK(first_dialog_create),
        data->window_ctx);
    /* add button to the container */
    gtk_container_add(GTK_CONTAINER(data->window_ctx->container), button);
    /* show button */
    gtk_widget_show(button);

    /* create another dialog */
    button_text_dialog = gtk_dialog_new_with_buttons("new button",
        data->window_ctx->window, GTK_DIALOG_DESTROY_WITH_PARENT, "OK",
        GTK_RESPONSE_OK, NULL);
    g_signal_connect(button_text_dialog, "response",
        G_CALLBACK(another_dialog_response), (gpointer)data->window_ctx);

    gtk_widget_show_all(button_text_dialog);

Exit:
    gtk_widget_destroy(dialog);
}

static void first_dialog_create(gpointer context)
{
    first_dialog_data_t *data;
    window_ctx_t *win_ctx = context;

    if (win_ctx->dialogs_created)
        return;

    /* lock buttons handler */
    win_ctx->dialogs_created = TRUE;

    /* allocate structure for dialog context */
    data = g_new0(first_dialog_data_t, 1);

    /* create first dialog, its label and text entry */
    GtkWidget *new_button_dialog = gtk_dialog_new_with_buttons("new button",
        win_ctx->window, GTK_DIALOG_DESTROY_WITH_PARENT,"OK",
        GTK_RESPONSE_OK, NULL);

    GtkWidget *content_area = gtk_dialog_get_content_area(
    GTK_DIALOG(new_button_dialog));
    GtkWidget *button_name_label = gtk_label_new("Press escape at any time to "
        "cancel.\ntype in the button name");
    gtk_container_add(GTK_CONTAINER(content_area), button_name_label);

    GtkWidget * button_name_entry = gtk_entry_new();
    gtk_entry_set_activates_default((GtkEntry*)button_name_entry,TRUE);
    gtk_container_add(GTK_CONTAINER(content_area), button_name_entry);

    /* provide data to response handler */
    data->entry = (GtkEntry *)button_name_entry;
    data->window_ctx = win_ctx;
    g_signal_connect(new_button_dialog, "response", G_CALLBACK(add_new_button),
        data);

    /* handler to free dialog context 'data' when destroed */
    g_signal_connect(new_button_dialog, "destroy",
        G_CALLBACK(cleanup_first_dialog), data);

    /* show first dialog */
    gtk_widget_show_all(new_button_dialog);
}

static void destroy(GtkWidget *widget, gpointer data)
{
    gtk_main_quit();
}

int main(int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *box1;
    GtkWidget *button;
    window_ctx_t win_ctx;

    gtk_init (&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    box1 = gtk_hbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), box1);

    /* set window context */
    win_ctx.window = (GtkWindow *)window;
    win_ctx.container = box1;
    win_ctx.dialogs_created = FALSE;

    g_signal_connect (window, "destroy", G_CALLBACK(destroy), NULL);
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);

    button = gtk_button_new_with_label("Start");
    g_signal_connect_swapped(button, "clicked", G_CALLBACK(first_dialog_create),
        &win_ctx);
    gtk_container_add(GTK_CONTAINER(box1), button);

    gtk_widget_show_all(window);

    gtk_main();

    return 0;
}

#1


2  

The response of a dialog cannot be handled in the same function that the dialog is created. It means that in one function you cannot create a dialog, handle its input, close that dialog and open a new dialog. It cannot be done since when that function exits the dialog entry is empty and the first dialog is just shown.

无法在创建对话框的同一函数中处理对话框的响应。这意味着在一个函数中,您无法创建对话框,处理其输入,关闭该对话框并打开新对话框。当该函数退出对话框条目为空并且仅显示第一个对话框时,无法完成。

It should be done as a chain of separate event handlers. All needed variables (data context) should be transferred between those separate handlers using a pointer to structure that holds that context.

它应该作为一系列独立的事件处理程序来完成。应使用指向保存该上下文的结构的指针在这些单独的处理程序之间传输所有需要的变量(数据上下文)。

The below full runnable example demonstrates such flow.

以下完整的可运行示例演示了此类流程。

In the fist dialog handler we want to do something with the main window and some container object and maybe we want some other data that is shared between widgets of that main window. The structure window_ctx_t is declared for such context. There is a boolean flag in that context to lock creation on new dialog chains before closing active dialogs.

在第一个对话框处理程序中,我们想要对主窗口和一些容器对象做一些事情,也许我们想要在该主窗口的窗口小部件之间共享一些其他数据。为此类上下文声明了结构window_ctx_t。在关闭活动对话框之前,该上下文中有一个布尔标志用于锁定新对话链上的创建。

The function first_dialog_create creates the first dialog with text entry field. It receives window_ctx_t, where the main window pointer is stored that is used for the dialog creation. Now we need to attach to that dialog response handler and provide to the handler enough data for its functionality. In that example we provide pointer to text entry that is used to read text.

函数first_dialog_create创建带有文本输入字段的第一个对话框。它接收window_ctx_t,其中存储用于对话创建的主窗口指针。现在我们需要附加到该对话框响应处理程序,并为处理程序提供足够的数据以实现其功能。在该示例中,我们提供指向用于读取文本的文本条目的指针。

Using provided data the response handler add_new_button is able to read text entry, to create a new dialog attached to the main window and also to do something with provided container.

使用提供的数据,响应处理程序add_new_button能够读取文本条目,创建一个附加到主窗口的新对话框,还可以使用提供的容器执行某些操作。

When the first dialog data context is not needed it is freed by calling g_free() in the dialog destroyed handler.

当不需要第一个对话框数据上下文时,通过在对话框销毁的处理程序中调用g_free()来释放它。

Build the example:

建立示例:

gcc -Wall -g dialogs.c -o dialogs `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`

Example "dialogs.c"

#include <gtk/gtk.h>

typedef struct {
    GtkWidget *container;
    GtkWindow *window;
    gboolean dialogs_created;
} window_ctx_t;

typedef struct {
    GtkEntry *entry;
    window_ctx_t *window_ctx;
} first_dialog_data_t;

static void first_dialog_create(gpointer context);

static void another_dialog_response(GtkWidget *dialog, gint response_id,
    gpointer ctx)
{
    window_ctx_t *win_ctx = ctx;

    gtk_widget_destroy(dialog);
    win_ctx->dialogs_created = FALSE;
}

static void cleanup_first_dialog(GtkWidget *widget, gpointer data)
{
    g_free(data);
}

/* response callback of the first dialog */
static void add_new_button(GtkWidget *dialog, gint response_id,
    gpointer ctx)
{
    GtkWidget *button;
    GtkWidget *button_text_dialog;
    first_dialog_data_t *data = ctx;

    if (response_id != GTK_RESPONSE_OK) {
        data->window_ctx->dialogs_created = FALSE;
        goto Exit;
    }

    /* Create a new button with the label from text entry */
    button = gtk_button_new_with_label(gtk_entry_get_text(data->entry));
    /* When the button receives the "clicked" signal, it will again open
     * "new button" dialog */
    g_signal_connect_swapped(button, "clicked", G_CALLBACK(first_dialog_create),
        data->window_ctx);
    /* add button to the container */
    gtk_container_add(GTK_CONTAINER(data->window_ctx->container), button);
    /* show button */
    gtk_widget_show(button);

    /* create another dialog */
    button_text_dialog = gtk_dialog_new_with_buttons("new button",
        data->window_ctx->window, GTK_DIALOG_DESTROY_WITH_PARENT, "OK",
        GTK_RESPONSE_OK, NULL);
    g_signal_connect(button_text_dialog, "response",
        G_CALLBACK(another_dialog_response), (gpointer)data->window_ctx);

    gtk_widget_show_all(button_text_dialog);

Exit:
    gtk_widget_destroy(dialog);
}

static void first_dialog_create(gpointer context)
{
    first_dialog_data_t *data;
    window_ctx_t *win_ctx = context;

    if (win_ctx->dialogs_created)
        return;

    /* lock buttons handler */
    win_ctx->dialogs_created = TRUE;

    /* allocate structure for dialog context */
    data = g_new0(first_dialog_data_t, 1);

    /* create first dialog, its label and text entry */
    GtkWidget *new_button_dialog = gtk_dialog_new_with_buttons("new button",
        win_ctx->window, GTK_DIALOG_DESTROY_WITH_PARENT,"OK",
        GTK_RESPONSE_OK, NULL);

    GtkWidget *content_area = gtk_dialog_get_content_area(
    GTK_DIALOG(new_button_dialog));
    GtkWidget *button_name_label = gtk_label_new("Press escape at any time to "
        "cancel.\ntype in the button name");
    gtk_container_add(GTK_CONTAINER(content_area), button_name_label);

    GtkWidget * button_name_entry = gtk_entry_new();
    gtk_entry_set_activates_default((GtkEntry*)button_name_entry,TRUE);
    gtk_container_add(GTK_CONTAINER(content_area), button_name_entry);

    /* provide data to response handler */
    data->entry = (GtkEntry *)button_name_entry;
    data->window_ctx = win_ctx;
    g_signal_connect(new_button_dialog, "response", G_CALLBACK(add_new_button),
        data);

    /* handler to free dialog context 'data' when destroed */
    g_signal_connect(new_button_dialog, "destroy",
        G_CALLBACK(cleanup_first_dialog), data);

    /* show first dialog */
    gtk_widget_show_all(new_button_dialog);
}

static void destroy(GtkWidget *widget, gpointer data)
{
    gtk_main_quit();
}

int main(int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *box1;
    GtkWidget *button;
    window_ctx_t win_ctx;

    gtk_init (&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    box1 = gtk_hbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), box1);

    /* set window context */
    win_ctx.window = (GtkWindow *)window;
    win_ctx.container = box1;
    win_ctx.dialogs_created = FALSE;

    g_signal_connect (window, "destroy", G_CALLBACK(destroy), NULL);
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);

    button = gtk_button_new_with_label("Start");
    g_signal_connect_swapped(button, "clicked", G_CALLBACK(first_dialog_create),
        &win_ctx);
    gtk_container_add(GTK_CONTAINER(box1), button);

    gtk_widget_show_all(window);

    gtk_main();

    return 0;
}