Qt的。从另一个线程与gui互动

时间:2018-05-24 09:10:13

标签: multithreading qt

我有一个库,它在单独的std :: thread中工作。该库的工作原理如下。在按钮上单击我调用库的对象方法,该方法启动长时间的任务。调用此方法时,可以提供进度回调,库会定期调用该回调以通知当前正在执行的操作。

回调定义为

var list = new List<Something> { new Something() { Tags = new HashSet<string>() { "tag1", "tag2" } }, new Something() { Tags = new HashSet<string>() { "tag3", "tag4" } } }; var searchList = new List<string> { "tag1", "tag4"}; var result = list.Where(x => x.Tags.Any(y => searchList.Contains(y)));

我写了非常简单的例子,描述了我的情况。这是它:

typedef std::function <void (const std::string &message)> Callback;

它依赖于向textEdit追加消息。如果我评论这一行都没问题,qDebug正确打印我的消息。

如果不是附加消息来登录lambda我发出信号并在相应的插槽中附加,它也可以正常工作:

class FakeLibrary
{
    typedef std::function<void (const std::string &str)> Callback;
public:
    FakeLibrary() {}
    void run(Callback callback)
    {
        auto lambda = [this, callback]() {
            callback("blahblah");
        };

        std::thread thread(lambda);
        thread.detach();
    }
};

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    FakeLibrary *library_obj = new FakeLibrary;
    connect(ui->pushButton, &QPushButton::clicked, [this, library_obj]() {
        library_obj->run([this](const std::string &message) {
            ui->textEdit->append(QString::fromStdString(message));
            qDebug() << QString::fromStdString(message);
        });
    });
}

所以有人可以解释一下有什么区别以及为什么会出现这种情况?

2 个答案:

答案 0 :(得分:2)

library_obj->run([this](const std::string &message) {
    ui->textEdit->append(QString::fromStdString(message));
    qDebug() << QString::fromStdString(message);
});

您传递了一个包含GUI对象操作的lambda函数。 不应该超出主线程。

  

如上所述,每个程序在启动时都有一个线程。这个   线程被称为&#34;主线程&#34; (也称为&#34; GUI线程&#34; in   Qt应用程序)。 Qt GUI必须在此线程中运行。所有小部件和   几个相关的课程,例如QPixmap,不在中学工作   线程。辅助线程通常被称为&#34;工作者   螺纹&#34;因为它用于从主要卸载处理工作   线程。

第二个实际使用:

QMetaObject::Connection QObject::connect(const QObject *sender, 
                                         PointerToMemberFunction signal, 
                                         const QObject *receiver, 
                                         PointerToMemberFunction method, 
                                         Qt::ConnectionType type = Qt::AutoConnection)

http://doc.qt.io/qt-5/qobject.html#connect

最后一个参数的默认值是Qt::AutoConnection,这使得GUI操作交叉线程成为可能。第一个直接调用该函数,与将Qt::ConnectionType更改为Qt::DirectConnection

相同

答案 1 :(得分:1)

您只能在主线程中访问GUI。这就是第一个例子失败的原因。

第二个例子有效,因为信号槽连接可以跨越线程边界(通过将事件发布到引擎盖下的目标对象的线程)。

您可以在Qt's threading documentation中阅读此内容,尤其是有关线程关联性和信号槽连接的部分。