简体   繁体   English

Qt - 从c ++线程发出信号

[英]Qt - emit a signal from a c++ thread

I want to emit a signal from a C++ thread (std::thread) in Qt. 我想从Qt中的C ++线程(std :: thread)发出信号。

How can I do it? 我该怎么做?

You definitely can emit a signal from a thread ( QThread , std::thread or even boost::thread ). 你绝对可以从线程发出信号( QThreadstd::thread甚至boost::thread )。 Only you must be careful of your connect function's fifth parameter ( Qt::ConnectionType ): 只有你必须小心你的connect函数的第五个参数( Qt::ConnectionType ):

If Qt::DirectConnection : The slot is invoked immediately (from the current thread), when the signal is emitted. 如果Qt::DirectConnection :立即调用插槽(从当前线程),则发出信号。 If Qt::QueuedConnection : The slot is invoked when control returns to the event loop of the receiver's thread. 如果Qt::QueuedConnection :当控制返回到接收者线程的事件循环时调用该槽。 The slot is executed in the receiver's thread. 插槽在接收器的线程中执行。

See ConnectionType-enum for more options. 有关更多选项,请参阅ConnectionType-enum

The problem is not really from which thread you emit the signal, it's more from which thread the slot is being invoked. 问题不在于您从哪个线程发出信号,而是从调用插槽的哪个线程开始。 For instance, I think QLabel::setText must be executed from QLabel 's owner thread (most likely main thread). 例如,我认为QLabel::setText必须从QLabel的所有者线程(很可能是主线程)执行。 So if you emit a signal connected to a QLabel 's setText from a thread, connection must be done with Qt::AutoConnection , Qt::QueuedConnection or Qt::BlockingQueuedConnection . 因此,如果从线程发出连接到QLabelsetText的信号,则必须使用Qt::AutoConnectionQt::QueuedConnectionQt::BlockingQueuedConnection

You probably should not emit a Qt signal from a std::thread -created thread in general without care. 您可能不应该小心地从std::thread -created线程发出Qt信号。 See Jpo38's answer : connection type matters, etc... Jpo38的答案 :连接类型很重要等等......

If the thread is running some Qt event loop, you probably could. 如果线程正在运行一些Qt事件循环,你可能会。 See threads and QObject 请参阅线程和QObject

There is a (Unix-specific probably) work-around, doing the same as for Unix signals with Qt : use a pipe from your std::thread to the main thread. 有一个(特定于Unix的)解决方法, 与使用Qt的Unix信号相同:使用从std::thread到主线程的管道。

But, as commented by Joachim Pileborg , you should make your own QThread . 但是,正如Joachim Pileborg评论的那样 ,你应该制作自己的QThread It is the simplest, and probably the shortest (in term of source code), and you just need to copy and paste some existing example and adapt it to your need. 它是最简单的,也可能是最短的(在源代码方面),您只需复制并粘贴一些现有示例并根据您的需要进行调整。

Beware that AFAIK only the main thread should do Qt GUI manipulations. 请注意,AFAIK只有主线程才能进行Qt GUI操作。 You should not use any QWidget (etc...) outside of the main thread! 你不应该在主线程之外使用任何QWidget(etc ...)! (BTW, GTK has the same restriction, at least on Linux: only the main thread is supposed to use the X Windows system protocols ) (顺便说一句,GTK有相同的限制,至少在Linux上:只有主线程应该使用X Windows系统协议

If you're keeping pointer to your QObject then you could use one of QMetaObject::invokeMethod member http://qt-project.org/doc/qt-5/qmetaobject.html#invokeMethod 如果您保持指向QObject的指针,那么您可以使用QMetaObject::invokeMethod成员之一http://qt-project.org/doc/qt-5/qmetaobject.html#invokeMethod

Probably you will have to use Qt::QueuedConnection so your signal will be invoked at proper thread (not your std::thread). 可能你必须使用Qt::QueuedConnection所以你的信号将在适当的线程(而不是你的std :: thread)调用。 Remember that your signal won't be invoked immedietly. 请记住,您的信号不会立即被调用。

class MainForm : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainForm(QWidget *parent = nullptr);
    virtual ~MainForm();

private:
signals:
    void signalSendButtonEnable(bool);

private slots:
    void singalReceiveButtonEnable(bool);


};

MainForm::MainForm(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainForm), status_{false}, io_context_{}, timer_{io_context_}
{
    ui->setupUi(this);

    // bind SIGNAL & SLOT
    connect(this, SIGNAL(signalSendButtonEnable(bool)), this, SLOT(singalReceiveButtonEnable(bool)));
}

MainForm::~MainForm()
{
    delete ui;
}

void MainForm::singalReceiveButtonEnable(bool status){  //recv signal
    qDebug() << "singalReceiveButtonEnable";
    this->ui->btnConnect->setEnabled(status);
}

void MainForm::start(){
    std::thread t([](){
        sleep(20);
        emit signalSendButtonEnable(true);   //send signal
    });
    t.detach();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM