题
我一直在尝试实现Win32的 MessageBox
使用GTK。该应用程序使用 SDL/OpenGL,因此这不是 GTK 应用程序。
我处理初始化(gtk_init
)里面的东西 MessageBox
函数如下:
int MessageBox(HWND hwnd, const char* text, const char* caption, UINT type)
{
GtkWidget *window = NULL;
GtkWidget *dialog = NULL;
gtk_init(>kArgc, >kArgv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
// gcallback calls gtk_main_quit()
gtk_init_add((GtkFunction)gcallback, NULL);
if (type & MB_YESNO) {
dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, text);
} else {
dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, text);
}
gtk_window_set_title(GTK_WINDOW(dialog), caption);
gint result = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_main();
gtk_widget_destroy(dialog);
if (type & MB_YESNO) {
switch (result) {
default:
case GTK_RESPONSE_DELETE_EVENT:
case GTK_RESPONSE_NO:
return IDNO;
break;
case GTK_RESPONSE_YES:
return IDYES;
break;
}
}
return IDOK;
}
现在,我绝不是一位经验丰富的 GTK 程序员,并且我意识到我可能正在做一些严重错误的事情。
但是,我的问题是,使用此函数弹出的最后一个对话框一直保留到进程退出为止。有任何想法吗?
解决方案
嗯。。好。我建议这样的代码:
typedef struct {
int type;
int result;
} DialogData;
static gboolean
display_dialog(gpointer user_data)
{
DialogData *dialog_data = user_data;
GtkWidget *dialog;
if (dialog_data->type & MB_YESNO)
dialog = gtk_message_dialog_new(...);
else
dialog = gtk_message_dialog_new(...);
// Set title, etc.
dialog_data->result = gtk_dialog_run(...);
gtk_main_quit(); // Quits the main loop run in MessageBox()
return FALSE;
}
int MessageBox(...)
{
DialogData dialog_data;
dialog_data.type = type;
gtk_idle_add(display_dialog, &dialog_data);
gtk_main();
// Do stuff based on dialog_data.result
}
该结构是因为您需要传递一些数据。这 gtk_idle_add()
call 添加一个在主循环运行和空闲时运行的方法,并且 FALSE
返回值来自 display_dialog()
call 意味着它只运行一次。从对话框中获得结果后,我们退出主循环。这会导致 gtk_main()
在你的主要 MessageBox()
方法返回,您将能够从那里访问结果。
希望这可以帮助!
其他提示
要使用 GTK+ 管理对话框,请使用 GtkDialog 并 gtk_dialog_run() 而不是自己管理一个窗口和一个主循环。
编辑/附录:
我的意思是“只使用”:我不明白为什么你创建一个你从未使用过的窗口和一个似乎无用的主循环(至少从你发布的代码来看)。您可以写一些简短的内容:
int MessageBox(HWND hwnd, const char* text, const char* caption, UINT type)
{
GtkWidget *dialog ;
/* Instead of 0, use GTK_DIALOG_MODAL to get a modal dialog box */
if (type & MB_YESNO)
dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, text );
else
dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, text );
gtk_window_set_title(GTK_WINDOW(dialog), caption);
gint result = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy( GTK_WIDGET(dialog) );
if (type & MB_YESNO)
{
switch (result)
{
default:
case GTK_RESPONSE_DELETE_EVENT:
case GTK_RESPONSE_NO:
return IDNO;
case GTK_RESPONSE_YES:
return IDYES;
}
return IDOK;
}
}
一些东西:
您正在创建(而不是使用)一个不必要的顶级窗口,名为 window
. 。您只需删除这些行即可:
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
而且,流程似乎不太正确。 gtk_main()
启动 GTK 主循环,该循环会阻塞,直到有东西退出为止。 gtk_dialog_run()
也会启动一个主循环,但一旦单击其中一个按钮,它就会退出。
我认为您删除它可能就足够了 gtk_init_add()
和 gtk_main()
调用,并简单处理返回值。还有 gtk_widget_destroy()
调用是不必要的,因为当 gtk_dialog_run() 返回时对话框窗口会自动销毁。