首页 技术 正文
技术 2022年11月10日
0 收藏 828 点赞 4,273 浏览 13269 个字

原文地址: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的事件机制打下了基础。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,492
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,495
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,132
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,295