我是Gtk的新手,这是我的第一个Gtk项目。我在Windows 7上的Code :: Blocks上使用C和Gtk + 2.在我的项目中,我有一个主窗口,最初显示一个主屏幕,按住“运行”项目和其他一些按钮(“退出”, “关于”等)。单击此“运行”按钮时,程序必须读取和写入一些大文本文件,然后显示带有一些新数据的新屏幕(我通过销毁主窗口的所有先前子项并放置来创建此新屏幕在新的东西里面。)
现在由于这些文本文件的大小很大,程序在单击“运行”时会滞后一段时间,因此我想显示一个中间屏幕,其中包含一些消息,如“正在加载...”。但是我无法做到,因为这个中间屏幕从未显示过。
这就是我所拥有的;我希望代码说清楚:
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()函数完成后显示“正在加载”消息 - 因此没有用。在所有这段时间内,只显示主屏幕...实际上,next_screen()会立即显示,因此“加载”甚至不显示。但是不应该在所有延迟期间显示加载消息,因为稍后会调用prepare_files()函数吗?
我做错了什么,我该怎么做呢?
对不起,如果这是显而易见的事情。正如我所说,我是Gtk +的初学者。
答案 0 :(得分:2)
Gtk +绘图发生在与代码在同一个线程中触发的计时器上。换句话说,绘图代码只能在代码不运行时运行:当单击“运行”时,下一次绘制只能在intermediate_screen()
返回后发生(并且“正在加载.. 。“屏幕已被替换。”
你可以在intermediate_screen()中添加一些hacks来运行主循环的几次迭代,这样至少会有一次绘制,但这仍然是糟糕且无响应的设计。有两种可能的更好的解决方案:
使用像GIO这样的异步API来读取和写入文件:这意味着代码中的任何函数都不会运行足够长的时间来破坏绘图或与UI交互。实现它比同步读取(比你现在可能使用的那些)稍微复杂一点,一个可能的短版本是:在回调调用g_file_read_async()
中创建一个GFile,调用g_file_read_finish()
,创建一个GDataInputStream从你获得的GFileInputStream中,然后使用g_data_input_stream_read_*_async()
函数开始读取文件的行或其他块,并在该回调中获取g_data_input_stream_read_*_finish()
的数据。
或者创建一个新线程,并使用您现在使用的相同读取代码读取该线程中的数据。不好的一面是你现在必须自己处理线程安全 - 这可能很困难,并且线程错误是最难调试的。
在我看来,在异步API可用的几乎所有情况下,选项#1是最佳折衷方案。请注意,如果您自己处理文件内容需要很长时间,那么您也应该以小块的方式执行此操作(通常它可以很好地工作,因此您可以异步读取一行或更大的块并处理回调中的行/块) )。