来源于 fly542 的一篇blog中描述的一个问题:将一个QMainWindow 作为 QDockWidget的内容widget时,QMainWindow 会作为顶级窗口弹出。
本着精简的原则,我们提供下面可重现问题的例子:
#include <QtGui/QApplication> #include <QtGui/QMainWindow> #include <QtGui/QDockWidget> #define CASE1 int main(int argc, char *argv[]) { QApplication app(argc, argv); QDockWidget dw; #ifdef CASE1 QMainWindow mw(&dw); #elif defined CASE2 QMainWindow mw; mw.setParent(&dw); #else QMainWindow mw; #endif dw.setWidget(&mw) dw.show(); return app.exec(); }
编译预处理部分的两段代码会产生什么不同的结果呢??
QMainWindow mw(&dw); |
会出现两个窗口,一个是dw,一个是mw |
QMainWindow mw; |
只出现一个窗口dw,而mw是dw的子widget |
QMainWindow mw; |
同上 |
其实,在这之前,我一直认为上面的CASE1和CASE2代码是等价的。但现在,显然不能再这样认为了。
之所以会这样,是因为两种情况下,WindowFlags 标记不同!!前者之所以会弹出,是因为mw是顶级窗口(设置有 Qt::Window 标记位),后者则清除了该标记位。
QMainWindow::QMainWindow(QWidget *parent, Qt::WindowFlags flags) : QWidget(*(new QMainWindowPrivate()), parent, flags | Qt::Window) { d_func()->init(); }
void QWidget::setParent(QWidget *parent) { if (parent == parentWidget()) return; setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask); }
void QDockWidget::setWidget(QWidget *widget) { QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout()); layout->setWidgetForRole(QDockWidgetLayout::Content, widget); } void QLayout::addChildWidget(QWidget *w) { QWidget *mw = parentWidget(); QWidget *pw = w->parentWidget(); ... if (!pw && mw) w->setParent(mw); ... }
去掉 dw.show() 后,CASE1 其实仍然会弹出mw窗口。原因何在呢?
答案在:QDockWidget::setWidget 调用的函数:
void QDockWidgetLayout::setWidgetForRole(Role r, QWidget *w) { ... if (w != 0) { addChildWidget(w); item_list[r] = new QWidgetItemV2(w); w->show();
会设置 w 可见!!
贴出另一个例子:感兴趣可以自己来做些测试。该说的前面都说了,就不解释了
#include <QtGui/QApplication> #include <QtGui/QMainWindow> #include <QtGui/QDockWidget> #define CASE3 class MainWindow:public QMainWindow { public: MainWindow() { QDockWidget * dock1 = new QDockWidget(this); #ifdef CASE1 QWidget * w = new QMainWindow(dock1); #elif defined CASE2 QWidget * w = new QMainWindow; #elif defined CASE3 QWidget * w = new QWidget(dock1); w->setWindowFlags(w->windowFlags()|Qt::Window); #endif w->setStyleSheet("background-color: rgb(0, 255, 255);"); dock1->setWidget(w); // dock1->hide(); this->addDockWidget(Qt::LeftDockWidgetArea, dock1); } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow w; w.show(); return app.exec(); }
http://blog.csdn.net/fly542/article/details/6678527