上一篇说到QApplication注册了一个qt_internal_proc方法来处理消息循环,但是在整个过程中都没有看到处理用户输入事件的过程。例如鼠标事件、键盘事件等。
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
上篇文章分析了QApplication的构造,主事件循环启动、运行。 对于鼠标、键盘事件的响应肯定依托于一个可见的窗口,QApplication本身并不属于窗体,接下来针对于QWidget展开分析。
一、启动用户输入事件循环
Step 1
// src\widgets\kernel\qwidget.cpp
void QWidget::show()
{
Qt::WindowState defaultState = QGuiApplicationPrivate::platformIntegration()->defaultWindowState(data->window_flags);
if (defaultState == Qt::WindowFullScreen)
showFullScreen();
else if (defaultState == Qt::WindowMaximized)
showMaximized();
else
setVisible(true); // Don't call showNormal() as not to clobber Qt::Window(Max/Min)imized
}
void QWidget::setVisible(bool visible)
{
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) == !visible)
return;
// Remember that setVisible was called explicitly
setAttribute(Qt::WA_WState_ExplicitShowHide);
Q_D(QWidget);
d->setVisible(visible);
}
void QWidgetPrivate::setVisible(bool visible)
{
Q_Q(QWidget);
if (visible) {
// show
/**
* 代码省略 .......
*/
//create toplevels but not children of non-visible parents
QWidget *pw = q->parentWidget();
if (!q->testAttribute(Qt::WA_WState_Created)
&& (q->isWindow() || pw->testAttribute(Qt::WA_WState_Created))) {
q->create();
}
}
}
QWidget在调用show函数显示一个窗口时,无论是全屏显示还是最大化显示最总都会调用QWidgetPrivate::setVisible函数。由于此Widget无父对象,在构造时将type设置为Qt::Window,因此会调用QWidget::create函数
Step 2
// src\widgets\kernel\qwidget.cpp
void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
{
/**
* 代码省略 .......
*/
setAttribute(Qt::WA_WState_Created); // set created flag
d->create();
/**
* 代码省略 .......
*/
}
void QWidgetPrivate::create()
{
/**
* 代码省略 .......
*/
QWidgetWindow *win = topData()->window;
// topData() ensures the extra is created but does not ensure 'window' is non-null
// in case the extra was already valid.
if (!win) {
createTLSysExtra();
win = topData()->window;
}
/**
* 代码省略 .......
*/
if (q->windowType() != Qt::Desktop || q->testAttribute(Qt::WA_NativeWindow)) {
win->create();
// Enable nonclient-area events for QDockWidget and other NonClientArea-mouse event processing.
if (QPlatformWindow *platformWindow = win->handle())
platformWindow->setFrameStrutEventsEnabled(true);
}
/**
* 代码省略 .......
*/
}
void QWidgetPrivate::createTLSysExtra()
{
Q_Q(QWidget);
if (!extra->topextra->window && (q->testAttribute(Qt::WA_NativeWindow) || q->isWindow())) {
extra->topextra->window = new QWidgetWindow(q);
/**
* 代码省略 .......
*/
}
}
通过QWidgetPrivate::createTLSysExtra()创建QWidgetWindow对象,q->windowType()的类型为Qt::Window,通过QWindowPrivate::create创建窗口
Step 3
// src\widgets\kernel\qwidget.cpp
void QWindowPrivate::create(bool recursive, WId nativeHandle)
{
Q_Q(QWindow);
if (platformWindow)
return;
// avoid losing update requests when re-creating
const bool needsUpdate = updateRequestPending;
// the platformWindow, if there was one, is now gone, so make this flag reflect reality now
updateRequestPending = false;
if (q->parent())
q->parent()->create();
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
platformWindow = nativeHandle ? platformIntegration->createForeignWindow(q, nativeHandle)
: platformIntegration->createPlatformWindow(q);
/**
* 代码省略 .......
*/
}
// src\plugins\platforms\windows\qwindowsintegration.cpp
QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const
{
if (window->type() == Qt::Desktop) {
auto *result = new QWindowsDesktopWindow(window);
qCDebug(lcQpaWindows) << "Desktop window:" << window
<< Qt::showbase << Qt::hex << result->winId() << Qt::noshowbase << Qt::dec << result->geometry();
return result;
}
QWindowsWindowData requested;
requested.flags = window->flags();
requested.geometry = window->isTopLevel()
? QHighDpi::toNativePixels(window->geometry(), window)
: QHighDpi::toNativeLocalPosition(window->geometry(), window);
// Apply custom margins (see QWindowsWindow::setCustomMargins())).
const QVariant customMarginsV = window->property("_q_windowsCustomMargins");
if (customMarginsV.isValid())
requested.customMargins = qvariant_cast<QMargins>(customMarginsV);
QWindowsWindowData obtained =
QWindowsWindowData::create(window, requested,
QWindowsWindow