我想从Qt中的C ++线程(std :: thread)发出信号。
我该怎么做?
你绝对可以从一个线程(QThread
,std::thread
甚至boost::thread
)发出信号。只有你必须小心你的连接功能的第五个参数(Qt::ConnectionType
):
如果Qt::DirectConnection
:当发出信号时,立即(从当前线程)调用槽。如果Qt::QueuedConnection
:当控制返回到接收者线程的事件循环时调用slot。插槽在接收器的线程中执行。
有关更多选项,请参阅ConnectionType-enum。
问题不在于您从哪个线程发出信号,而是从调用插槽的哪个线程开始。例如,我认为QLabel::setText
必须从QLabel
的所有者线程(很可能是主线程)执行。因此,如果从线程发出连接到QLabel
的setText
的信号,则必须使用Qt::AutoConnection
,Qt::QueuedConnection
或Qt::BlockingQueuedConnection
进行连接。
您可能不应该小心地从std::thread
创建的线程发出Qt信号。请参阅Jpo38's answer:连接类型问题等...
如果线程正在运行一些Qt事件循环,你可能会。见threads and QObject
有一个(特定于Unix的)解决方法,与Unix signals with Qt相同:使用std::thread
中的管道到主线程。
但是,正如Joachim Pileborg评论的那样,你应该制作自己的QThread。它是最简单的,也可能是最短的(在源代码方面),您只需复制并粘贴一些现有示例并根据您的需要进行调整。
请注意,AFAIK只有主线程才能进行Qt GUI操作。你不应该在主线程之外使用任何QWidget(etc ...)! (顺便说一句,GTK有相同的限制,至少在Linux上:只有主线程应该使用X Windows system protocols)
如果您保持指向QObject的指针,那么您可以使用QMetaObject::invokeMethod
成员之一http://qt-project.org/doc/qt-5/qmetaobject.html#invokeMethod
可能你将不得不使用Qt::QueuedConnection
所以你的信号将在适当的线程(而不是你的std :: thread)调用。请记住,您的信号不会立即被调用。
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();
}