谈QWidget及其派生类

2013年12月25日 由 Creater 留言 »

QWidget

QWidget 是Qt中所有widget部件(比如QDialog、QPushButton、QLabel)的基类,任何你可以通过其派生类实现的东西,你都可以通过QWidget实现。

QDialog有模态非模态之说

QWidget 也有

QDialog dlg(this)是一个窗口

QWidget wgt(this)也可以是窗口

QMainWindow可以有菜单栏、工具栏等

QWidget 同样可以有这些

Window 与 Widget异同

Qt中的部件有Window和普通widget之说:

Window

窗口

Window是这样的Widget:它不是其他Widget的一部分区域,通常有标题栏等窗口装饰器!(和是否有parent无关)

Widget

普通部件(非窗口)

除Window外的部件

如何可以知道一个Widget是否是Window?通过函数QWidget::isWindow()

inline bool QWidget::isWindow() const
{ return (windowType() & Qt::Window); }

其中的windowType()为

inline Qt::WindowType QWidget::windowType() const
{ return static_cast<Qt::WindowType>(int(data->window_flags & Qt::WindowType_Mask)); }

根据其提示,可以得知和windowFlags()有关。

来看下面的函数

QWidget::QWidget(QWidget * parent = 0, Qt::WindowFlags f = 0 )
void QWidget::setWindowFlags(Qt::WindowFlags type )

QDialog::QDialog(QWidget * parent = 0, Qt::WindowFlags f = 0 )
...

你可以通过构造函数或者成员函数setWindowFlags传递这个参数。 而且,你从前面的isWindow()的源码可以得出结论: 一个Widget是不是一个Window,只取决于它的的WindowFlags中是否包含Qt::Window

综上所述,一个Widget是不是一个Window,只取决于它的的WindowFlags中是否包含Qt::Window,即与 Qt::WindowFlags有关,与parent无关。下面先例举所有的WindowFlags,其实WindowFlags是WindowType强化了类型安全。

    enum WindowType {
        Widget = 0x00000000,
        Window = 0x00000001,
        Dialog = 0x00000002 | Window,
        Sheet = 0x00000004 | Window,
        Drawer = Sheet | Dialog,
        Popup = 0x00000008 | Window,
        Tool = Popup | Dialog,
        ToolTip = Popup | Sheet,
        SplashScreen = ToolTip | Dialog,
        Desktop = 0x00000010 | Window,
        SubWindow = 0x00000012,
        ForeignWindow = 0x00000020 | Window,
        CoverWindow = 0x00000040 | Window,

        WindowType_Mask = 0x000000ff,
        MSWindowsFixedSizeDialogHint = 0x00000100,
        MSWindowsOwnDC = 0x00000200,
        BypassWindowManagerHint = 0x00000400,
        X11BypassWindowManagerHint = BypassWindowManagerHint,
        FramelessWindowHint = 0x00000800,
        WindowTitleHint = 0x00001000,
        WindowSystemMenuHint = 0x00002000,
        WindowMinimizeButtonHint = 0x00004000,
        WindowMaximizeButtonHint = 0x00008000,
        WindowMinMaxButtonsHint = WindowMinimizeButtonHint | WindowMaximizeButtonHint,
        WindowContextHelpButtonHint = 0x00010000,
        WindowShadeButtonHint = 0x00020000,
        WindowStaysOnTopHint = 0x00040000,
        WindowTransparentForInput = 0x00080000,
        WindowOverridesSystemGestures = 0x00100000,
        WindowDoesNotAcceptFocus = 0x00200000,

        CustomizeWindowHint = 0x02000000,
        WindowStaysOnBottomHint = 0x04000000,
        WindowCloseButtonHint = 0x08000000,
        MacWindowToolBarButtonHint = 0x10000000,
        BypassGraphicsProxyWidget = 0x20000000,
        WindowOkButtonHint = 0x00080000,
        WindowCancelButtonHint = 0x00100000,
        NoDropShadowWindowHint = 0x40000000,
        WindowFullscreenButtonHint = 0x80000000
    };

    Q_DECLARE_FLAGS(WindowFlags, WindowType)

来看下面几个例子:
1.比如:一个QPushButton,如果没有parent,它就是一个窗口。而设置了parent,它却不是一个窗口了。感觉就是和parent有关,而与flags无关。
其实对于QWidget,如果其parent为空,构造时会有下面的动作:

uint type = (flags & Qt::WindowType_Mask);

    if ((type == Qt::Widget || type == Qt::SubWindow) && w && !w->parent()) {
        type = Qt::Window;
        flags |= Qt::Window;
    }

当没有parent时, Qt::WindowFlags f =0,并且!w->parent()为true,得到flags |= Qt::Window,所以为windows。
当有parent时,w->parent()返回非null,Qt::WindowFlags f =0,所以为widget。

2.再来看个例子

QDialog::QDialog(QWidget *parent, Qt::WindowFlags f)
    : QWidget(*new QDialogPrivate, parent,
              f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
{
...

QDialog是派生类,它构造函数中传给基类的参数包含了Qt::Dailog(即0x00000002|Qt::Window)。既然包含了Qt::Widnow标记,也即为window了。

3.再看

QPushButton * btn = new QPushButton(this);
btn-&gt;setWindowFlags(Qt::Window);

通过setWindowFlags也是可以的,前边也说了,可以通过构造函数设置,也可以通过setWindowFlags函数,运行后可以看见QPushButton 变成了窗口。

广告位

发表评论

你必须 登陆 方可发表评论.