Gtk&x2B;窗口未显示C程序中的新更改

Gtk&x2B;窗口未显示C程序中的新更改,c,gtk,gtk2,C,Gtk,Gtk2,我是Gtk新手,这是我的第一个Gtk项目。我在Windows7的Code::Blocks上使用C和Gtk+2。在我的项目中,我有一个主窗口,最初显示一个主屏幕,按住一个按钮“运行”项目和一些其他按钮(“退出”、“关于”等)。当点击这个“运行”按钮时,程序必须读写一些大的文本文件,然后显示一个包含一些新数据的新屏幕(我通过销毁主窗口的所有以前的子窗口并在其中添加新内容来创建这个新屏幕) 现在,由于这些文本文件的大小很大,当单击Run时,程序会延迟一段时间,因此我想显示一个中间屏幕,其中包含一些消息

我是Gtk新手,这是我的第一个Gtk项目。我在Windows7的Code::Blocks上使用C和Gtk+2。在我的项目中,我有一个主窗口,最初显示一个主屏幕,按住一个按钮“运行”项目和一些其他按钮(“退出”、“关于”等)。当点击这个“运行”按钮时,程序必须读写一些大的文本文件,然后显示一个包含一些新数据的新屏幕(我通过销毁主窗口的所有以前的子窗口并在其中添加新内容来创建这个新屏幕)

现在,由于这些文本文件的大小很大,当单击Run时,程序会延迟一段时间,因此我想显示一个中间屏幕,其中包含一些消息,如“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);
}
GtkWidget*windowMain=NULL;
GtkWidget*vboxMain=NULL;
//这两个是全球性的。
void home\u screen()//工作正常
{
//…已创建新的主窗口。。。
//…已创建新的主vbox。。。
//…已将vboxMain添加到windowMain。。。
GtkWidget*menuButton=gtk_按钮带_标签的新按钮(“运行”);
g_信号连接(菜单按钮,“点击”,g_回调(中间屏幕),空);
gtk_box_pack_start(gtk_box(vboxMain),菜单按钮,TRUE,TRUE,0);//将按钮添加到vboxMain。
gtk_widget_show_all(windowMain);
}
void intermediate_screen()//未在正确的时间显示
{
//清除主窗口:
GList*儿童,*国际热核实验堆;
children=gtk_container_get_children(gtk_container(windowMain));
for(iter=children;iter!=NULL;iter=g\u list\u next(iter))
gtk_widget_destroy(iter->data);
g_清单_免费(儿童);
GtkWidget*label=gtk_label_new(空);
gtk_标签设置标记(gtk_标签(标签1),“加载…”);
gtk_容器添加(gtk_容器(windowMain),标签);
gtk_widget_show_all(windowMain);
prepare_files();//用于处理文本文件的函数
}
void prepare_files()//在显示“加载…”之前开始工作
{
//一些需要一些时间才能完成的文件处理。
下一个屏幕();
}
作废下一个屏幕()
{
//再次清除主窗口以清除“加载…”标签:
GList*儿童,*国际热核实验堆;
children=gtk_container_get_children(gtk_container(windowMain));
for(iter=children;iter!=NULL;iter=g\u list\u next(iter))
gtk_widget_destroy(iter->data);
g_清单_免费(儿童);
vboxMain=gtk_vbox_new(FALSE,5);
gtk_小部件_设置_大小_请求(vboxMain,600600);
gtk_容器添加(gtk_容器(windowMain)、vboxMain);
//将组件添加到vboxMain
gtk_widget_show_all(windowMain);
}
问题是,intermediate_screen()仅在prepare_files()函数完成后才显示“Loading”消息,因此它没有任何用处。在此期间,只显示主屏幕。。。事实上,下一个_screen()会在之后立即显示,因此“加载”甚至不会显示。但是,它不应该在所有延迟期间显示加载消息吗,因为稍后会调用prepare_files()函数

我做错了什么?我应该如何正确地做


如果这是显而易见的,我很抱歉。正如我所说,我是Gtk+的初学者。

Gtk+绘图发生在与代码在同一线程中触发的计时器上。换句话说,绘图代码只能在代码未运行时运行:单击“运行”时,下一次绘图只能在
intermediate\u screen()
返回后进行(“加载…”屏幕已被替换)

您可以在intermediate_screen()中添加一些hacks,以运行主循环的几个迭代,这样至少会发生一次绘制,但这仍然是糟糕且无响应的设计。有两种可能更好的解决方案:

  • 使用异步API(比如读写文件):这意味着代码中没有函数运行足够长的时间来中断绘图或与UI交互。实现这一点比同步读取(比如您现在可能使用的同步读取)稍微复杂一些,一个可能的简短版本是:创建一个GFile,调用
    g\u file\u read\u async()
    ,在回调调用
    g\u file\u read\u finish()
    ,从您得到的GFileInputStream创建一个GDataInputStream,然后使用
    g\u data\u input\u stream\u read.*\u async()
    函数开始读取文件的行或其他块,并在该回调中使用
    g\u data\u input\u stream\u read.*\u finish()
    获取数据

  • 或者,创建一个新线程,并使用现在使用的相同读取代码读取该线程中的数据。不利的一面是,您现在必须自己处理线程安全问题——这可能很困难,而线程错误是最难调试的

  • 在我看来,在几乎所有异步API可用的情况下,选项1是最好的折衷方案。请注意,如果您自己对文件内容的处理需要很长时间,那么您也应该在小数据块中进行处理(通常效果很好,因此您可以异步读取一行或更大的数据块,并在回调中处理该行/数据块)