【问题标题】:How to hide a QDialog (not showing GUI) on exec()如何在 exec() 上隐藏 QDialog(不显示 GUI)
【发布时间】:2014-08-08 02:03:14
【问题描述】:

我想 exec() 一个没有 GUI 的 QDialog 用于我的测试 - 不需要显示 GUI。

在主窗口中,当我 exec() 一个 QDialog 时,它会显示它的 GUI 窗口。我将来自 QDialog 中线程的信号连接到 QDialog 中的插槽,因此需要 QDialog.exec()。 QDialog.hide() 不起作用。

有什么解决办法吗?

【问题讨论】:

    标签: qt


    【解决方案1】:

    你永远不应该exec() 对话。这可能会导致细微的错误,因为exec() 调用可以重新输入您不打算重新输入的代码。

    如果你真的坚持使用exec(),那么简单的解决方案是在对话框中发布CloseEvent。一旦对话框的事件循环开始运行,就会处理该事件。

    MyDialog dialog;
    QCoreApplication::postEvent(&dialog, new QCloseEvent());
    dialog.exec();
    

    此代码在功能上等同于以下代码:

    MyDialog dialog;
    QMetaObject::invokeMethod(&dialog, "close", Qt::QueuedConnection);
    dialog.exec();
    

    另一种更安全的方法是不使用exec。只需将对话框的 accepted()rejected() 信号连接到代码中的槽 - 毕竟,对话框的接受或拒绝是异步发生的。

    这样就很容易了,只需不在测试代码路径中show() 对话框。您还可以通过调用acceptreject 插槽轻松模拟被接受或拒绝的对话框。

    我真的不明白您是如何将信号从线程“连接”到对话框的插槽等的。随意将下面的示例粘贴到您的问题中,修改它以执行线程化的“东西”,并展示它是如何不起作用的。了解您是如何实现测试工具的也会有所帮助。

    下面的示例都是一个文件,如果您在生成说明您的问题的测试用例时保持这种方式会有所帮助。

    // main.cpp
    #include <QApplication>
    #include <QDialog>
    #include <QLabel>
    #include <QGridLayout>
    #include <QPushButton>
    #include <QDialogButtonBox>
    
    class MyDialog : public QDialog {
       QGridLayout m_layout;
       QDialogButtonBox m_box;
    public:
       MyDialog(QWidget * parent = 0) : QDialog(parent), m_layout(this),
          m_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
       {
          m_layout.addWidget(&m_box);
          connect(&m_box, SIGNAL(accepted()), SLOT(accept()));
          connect(&m_box, SIGNAL(rejected()), SLOT(reject()));
       }
    };
    
    class MyGui : public QWidget {
       Q_OBJECT
       QGridLayout m_layout;
       QLabel m_label;
       QPushButton m_button;
       MyDialog m_dialog;
       Q_SLOT void on_button_clicked() {
          m_dialog.show();
       }
       Q_SLOT void on_dialog_accepted() {
          m_label.setText("The dialog was accepted");
       }
       Q_SLOT void on_dialog_rejected() {
          m_label.setText("The dialog was rejected");
       }
    public:
       MyGui() : m_layout(this), m_button("Show Dialog"), m_dialog(this) {
          m_button.setObjectName("button");
          m_dialog.setObjectName("dialog");
          m_layout.addWidget(&m_label);
          m_layout.addWidget(&m_button);
          QMetaObject::connectSlotsByName(this);
       }
    };
    
    int main(int argc, char *argv[])
    {
       QApplication app(argc, argv);
       MyGui gui;
       gui.show();
       return app.exec();
    }
    
    #include "main.moc"
    

    【讨论】:

    • 感谢非常详细的回答。我在主窗口类中创建了 QDialog 变量,并且没有 exec(),而是调用了我的 QDialog 公共函数来执行线程工作( thread finish() 调用 accept() )。现在我没有看到 QDialog 的任何 GUI。
    • @user18640 你确定你只在 GUI 线程上调用对话框的方法吗?您永远不应该在主线程以外的线程中调用任何QWidgetQPixmap 方法。您可以使用QMetaObject::invokeMethod(widget, "method", Qt::QueuedConnection) 安全地对可调用方法进行跨线程调用。
    • 我只在对话框的构造函数(即 setupUi()、connect() )中调用对话框的方法,而不是在其他地方,在我的测试模式下(无 GUI)。现在我的测试模式运行良好(也许?)。难道我做错了什么?感谢您的建议。
    • @user18640 构造函数是在主线程中调用的,还是在工作线程中调用的?在除 gui 线程之外的任何线程中构造小部件都是错误的。
    • 对不起,迟到的评论。对话框的构造函数在主线程(主窗口)中调用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 2020-04-19
    相关资源
    最近更新 更多