Gtk+ Window 未显示 C 程序中的新更改
Gtk+ Window Not Showing New Changes in C Program
我是 Gtk 新手,这是我的第一个 Gtk 项目。我在 Windows 7 上的 Code::Blocks 上使用 C 和 Gtk+ 2。在我的项目中,我有一个主 window,它最初显示主屏幕,按住一个按钮 "Run"项目和一些其他按钮("Exit"、"About" 等)。单击 "Run" 按钮时,程序必须读取和写入一些大文本文件,然后显示一个包含一些新数据的新屏幕(我通过销毁主 window 并向其中添加新内容)。
现在由于这些文本文件很大,单击 运行 时程序会滞后一段时间,所以我想显示一个中间屏幕,其中包含一些消息,例如 "Loading..."。但是我做不到,因为这个中间屏幕从来没有显示过。
这是我所拥有的;希望代码能说清楚:
GtkWidget *windowMain = NULL;
GtkWidget *vboxMain = NULL;
//These 2 are global.
void home_screen() //Works well
{
//...Created new main window...
//...Created new main vbox...
//...Added vboxMain to windowMain...
GtkWidget *menuButton = gtk_button_new_with_label("Run");
g_signal_connect (menuButton, "clicked", G_CALLBACK (intermediate_screen), NULL);
gtk_box_pack_start (GTK_BOX (vboxMain), menuButton, TRUE, TRUE, 0); //Add button to vboxMain.
gtk_widget_show_all (windowMain);
}
void intermediate_screen() //Is not shown at correct time
{
// CLEAR MAIN WINDOW:
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(windowMain));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_widget_destroy(iter->data);
g_list_free(children);
GtkWidget *label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label1), "<b>Loading...</b>");
gtk_container_add (GTK_CONTAINER (windowMain), label);
gtk_widget_show_all(windowMain);
prepare_files(); //Function to work with the text files
}
void prepare_files() //Starts working before "Loading..." is shown
{
//Some file handling which takes some time to complete.
next_screen();
}
void next_screen()
{
// CLEAR MAIN WINDOW AGAIN TO CLEAR THE "Loading..." LABEL:
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(windowMain));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_widget_destroy(iter->data);
g_list_free(children);
vboxMain = gtk_vbox_new (FALSE, 5);
gtk_widget_set_size_request (vboxMain, 600, 600);
gtk_container_add (GTK_CONTAINER (windowMain), vboxMain);
//Add components to the vboxMain
gtk_widget_show_all(windowMain);
}
问题是 intermediate_screen() 仅在 prepare_files() 函数完成后才显示 "Loading" 消息 - 因此它没有用。在那段时间里,只有主屏幕被显示...事实上, next_screen() 紧随其后显示,所以 "Loading" 甚至没有出现。但是它不应该在所有延迟期间显示加载消息,因为稍后调用 prepare_files() 函数吗?
我做错了什么,我应该如何正确地做?
抱歉,如果这是显而易见的。正如我所说,我是 Gtk+ 的初学者。
Gtk+ 绘图发生在一个计时器上,该计时器在与您的代码相同的线程中触发。换句话说绘图代码只能运行当你的代码是not 运行ning:当"Run"被点击时,下一个绘图只能发生intermediate_screen()
返回后(并且 "Loading..." 屏幕已更换)。
您可以在 intermediate_screen() 中添加一些 hack,运行 主循环的几次迭代因此至少会发生一次平局,但这仍然是糟糕且无响应的设计。有 2 种可能的更好解决方案:
使用像 GIO 这样的异步 API 来读取和写入文件:这意味着您的代码中没有函数 运行 足够长的时间来中断绘图或与 UI 互动。实现它比同步读取(就像您现在可能使用的那些)稍微复杂一些,一个可能的简短版本是:创建一个 GFile,调用 g_file_read_async()
,在回调调用 g_file_read_finish()
中,创建一个 GDataInputStream从您获得的 GFileInputStream 中,然后使用 g_data_input_stream_read_*_async()
函数开始读取行或文件的其他块,并在该回调中使用 g_data_input_stream_read_*_finish()
.
获取数据
或者创建一个新线程并使用您现在使用的相同读取代码读取该线程中的数据。缺点是您现在必须自己处理线程安全——这可能很困难,而且线程错误最难调试。
在我看来,选项 #1 是几乎所有异步 API 可用情况下的最佳折衷方案。请注意,如果您自己处理文件内容需要很长时间,您也应该分小块进行处理(通常效果很好,因此您可以例如异步读取一行或更大的块并处理 line/chunk回调)。
我是 Gtk 新手,这是我的第一个 Gtk 项目。我在 Windows 7 上的 Code::Blocks 上使用 C 和 Gtk+ 2。在我的项目中,我有一个主 window,它最初显示主屏幕,按住一个按钮 "Run"项目和一些其他按钮("Exit"、"About" 等)。单击 "Run" 按钮时,程序必须读取和写入一些大文本文件,然后显示一个包含一些新数据的新屏幕(我通过销毁主 window 并向其中添加新内容)。
现在由于这些文本文件很大,单击 运行 时程序会滞后一段时间,所以我想显示一个中间屏幕,其中包含一些消息,例如 "Loading..."。但是我做不到,因为这个中间屏幕从来没有显示过。
这是我所拥有的;希望代码能说清楚:
GtkWidget *windowMain = NULL;
GtkWidget *vboxMain = NULL;
//These 2 are global.
void home_screen() //Works well
{
//...Created new main window...
//...Created new main vbox...
//...Added vboxMain to windowMain...
GtkWidget *menuButton = gtk_button_new_with_label("Run");
g_signal_connect (menuButton, "clicked", G_CALLBACK (intermediate_screen), NULL);
gtk_box_pack_start (GTK_BOX (vboxMain), menuButton, TRUE, TRUE, 0); //Add button to vboxMain.
gtk_widget_show_all (windowMain);
}
void intermediate_screen() //Is not shown at correct time
{
// CLEAR MAIN WINDOW:
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(windowMain));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_widget_destroy(iter->data);
g_list_free(children);
GtkWidget *label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label1), "<b>Loading...</b>");
gtk_container_add (GTK_CONTAINER (windowMain), label);
gtk_widget_show_all(windowMain);
prepare_files(); //Function to work with the text files
}
void prepare_files() //Starts working before "Loading..." is shown
{
//Some file handling which takes some time to complete.
next_screen();
}
void next_screen()
{
// CLEAR MAIN WINDOW AGAIN TO CLEAR THE "Loading..." LABEL:
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(windowMain));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_widget_destroy(iter->data);
g_list_free(children);
vboxMain = gtk_vbox_new (FALSE, 5);
gtk_widget_set_size_request (vboxMain, 600, 600);
gtk_container_add (GTK_CONTAINER (windowMain), vboxMain);
//Add components to the vboxMain
gtk_widget_show_all(windowMain);
}
问题是 intermediate_screen() 仅在 prepare_files() 函数完成后才显示 "Loading" 消息 - 因此它没有用。在那段时间里,只有主屏幕被显示...事实上, next_screen() 紧随其后显示,所以 "Loading" 甚至没有出现。但是它不应该在所有延迟期间显示加载消息,因为稍后调用 prepare_files() 函数吗?
我做错了什么,我应该如何正确地做?
抱歉,如果这是显而易见的。正如我所说,我是 Gtk+ 的初学者。
Gtk+ 绘图发生在一个计时器上,该计时器在与您的代码相同的线程中触发。换句话说绘图代码只能运行当你的代码是not 运行ning:当"Run"被点击时,下一个绘图只能发生intermediate_screen()
返回后(并且 "Loading..." 屏幕已更换)。
您可以在 intermediate_screen() 中添加一些 hack,运行 主循环的几次迭代因此至少会发生一次平局,但这仍然是糟糕且无响应的设计。有 2 种可能的更好解决方案:
使用像 GIO 这样的异步 API 来读取和写入文件:这意味着您的代码中没有函数 运行 足够长的时间来中断绘图或与 UI 互动。实现它比同步读取(就像您现在可能使用的那些)稍微复杂一些,一个可能的简短版本是:创建一个 GFile,调用
g_file_read_async()
,在回调调用g_file_read_finish()
中,创建一个 GDataInputStream从您获得的 GFileInputStream 中,然后使用g_data_input_stream_read_*_async()
函数开始读取行或文件的其他块,并在该回调中使用g_data_input_stream_read_*_finish()
. 获取数据
或者创建一个新线程并使用您现在使用的相同读取代码读取该线程中的数据。缺点是您现在必须自己处理线程安全——这可能很困难,而且线程错误最难调试。
在我看来,选项 #1 是几乎所有异步 API 可用情况下的最佳折衷方案。请注意,如果您自己处理文件内容需要很长时间,您也应该分小块进行处理(通常效果很好,因此您可以例如异步读取一行或更大的块并处理 line/chunk回调)。