我已经用vala做了一个应用,在某些时候我必须处理很多文件。我已经创建了一个窗口来选择一个文件夹,然后我得到了文件的路径并对它们进行了一些处理。
我在此窗口中添加了一个进度条,以显示已处理的文件数,但由于某种原因,它始终为空。 关于窗口的代码:
checks.AddFullMicroserviceIncludingDatabaseAndUrlCheck(Configuration["OrderingUrl"])
正如您所看到的,我将“select”按钮连接到“do_stuff”方法,在那里我获取所选文件的路径并进行一些处理。
我正确更新了progre bar的分数,因为我添加了一些打印件来知道值是否正确而且确实如此。只是窗口没有刷新,可能是因为它正在处理文件的所有工作。这是关于do_stuff()方法的代码:
this.files_window = new Gtk.Window();
this.files_window.window_position = Gtk.WindowPosition.CENTER;
this.files_window.destroy.connect (Gtk.main_quit);
// VBox:
Gtk.Box vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 5);
this.files_window.add (vbox);
// Buttons to open and close
Gtk.Button cancel = new Gtk.Button.with_label ("Cancel");
Gtk.Button select = new Gtk.Button.with_label ("Select");
vbox.add (select);
vbox.add (cancel);
// proogress bar
this.progress_bar = new Gtk.ProgressBar();
vbox.add(this.progress_bar);
// conect select to method do_stuff
select.clicked.connect (do_stuff);
this.files_window.show_all ();
printf显示正在更新progres栏的值,但在窗口中栏始终为空。
我错过了什么吗?这是进行进度条的正确方法吗?我应该制作另一个线程吗?
答案 0 :(得分:1)
除非您没有显示某些相关代码,否则您将屏蔽main loop。一种选择是在线程中执行所有操作,并使用空闲回调来更新UI。基本想法是这样的:
new GLib.Thread<void*>("file-processor", () => {
foreach (string sfile in sfiles) {
/* do stuff */
GLib.Idle.add(() => {
/* Update progress */
return false;
});
}
return null;
});
根据您的应用程序,您可能需要添加互斥锁以避免竞争条件。您可能还需要添加一些逻辑来取消操作。
更好的选择可能是使用GLib.ThreadPool。您仍然希望从空闲回调更新UI,但这将允许每个任务并行执行,这可以提供显着的加速。
如果我是你,我可能会把它全部包裹在async function中以保持API整洁,但你真的不需要。
答案 1 :(得分:1)
正如@nemequ所说,你的代码阻塞了主循环线程(它处理用户输入和调度/绘制窗口小部件更新),因此在方法完成之前不会更新进度条。
使用线程是解决问题的一种方法,但是使用线程可能会导致很多错误,因为线程之间的简单交互很难安全。
异步方法通过将代码与主循环完成的其他工作交错来避免这种情况。您do_stuff()
的异步版本非常简单,只需将其声明为async并在for循环中放置一个yield:
public async void do_stuff() {
...
foreach (string sfile in sfiles) {
// all of this is as before
do_some_proces_to_file(sfile);
processed_files += 1;
fraction = (double)processed_files/(double)sfiles.length;
this.progress_bar.set_fraction (fraction);
// Schedule the method to resume when idle, then
// yield control back to the caller
Idle.add(do_stuff.callback);
yield;
}
}
然后,您可以通过调用do_stuff.begin()
。