Qt 之 WindowFlags 引发的有趣问题一则

来源

来源于 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;
mw.setParent(&dw);

只出现一个窗口dw,而mw是dw的子widget

QMainWindow mw;

同上

原因何在?

其实,在这之前,我一直认为上面的CASE1和CASE2代码是等价的。但现在,显然不能再这样认为了。

之所以会这样,是因为两种情况下,WindowFlags 标记不同!!前者之所以会弹出,是因为mw是顶级窗口(设置有 Qt::Window 标记位),后者则清除了该标记位。

源码

  • QMainWindow 构造时会设置 Qt::Window 标记位!

QMainWindow::QMainWindow(QWidget *parent, Qt::WindowFlags flags)
    : QWidget(*(new QMainWindowPrivate()), parent, flags | Qt::Window)
{
    d_func()->init();
}
  • QWidget::setParent 会清除 Qt::Window 标记位!

void QWidget::setParent(QWidget *parent)
{
    if (parent == parentWidget())
        return;
    setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask);
}
  • QDockWidget如果发现被设置的widget不是自己的子对象,则也辗转调用 QWidget::setParent,进而清除Qt::Window 标记
    • 其实是QLayout 提供的功能

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


你可能感兴趣的:(list,测试,Blog,layout,Class,qt)