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

在简单的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, )
{
Q_D(QAbstractButton); // 声明并获得QAbstractButtonPrivate函数指针d
d->init(); // 调用QAbstractButtonPrivate::init()
}

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

继续看QWidget的初始化过程。

 QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f)
: QObject(dd, ), 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 = ;
if (parentWidget && parentWidget->windowType() == Qt::Desktop) {
desktopWidget = parentWidget;
parentWidget = ;
} 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 = ;
data.widget_attributes = ;
data.window_flags = f;
data.window_state = ;
data.focus_policy = ;
data.context_menu_policy = Qt::DefaultContextMenu;
data.window_modality = Qt::NonModal; data.sizehint_forced = ;
data.is_closing = ;
data.in_show = ;
data.in_set_window_state = ;
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(,,,) : QRect(,,,); 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 = ;
}

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

 void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
{
Q_D(QWidget);
if (testAttribute(Qt::WA_WState_Created) && window == && 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 = -;
if (paintOnScreenEnv == -)
paintOnScreenEnv = qgetenv("QT_ONSCREEN_PAINT").toInt() > ? : ;
if (paintOnScreenEnv == )
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 = ;
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 = -, sh = -; 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 = ;
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 < ) { // 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( /* SM_XVIRTUALSCREEN */), GetSystemMetrics( /* SM_YVIRTUALSCREEN */),
GetSystemMetrics( /* SM_CXVIRTUALSCREEN */), GetSystemMetrics( /* SM_CYVIRTUALSCREEN */));
else
data.crect.setRect(, , GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
} parentw = q->parentWidget() ? q->parentWidget()->effectiveWinId() : ; #ifdef UNICODE
QString title;
const TCHAR *ttitle = ;
#endif
QByteArray title95;
int style = WS_CHILD;
int exsty = ; 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 = ;
}
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 = ; 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 = {,,,};
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/;
h = *sh/;
}
if (!wasMoved) {
x = sw/ - w/;
y = sh/ - h/;
}
} QT_WA({
const TCHAR *cname = (TCHAR*)windowClassName.utf16();
id = CreateWindowEx(exsty, cname, ttitle, style,
x, y, w, h,
parentw, , appinst, );
} , {
id = CreateWindowExA(exsty, windowClassName.toLatin1(), title95, style,
x, y, w, h,
parentw, , appinst, );
});
if (!id)
qErrnoWarning("QWidget::create: Failed to create window");
setWinId(id);
if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
SetWindowPos(id, HWND_TOPMOST, , , , , 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, , , , , 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, , , , , 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 = ;
pt.y = ;
ClientToScreen(id, &pt); if (data.crect.width() == || data.crect.height() == ) {
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 - , pt.y + cr.bottom - ));
} if (data.fstrut_dirty) {
// be nice to activeqt
updateFrameStrut();
}
} q->setAttribute(Qt::WA_WState_Created); // accept move/resize events
hd = ; // 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 != )
q->setWindowOpacity(maybeTopData()->opacity/.); if (topLevel && (data.crect.width() == || data.crect.height() == )) {
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分析之QPushButton的初始化的更多相关文章

  1. 2、QT分析之QPushButton的初始化

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201001003326522/ 在简单的QT程序的第二行,声明了一个QPushButto ...

  2. 1、QT分析之QApplication的初始化

    原文地址:http://blog.163.com/net_worm/blog/static/1277024192010097430321/ 在开始分析之前交代一下,一是分析的QT在Window平台实现 ...

  3. QT分析之QApplication的初始化

    原文地址:http://blog.163.com/net_worm/blog/static/1277024192010097430321/ 在开始分析之前交代一下,一是分析的QT在Window平台实现 ...

  4. 3、QT分析之消息事件机制

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201001432028526/ 上回我们分析到QPushButton的初始化,知道了Wi ...

  5. QT分析之消息事件机制

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201001432028526/ 上回我们分析到QPushButton的初始化,知道了Wi ...

  6. 10、QT分析之WebKit

    该文章整理自 网易博客 http://blog.163.com/net_worm/blog/static/12770241920101831312381/ 转载请注明出处 WebKit是QT4新整合的 ...

  7. 5、QT分析之网络编程

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201002842553382/ 首先对Windows下的网络编程总结一下: 如果是服务器 ...

  8. QT分析之WebKit

    该文章整理自 网易博客 http://blog.163.com/net_worm/blog/static/12770241920101831312381/ 转载请注明出处 WebKit是QT4新整合的 ...

  9. QT分析之网络编程

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201002842553382/ 首先对Windows下的网络编程总结一下: 如果是服务器 ...

随机推荐

  1. Python在线编程环境

    除了安装Python的IDE之外,也可以使用在网页中随时随地编写Python程序. Python官网:https://www.python.org/shell Python123:https://py ...

  2. 网站漏洞检测之WordPress 5.0.0 系统修复方案

    2019年正月刚开始,WordPress最新版本存在远程代码注入获取SHELL漏洞,该网站漏洞影响的版本是wordpress5.0.0,漏洞的产生是因为image模块导致的,因为代码里可以进行获取目录 ...

  3. git 操作几个命令

     git clone ssh://lijianfeng@192.168.1.246:29418/GMGameSDK压栈:git stash查状态:git status切换到要修改的提交:git reb ...

  4. hdu1969Pie(根据体积二分,分馅饼)

    Pie Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...

  5. 手机APP测试如何进行兼容性测试?

    Android App兼容性测试是一个比较重要的App评价内容,实际上兼容性测试不仅仅和测试人员相关,在开发阶段就应当着重考虑,因为兼容性问题是除了实现App本身要求的功能后,必须要关注.而且至关重要 ...

  6. MySQL☞关联查询

    关联查询:所需要的数据来源于多张表,通过表的连接查询(关联查询)来查询多张表中的数据 格式: select 别名1 . */列名 , 别名2 . */列名 from 表名1  别名1 , 表名2  别 ...

  7. JavaScript实现无刷新评论及在IE下的剪切板访问(学习)

    1.无刷新评论 tips: appendChild:将新元素作为父元素的最后一个子元素进行添加. insertBefore:在一个指定的子节点之前插入一个节点 实现: <!DOCTYPE htm ...

  8. JAVA中 "\" 和 "/" 的区别

    1.在java中路径一般用”/” 2.linux.unix中的路径一般用”/” 3.windows中的路径一般用”\” 所以在java中写windows路径一般用”/”,或用“\”将”\”转义一下(& ...

  9. 银行系统ps:不太完善,蟹蟹评论

    # 主程序运行 import time from guanli import GuanLi from atm import ATM from user import User def main(): ...

  10. JS里点击事件判断是否 触发了节点 和给标签添加class属性

    $("#activityType").click(function(e){ if(e.target==$("#bb")[0]){ var bb=document ...