【问题标题】:Qt - How to do what I want when another dialog is closed?Qt - 当另一个对话框关闭时如何做我想要的?
【发布时间】:2013-12-19 15:01:19
【问题描述】:

我有两个班级AB,这是B.h 中的一个sn-p:

#include "A.h"
class B : public QDialog
{
    Q_OBJECT
public:
    void do_something();
private:
    A *a;
}

B.cpp:

B::B(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::B)
{
    a = new A();
    a.show();
}

那么如果我想在Aui 关闭时(例如按Alt-F4)调用do_something() 该怎么办?好像signal-slot的方式在这里不适用。
非常感谢!

【问题讨论】:

  • A 的类型是什么? QWidget 还是 QDialog?
  • @UmNyobe 两个对话框。顺便说一句,这有什么关系?

标签: c++ qt user-interface qt5


【解决方案1】:

修改类 A 以在关闭时发出信号

如果修改 A 小部件是选项,请向其添加信号并覆盖 closeEventhideEvent 并在那里发出新信号。这是强大的,您可以完全控制发生的事情。但是,其余的答案是针对无论出于何种原因,您无法或不愿意与 A 混淆并希望在 B 类中找到解决方案的情况。

使用 Qt 信号进行 QObject 删除

如果您可以在A 上设置Qt::WA_DeleteOnClose attribute,那么简单的方法是使B::doSomething()(注意常见的Qt 方法命名约定)成为一个插槽并将A 实例的destroyed signal 连接到该插槽。

B::B(QWidget *parent) : QDialog(parent), ui(new Ui::B)
{
    a = new A();
    a->setAttribute(Qt::WA_DeleteOnClose);
    connect(a, SIGNAL(destroyed(QObject*)), SLOT(doSomething()));
    a.show();
}

当然,即使您明确地delete a;,这也有效,而不是自动使用该属性。

注意:在这种情况下,当对象随时可能被删除时,您应该真正使用QPointer 作为a 指针,以避免意外引用悬空指针。

使用 Qt 事件过滤器

如果您不想在A实例关闭时将其删除(如果再次需要则重新创建),那么另一种方法是在A实例上安装事件过滤器,并检测closeEvent .这有一个潜在的问题,小部件可以拒绝关闭事件,并且无论如何doSomething 在关闭之前被调用。如果这是一个问题,可以通过使用QMetaObject::invokeMethod static method 来延迟doSomething(它必须是槽或可调用的方法!)调用在关闭事件结束并且程序返回事件循环后发生。然后在doSomething 中检查a 是否真的被隐藏了。代替QEvent::Close,检测QEvent::Hide 也可能效果很好。

要实现这一点,请覆盖 B 中的虚拟 eventFilter method,如下所示:

bool B::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::Close) { //or QEvent::Hide maybe
        qDebug("QCloseEvent!");

        // check that object is indeed this->a before calling this->doSomething()
        if (qobject_cast<QObject *>(a) == obj) {
            doSomething();
            //alternative, make doSomething to be called later from event loop:
            //QMetaObject::invokeMethod(this, "doSomething", Qt::QueuedConnection);
        } else {
            qDebug("...but the object is not what is expected, a bug?");
        }
        // do not block the event, just detect it
    }

    // proceed with standard event processing
    return QObject::eventFilter(obj, event);
}

然后使用installEventFilter 开始监听A 实例的事件,类似于:

B::B(QWidget *parent) : QDialog(parent), ui(new Ui::B)
{
    a = new A();
    installEventFilter(a);
    a.show();
}

【讨论】:

  • 事件过滤器解决方案有一个严重缺陷:doSomething 在关闭 A 之前调用,如果 A 忽略事件并因此保持打开状态,也会调用它。正确的方法是在 A 接受 closeEvent 时从 A 发出信号。 (隐藏和关闭之间也有区别;接受关闭将隐藏小部件)。
  • @peppe 我不会称其为严重缺陷,因为它取决于 doSomething 的作用,以及实际的小部件是否有拒绝关闭事件的代码。无论如何,解决方法是通过事件循环调用 doSomething,并测试 a 是否确实隐藏(或删除...)。但是,好点!稍后我会改进答案。
  • @yakiang 答案在 peppe 的评论后编辑,你可能想看看。
【解决方案2】:

如果你不能使用模式窗口(或对话框)而不是你有更多的工作,你需要继承 QWidget(或 QDialog 或其他 QWidget 派生类,无论你需要什么)并覆盖 QWidget::closeEvent (对于类 A) 并从这里调用父类的方法(我想 a 将是您代码中 this 的子类:a = new A(this);) 或编写自己的信号/槽。

如果您决定使用模态对话框,代码会变得更简单,请参阅 QDialog 的documentation 中的示例代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-04
    • 2023-01-19
    • 2020-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多