我的主线程上有一个QDialog,我有一些逻辑发生在一个单独的线程上。逻辑开始时,会在对话框上发出连接到show()的信号。当逻辑结束时,会发出一个信号,该信号连接到对话框上的hide()。当逻辑确实起作用时,对话框将正确显示/隐藏。如果逻辑“无”并且信号仅按顺序发出,则对话框并不总是正确显示/隐藏。
我的联系类似于:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = 0) :
Ui(new Ui::MainWindowUi),
Transferer(new DataTransferer()),
TransferProgress(this),
TransferThread()
{
Ui->setupUi();
connect(&Transferer, SIGNAL(Begin()), &TransferProgress, SLOT(show()));
connect(&Transferer, SIGNAL(End()), &TransferProgress, SLOT(hide()));
Transferer.moveToThread(&TransferThread);
TransferThread.start();
Transferer.DoStuff(true);
}
virtual ~MainWindow()
{
TransferThread.quit();
TransferThread.wait(1000);
delete Ui;
Ui = NULL;
}
private:
Ui::MainWindowUi* Ui;
DataTransferer Transferer;
TransferProgressDialog TransferProgress;
QThread TransferThread;
}
逻辑看起来类似于:
class DataTransferer : public QObject
{
Q_OBJECT
public:
DataTransferer(QObject *parent) : QObject(parent) {}
virtual ~DataTransferer() {}
void DoStuff(bool dontDoStuff)
{
emit Start();
if (!dontDoStuff)
{
QThread::sleep(1);
}
emit End();
}
}
当DataTransferer执行操作时,一切正常。当对话框快速连续显示和隐藏时,我几乎每隔一次调用DoStuff()就会得到一个ghost对话框。
我使用了QThread :: currentThreadId()并验证了对话框和逻辑在不同的线程上运行。
为什么我的对话框在这种情况下无法正确隐藏?我应该强迫我的逻辑始终运行至少几百毫秒(该解决方案是坏的)?有没有办法让我的对话框确保它完全加载后再尝试隐藏自己?我应该以不同方式处理这些信号/插槽吗?
编辑:在我发出信号以显示()对话框之后,我现在已经辞职,只是放了一个QThread :: sleep(1)。我不喜欢这个解决方案,但似乎没有其他任何工作。 sleep(1)允许对话框在隐藏之前一直向上。我也能够使用QThread :: msleep(10),但这仍然导致了鬼对话,大约有6次尝试。每当我调用show()或hide()时,我都尝试在对话逻辑中使用成员QMutex,但这不起作用。
我更改了所有跨线程连接以使用Qt :: BlockingQueuedConnection和Qt :: QueuedConnection,并且两次尝试均未成功。
我尝试将插槽连接从对话框移动到设置连接的对象,然后直接调用插槽,但这也没有成功。
答案 0 :(得分:1)
我也有同样的问题,显示对话框,当收到一些信号将其关闭时,如果时间少于20ms(这意味着快速隐藏对话框),它将留下一个幽灵对话框。
所以,我只是使用
QTimer::singleShot(50, this, [this](){
hide(); //hide dialog
});
在关闭处理程序函数中。看来效果很好。
答案 1 :(得分:0)
我的猜测是因为“show”和“hide”调用隔行扫描而出现问题。要验证这一点,请使用信号量 - 锁定对象直到show完成,然后在hide中等待它。另请参阅此处最高投票的答案,了解另一种可能(可能更好)的解决方案:connecting signal/slot across different threads between QObjects
答案 2 :(得分:0)
使用Qt::BlockingQueuedConnection
将信号连接到插槽。确保未阻止主线程的事件循环。此外,如果您的工作线程使用了大量的cpu时间 - 您可以拨打QThread::yeldCurrentThread()
电话。