QT分析之QPushButton的初始化
2016-03-15 12:54
567 查看
原文地址:http://blog.163.com/net_worm/blog/static/127702419201001003326522/
在简单的QT程序的第二行,声明了一个QPushButton的对象。先简单看看其初始化过程。
QPushButton的类继承关系为:
QPushButton的构造:
新生成的QPushButtonPrivate对象传递给QAbstractButton之后,发生了什么事呢?
QAbstractButtonPrivate::init()做了什么呢?其实只是调用了QPushButton的几个设定函数。
继续看QWidget的初始化过程。
其中d_func()是宏定义Q_DECLARE_PRIVATE(QWidget)中定义的,获取QWidgetPrivate指针的函数。有点奇怪的是,这里怎么没有用Q_D宏定义,与之前的风格有点不同。
QWidgetPrivate::init()里做了什么动作呢?(关键语句用颜色标记)
看看QWidget::create()的实现:
这里QWidgetPrivate::create_sys()定义在QWidget_win.cpp里。
这里调用了qt_reg_winclass()(在QApplication_win.cpp里定义),查看其代码就是RegisterWindows,把window窗口的消息处理设定为:QtWndProc。QObject的初始化没有什么新意,参看QApplication得初始化。
到目前为止的初始化分析,为下一步我们分析Windows消息传递,也就是QT的事件机制打下了基础。
在简单的QT程序的第二行,声明了一个QPushButton的对象。先简单看看其初始化过程。
QPushButton的类继承关系为:
QPushButton :public QAbstractButton :pubic QWidget :public QObject, public QPaintDevice
QPushButton的构造:
QPushButton::QPushButton(const QString &text, QWidget *parent) : QAbstractButton(*new QPushButtonPrivate, parent) { Q_D(QPushButton); // 声明并获得QPushButtonPrivate函数指针d setText(text); // 设置按钮的名字 d->init(); // 调用QPushButtonPrivate::init(),其实只是重新设定排布间隔 }
新生成的QPushButtonPrivate对象传递给QAbstractButton之后,发生了什么事呢?
QAbstractButton::QAbstractButton(QAbstractButtonPrivate &dd, QWidget *parent) : QWidget(dd, parent, 0) { Q_D(QAbstractButton); // 声明并获得QAbstractButtonPrivate函数指针d d->init(); // 调用QAbstractButtonPrivate::init() }
QAbstractButtonPrivate::init()做了什么呢?其实只是调用了QPushButton的几个设定函数。
继续看QWidget的初始化过程。
QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, 0), QPaintDevice() { d_func()->init(parent, f); }
其中d_func()是宏定义Q_DECLARE_PRIVATE(QWidget)中定义的,获取QWidgetPrivate指针的函数。有点奇怪的是,这里怎么没有用Q_D宏定义,与之前的风格有点不同。
QWidgetPrivate::init()里做了什么动作呢?(关键语句用颜色标记)
void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) { Q_Q(QWidget); if (qApp->type() == QApplication::Tty) qFatal("QWidget: Cannot create a QWidget when no GUI is being used"); Q_ASSERT(uncreatedWidgets); uncreatedWidgets->insert(q); QWidget *desktopWidget = 0; if (parentWidget && parentWidget->windowType() == Qt::Desktop) { desktopWidget = parentWidget; parentWidget = 0; } q->data = &data; if (!q->parent()) { Q_ASSERT_X(q->thread() == qApp->thread(), "QWidget", "Widgets must be created in the GUI thread."); } data.fstrut_dirty = true; data.winid = 0; data.widget_attributes = 0; data.window_flags = f; data.window_state = 0; data.focus_policy = 0; data.context_menu_policy = Qt::DefaultContextMenu; data.window_modality = Qt::NonModal; data.sizehint_forced = 0; data.is_closing = 0; data.in_show = 0; data.in_set_window_state = 0; data.in_destructor = false; // Widgets with Qt::MSWindowsOwnDC (typically QGLWidget) must have a window handle. if (f & Qt::MSWindowsOwnDC) q->setAttribute(Qt::WA_NativeWindow); q->setAttribute(Qt::WA_QuitOnClose); // might be cleared in adjustQuitOnCloseAttribute() adjustQuitOnCloseAttribute(); q->setAttribute(Qt::WA_WState_Hidden); //give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,640,480); focus_next = focus_prev = q; if ((f & Qt::WindowType_Mask) == Qt::Desktop) q->create(); // 调用了QWidget::create() else if (parentWidget) q->setParent(parentWidget, data.window_flags); else { adjustFlags(data.window_flags, q); resolveLayoutDirection(); // opaque system background? const QBrush &background = q->palette().brush(QPalette::Window); setOpaque(q->isWindow() && background.style() != Qt::NoBrush && background.isOpaque()); } data.fnt = QFont(data.fnt, q); q->setAttribute(Qt::WA_PendingMoveEvent); q->setAttribute(Qt::WA_PendingResizeEvent); if (++QWidgetPrivate::instanceCounter > QWidgetPrivate::maxInstances) QWidgetPrivate::maxInstances = QWidgetPrivate::instanceCounter; if (QApplicationPrivate::app_compile_version < 0x040200 || QApplicationPrivate::testAttribute(Qt::AA_ImmediateWidgetCreation)) q->create(); // 下面的三行,产生并发送了Create事件 QEvent e(QEvent::Create); QApplication::sendEvent(q, &e); QApplication::postEvent(q, new QEvent(QEvent::PolishRequest)); extraPaintEngine = 0; }
看看QWidget::create()的实现:
void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) { Q_D(QWidget); if (testAttribute(Qt::WA_WState_Created) && window == 0 && internalWinId()) return; if (d->data.in_destructor) return; Qt::WindowType type = windowType(); Qt::WindowFlags &flags = data->window_flags; if ((type == Qt::Widget || type == Qt::SubWindow) && !parentWidget()) { type = Qt::Window; flags |= Qt::Window; } if (QWidget *parent = parentWidget()) { if (type & Qt::Window) { if (!parent->testAttribute(Qt::WA_WState_Created)) parent->createWinId(); } else if (testAttribute(Qt::WA_NativeWindow) && !parent->internalWinId() && !testAttribute(Qt::WA_DontCreateNativeAncestors)) { // We're about to create a native child widget that doesn't have a native parent; // enforce a native handle for the parent unless the Qt::WA_DontCreateNativeAncestors // attribute is set. d->createWinId(window); // Nothing more to do. Q_ASSERT(testAttribute(Qt::WA_WState_Created)); Q_ASSERT(internalWinId()); return; } } static int paintOnScreenEnv = -1; if (paintOnScreenEnv == -1) paintOnScreenEnv = qgetenv("QT_ONSCREEN_PAINT").toInt() > 0 ? 1 : 0; if (paintOnScreenEnv == 1) setAttribute(Qt::WA_PaintOnScreen); if (QApplicationPrivate::testAttribute(Qt::AA_NativeWindows)) setAttribute(Qt::WA_NativeWindow); #ifdef ALIEN_DEBUG qDebug() << "QWidget::create:" << this << "parent:" << parentWidget() << "Alien?" << !testAttribute(Qt::WA_NativeWindow); #endif // Unregister the dropsite (if already registered) before we // re-create the widget with a native window. if (testAttribute(Qt::WA_WState_Created) && !internalWinId() && testAttribute(Qt::WA_NativeWindow) && d->extra && d->extra->dropTarget) { d->registerDropSite(false); } d->updateIsOpaque(); setAttribute(Qt::WA_WState_Created); // set created flag d->create_sys(window, initializeWindow, destroyOldWindow); // a real toplevel window needs a backing store if (isWindow()) { delete d->topData()->backingStore; // QWidgetBackingStore will check this variable, hence it must be 0 d->topData()->backingStore = 0; if (hasBackingStoreSupport()) d->topData()->backingStore = new QWidgetBackingStore(this); } d->setModal_sys(); if (!isWindow() && parentWidget() && parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)) setAttribute(Qt::WA_DropSiteRegistered, true); // need to force the resting of the icon after changing parents if (testAttribute(Qt::WA_SetWindowIcon)) d->setWindowIcon_sys(true); if (isWindow() && !d->topData()->iconText.isEmpty()) d->setWindowIconText_helper(d->topData()->iconText); if (windowType() != Qt::Desktop) { d->updateSystemBackground(); if (isWindow() && !testAttribute(Qt::WA_SetWindowIcon)) d->setWindowIcon_sys(); } }
这里QWidgetPrivate::create_sys()定义在QWidget_win.cpp里。
void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) { Q_Q(QWidget); static int sw = -1, sh = -1; Qt::WindowType type = q->windowType(); Qt::WindowFlags flags = data.window_flags; bool topLevel = (flags & Qt::Window); bool popup = (type == Qt::Popup); bool dialog = (type == Qt::Dialog || type == Qt::Sheet || (flags & Qt::MSWindowsFixedSizeDialogHint)); bool desktop = (type == Qt::Desktop); bool tool = (type == Qt::Tool || type == Qt::Drawer); HINSTANCE appinst = qWinAppInst(); HWND parentw, destroyw = 0; WId id; QString windowClassName = qt_reg_winclass(q); if (!window) // always initialize initializeWindow = true; if (popup) flags |= Qt::WindowStaysOnTopHint; // a popup stays on top if (sw < 0) { // get the (primary) screen size sw = GetSystemMetrics(SM_CXSCREEN); sh = GetSystemMetrics(SM_CYSCREEN); } if (desktop && !q->testAttribute(Qt::WA_DontShowOnScreen)) { // desktop widget popup = false; // force this flags off if (QSysInfo::WindowsVersion != QSysInfo::WV_NT && QSysInfo::WindowsVersion != QSysInfo::WV_95) data.crect.setRect(GetSystemMetrics(76 /* SM_XVIRTUALSCREEN */), GetSystemMetrics(77 /* SM_YVIRTUALSCREEN */), GetSystemMetrics(78 /* SM_CXVIRTUALSCREEN */), GetSystemMetrics(79 /* SM_CYVIRTUALSCREEN */)); else data.crect.setRect(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); } parentw = q->parentWidget() ? q->parentWidget()->effectiveWinId() : 0; #ifdef UNICODE QString title; const TCHAR *ttitle = 0; #endif QByteArray title95; int style = WS_CHILD; int exsty = 0; if (window) { style = GetWindowLongA(window, GWL_STYLE); if (!style) qErrnoWarning("QWidget::create: GetWindowLong failed"); topLevel = false; // #### needed for some IE plugins?? } else if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) { style = WS_POPUP; } else if (topLevel && !desktop) { if (flags & Qt::FramelessWindowHint) style = WS_POPUP; // no border else if (flags & Qt::WindowTitleHint) style = WS_OVERLAPPED; else style = 0; } if (!desktop) { // if (!testAttribute(Qt::WA_PaintUnclipped)) // ### Commented out for now as it causes some problems, but // this should be correct anyway, so dig some more into this #ifndef Q_FLATTEN_EXPOSE style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ; #endif if (topLevel) { if ((type == Qt::Window || dialog || tool)) { if (!(flags & Qt::FramelessWindowHint)) { if (!(flags & Qt::MSWindowsFixedSizeDialogHint)) { style |= WS_THICKFRAME; if(!(flags & ( Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint))) style |= WS_POPUP; } else { style |= WS_POPUP | WS_DLGFRAME; } } if (flags & Qt::WindowTitleHint) style |= WS_CAPTION; if (flags & Qt::WindowSystemMenuHint) style |= WS_SYSMENU; if (flags & Qt::WindowMinimizeButtonHint) style |= WS_MINIMIZEBOX; if (shouldShowMaximizeButton()) style |= WS_MAXIMIZEBOX; if (tool) exsty |= WS_EX_TOOLWINDOW; if (flags & Qt::WindowContextHelpButtonHint) exsty |= WS_EX_CONTEXTHELP; } else { exsty |= WS_EX_TOOLWINDOW; } } } if (flags & Qt::WindowTitleHint) { QT_WA({ title = q->isWindow() ? qAppName() : q->objectName(); ttitle = (TCHAR*)title.utf16(); } , { title95 = q->isWindow() ? qAppName().toLocal8Bit() : q->objectName().toLatin1(); }); } // The Qt::WA_WState_Created flag is checked by translateConfigEvent() in // qapplication_win.cpp. We switch it off temporarily to avoid move // and resize events during creationt q->setAttribute(Qt::WA_WState_Created, false); if (window) { // override the old window if (destroyOldWindow) destroyw = data.winid; id = window; setWinId(window); LONG res = SetWindowLongA(window, GWL_STYLE, style); if (!res) qErrnoWarning("QWidget::create: Failed to set window style"); #ifdef _WIN64 res = SetWindowLongPtrA( window, GWLP_WNDPROC, (LONG_PTR)QtWndProc ); #else res = SetWindowLongA( window, GWL_WNDPROC, (LONG)QtWndProc ); #endif if (!res) qErrnoWarning("QWidget::create: Failed to set window procedure"); } else if (desktop) { // desktop widget id = GetDesktopWindow(); // QWidget *otherDesktop = QWidget::find(id); // is there another desktop? // if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) { // otherDesktop->d_func()->setWinId(0); // remove id from widget mapper // d->setWinId(id); // make sure otherDesktop is // otherDesktop->d_func()->setWinId(id); // found first // } else { setWinId(id); // } } else if (topLevel) { // create top-level widget if (popup) parentw = 0; const bool wasMoved = q->testAttribute(Qt::WA_Moved); int x = wasMoved ? data.crect.left() : CW_USEDEFAULT; int y = wasMoved ? data.crect.top() : CW_USEDEFAULT; int w = CW_USEDEFAULT; int h = CW_USEDEFAULT; // Adjust for framestrut when needed RECT rect = {0,0,0,0}; bool isVisibleOnScreen = !q->testAttribute(Qt::WA_DontShowOnScreen); if (isVisibleOnScreen && AdjustWindowRectEx(&rect, style & ~WS_OVERLAPPED, FALSE, exsty)) { QTLWExtra *td = maybeTopData(); if (wasMoved && (td && !td->posFromMove)) { x = data.crect.x() + rect.left; y = data.crect.y() + rect.top; } if (q->testAttribute(Qt::WA_Resized)) { w = data.crect.width() + (rect.right - rect.left); h = data.crect.height() + (rect.bottom - rect.top); } } //update position & initial size of POPUP window if (isVisibleOnScreen && topLevel && initializeWindow && (style & WS_POPUP)) { if (!q->testAttribute(Qt::WA_Resized)) { w = sw/2; h = 4*sh/10; } if (!wasMoved) { x = sw/2 - w/2; y = sh/2 - h/2; } } QT_WA({ const TCHAR *cname = (TCHAR*)windowClassName.utf16(); id = CreateWindowEx(exsty, cname, ttitle, style, x, y, w, h, parentw, 0, appinst, 0); } , { id = CreateWindowExA(exsty, windowClassName.toLatin1(), title95, style, x, y, w, h, parentw, 0, appinst, 0); }); if (!id) qErrnoWarning("QWidget::create: Failed to create window"); setWinId(id); if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) { SetWindowPos(id, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); if (flags & Qt::WindowStaysOnBottomHint) qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time"; } else if (flags & Qt::WindowStaysOnBottomHint) SetWindowPos(id, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); winUpdateIsOpaque(); } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create child widget QT_WA({ const TCHAR *cname = (TCHAR*)windowClassName.utf16(); id = CreateWindowEx(exsty, cname, ttitle, style, data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), parentw, NULL, appinst, NULL); } , { id = CreateWindowExA(exsty, windowClassName.toLatin1(), title95, style, data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), parentw, NULL, appinst, NULL); }); if (!id) qErrnoWarning("QWidget::create: Failed to create window"); SetWindowPos(id, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); setWinId(id); } if (desktop) { q->setAttribute(Qt::WA_WState_Visible); } else if (topLevel && !q->testAttribute(Qt::WA_DontShowOnScreen)) { RECT cr; GetClientRect(id, &cr); // one cannot trust cr.left and cr.top, use a correction POINT instead POINT pt; pt.x = 0; pt.y = 0; ClientToScreen(id, &pt); if (data.crect.width() == 0 || data.crect.height() == 0) { data.crect = QRect(pt.x, pt.y, data.crect.width(), data.crect.height()); } else { data.crect = QRect(QPoint(pt.x, pt.y), QPoint(pt.x + cr.right - 1, pt.y + cr.bottom - 1)); } if (data.fstrut_dirty) { // be nice to activeqt updateFrameStrut(); } } q->setAttribute(Qt::WA_WState_Created); // accept move/resize events hd = 0; // no display context if (window) { // got window from outside if (IsWindowVisible(window)) q->setAttribute(Qt::WA_WState_Visible); else q->setAttribute(Qt::WA_WState_Visible, false); } if (extra && !extra->mask.isEmpty()) setMask_sys(extra->mask); #if defined(QT_NON_COMMERCIAL) QT_NC_WIDGET_CREATE #endif if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled)) q->inputContext()->setFocusWidget(q); if (destroyw) { DestroyWindow(destroyw); } if (q != qt_tablet_widget && QWidgetPrivate::mapper) qt_tablet_init(); if (q->testAttribute(Qt::WA_DropSiteRegistered)) registerDropSite(true); if (maybeTopData() && maybeTopData()->opacity != 255) q->setWindowOpacity(maybeTopData()->opacity/255.); if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0)) { q->setAttribute(Qt::WA_OutsideWSRange, true); } if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) { Q_ASSERT(q->internalWinId()); ShowWindow(q->internalWinId(), SW_SHOW); } }
这里调用了qt_reg_winclass()(在QApplication_win.cpp里定义),查看其代码就是RegisterWindows,把window窗口的消息处理设定为:QtWndProc。QObject的初始化没有什么新意,参看QApplication得初始化。
到目前为止的初始化分析,为下一步我们分析Windows消息传递,也就是QT的事件机制打下了基础。
相关文章推荐
- QT分析之WebKit
- Qt 实时读串口数据,并将读到的数据从网口发送出去
- 发布Qt Widgets桌面应用程序的方法
- Qt中信号和槽的问题解析
- QML中的SmoothedAnimation平滑动画
- QML之PathAnimation路径动画
- QTsocket和标准C库socket混用遇到的问题
- QML之ColorAnimation颜色动画
- Qt中如何使用Sleep函数
- QML动画之NumberAnimation数字类动画
- QML中在信号处理器中处理动画
- Windows下QT程序中调用boost库
- QT异形图形的开发
- 在 QT5 中使用 SQLITE
- QT学习之路————QT程序在开发板上旋转
- Qt制作应用插件
- 笔记:QT的模态对话框、非模态对话框及QLineEdit的验证器和补全器
- QT解析命令行(QCommandLineOption和QCommandLineParser类)
- 配置QtCreator+CDB远程调试环境(要设置_NT_SYMBOL_PATH和QT_PLUGIN_PATH和Path)
- 让VC2012生成的程序支持XP系统(QT的DLL都是支持XP的,只与EXE有关)