快速调用show / hide时,QT QDialog无法正确隐藏

时间:2013-08-03 21:46:22

标签: c++ qt qthread qdialog

我的主线程上有一个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,并且两次尝试均未成功。

我尝试将插槽连接从对话框移动到设置连接的对象,然后直接调用插槽,但这也没有成功。

3 个答案:

答案 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()电话。