如何从长时间的操作中更新Vala中的GTK + UI而不阻塞UI [英] How can one update GTK+ UI in Vala from a long operation without blocking the UI

查看:203
本文介绍了如何从长时间的操作中更新Vala中的GTK + UI而不阻塞UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用此页面中的任何代码而不进行任何修改时: https://wiki. gnome.org/Projects/Vala/AsyncSamples

When I use any of the codes in this page without modifying anything: https://wiki.gnome.org/Projects/Vala/AsyncSamples

我总是得到: warning: ‘g_simple_async_result_new’ is deprecated: Use 'g_task_new' instead.

因此,我建议使用 GTask .但是,当我尝试在Vala中使用GLib.Task时,仅声明一个任务就卡住了.因此,由于已弃用它,所以我不尝试在我自己的代码中使用来自GIO的异步,而是尝试使用GLib.Task来简单地使用for循环中的数字更新Gtk Button的标签,使得代码如下所示:

So I proceed with the recommendation of using GTask. However, when I try to use GLib.Task in Vala, I get stuck just declaring a task. So instead of using async from GIO in my own code, since it is deprecated, I try to use GLib.Task to simply update the label of a Gtk Button with numbers from a for loop, such that the code looks like this:

using Gtk;
Button button;

public static int main (string[] args) {
    Gtk.init (ref args);

    var window = new Window ();
    window.title = "Count without blocking the UI";
    window.border_width = 10;
    window.window_position = WindowPosition.CENTER;
    window.set_default_size (350, 70);
    window.destroy.connect (Gtk.main_quit);
    button = new Button.with_label ("Start counting");
    button.clicked.connect (() => {
    GLib.Task task = new GLib.Task(button, new Cancellable());
});

window.add (button);
window.show_all ();

Gtk.main ();

return 0;
}

void count(){
    for(int i = 0; i < 10000; i++){
        button.label = i.to_string();
    }
}

但是在编译时我得到:error: ‘_data_’ undeclared (first use in this function) _tmp3_ = g_task_new_finish (_data_->_res_);

But when compiling I get: error: ‘_data_’ undeclared (first use in this function) _tmp3_ = g_task_new_finish (_data_->_res_);

第15行是导致编译器抛出该错误的原因.它来自vala编译器生成的C代码.

The line number 15 is what is causing the compiler to throw that error. It comes from the C code that the vala compiler generates.

我发现的主要问题是Vala中的GTask构造函数签名不同于C.因此,我无法重新创建此处找到的代码:

The main problem I found is that the GTask constructor signatures in Vala are different from C. Therefore, I could not re-create the code found here: GUI becomes unresponsive after clicking the button using GTK+ in C

因为对于初学者来说,我不允许将两个以上的参数传递给GLib.Task对象构造函数.每种语言中Task对象的构造函数都不同.可以在此处找到GLib.Task的构造函数.

Because for starters, I am not allowed to pass more than two arguments to the GLib.Task object constructor. The constructors of the Task object are different in each language. The constructor for GLib.Task in Vala can be found here.

提出我的问题:

是否存在有关如何在Vala中使用GLib任务(GTask)来执行更新UI而不阻止UI的操作的示例?如果不是,是否有另一种方法可以在不阻止UI的情况下更新UI?一种不被淘汰的方式?

Are there any examples on how to use GLib Task (GTask) in Vala to perform an operation that updates the UI without blocking it? If not, is there another way to update the UI without blocking it? A way that is not deprecated?

谢谢.

P.S:我已经尝试了GLib.Thread,GLib.ThreadPool和GLib.Idle.它们都在for循环中阻塞了UI. GLib.Idle不能完全阻止UI,但是会在出现循环的过程中响应用户输入变得非常缓慢,从而使它变得有问题.

P.S: I have already tried GLib.Thread, GLib.ThreadPool, and GLib.Idle. They all block the UI while in the for loop. GLib.Idle does not block the UI completely, but it renders it buggy in the sense that it becomes really slow to respond to user input while the loop is running.

推荐答案

使用异步非常好,并且

It's perfectly fine to use async and there's some work already for porting the current code to use GTask.

您的计数代码正在阻塞,因此即使使用GTask对它的执行进行缓冲,它仍然会阻塞UI.

Your counting code is blocking, so even if its execution is cushioned with GTask, it will still block the UI.

执行CPU密集型后台操作的正确方法是异步使用子进程,或者在线程中启动工作并在主循环中分派.

The correct way of performing CPU intensive background operations either use subprocess asynchronously or launch the work in a thread and dispatch in the main loop.

async void test_async () {
    new Thread<void> (() => {
         // count here...
        test_async.callback ();
    });
    yield;
}

GTask或更笼统的GAsyncResult仅提供用于容纳异步操作结果的容器.他们还建议使用GThreadPool,但这要简单一些.

The GTask or more generally GAsyncResult only provide a container for holding the result of an asynchronous operation. They also recommend to use a GThreadPool, but it's a bit more boilerplate.

另一个有趣的事情是test_async.callback实际上是SourceFunc,因此您可以在GLib.Timeout中传递它.

Another interesting thing is that test_async.callback is actually a SourceFunc, so you can pass it around in GLib.Timeout.

要解决您的问题,如果您想在UI进行时更新它,请使用异步循环:

To fit more your question, if you want to update the UI while it progress, use an async loop:

async test_callback () {
    for (var i = 0; i < 10000; i++) {
        button.label = i.to_string ();
        Idle.add (test_async.callback);
        yield; // pause execution until retriggered in idle
    }
}

这是一个完整且有效的示例:

Here's a full and working example:

using Gtk;
Button button;

public static int main (string[] args) {
    Gtk.init (ref args);

    var window = new Window ();
    window.title = "Count without blocking the UI";
    window.border_width = 10;
    window.window_position = WindowPosition.CENTER;
    window.set_default_size (350, 70);
    window.destroy.connect (Gtk.main_quit);
    button = new Button.with_label ("Start counting");
    button.clicked.connect (() => {
        count ();
    });

    window.add (button);
    window.show_all ();

    Gtk.main ();

    return 0;
}

async void count(){
    for(int i = 0; i < 10000; i++){
        button.label = i.to_string();
        Idle.add (count.callback);
        yield;
    }
}

这篇关于如何从长时间的操作中更新Vala中的GTK + UI而不阻塞UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆