QT分析之QPushButton的初始化
原文地址: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的初始化的更多相关文章
- 2、QT分析之QPushButton的初始化
原文地址:http://blog.163.com/net_worm/blog/static/127702419201001003326522/ 在简单的QT程序的第二行,声明了一个QPushButto ...
- 1、QT分析之QApplication的初始化
原文地址:http://blog.163.com/net_worm/blog/static/1277024192010097430321/ 在开始分析之前交代一下,一是分析的QT在Window平台实现 ...
- QT分析之QApplication的初始化
原文地址:http://blog.163.com/net_worm/blog/static/1277024192010097430321/ 在开始分析之前交代一下,一是分析的QT在Window平台实现 ...
- 3、QT分析之消息事件机制
原文地址:http://blog.163.com/net_worm/blog/static/127702419201001432028526/ 上回我们分析到QPushButton的初始化,知道了Wi ...
- QT分析之消息事件机制
原文地址:http://blog.163.com/net_worm/blog/static/127702419201001432028526/ 上回我们分析到QPushButton的初始化,知道了Wi ...
- 10、QT分析之WebKit
该文章整理自 网易博客 http://blog.163.com/net_worm/blog/static/12770241920101831312381/ 转载请注明出处 WebKit是QT4新整合的 ...
- 5、QT分析之网络编程
原文地址:http://blog.163.com/net_worm/blog/static/127702419201002842553382/ 首先对Windows下的网络编程总结一下: 如果是服务器 ...
- QT分析之WebKit
该文章整理自 网易博客 http://blog.163.com/net_worm/blog/static/12770241920101831312381/ 转载请注明出处 WebKit是QT4新整合的 ...
- QT分析之网络编程
原文地址:http://blog.163.com/net_worm/blog/static/127702419201002842553382/ 首先对Windows下的网络编程总结一下: 如果是服务器 ...
随机推荐
- 472. Concatenated Words
class Solution { public: vector<string> res; vector<string> findAllConcatenatedWordsInAD ...
- C语言实现左旋字符串
#include<stdio.h> #include<stdlib.h> #include<string.h> void left_rotate(char *str ...
- 小Hi和小Ho的礼物
题目:小Hi和小Ho的礼物 注:[i.j.p.q]为下标 个人感觉这道题是有一定难度的.读者可以参考一下[四平方和]的解题思路 分析过程下次补上 代码如下: #include <iostream ...
- 我和Python的Py交易》》》》》》函数
一 函数是什么? 是数学中的函数? Python中 函数是指将一组语句的集合通过一个名字(函数名)封装起来的一段代码.(所以这里的函数是subroutine子程序) 那要函数干嘛.不都是代码吗?只不 ...
- 给无符号数赋值负数(有符号数)的理解(unsigned\signedf)
无符号数赋负数(有符号数)就类似于给字符型变量赋数值(char word=0x56),对相同的值不同的类型解析 //s16:signed short; u16:unsigned short s16 t ...
- 【Hutool】Hutool工具类之String工具——StrUtil
类似的是commons-lang中的StringUtils 空与非空的操作——经典的isBlank/isNotBlank.isEmpty/isNotEmpty isBlank()——是否为空白,空白的 ...
- 「日常训练」Woodcutters(Codeforces Round 303 Div.2 C)
这题惨遭被卡..卡了一个小时,太真实了. 题意与分析 (Codeforces 545C) 题意:给定\(n\)棵树,在\(x\)位置,高为\(h\),然后可以左倒右倒,然后倒下去会占据\([x-h,x ...
- XSS--编码绕过,qcms,鲶鱼cms
一.编码绕过 1)HTML进制编码 标签中的某些属性值可以使用html十进制.十六进制表示 2)JavaScript编码 JavaScript支持unicode.八进制.十六进制.十进制等 3)URL ...
- a链接传参的方法
//获取分案编号 var hrefVal=window.location.href.split("?")[1]; //得到id=楼主 //console.log(hrefVal+& ...
- String和StringBuffer以及StringBuilder的区别
今天在读<java编程思想>的时间,在看到String和StringBuffer以及StringBuffer这三个类的时间,做一个随笔小结,为自己的面试做好准备! 一:String,Str ...