如果设置了父级,QDialog::show()
不显示窗口是预期行为吗?
背景:我想使用QMetaObject::connectSlotsByName()
对其中一个对话框信号做出反应,这意味着父对象需要拥有它。如果没有标记为">这就是有问题的行"的行,我会收到一条运行时消息">QMetaObject::connectSlotsByName:on_child_accepted((没有匹配的信号"。但是有了这行,子对话框就不再出现了。
#include <QtCore/QDebug>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QVBoxLayout>
class Parent : public QDialog
{
Q_OBJECT
public:
Parent(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
: QDialog{parent, f}
{
b.setText(tr("Show child"));
connect(&b, &QPushButton::clicked, [&]() {
c.show();
});
l.addWidget(&b);
setLayout(&l);
c.setParent(this); // This is the line in question
c.setObjectName("child");
QMetaObject::connectSlotsByName(this);
}
private slots:
void on_child_accepted()
{
qDebug() << "I got called";
}
private:
QPushButton b;
QDialog c;
QVBoxLayout l;
};
#include "main.moc"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Parent w;
w.show();
return a.exec();
}
此测试在MSYS2 64位版本的Windows版Qt 5.11上失败。
有什么建议吗?提前谢谢。
对话框确实出现了,但并不是你想象的那样:它是窗口的一个非窗口子窗口小部件-它是透明的,但它遮挡了"显示对话框"按钮的大部分内容,消耗了所有鼠标事件,而且它已经显示了,因为当显示父窗口时,所有子窗口都会显示-所以由于这两个原因,按钮似乎都不起作用。
设置小部件的父级将清除其Qt::Window
标志。设置对话框的背景有助于将问题可视化。因此,您需要在设置其父对话框后将其设置为一个窗口。
以下内容再现了您的错误,并演示了修复方法。
// https://github.com/KubaO/stackoverflown/tree/master/questions/dialog-show-parenting-53208641
#include <QtWidgets>
class Parent : public QDialog {
Q_OBJECT
QVBoxLayout layout{this};
QDialog child;
QPushButton cShow{tr("Show child")}, cNonWindow{tr("Renew non-window child")},
cWindow{tr("Renew window child")};
Q_SLOT void on_child_accepted() {}
void reChild(bool makeWindow) {
child.~QDialog();
new (&child) QDialog;
Q_ASSERT(child.isWindow());
child.setParent(this);
child.setObjectName("child");
child.setStyleSheet("QWidget { background: blue }");
if (makeWindow) {
child.setWindowFlag(Qt::Dialog);
Q_ASSERT(child.isWindow());
} else {
Q_ASSERT(!child.isWindow());
child.show(); // The child gets shown when we're shown
}
QMetaObject::invokeMethod(this, &Parent::updateChild, Qt::QueuedConnection);
}
void updateChild() {
if (!child.isWindow()) child.move(50, cWindow.y() + cWindow.height() / 2);
this->update(); // Work around a refresh bug (affects OS X on 5.11 at least)
}
public:
Parent(QWidget *parent = nullptr, Qt::WindowFlags f = {}) : QDialog{parent, f} {
connect(&cShow, &QPushButton::clicked, [&]() { child.show(); });
connect(&cNonWindow, &QPushButton::clicked, [&] { reChild(false); });
connect(&cWindow, &QPushButton::clicked, [&] { reChild(true); });
for (auto *w : {&cShow, &cNonWindow, &cWindow}) layout.addWidget(w);
cNonWindow.click();
QMetaObject::connectSlotsByName(this);
}
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Parent w;
w.show();
return a.exec();
}
#include "main.moc"