概述
QT是基于事件驱动的,消息处理逻辑如下:
主函数的逻辑:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
调用 QApplication::exec:
int QApplication::exec()
{
return QGuiApplication::exec();
}
调用 QGuiApplication::exec():
int QGuiApplication::exec()
{
#ifndef QT_NO_ACCESSIBILITY
QAccessible::setRootObject(qApp);
#endif
return QCoreApplication::exec();
}
QCoreApplication::exec():
int QCoreApplication::exec()
{
if (!QCoreApplicationPrivate::checkInstance("exec"))
return -1;
QThreadData *threadData = self->d_func()->threadData;
if (threadData != QThreadData::current()) {
qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
return -1;
}
if (!threadData->eventLoops.isEmpty()) {
qWarning("QCoreApplication::exec: The event loop is already running");
return -1;
}
threadData->quitNow = false;
QEventLoop eventLoop;
self->d_func()->in_exec = true;
self->d_func()->aboutToQuitEmitted = false;
int returnCode = eventLoop.exec();
threadData->quitNow = false;
if (self)
self->d_func()->execCleanup();
return returnCode;
}
调用eventLoop.exec():
int QEventLoop::exec(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
//we need to protect from race condition with QThread::exit
QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread.loadAcquire()))->mutex);
if (d->threadData->quitNow)
return -1;
if (d->inExec) {
qWarning("QEventLoop::exec: instance %p has already called exec()", this);
return -1;
}
struct LoopReference {
QEventLoopPrivate *d;
QMutexLocker &locker;
bool exceptionCaught;
LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
{
d->inExec = true;
d->exit.storeRelease(false);
++d->threadData->loopLevel;
d->threadData->eventLoops.push(d->q_func());
locker.unlock();
}
~LoopReference()
{
if (exceptionCaught) {
qWarning("Qt has caught an exception thrown from an event handler. Throwingn"
"exceptions from an event handler is not supported in Qt.n"
"You must not let any exception whatsoever propagate through Qt code.n"
"If that is not possible, in Qt 5 you must at least reimplementn"
"QCoreApplication::notify() and catch all exceptions there.n");
}
locker.relock();
QEventLoop *eventLoop = d->threadData->eventLoops.pop();
Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
Q_UNUSED(eventLoop); // --release warning
d->inExec = false;
--d->threadData->loopLevel;
}
};
LoopReference ref(d, locker);
// remove posted quit events when entering a new event loop
QCoreApplication *app = QCoreApplication::instance();
if (app && app->thread() == thread())
QCoreApplication::removePostedEvents(app, QEvent::Quit);
#ifdef Q_OS_WASM
// Partial support for nested event loops: Make the runtime throw a JavaSrcript
// exception, which returns control to the browser while preserving the C++ stack.
// Event processing then continues as normal. The sleep call below never returns.
// QTBUG-70185
if (d->threadData->loopLevel > 1)
emscripten_sleep(1);
#endif
while (!d->exit.loadAcquire())
processEvents(flags | WaitForMoreEvents | EventLoopExec);
ref.exceptionCaught = false;
return d->returnCode.loadRelaxed();
}
QT绘制机制:
void QWidgetPrivate::setVisible(bool visible)
{
Q_Q(QWidget);
if (visible) { // show
// Designer uses a trick to make grabWidget work without showing
if (!q->isWindow() && q->parentWidget() && q->parentWidget()->isVisible()
&& !q->parentWidget()->testAttribute(Qt::WA_WState_Created))
q->parentWidget()->window()->d_func()->createRecursively();
//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();
}
bool wasResized = q->testAttribute(Qt::WA_Resized);
Qt::WindowStates initialWindowState = q->windowState();
// polish if necessary
q->ensurePolished();
// whether we need to inform the parent widget immediately
bool needUpdateGeometry = !q->isWindow() && q->testAttribute(Qt::WA_WState_Hidden);
// we are no longer hidden
q->setAttribute(Qt::WA_WState_Hidden, false);
if (needUpdateGeometry)
updateGeometry_helper(true);
// activate our layout before we and our children become visible
if (layout)
layout->activate();
if (!q->isWindow()) {
QWidget *parent = q->parentWidget();
while (parent && parent->isVisible() && parent->d_func()->layout && !parent->data->in_show) {
parent->d_func()->layout->activate();
if (parent->isWindow())
break;
parent = parent->parentWidget();
}
if (parent)
parent->d_func()->setDirtyOpaqueRegion();
}
// adjust size if necessary
if (!wasResized
&& (q->isWindow() || !q->parentWidget()->d_func()->layout)) {
if (q->isWindow()) {
q->adjustSize();
if (q->windowState() != initialWindowState)
q->setWindowState(initialWindowState);
} else {
q->adjustSize();
}
q->setAttribute(Qt::WA_Resized, false);
}
q->setAttribute(Qt::WA_KeyboardFocusChange, false);
if (q->isWindow() || q->parentWidget()->isVisible()) {
show_helper();
qApp->d_func()->sendSyntheticEnterLeave(q);
}
QEvent showToParentEvent(QEvent::ShowToParent);
QCoreApplication::sendEvent(q, &showToParentEvent);
} else { // hide
if (QApplicationPrivate::hidden_focus_widget == q)
QApplicationPrivate::hidden_focus_widget = 0;
// hw: The test on getOpaqueRegion() needs to be more intelligent
// currently it doesn't work if the widget is hidden (the region will
// be clipped). The real check should be testing the cached region
// (and dirty flag) directly.
if (!q->isWindow() && q->parentWidget()) // && !d->getOpaqueRegion().isEmpty())
q->parentWidget()->d_func()->setDirtyOpaqueRegion();
q->setAttribute(Qt::WA_WState_Hidden);
if (q->testAttribute(Qt::WA_WState_Created))
hide_helper();
// invalidate layout similar to updateGeometry()
if (!q->isWindow() && q->parentWidget()) {
if (q->parentWidget()->d_func()->layout)
q->parentWidget()->d_func()->layout->invalidate();
else if (q->parentWidget()->isVisible())
QCoreApplication::postEvent(q->parentWidget(), new QEvent(QEvent::LayoutRequest));
}
QEvent hideToParentEvent(QEvent::HideToParent);
QCoreApplication::sendEvent(q, &hideToParentEvent);
}
}
paintEvent:
void paintEvent(QPaintEvent *event);
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
setMaximumSize(600,500);
MyLabel * myLabel = new MyLabel(this);
myLabel->setGeometry(0,0,300,300);
myLabel->setText("hello,world");
}
Widget::~Widget()
{
}
void Widget::dealClick(bool flag){
qDebug() << flag;
if (!flag){
lineEdit->undo();
}
}
void Widget::listChildrens(QWidget * widget){
QObjectList objectList = widget->children();
for (int i=0;i<objectList.size();i++){
qDebug() << objectList[i]->objectName();
qDebug() << objectList[i]->metaObject()->className();
listChildrens(qobject_cast<QWidget *>(objectList[i]));
}
}
总结:paibeEvent,被组件子类重写后,父类的绘制会调用paintEvent,所以会被重新绘制!!!
最后
以上就是敏感河马为你收集整理的QT源码剖析的全部内容,希望文章能够帮你解决QT源码剖析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复