zoukankan      html  css  js  c++  java
  • QT分析之QPushButton的初始化

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201001003326522/

    在简单的QT程序的第二行,声明了一个QPushButton的对象。先简单看看其初始化过程。

    QPushButton的类继承关系为:

    1 QPushButton :public QAbstractButton :pubic QWidget :public QObject, public QPaintDevice

    QPushButton的构造:

    1 QPushButton::QPushButton(const QString &text, QWidget *parent)
    2     : QAbstractButton(*new QPushButtonPrivate, parent)
    3 {
    4     Q_D(QPushButton);  // 声明并获得QPushButtonPrivate函数指针d
    5     setText(text);    // 设置按钮的名字
    6     d->init();   // 调用QPushButtonPrivate::init(),其实只是重新设定排布间隔
    7 }

    新生成的QPushButtonPrivate对象传递给QAbstractButton之后,发生了什么事呢?

    1 QAbstractButton::QAbstractButton(QAbstractButtonPrivate &dd, QWidget *parent)
    2     : QWidget(dd, parent, 0)
    3 {
    4     Q_D(QAbstractButton);  // 声明并获得QAbstractButtonPrivate函数指针d
    5     d->init();   // 调用QAbstractButtonPrivate::init()
    6 }

    QAbstractButtonPrivate::init()做了什么呢?其实只是调用了QPushButton的几个设定函数。

    继续看QWidget的初始化过程。

    1 QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f)
    2     : QObject(dd, 0), QPaintDevice()
    3 {
    4     d_func()->init(parent, f);
    5 }

    其中d_func()是宏定义Q_DECLARE_PRIVATE(QWidget)中定义的,获取QWidgetPrivate指针的函数。有点奇怪的是,这里怎么没有用Q_D宏定义,与之前的风格有点不同。

    QWidgetPrivate::init()里做了什么动作呢?(关键语句用颜色标记)

     1 void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
     2 {
     3     Q_Q(QWidget);
     4     if (qApp->type() == QApplication::Tty)
     5         qFatal("QWidget: Cannot create a QWidget when no GUI is being used");
     6 
     7     Q_ASSERT(uncreatedWidgets);
     8     uncreatedWidgets->insert(q);
     9 
    10     QWidget *desktopWidget = 0;
    11     if (parentWidget && parentWidget->windowType() == Qt::Desktop) {
    12         desktopWidget = parentWidget;
    13         parentWidget = 0;
    14     }
    15 
    16     q->data = &data;
    17 
    18     if (!q->parent()) {
    19         Q_ASSERT_X(q->thread() == qApp->thread(), "QWidget",
    20                    "Widgets must be created in the GUI thread.");
    21     }
    22 
    23     data.fstrut_dirty = true;
    24 
    25     data.winid = 0;
    26     data.widget_attributes = 0;
    27     data.window_flags = f;
    28     data.window_state = 0;
    29     data.focus_policy = 0;
    30     data.context_menu_policy = Qt::DefaultContextMenu;
    31     data.window_modality = Qt::NonModal;
    32 
    33     data.sizehint_forced = 0;
    34     data.is_closing = 0;
    35     data.in_show = 0;
    36     data.in_set_window_state = 0;
    37     data.in_destructor = false;
    38 
    39     // Widgets with Qt::MSWindowsOwnDC (typically QGLWidget) must have a window handle.
    40     if (f & Qt::MSWindowsOwnDC)
    41         q->setAttribute(Qt::WA_NativeWindow);
    42 
    43     q->setAttribute(Qt::WA_QuitOnClose); // might be cleared in adjustQuitOnCloseAttribute()
    44     adjustQuitOnCloseAttribute();
    45 
    46     q->setAttribute(Qt::WA_WState_Hidden);
    47 
    48     //give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later
    49     data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,640,480);
    50 
    51     focus_next = focus_prev = q;
    52 
    53     if ((f & Qt::WindowType_Mask) == Qt::Desktop)
    54         q->create();  // 调用了QWidget::create()
    55     else if (parentWidget)
    56         q->setParent(parentWidget, data.window_flags);
    57     else {
    58         adjustFlags(data.window_flags, q);
    59         resolveLayoutDirection();
    60         // opaque system background?
    61         const QBrush &background = q->palette().brush(QPalette::Window);
    62         setOpaque(q->isWindow() && background.style() != Qt::NoBrush && background.isOpaque());
    63     }
    64     data.fnt = QFont(data.fnt, q);
    65 
    66     q->setAttribute(Qt::WA_PendingMoveEvent);
    67     q->setAttribute(Qt::WA_PendingResizeEvent);
    68 
    69     if (++QWidgetPrivate::instanceCounter > QWidgetPrivate::maxInstances)
    70         QWidgetPrivate::maxInstances = QWidgetPrivate::instanceCounter;
    71 
    72     if (QApplicationPrivate::app_compile_version < 0x040200
    73         || QApplicationPrivate::testAttribute(Qt::AA_ImmediateWidgetCreation))
    74         q->create();
    75 
    76     // 下面的三行,产生并发送了Create事件
    77     QEvent e(QEvent::Create);
    78     QApplication::sendEvent(q, &e);
    79     QApplication::postEvent(q, new QEvent(QEvent::PolishRequest));
    80 
    81     extraPaintEngine = 0;
    82 }

    看看QWidget::create()的实现:

     1 void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
     2 {
     3     Q_D(QWidget);
     4     if (testAttribute(Qt::WA_WState_Created) && window == 0 && internalWinId())
     5         return;
     6 
     7     if (d->data.in_destructor)
     8         return;
     9 
    10     Qt::WindowType type = windowType();
    11     Qt::WindowFlags &flags = data->window_flags;
    12 
    13     if ((type == Qt::Widget || type == Qt::SubWindow) && !parentWidget()) {
    14         type = Qt::Window;
    15         flags |= Qt::Window;
    16     }
    17 
    18     if (QWidget *parent = parentWidget()) {
    19         if (type & Qt::Window) {
    20             if (!parent->testAttribute(Qt::WA_WState_Created))
    21                 parent->createWinId();
    22         } else if (testAttribute(Qt::WA_NativeWindow) && !parent->internalWinId()
    23                    && !testAttribute(Qt::WA_DontCreateNativeAncestors)) {
    24             // We're about to create a native child widget that doesn't have a native parent;
    25             // enforce a native handle for the parent unless the Qt::WA_DontCreateNativeAncestors
    26             // attribute is set.
    27             d->createWinId(window);
    28             // Nothing more to do.
    29             Q_ASSERT(testAttribute(Qt::WA_WState_Created));
    30             Q_ASSERT(internalWinId());
    31             return;
    32         }
    33     }
    34 
    35     static int paintOnScreenEnv = -1;
    36     if (paintOnScreenEnv == -1)
    37         paintOnScreenEnv = qgetenv("QT_ONSCREEN_PAINT").toInt() > 0 ? 1 : 0;
    38     if (paintOnScreenEnv == 1)
    39         setAttribute(Qt::WA_PaintOnScreen);
    40 
    41     if (QApplicationPrivate::testAttribute(Qt::AA_NativeWindows))
    42         setAttribute(Qt::WA_NativeWindow);
    43 
    44 #ifdef ALIEN_DEBUG
    45     qDebug() << "QWidget::create:" << this << "parent:" << parentWidget()
    46              << "Alien?" << !testAttribute(Qt::WA_NativeWindow);
    47 #endif
    48 
    49     // Unregister the dropsite (if already registered) before we
    50     // re-create the widget with a native window.
    51     if (testAttribute(Qt::WA_WState_Created) && !internalWinId() && testAttribute(Qt::WA_NativeWindow)
    52             && d->extra && d->extra->dropTarget) {
    53         d->registerDropSite(false);
    54     }
    55 
    56     d->updateIsOpaque();
    57 
    58     setAttribute(Qt::WA_WState_Created);                        // set created flag
    59     d->create_sys(window, initializeWindow, destroyOldWindow);
    60 
    61     // a real toplevel window needs a backing store
    62     if (isWindow()) {
    63         delete d->topData()->backingStore;
    64         // QWidgetBackingStore will check this variable, hence it must be 0
    65         d->topData()->backingStore = 0;
    66         if (hasBackingStoreSupport())
    67             d->topData()->backingStore = new QWidgetBackingStore(this);
    68     }
    69 
    70     d->setModal_sys();
    71 
    72     if (!isWindow() && parentWidget() && parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))
    73         setAttribute(Qt::WA_DropSiteRegistered, true);
    74 
    75     // need to force the resting of the icon after changing parents
    76     if (testAttribute(Qt::WA_SetWindowIcon))
    77         d->setWindowIcon_sys(true);
    78     if (isWindow() && !d->topData()->iconText.isEmpty())
    79         d->setWindowIconText_helper(d->topData()->iconText);
    80     if (windowType() != Qt::Desktop) {
    81         d->updateSystemBackground();
    82 
    83         if (isWindow() && !testAttribute(Qt::WA_SetWindowIcon))
    84             d->setWindowIcon_sys();
    85     }
    86 }

    这里QWidgetPrivate::create_sys()定义在QWidget_win.cpp里。

      1 void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
      2 {
      3     Q_Q(QWidget);
      4     static int sw = -1, sh = -1;
      5 
      6     Qt::WindowType type = q->windowType();
      7     Qt::WindowFlags flags = data.window_flags;
      8 
      9     bool topLevel = (flags & Qt::Window);
     10     bool popup = (type == Qt::Popup);
     11     bool dialog = (type == Qt::Dialog
     12                    || type == Qt::Sheet
     13                    || (flags & Qt::MSWindowsFixedSizeDialogHint));
     14     bool desktop = (type == Qt::Desktop);
     15     bool tool = (type == Qt::Tool || type == Qt::Drawer);
     16 
     17     HINSTANCE appinst  = qWinAppInst();
     18     HWND parentw, destroyw = 0;
     19     WId id;
     20 
     21     QString windowClassName = qt_reg_winclass(q);
     22 
     23     if (!window)                                // always initialize
     24         initializeWindow = true;
     25 
     26     if (popup)
     27         flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
     28 
     29     if (sw < 0) {                                // get the (primary) screen size
     30         sw = GetSystemMetrics(SM_CXSCREEN);
     31         sh = GetSystemMetrics(SM_CYSCREEN);
     32     }
     33 
     34     if (desktop && !q->testAttribute(Qt::WA_DontShowOnScreen)) {                                // desktop widget
     35         popup = false;                                // force this flags off
     36         if (QSysInfo::WindowsVersion != QSysInfo::WV_NT && QSysInfo::WindowsVersion != QSysInfo::WV_95)
     37             data.crect.setRect(GetSystemMetrics(76 /* SM_XVIRTUALSCREEN  */), GetSystemMetrics(77 /* SM_YVIRTUALSCREEN  */),
     38                            GetSystemMetrics(78 /* SM_CXVIRTUALSCREEN */), GetSystemMetrics(79 /* SM_CYVIRTUALSCREEN */));
     39         else
     40             data.crect.setRect(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
     41     }
     42 
     43     parentw = q->parentWidget() ? q->parentWidget()->effectiveWinId() : 0;
     44 
     45 #ifdef UNICODE
     46     QString title;
     47     const TCHAR *ttitle = 0;
     48 #endif
     49     QByteArray title95;
     50     int style = WS_CHILD;
     51     int exsty = 0;
     52 
     53     if (window) {
     54         style = GetWindowLongA(window, GWL_STYLE);
     55         if (!style)
     56             qErrnoWarning("QWidget::create: GetWindowLong failed");
     57         topLevel = false; // #### needed for some IE plugins??
     58     } else if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
     59         style = WS_POPUP;
     60     } else if (topLevel && !desktop) {
     61         if (flags & Qt::FramelessWindowHint)
     62             style = WS_POPUP;                // no border
     63         else if (flags & Qt::WindowTitleHint)
     64             style = WS_OVERLAPPED;
     65         else
     66             style = 0;
     67     }
     68     if (!desktop) {
     69         // if (!testAttribute(Qt::WA_PaintUnclipped))
     70         // ### Commented out for now as it causes some problems, but
     71         // this should be correct anyway, so dig some more into this
     72 #ifndef Q_FLATTEN_EXPOSE
     73         style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
     74 #endif
     75         if (topLevel) {
     76             if ((type == Qt::Window || dialog || tool)) {
     77                 if (!(flags & Qt::FramelessWindowHint)) {
     78                     if (!(flags & Qt::MSWindowsFixedSizeDialogHint)) {
     79                         style |= WS_THICKFRAME;
     80                         if(!(flags &
     81                             ( Qt::WindowSystemMenuHint
     82                             | Qt::WindowTitleHint
     83                             | Qt::WindowMinMaxButtonsHint
     84                             | Qt::WindowCloseButtonHint
     85                             | Qt::WindowContextHelpButtonHint)))
     86                             style |= WS_POPUP;
     87                     } else {
     88                         style |= WS_POPUP | WS_DLGFRAME;
     89                     }
     90                 }
     91                 if (flags & Qt::WindowTitleHint)
     92                     style |= WS_CAPTION;
     93                 if (flags & Qt::WindowSystemMenuHint)
     94                     style |= WS_SYSMENU;
     95                 if (flags & Qt::WindowMinimizeButtonHint)
     96                     style |= WS_MINIMIZEBOX;
     97                 if (shouldShowMaximizeButton())
     98                     style |= WS_MAXIMIZEBOX;
     99                 if (tool)
    100                     exsty |= WS_EX_TOOLWINDOW;
    101                 if (flags & Qt::WindowContextHelpButtonHint)
    102                     exsty |= WS_EX_CONTEXTHELP;
    103             } else {
    104                  exsty |= WS_EX_TOOLWINDOW;
    105             }
    106         }
    107     }
    108 
    109     if (flags & Qt::WindowTitleHint) {
    110         QT_WA({
    111             title = q->isWindow() ? qAppName() : q->objectName();
    112             ttitle = (TCHAR*)title.utf16();
    113         } , {
    114             title95 = q->isWindow() ? qAppName().toLocal8Bit() : q->objectName().toLatin1();
    115         });
    116     }
    117 
    118     // The Qt::WA_WState_Created flag is checked by translateConfigEvent() in
    119     // qapplication_win.cpp. We switch it off temporarily to avoid move
    120     // and resize events during creationt
    121     q->setAttribute(Qt::WA_WState_Created, false);
    122 
    123     if (window) {                                // override the old window
    124         if (destroyOldWindow)
    125             destroyw = data.winid;
    126         id = window;
    127         setWinId(window);
    128         LONG res = SetWindowLongA(window, GWL_STYLE, style);
    129         if (!res)
    130             qErrnoWarning("QWidget::create: Failed to set window style");
    131 #ifdef _WIN64
    132         res = SetWindowLongPtrA( window, GWLP_WNDPROC, (LONG_PTR)QtWndProc );
    133 #else
    134         res = SetWindowLongA( window, GWL_WNDPROC, (LONG)QtWndProc );
    135 #endif
    136         if (!res)
    137             qErrnoWarning("QWidget::create: Failed to set window procedure");
    138     } else if (desktop) {                        // desktop widget
    139         id = GetDesktopWindow();
    140 //         QWidget *otherDesktop = QWidget::find(id);        // is there another desktop?
    141 //         if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) {
    142 //             otherDesktop->d_func()->setWinId(0);        // remove id from widget mapper
    143 //             d->setWinId(id);                     // make sure otherDesktop is
    144 //             otherDesktop->d_func()->setWinId(id);       //   found first
    145 //         } else {
    146             setWinId(id);
    147 //         }
    148     } else if (topLevel) {                       // create top-level widget
    149         if (popup)
    150             parentw = 0;
    151 
    152         const bool wasMoved = q->testAttribute(Qt::WA_Moved);
    153         int x = wasMoved ? data.crect.left() : CW_USEDEFAULT;
    154         int y = wasMoved ? data.crect.top() : CW_USEDEFAULT;
    155         int w = CW_USEDEFAULT;
    156         int h = CW_USEDEFAULT;
    157 
    158         // Adjust for framestrut when needed
    159         RECT rect = {0,0,0,0};
    160         bool isVisibleOnScreen = !q->testAttribute(Qt::WA_DontShowOnScreen);
    161         if (isVisibleOnScreen && AdjustWindowRectEx(&rect, style & ~WS_OVERLAPPED, FALSE, exsty)) {
    162             QTLWExtra *td = maybeTopData();
    163             if (wasMoved && (td && !td->posFromMove)) {
    164                 x = data.crect.x() + rect.left;
    165                 y = data.crect.y() + rect.top;
    166             }
    167 
    168             if (q->testAttribute(Qt::WA_Resized)) {
    169                 w = data.crect.width() + (rect.right - rect.left);
    170                 h = data.crect.height() + (rect.bottom - rect.top);
    171             }
    172         }
    173         //update position & initial size of POPUP window
    174         if (isVisibleOnScreen && topLevel && initializeWindow && (style & WS_POPUP)) {
    175             if (!q->testAttribute(Qt::WA_Resized)) {
    176                 w = sw/2;
    177                 h = 4*sh/10;
    178             }
    179             if (!wasMoved) {
    180                 x = sw/2 - w/2;
    181                 y = sh/2 - h/2;
    182             }
    183         }
    184 
    185         QT_WA({
    186             const TCHAR *cname = (TCHAR*)windowClassName.utf16();
    187             id = CreateWindowEx(exsty, cname, ttitle, style,
    188                                 x, y, w, h,
    189                                 parentw, 0, appinst, 0);
    190         } , {
    191             id = CreateWindowExA(exsty, windowClassName.toLatin1(), title95, style,
    192                                  x, y, w, h,
    193                                  parentw, 0, appinst, 0);
    194         });
    195         if (!id)
    196             qErrnoWarning("QWidget::create: Failed to create window");
    197         setWinId(id);
    198         if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
    199             SetWindowPos(id, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
    200             if (flags & Qt::WindowStaysOnBottomHint)
    201                 qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
    202         } else if (flags & Qt::WindowStaysOnBottomHint)
    203             SetWindowPos(id, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
    204         winUpdateIsOpaque();
    205     } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create child widget
    206         QT_WA({
    207             const TCHAR *cname = (TCHAR*)windowClassName.utf16();
    208             id = CreateWindowEx(exsty, cname, ttitle, style,
    209                                 data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(),
    210                             parentw, NULL, appinst, NULL);
    211         } , {
    212             id = CreateWindowExA(exsty, windowClassName.toLatin1(), title95, style,
    213                                  data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(),
    214                             parentw, NULL, appinst, NULL);
    215         });
    216         if (!id)
    217             qErrnoWarning("QWidget::create: Failed to create window");
    218         SetWindowPos(id, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    219         setWinId(id);
    220     }
    221 
    222     if (desktop) {
    223         q->setAttribute(Qt::WA_WState_Visible);
    224     } else if (topLevel && !q->testAttribute(Qt::WA_DontShowOnScreen)) {
    225         RECT  cr;
    226         GetClientRect(id, &cr);
    227         // one cannot trust cr.left and cr.top, use a correction POINT instead
    228         POINT pt;
    229         pt.x = 0;
    230         pt.y = 0;
    231         ClientToScreen(id, &pt);
    232 
    233         if (data.crect.width() == 0 || data.crect.height() == 0) {
    234             data.crect = QRect(pt.x, pt.y, data.crect.width(), data.crect.height());
    235         } else {
    236             data.crect = QRect(QPoint(pt.x, pt.y),
    237                                QPoint(pt.x + cr.right - 1, pt.y + cr.bottom - 1));
    238         }
    239 
    240         if (data.fstrut_dirty) {
    241             // be nice to activeqt
    242             updateFrameStrut();
    243         }
    244     }
    245 
    246     q->setAttribute(Qt::WA_WState_Created);                // accept move/resize events
    247     hd = 0;                                        // no display context
    248 
    249     if (window) {                                // got window from outside
    250         if (IsWindowVisible(window))
    251             q->setAttribute(Qt::WA_WState_Visible);
    252         else
    253             q->setAttribute(Qt::WA_WState_Visible, false);
    254     }
    255 
    256     if (extra && !extra->mask.isEmpty())
    257         setMask_sys(extra->mask);
    258 
    259 #if defined(QT_NON_COMMERCIAL)
    260     QT_NC_WIDGET_CREATE
    261 #endif
    262 
    263     if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled))
    264         q->inputContext()->setFocusWidget(q);
    265 
    266     if (destroyw) {
    267         DestroyWindow(destroyw);
    268     }
    269 
    270     if (q != qt_tablet_widget && QWidgetPrivate::mapper)
    271         qt_tablet_init();
    272 
    273     if (q->testAttribute(Qt::WA_DropSiteRegistered))
    274         registerDropSite(true);
    275 
    276     if (maybeTopData() && maybeTopData()->opacity != 255)
    277         q->setWindowOpacity(maybeTopData()->opacity/255.);
    278 
    279     if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0)) {
    280         q->setAttribute(Qt::WA_OutsideWSRange, true);
    281     }
    282 
    283     if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) {
    284         Q_ASSERT(q->internalWinId());
    285         ShowWindow(q->internalWinId(), SW_SHOW);
    286     }
    287 }

    这里调用了qt_reg_winclass()(在QApplication_win.cpp里定义),查看其代码就是RegisterWindows,把window窗口的消息处理设定为:QtWndProc。QObject的初始化没有什么新意,参看QApplication得初始化。

    到目前为止的初始化分析,为下一步我们分析Windows消息传递,也就是QT的事件机制打下了基础。

  • 相关阅读:
    SharePoint文件磁盘存储组件使用指南
    自定义SharePoint新网站创建过程(1)
    SharePoint : 超级Web Application Framework
    Video:使用VSeWSS创建定制SharePoint页面
    SharePoint Designer 2007 is now FREE !
    关于SharePoint解决方案开发模型的凌乱文章…
    初试Silverlight Streaming服务
    Feature Schema中Module和File节点属性含义的解释
    如何定制列表项编辑页面
    使用SharePoint Server 2007搜索Domino Notes
  • 原文地址:https://www.cnblogs.com/lfsblack/p/5279016.html
Copyright © 2011-2022 走看看