【问题标题】:QT QDialog not hiding properly when show/hide called quickly快速调用显示/隐藏时QT QDialog没有正确隐藏
【发布时间】:2013-08-03 21:46:21
【问题描述】:

我的主线程上有一个 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() 就会得到一个幽灵对话框。

我使用了 QThread::currentThreadId() 并验证了对话框和逻辑在不同的线程上运行。

为什么在这种情况下我的对话框不能正确隐藏?我是否应该强制我的逻辑始终运行至少几百毫秒(该解决方案很糟糕)?有没有办法让我的对话框在尝试隐藏之前确保它已完全加载?我应该以不同的方式处理这些信号/插槽吗?

编辑:我目前已经辞职,只是在我发出信号以显示()对话框后放置一个 QThread::sleep(1) 。我不喜欢这个解决方案,但似乎没有其他方法有效。 sleep(1) 允许对话框在隐藏之前一直出现。我也能够让它与 QThread::msleep(10) 一起工作,但这仍然导致大约 6 次尝试中出现鬼对话框。

每当我调用 show() 或 hide() 时,我都尝试在对话框逻辑中使用成员 QMutex,但这不起作用。

我将所有跨线程连接更改为使用 Qt::BlockingQueuedConnection 和 Qt::QueuedConnection,但都没有成功。

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

【问题讨论】:

    标签: c++ qt qthread qdialog


    【解决方案1】:

    我也有同样的问题,显示对话框,当得到一些信号关闭它时,当时间小于 20ms(意味着快速隐藏对话框),它会留下一个幽灵对话框。

    所以,我只是使用

    QTimer::singleShot(50, this, [this](){
        hide(); //hide dialog
    });
    

    在关闭处理函数中。看起来效果不错。

    【讨论】:

    • 50 毫秒对我来说是不够的。我不得不使用更大的超时时间(我使用 2000 毫秒,这对我来说还可以,但也可能有更低的值)
    【解决方案2】:

    我的猜测是出现问题是因为“显示”和“隐藏”调用交错。要验证这一点,请使用信号量 - 锁定对象直到显示完成,然后在隐藏中等待它。另请查看此处投票最多的答案以获取另一种可能(也许更好)的解决方案:connecting signal/slot across different threads between QObjects

    【讨论】:

    • 使用 QMutex 在 Show()/Hide() 函数中设置锁定以在操作之前和之后锁定/解锁;没有成功。我还通读了链接的解决方案并尝试了所有逻辑连接类型,但问题仍然存在。
    【解决方案3】:

    使用Qt::BlockingQueuedConnection 将信号连接到插槽。确保主线程的事件循环没有被阻塞。此外,如果您的工作线程使用大量 cpu 时间 - 您可以调用 QThread::yeldCurrentThread() 调用。

    【讨论】:

      猜你喜欢
      • 2020-06-09
      • 2012-05-18
      • 1970-01-01
      • 1970-01-01
      • 2015-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多