组件依赖关系
应用
QGuiApplication QApplication QCoreApplication
QApplication:widget对应的应用
QGuiApplication :gui对应的应用
QCoreApplication :无gui对应的应用
widget
QWidget QMainWindow QWidgetWindow QWindow QPlatformIntegration QPlatformWindow
QPlatformIntegration:平台抽象
QPlatformWindow :平台 抽象窗口
windows平台
QPlatformIntegration QWindowsIntegration QPlatformWindow QWindowsBaseWindow QWindowsWindow QWindowsDesktopWindow QWindowsForeignWindow QWindowsContext
在QWindowsIntegration创建createPlatformWindow时,其先创建QWindowsWindowData::create
cpp
QWindowsWindowData
WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const
{
WindowData result;
result.flags = flags;
const auto appinst = reinterpret_cast<HINSTANCE>(GetModuleHandle(nullptr));
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w);
const QScreen *screen{};
const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry,
defaultWindowWidth, defaultWindowHeight,
&screen);
if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
title = topLevel ? qAppName() : w->objectName();
const auto *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
const auto *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
// Capture events before CreateWindowEx() returns. The context is cleared in
// the QWindowsWindow constructor.
const QWindowCreationContextPtr context(new QWindowCreationContext(w, screen, data.geometry,
rect, data.customMargins,
style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context);
const bool hasFrame = (style & (WS_DLGFRAME | WS_THICKFRAME));
QMargins invMargins = topLevel && hasFrame && QWindowsGeometryHint::positionIncludesFrame(w)
? invisibleMargins(QPoint(context->frameX, context->frameY)) : QMargins();
qCDebug(lcQpaWindows).nospace()
<< "CreateWindowEx: " << w << " class=" << windowClassName << " title=" << title
<< '\n' << *this << "\nrequested: " << rect << ": "
<< context->frameWidth << 'x' << context->frameHeight
<< '+' << context->frameX << '+' << context->frameY
<< " custom margins: " << context->customMargins
<< " invisible margins: " << invMargins;
QPoint pos = calcPosition(w, context, invMargins);
// Mirror the position when creating on a parent in RTL mode, ditto for the obtained geometry.
int mirrorParentWidth = 0;
if (!w->isTopLevel() && QWindowsBaseWindow::isRtlLayout(parentHandle)) {
RECT rect;
GetClientRect(parentHandle, &rect);
mirrorParentWidth = rect.right;
}
if (mirrorParentWidth != 0 && pos.x() != CW_USEDEFAULT && context->frameWidth != CW_USEDEFAULT)
pos.setX(mirrorParentWidth - context->frameWidth - pos.x());
result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
style,
pos.x(), pos.y(),
context->frameWidth, context->frameHeight,
parentHandle, nullptr, appinst, nullptr);
qCDebug(lcQpaWindows).nospace()
<< "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
<< context->obtainedPos << context->obtainedSize << ' ' << context->margins;
if (!result.hwnd) {
qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__);
return result;
}
if (mirrorParentWidth != 0) {
context->obtainedPos.setX(mirrorParentWidth - context->obtainedSize.width()
- context->obtainedPos.x());
}
QRect obtainedGeometry(context->obtainedPos, context->obtainedSize);
result.geometry = obtainedGeometry;
result.fullFrameMargins = context->margins;
result.embedded = embedded;
result.hasFrame = hasFrame;
result.customMargins = context->customMargins;
return result;
}
内部会先注册registerWindowClass,设置窗口的处理函数registerWindowClass(cname, qWindowsWndProc, style, GetSysColorBrush(COLOR_WINDOW), icon);
qWindowsWndProc处理函数主要是调用 QWindowsContext的windowsProc
cpp
QString QWindowsContext::registerWindowClass(QString cname,
WNDPROC proc,
unsigned style,
HBRUSH brush,
bool icon)
{
// since multiple Qt versions can be used in one process
// each one has to have window class names with a unique name
// The first instance gets the unmodified name; if the class
// has already been registered by another instance of Qt then
// add a UUID. The check needs to be performed for each name
// in case new message windows are added (QTBUG-81347).
const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
WNDCLASS wcinfo;
const bool classExists = GetClassInfo(appInstance, reinterpret_cast<LPCWSTR>(cname.utf16()), &wcinfo) == TRUE
&& wcinfo.lpfnWndProc != proc;
if (classExists)
cname += QUuid::createUuid().toString();
if (d->m_registeredWindowClassNames.contains(cname)) // already registered in our list
return cname;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = style;
wc.lpfnWndProc = proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = appInstance;
wc.hCursor = nullptr;
wc.hbrBackground = brush;
if (icon) {
wc.hIcon = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
if (wc.hIcon) {
int sw = GetSystemMetrics(SM_CXSMICON);
int sh = GetSystemMetrics(SM_CYSMICON);
wc.hIconSm = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, sw, sh, 0));
} else {
wc.hIcon = static_cast<HICON>(LoadImage(nullptr, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED));
wc.hIconSm = nullptr;
}
} else {
wc.hIcon = nullptr;
wc.hIconSm = nullptr;
}
wc.lpszMenuName = nullptr;
wc.lpszClassName = reinterpret_cast<LPCWSTR>(cname.utf16());
ATOM atom = RegisterClassEx(&wc);
if (!atom)
qErrnoWarning("QApplication::regClass: Registering window class '%s' failed.",
qPrintable(cname));
d->m_registeredWindowClassNames.insert(cname);
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << cname
<< " style=0x" << Qt::hex << style << Qt::dec
<< " brush=" << brush << " icon=" << icon << " atom=" << atom;
return cname;
}