假设有以下QT代码(QT5.3.1):
void SenderClass::runSignal()
{
emit mySignal();
}
void ReceiverClass::ReceiverClass()
{
...
connect (senderClassRef, SIGNAL(mySignal()), this, SLOT(mySlot()) );
}
void ReceiverClass::mySlot()
{
//Long operation executions
Sleep(1000);
qDebug() << "1";
Sleep(1000);
qDebug() << "2";
Sleep(1000);
qDebug() << "3";
}在连续调用runSignal()时,控制台显示的内容如下:
1 2 1 3 2 3
这两个类生活在同一个线程中。我必须在插槽中使用QMutexLocker吗?或者有另一种方法可以得到有序的输出,比如:
1 2 3 1 2 3
因此,如果仍然有一个正在执行的函数,则阻止mySlot()函数调用。
更新
下面是一个真正的代码片段。发件人:
//Sender.h
#include <QtWidgets/QWidget>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTextBrowser>
class Receiver;
class Sender : public QWidget
{
Q_OBJECT
public:
Sender(QWidget *parent = 0);
QPushButton *pushButton;
QTextBrowser *textBrowser;
Receiver* receiver;
signals:
void buttonClickedSignal();
public slots:
void ButtonClickedSlot();
};
//Sender.cpp
#include "Sender.h"
#include "Receiver.h"
#include <QObject>
Sender::Sender(QWidget *parent)
: QWidget(parent)
{
pushButton = new QPushButton(this);
pushButton->setObjectName(QStringLiteral("pushButton"));
pushButton->setGeometry(QRect(150, 30, 75, 23));
pushButton->setText("Button");
textBrowser = new QTextBrowser(this);
textBrowser->setObjectName(QStringLiteral("textBrowser"));
textBrowser->setGeometry(QRect(50, 90, 256, 192));
receiver = new Receiver(this);
QObject::connect(pushButton, SIGNAL(clicked()), this, SLOT(ButtonClickedSlot()));
}
void Sender::ButtonClickedSlot()
{
emit buttonClickedSignal();
}接受者:
//Receiver.h
#include "Sender.h"
class Receiver : QObject
{
Q_OBJECT
public:
Receiver(Sender *sender);
Sender *m_sender;
public slots:
void ReceiverSlot();
};
//Receiver.cpp
#include "Receiver.h"
#include <QObject>
#include <QThread>
#include <QApplication>
Receiver::Receiver(Sender *sender)
{
m_sender = sender;
QObject::connect(m_sender, SIGNAL(buttonClickedSignal()), this, SLOT(ReceiverSlot()), Qt::QueuedConnection);
}
void Receiver::ReceiverSlot()
{
m_sender->textBrowser->append("1");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("2");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("3");
QThread::msleep(100);
qApp->processEvents();
m_sender->textBrowser->append("4");
QThread::msleep(100);
qApp->processEvents();
}单击该按钮会很快在QTextBrowser中生成不连续的数字,即使设置了QueuedConnection。

更新2
我想要实现的是对ReceiverSlot的排队访问。用户可以随心所欲地按下按钮(当他想要的时候,以任何速度)。ReceiverSlot不能错过任何事件。我需要某种类型的事件队列,以便ReceiverSlot中的(long)操作总是被执行,可能会延迟,但会被执行。
发布于 2015-02-13 08:02:50
摆脱QApplication::processEvents,将冻结GUI的长时间操作移动到一个新线程。例如,可以使用移动到新线程的worker对象。有一个这在文档中很好的例子。。
您还应该阅读这来了解更多关于Qt中的线程和事件的信息。与您在强迫事件调度部分中解释的情况完全相同:
当“通过其他路径”重新进入事件循环时要非常小心:它可能导致不必要的递归!让我们回到Button示例。如果我们在doWork()槽内调用QCoreApplication::processEvents(),并且用户再次单击该按钮,则将再次调用doWork()槽:
通常,您希望避免使用QApplication::processEvents并创建本地事件循环。如果您的代码中有这些,那么您应该重新设计它,这样您就不必使用这些了。
Worker对象从文档中进行检查:
class Worker : public QObject
{
Q_OBJECT
QThread workerThread;
public slots:
void doWork(const QString ¶meter) {
// ...
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};发布于 2015-02-12 15:26:59
把我的意见变成一个恰当的答案:
如果在您的插槽中调用qApp->processEvents()时,有一个鼠标按事件等待被传递到按钮,则它将被传递,clicked()信号将再次发出,因此您的插槽将再次被调用。
QMutex不会有帮助,因为不涉及线程。添加一个很可能会导致程序死锁。
使用Qt::QueuedConnection没有帮助,因为这会将一个事件发布到队列中,在处理该事件时,将导致调用插槽。因此,充其量,它只是将其推迟到下次调用qApp->processEvents()时。
在示例的上下文中,我的建议是摆脱排队的连接,而是在插槽工作时禁用按钮。这将防止再次发出clicked()信号,并显示用户此时不应该试图单击按钮。
如果出于任何原因您不想这样做,您可以添加一个标志到您的接收类,以防止递归调用。像这样的东西会起作用的,尽管它不是很漂亮:
void Receiver::ReceiverSlot()
{
if( m_inSlot )
return;
m_inSlot = true;
// do work
m_inSlot = false;
}https://stackoverflow.com/questions/28473563
复制相似问题