首先,了解一下事件循环:
http://blog.youkuaiyun.com/houwenbin1986/article/details/79078446
接着,来看看最简单的按钮的点击响应:
又是贴代码
//处理事件分发
void QWindowsGuiEventDispatcher::sendPostedEvents()
{
QEventDispatcherWin32::sendPostedEvents();
QWindowSystemInterface::sendWindowSystemEvents(m_flags);
}
//针对Windows事件分发
bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
{
int nevents = 0;
while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
QWindowSystemInterfacePrivate::WindowSystemEvent *event =
(flags & QEventLoop::ExcludeUserInputEvents) ?
QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
QWindowSystemInterfacePrivate::getWindowSystemEvent();
if (!event)
break;
if (QWindowSystemInterfacePrivate::eventHandler) {
if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
nevents++;
} else {
nevents++;
QGuiApplicationPrivate::processWindowSystemEvent(event);//比如Windows下的事件
}
// Record the accepted state for the processed event
// (excluding flush events). This state can then be
// returned by flushWindowSystemEvents().
if (event->type != QWindowSystemInterfacePrivate::FlushEvents)
QWindowSystemInterfacePrivate::eventAccepted.store(event->eventAccepted);
delete event;
}
return (nevents > 0);
}
void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
{
switch(e->type) {
case QWindowSystemInterfacePrivate::FrameStrutMouse:
case QWindowSystemInterfacePrivate::Mouse://比如鼠标事件响应
QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Wheel:
QGuiApplicationPrivate::processWheelEvent(static_cast<QWindowSystemInterfacePrivate::WheelEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Key:
QGuiApplicationPrivate::processKeyEvent(static_cast<QWindowSystemInterfacePrivate::KeyEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Touch:
QGuiApplicationPrivate::processTouchEvent(static_cast<QWindowSystemInterfacePrivate::TouchEvent *>(e));
break;
case QWindowSystemInterfacePrivate::GeometryChange:
QGuiApplicationPrivate::processGeometryChangeEvent(static_cast<QWindowSystemInterfacePrivate::GeometryChangeEvent*>(e));
break;
case QWindowSystemInterfacePrivate::Enter:
QGuiApplicationPrivate::processEnterEvent(static_cast<QWindowSystemInterfacePrivate::EnterEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Leave:
QGuiApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ActivatedWindow:
QGuiApplicationPrivate::processActivatedEvent(static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>(e));
break;
case QWindowSystemInterfacePrivate::WindowStateChanged:
QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
break;
case QWindowSystemInterfacePrivate::WindowScreenChanged:
QGuiApplicationPrivate::processWindowScreenChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowScreenChangedEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ApplicationStateChanged: {
QWindowSystemInterfacePrivate::ApplicationStateChangedEvent * changeEvent = static_cast<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *>(e);
QGuiApplicationPrivate::setApplicationState(changeEvent->newState, changeEvent->forcePropagate); }
break;
case QWindowSystemInterfacePrivate::FlushEvents: {
QWindowSystemInterfacePrivate::FlushEventsEvent *flushEventsEvent = static_cast<QWindowSystemInterfacePrivate::FlushEventsEvent *>(e);
QWindowSystemInterface::deferredFlushWindowSystemEvents(flushEventsEvent->flags); }
break;
case QWindowSystemInterfacePrivate::Close:
QGuiApplicationPrivate::processCloseEvent(
static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ScreenOrientation:
QGuiApplicationPrivate::reportScreenOrientationChange(
static_cast<QWindowSystemInterfacePrivate::ScreenOrientationEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ScreenGeometry:
QGuiApplicationPrivate::reportGeometryChange(
static_cast<QWindowSystemInterfacePrivate::ScreenGeometryEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInch:
QGuiApplicationPrivate::reportLogicalDotsPerInchChange(
static_cast<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ScreenRefreshRate:
QGuiApplicationPrivate::reportRefreshRateChange(
static_cast<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ThemeChange:
QGuiApplicationPrivate::processThemeChanged(
static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Expose:
QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Tablet:
QGuiApplicationPrivate::processTabletEvent(
static_cast<QWindowSystemInterfacePrivate::TabletEvent *>(e));
break;
case QWindowSystemInterfacePrivate::TabletEnterProximity:
QGuiApplicationPrivate::processTabletEnterProximityEvent(
static_cast<QWindowSystemInterfacePrivate::TabletEnterProximityEvent *>(e));
break;
case QWindowSystemInterfacePrivate::TabletLeaveProximity:
QGuiApplicationPrivate::processTabletLeaveProximityEvent(
static_cast<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *>(e));
break;
#ifndef QT_NO_GESTURES
case QWindowSystemInterfacePrivate::Gesture:
QGuiApplicationPrivate::processGestureEvent(
static_cast<QWindowSystemInterfacePrivate::GestureEvent *>(e));
break;
#endif
case QWindowSystemInterfacePrivate::PlatformPanel:
QGuiApplicationPrivate::processPlatformPanelEvent(
static_cast<QWindowSystemInterfacePrivate::PlatformPanelEvent *>(e));
break;
case QWindowSystemInterfacePrivate::FileOpen:
QGuiApplicationPrivate::processFileOpenEvent(
static_cast<QWindowSystemInterfacePrivate::FileOpenEvent *>(e));
break;
#ifndef QT_NO_CONTEXTMENU
case QWindowSystemInterfacePrivate::ContextMenu:
QGuiApplicationPrivate::processContextMenuEvent(
static_cast<QWindowSystemInterfacePrivate::ContextMenuEvent *>(e));
break;
#endif
case QWindowSystemInterfacePrivate::EnterWhatsThisMode:
QGuiApplication::postEvent(QGuiApplication::instance(), new QEvent(QEvent::EnterWhatsThisMode));
break;
default:
qWarning() << "Unknown user input event type:" << e->type;
break;
}
}
//响应鼠标事件啦!!!
void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e)
{
QEvent::Type type;
Qt::MouseButtons stateChange = e->buttons ^ buttons;
if (e->globalPos != QGuiApplicationPrivate::lastCursorPosition && (stateChange != Qt::NoButton)) {
// A mouse event should not change both position and buttons at the same time. Instead we
// should first send a move event followed by a button changed event. Since this is not the case
// with the current event, we split it in two.
QWindowSystemInterfacePrivate::MouseEvent mouseButtonEvent(
e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers, e->source);
if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic)
mouseButtonEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
e->buttons = buttons;
processMouseEvent(e);
processMouseEvent(&mouseButtonEvent);
return;
}
QWindow *window = e->window.data();
modifier_buttons = e->modifiers;
QPointF localPoint = e->localPos;
QPointF globalPoint = e->globalPos;
if (e->nullWindow()) {
window = QGuiApplication::topLevelAt(globalPoint.toPoint());
if (window) {
// Moves and the release following a press must go to the same
// window, even if the cursor has moved on over another window.
if (e->buttons != Qt::NoButton) {
if (!currentMousePressWindow)
currentMousePressWindow = window;
else
window = currentMousePressWindow;
} else if (currentMousePressWindow) {
window = currentMousePressWindow;
currentMousePressWindow = 0;
}
QPointF delta = globalPoint - globalPoint.toPoint();
localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
}
}
Qt::MouseButton button = Qt::NoButton;
bool doubleClick = false;
const bool frameStrut = e->type == QWindowSystemInterfacePrivate::FrameStrutMouse;
if (QGuiApplicationPrivate::lastCursorPosition != globalPoint) {
type = frameStrut ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove;
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
if (qAbs(globalPoint.x() - mousePressX) > mouse_double_click_distance||
qAbs(globalPoint.y() - mousePressY) > mouse_double_click_distance)
mousePressButton = Qt::NoButton;
} else { // Check to see if a new button has been pressed/released.
for (int check = Qt::LeftButton;
check <= int(Qt::MaxMouseButton);
check = check << 1) {
if (check & stateChange) {
button = Qt::MouseButton(check);
break;
}
}
if (button == Qt::NoButton) {
// Ignore mouse events that don't change the current state.
return;
}
mouse_buttons = buttons = e->buttons;
if (button & e->buttons) {
ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
type = frameStrut ? QEvent::NonClientAreaMouseButtonPress : QEvent::MouseButtonPress;
mousePressTime = e->timestamp;
mousePressButton = button;
const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint();
mousePressX = point.x();
mousePressY = point.y();
} else {
type = frameStrut ? QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
}
}
if (!window)
return;
#ifndef QT_NO_CURSOR
if (!e->synthetic()) {
if (const QScreen *screen = window->screen())
if (QPlatformCursor *cursor = screen->handle()->cursor()) {
const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen);
const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen);
QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint,
button, buttons, e->modifiers, e->source);
ev.setTimestamp(e->timestamp);
cursor->pointerEvent(ev);
}
}
#endif
QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers, e->source);
ev.setTimestamp(e->timestamp);
if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
// a modal window is blocking this window, don't allow mouse events through
return;
}
if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) {
// QtBUG-25831, used to suppress delivery in qwidgetwindow.cpp
setMouseEventFlags(&ev, ev.flags() | Qt::MouseEventCreatedDoubleClick);
}
QGuiApplication::sendSpontaneousEvent(window, &ev);
e->eventAccepted = ev.isAccepted();
if (!e->synthetic() && !ev.isAccepted()
&& !frameStrut
&& qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
if (!m_fakeTouchDevice) {
m_fakeTouchDevice = new QTouchDevice;
QWindowSystemInterface::registerTouchDevice(m_fakeTouchDevice);
}
QList<QWindowSystemInterface::TouchPoint> points;
QWindowSystemInterface::TouchPoint point;
point.id = 1;
point.area = QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4);
// only translate left button related events to
// avoid strange touch event sequences when several
// buttons are pressed
if (type == QEvent::MouseButtonPress && button == Qt::LeftButton) {
point.state = Qt::TouchPointPressed;
} else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) {
point.state = Qt::TouchPointReleased;
} else if (type == QEvent::MouseMove && (buttons & Qt::LeftButton)) {
point.state = Qt::TouchPointMoved;
} else {
return;
}
points << point;
QEvent::Type type;
QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type);
QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers);
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
processTouchEvent(&fake);
}
if (doubleClick) {
mousePressButton = Qt::NoButton;
if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press
const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick;
QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
button, buttons, e->modifiers, e->source);
dblClickEvent.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
}
}
}
//调用通知(回调)连接到槽函数
#ifndef QT_NO_QOBJECT
inline bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
{ if (event) event->spont = false; return notifyInternal2(receiver, event); }
inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
{ if (event) event->spont = true; return notifyInternal2(receiver, event); }//通知槽函数响应
#endif
//通知相应事件处理!!!
bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
{
bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication();
if (!self && selfRequired)
return false;
// Make it possible for Qt Script to hook into events even
// though QApplication is subclassed...
bool result = false;
void *cbdata[] = { receiver, event, &result };
if (QInternal::activateCallbacks(QInternal::EventNotifyCallback, cbdata)) {
return result;
}
// Qt enforces the rule that events can only be sent to objects in
// the current thread, so receiver->d_func()->threadData is
// equivalent to QThreadData::current(), just without the function
// call overhead.
QObjectPrivate *d = receiver->d_func();
QThreadData *threadData = d->threadData;
QScopedLoopLevelCounter loopLevelCounter(threadData);
if (!selfRequired)
return doNotify(receiver, event);//
return self->notify(receiver, event);//转到应用程序的响应里去
}
//应用的响应!!!
bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
{
// send to all application event filters
if (threadRequiresCoreApplication()
&& receiver->d_func()->threadData->thread == mainThread()
&& sendThroughApplicationEventFilters(receiver, e))
return true;
if (receiver->isWidgetType()) {
QWidget *widget = static_cast<QWidget *>(receiver);
#if !defined(Q_OS_WINCE) || (defined(GWES_ICONCURS) && !defined(QT_NO_CURSOR))
// toggle HasMouse widget state on enter and leave
if ((e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) &&
(!QApplication::activePopupWidget() || QApplication::activePopupWidget() == widget->window()))
widget->setAttribute(Qt::WA_UnderMouse, true);
else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave)
widget->setAttribute(Qt::WA_UnderMouse, false);
#endif
if (QLayout *layout=widget->d_func()->layout) {
layout->widgetEvent(e);
}
}
// send to all receiver event filters //注意多个连接槽函数!!!
if (sendThroughObjectEventFilters(receiver, e))
return true;
// deliver the event
bool consumed = receiver->event(e);//转到具体信号接收者的响应里去
QCoreApplicationPrivate::setEventSpontaneous(e, false);
return consumed;
}
//具体控件的事件响应里
bool QPushButton::event(QEvent *e)
{
Q_D(QPushButton);
if (e->type() == QEvent::ParentChange) {
if (QDialog *dialog = d->dialogParent()) {
if (d->defaultButton)
dialog->d_func()->setMainDefault(this);
}
} else if (e->type() == QEvent::StyleChange
#ifdef Q_OS_MAC
|| e->type() == QEvent::MacSizeChange
#endif
) {
d->resetLayoutItemMargins();
updateGeometry();
} else if (e->type() == QEvent::PolishRequest) {
updateGeometry();
}
return QAbstractButton::event(e);
}
//做一些事情!!!
bool QAbstractButton::event(QEvent *e)
{
// as opposed to other widgets, disabled buttons accept mouse
// events. This avoids surprising click-through scenarios
if (!isEnabled()) {
switch(e->type()) {
case QEvent::TabletPress:
case QEvent::TabletRelease:
case QEvent::TabletMove:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
case QEvent::HoverMove:
case QEvent::HoverEnter:
case QEvent::HoverLeave:
case QEvent::ContextMenu:
#ifndef QT_NO_WHEELEVENT
case QEvent::Wheel:
#endif
return true;
default:
break;
}
}
#ifndef QT_NO_SHORTCUT
if (e->type() == QEvent::Shortcut) {
Q_D(QAbstractButton);
QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
if (d->shortcutId != se->shortcutId())
return false;
if (!se->isAmbiguous()) {
if (!d->animateTimer.isActive())
animateClick();
} else {
if (focusPolicy() != Qt::NoFocus)
setFocus(Qt::ShortcutFocusReason);
window()->setAttribute(Qt::WA_KeyboardFocusChange);
}
return true;
}
#endif
return QWidget::event(e);
}
//再往下传递
bool QWidget::event(QEvent *event)
{
Q_D(QWidget);
// ignore mouse and key events when disabled
if (!isEnabled()) {
switch(event->type()) {
case QEvent::TabletPress:
case QEvent::TabletRelease:
case QEvent::TabletMove:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
case QEvent::TouchCancel:
case QEvent::ContextMenu:
case QEvent::KeyPress:
case QEvent::KeyRelease:
#ifndef QT_NO_WHEELEVENT
case QEvent::Wheel:
#endif
return false;
default:
break;
}
}
switch (event->type()) {
case QEvent::MouseMove:
mouseMoveEvent((QMouseEvent*)event);
break;
case QEvent::MouseButtonPress:
mousePressEvent((QMouseEvent*)event);
break;
case QEvent::MouseButtonRelease://这里响应一下
mouseReleaseEvent((QMouseEvent*)event);
break;
case QEvent::MouseButtonDblClick:
mouseDoubleClickEvent((QMouseEvent*)event);
break;
#ifndef QT_NO_WHEELEVENT
case QEvent::Wheel:
wheelEvent((QWheelEvent*)event);
break;
#endif
#ifndef QT_NO_TABLETEVENT
case QEvent::TabletMove:
case QEvent::TabletPress:
case QEvent::TabletRelease:
tabletEvent((QTabletEvent*)event);
break;
#endif
case QEvent::KeyPress: {
QKeyEvent *k = (QKeyEvent *)event;
bool res = false;
if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
if (k->key() == Qt::Key_Backtab
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
res = focusNextPrevChild(false);
else if (k->key() == Qt::Key_Tab)
res = focusNextPrevChild(true);
if (res)
break;
}
keyPressEvent(k);
#ifdef QT_KEYPAD_NAVIGATION
if (!k->isAccepted() && QApplication::keypadNavigationEnabled()
&& !(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::ShiftModifier))) {
if (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder) {
if (k->key() == Qt::Key_Up)
res = focusNextPrevChild(false);
else if (k->key() == Qt::Key_Down)
res = focusNextPrevChild(true);
} else if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
if (k->key() == Qt::Key_Up)
res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionNorth);
else if (k->key() == Qt::Key_Right)
res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionEast);
else if (k->key() == Qt::Key_Down)
res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionSouth);
else if (k->key() == Qt::Key_Left)
res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionWest);
}
if (res) {
k->accept();
break;
}
}
#endif
#ifndef QT_NO_WHATSTHIS
if (!k->isAccepted()
&& k->modifiers() & Qt::ShiftModifier && k->key() == Qt::Key_F1
&& d->whatsThis.size()) {
QWhatsThis::showText(mapToGlobal(inputMethodQuery(Qt::ImCursorRectangle).toRect().center()), d->whatsThis, this);
k->accept();
}
#endif
}
break;
case QEvent::KeyRelease:
keyReleaseEvent((QKeyEvent*)event);
// fall through
case QEvent::ShortcutOverride:
break;
case QEvent::InputMethod:
inputMethodEvent((QInputMethodEvent *) event);
break;
case QEvent::InputMethodQuery:
if (testAttribute(Qt::WA_InputMethodEnabled)) {
QInputMethodQueryEvent *query = static_cast<QInputMethodQueryEvent *>(event);
Qt::InputMethodQueries queries = query->queries();
for (uint i = 0; i < 32; ++i) {
Qt::InputMethodQuery q = (Qt::InputMethodQuery)(int)(queries & (1<<i));
if (q) {
QVariant v = inputMethodQuery(q);
if (q == Qt::ImEnabled && !v.isValid() && isEnabled())
v = QVariant(true); // special case for Qt4 compatibility
query->setValue(q, v);
}
}
query->accept();
}
break;
case QEvent::PolishRequest:
ensurePolished();
break;
case QEvent::Polish: {
style()->polish(this);
setAttribute(Qt::WA_WState_Polished);
if (!QApplication::font(this).isCopyOf(QApplication::font()))
d->resolveFont();
if (!QApplication::palette(this).isCopyOf(QApplication::palette()))
d->resolvePalette();
}
break;
case QEvent::ApplicationWindowIconChange:
if (isWindow() && !testAttribute(Qt::WA_SetWindowIcon)) {
d->setWindowIcon_sys();
d->setWindowIcon_helper();
}
break;
case QEvent::FocusIn:
focusInEvent((QFocusEvent*)event);
d->updateWidgetTransform(event);
break;
case QEvent::FocusOut:
focusOutEvent((QFocusEvent*)event);
break;
case QEvent::Enter:
#ifndef QT_NO_STATUSTIP
if (d->statusTip.size()) {
QStatusTipEvent tip(d->statusTip);
QApplication::sendEvent(const_cast<QWidget *>(this), &tip);
}
#endif
enterEvent(event);
break;
case QEvent::Leave:
#ifndef QT_NO_STATUSTIP
if (d->statusTip.size()) {
QString empty;
QStatusTipEvent tip(empty);
QApplication::sendEvent(const_cast<QWidget *>(this), &tip);
}
#endif
leaveEvent(event);
break;
case QEvent::HoverEnter:
case QEvent::HoverLeave:
update();
break;
case QEvent::Paint:
// At this point the event has to be delivered, regardless
// whether the widget isVisible() or not because it
// already went through the filters
paintEvent((QPaintEvent*)event);
break;
case QEvent::Move:
moveEvent((QMoveEvent*)event);
d->updateWidgetTransform(event);
break;
case QEvent::Resize:
resizeEvent((QResizeEvent*)event);
d->updateWidgetTransform(event);
break;
case QEvent::Close:
closeEvent((QCloseEvent *)event);
break;
#ifndef QT_NO_CONTEXTMENU
case QEvent::ContextMenu:
switch (data->context_menu_policy) {
case Qt::PreventContextMenu:
break;
case Qt::DefaultContextMenu:
contextMenuEvent(static_cast<QContextMenuEvent *>(event));
break;
case Qt::CustomContextMenu:
emit customContextMenuRequested(static_cast<QContextMenuEvent *>(event)->pos());
break;
#ifndef QT_NO_MENU
case Qt::ActionsContextMenu:
if (d->actions.count()) {
QMenu::exec(d->actions, static_cast<QContextMenuEvent *>(event)->globalPos(),
0, this);
break;
}
// fall through
#endif
default:
event->ignore();
break;
}
break;
#endif // QT_NO_CONTEXTMENU
#ifndef QT_NO_DRAGANDDROP
case QEvent::Drop:
dropEvent((QDropEvent*) event);
break;
case QEvent::DragEnter:
dragEnterEvent((QDragEnterEvent*) event);
break;
case QEvent::DragMove:
dragMoveEvent((QDragMoveEvent*) event);
break;
case QEvent::DragLeave:
dragLeaveEvent((QDragLeaveEvent*) event);
break;
#endif
case QEvent::Show:
showEvent((QShowEvent*) event);
break;
case QEvent::Hide:
hideEvent((QHideEvent*) event);
break;
case QEvent::ShowWindowRequest:
if (!isHidden())
d->show_sys();
break;
case QEvent::ApplicationFontChange:
d->resolveFont();
break;
case QEvent::ApplicationPaletteChange:
if (!(windowType() == Qt::Desktop))
d->resolvePalette();
break;
case QEvent::ToolBarChange:
case QEvent::ActivationChange:
case QEvent::EnabledChange:
case QEvent::FontChange:
case QEvent::StyleChange:
case QEvent::PaletteChange:
case QEvent::WindowTitleChange:
case QEvent::IconTextChange:
case QEvent::ModifiedChange:
case QEvent::MouseTrackingChange:
case QEvent::ParentChange:
case QEvent::LocaleChange:
case QEvent::MacSizeChange:
case QEvent::ContentsRectChange:
case QEvent::ThemeChange:
case QEvent::ReadOnlyChange:
changeEvent(event);
break;
case QEvent::WindowStateChange: {
const bool wasMinimized = static_cast<const QWindowStateChangeEvent *>(event)->oldState() & Qt::WindowMinimized;
if (wasMinimized != isMinimized()) {
QWidget *widget = const_cast<QWidget *>(this);
if (wasMinimized) {
// Always send the spontaneous events here, otherwise it can break the application!
if (!d->childrenShownByExpose) {
// Show widgets only when they are not yet shown by the expose event
d->showChildren(true);
QShowEvent showEvent;
QCoreApplication::sendSpontaneousEvent(widget, &showEvent);
}
d->childrenHiddenByWState = false; // Set it always to "false" when window is restored
} else {
QHideEvent hideEvent;
QCoreApplication::sendSpontaneousEvent(widget, &hideEvent);
d->hideChildren(true);
d->childrenHiddenByWState = true;
}
d->childrenShownByExpose = false; // Set it always to "false" when window state changes
}
changeEvent(event);
}
break;
case QEvent::WindowActivate:
case QEvent::WindowDeactivate: {
if (isVisible() && !palette().isEqual(QPalette::Active, QPalette::Inactive))
update();
QList<QObject*> childList = d->children;
for (int i = 0; i < childList.size(); ++i) {
QWidget *w = qobject_cast<QWidget *>(childList.at(i));
if (w && w->isVisible() && !w->isWindow())
QApplication::sendEvent(w, event);
}
break; }
case QEvent::LanguageChange:
changeEvent(event);
{
QList<QObject*> childList = d->children;
for (int i = 0; i < childList.size(); ++i) {
QObject *o = childList.at(i);
if (o)
QApplication::sendEvent(o, event);
}
}
update();
break;
case QEvent::ApplicationLayoutDirectionChange:
d->resolveLayoutDirection();
break;
case QEvent::LayoutDirectionChange:
if (d->layout)
d->layout->invalidate();
update();
changeEvent(event);
break;
case QEvent::UpdateRequest:
d->syncBackingStore();
break;
case QEvent::UpdateLater:
update(static_cast<QUpdateLaterEvent*>(event)->region());
break;
case QEvent::StyleAnimationUpdate:
if (isVisible() && !window()->isMinimized()) {
event->accept();
update();
}
break;
case QEvent::WindowBlocked:
case QEvent::WindowUnblocked:
if (!d->children.isEmpty()) {
QWidget *modalWidget = QApplication::activeModalWidget();
for (int i = 0; i < d->children.size(); ++i) {
QObject *o = d->children.at(i);
if (o && o != modalWidget && o->isWidgetType()) {
QWidget *w = static_cast<QWidget *>(o);
// do not forward the event to child windows; QApplication does this for us
if (!w->isWindow())
QApplication::sendEvent(w, event);
}
}
}
#if defined(Q_DEAD_CODE_FROM_QT4_WIN)
setDisabledStyle(this, (event->type() == QEvent::WindowBlocked));
#endif
break;
#ifndef QT_NO_TOOLTIP
case QEvent::ToolTip:
if (!d->toolTip.isEmpty())
QToolTip::showText(static_cast<QHelpEvent*>(event)->globalPos(), d->toolTip, this, QRect(), d->toolTipDuration);
else
event->ignore();
break;
#endif
#ifndef QT_NO_WHATSTHIS
case QEvent::WhatsThis:
if (d->whatsThis.size())
QWhatsThis::showText(static_cast<QHelpEvent *>(event)->globalPos(), d->whatsThis, this);
else
event->ignore();
break;
case QEvent::QueryWhatsThis:
if (d->whatsThis.isEmpty())
event->ignore();
break;
#endif
case QEvent::EmbeddingControl:
d->topData()->frameStrut.setCoords(0 ,0, 0, 0);
data->fstrut_dirty = false;
#if defined(Q_DEAD_CODE_FROM_QT4_WIN) || defined(Q_DEAD_CODE_FROM_QT4_X11)
d->topData()->embedded = 1;
#endif
break;
#ifndef QT_NO_ACTION
case QEvent::ActionAdded:
case QEvent::ActionRemoved:
case QEvent::ActionChanged:
actionEvent((QActionEvent*)event);
break;
#endif
case QEvent::KeyboardLayoutChange:
{
changeEvent(event);
// inform children of the change
QList<QObject*> childList = d->children;
for (int i = 0; i < childList.size(); ++i) {
QWidget *w = qobject_cast<QWidget *>(childList.at(i));
if (w && w->isVisible() && !w->isWindow())
QApplication::sendEvent(w, event);
}
break;
}
#ifdef Q_DEAD_CODE_FROM_QT4_MAC
case QEvent::MacGLWindowChange:
d->needWindowChange = false;
break;
#endif
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
case QEvent::TouchCancel:
{
event->ignore();
break;
}
#ifndef QT_NO_GESTURES
case QEvent::Gesture:
event->ignore();
break;
#endif
case QEvent::ScreenChangeInternal:
if (const QTLWExtra *te = d->maybeTopData()) {
const QWindow *win = te->window;
d->setWinId((win && win->handle()) ? win->handle()->winId() : 0);
}
#ifndef QT_NO_OPENGL
d->renderToTextureReallyDirty = 1;
#endif
break;
#ifndef QT_NO_PROPERTIES
case QEvent::DynamicPropertyChange: {
const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
if (propName.length() == 13 && !qstrncmp(propName, "_q_customDpi", 12)) {
uint value = property(propName.constData()).toUInt();
if (!d->extra)
d->createExtra();
const char axis = propName.at(12);
if (axis == 'X')
d->extra->customDpiX = value;
else if (axis == 'Y')
d->extra->customDpiY = value;
d->updateFont(d->data.fnt);
}
if (windowHandle() && !qstrncmp(propName, "_q_platform_", 12))
windowHandle()->setProperty(propName, property(propName));
// fall through
}
#endif
default:
return QObject::event(event);
}
return true;
}
//
void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QAbstractButton);
d->pressed = false;
if (e->button() != Qt::LeftButton) {
e->ignore();
return;
}
if (!d->down) {
// refresh is required by QMacStyle to resume the default button animation
d->refresh();
e->ignore();
return;
}
if (hitButton(e->pos())) {
d->repeatTimer.stop();
d->click();//触发点击事件
e->accept();
} else {
setDown(false);
e->ignore();
}
}
//发送相关的按钮事件
void QAbstractButtonPrivate::click()
{
Q_Q(QAbstractButton);
down = false;
blockRefresh = true;
bool changeState = true;
if (checked && queryCheckedButton() == q) {
// the checked button of an exclusive or autoexclusive group cannot be unchecked
#ifndef QT_NO_BUTTONGROUP
if (group ? group->d_func()->exclusive : autoExclusive)
#else
if (autoExclusive)
#endif
changeState = false;
}
QPointer<QAbstractButton> guard(q);
if (changeState) {
q->nextCheckState();
if (!guard)
return;
}
blockRefresh = false;
refresh();
q->repaint(); //flush paint event before invoking potentially expensive operation
QApplication::flush();
if (guard)
emitReleased();
if (guard)
emitClicked();//点击事件
}
void QAbstractButtonPrivate::emitClicked()//发送点击事件
{
Q_Q(QAbstractButton);
QPointer<QAbstractButton> guard(q);
emit q->clicked(checked);
#ifndef QT_NO_BUTTONGROUP
if (guard && group) {
emit group->buttonClicked(group->id(q));
if (guard && group)
emit group->buttonClicked(q);
}
#endif
}
//核心关键点
void QAbstractButton::clicked(bool _t1)
{
void *_a[] = { Q_NULLPTR, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 2, _a);//调用MetaCall!!!
}
//
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
void **argv)
{
activate(sender, QMetaObjectPrivate::signalOffset(m), local_signal_index, argv);
}
//QObject中具体调用那个槽函数了!!!
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
int signal_index = signalOffset + local_signal_index;
if (!sender->d_func()->isSignalConnected(signal_index)
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
return; // nothing connected to these signals, and no spy
}
if (sender->d_func()->blockSig)
return;
if (sender->d_func()->declarativeData && QAbstractDeclarativeData::signalEmitted)
QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender,
signal_index, argv);
void *empty_argv[] = { 0 };
if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index,
argv ? argv : empty_argv);
}
Qt::HANDLE currentThreadId = QThread::currentThreadId();
{
QMutexLocker locker(signalSlotLock(sender));
struct ConnectionListsRef {
QObjectConnectionListVector *connectionLists;
ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists)
{
if (connectionLists)
++connectionLists->inUse;
}
~ConnectionListsRef()
{
if (!connectionLists)
return;
--connectionLists->inUse;
Q_ASSERT(connectionLists->inUse >= 0);
if (connectionLists->orphaned) {
if (!connectionLists->inUse)
delete connectionLists;
}
}
QObjectConnectionListVector *operator->() const { return connectionLists; }
};
ConnectionListsRef connectionLists = sender->d_func()->connectionLists;
if (!connectionLists.connectionLists) {
locker.unlock();
if (qt_signal_spy_callback_set.signal_end_callback != 0)
qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
return;
}
const QObjectPrivate::ConnectionList *list;
if (signal_index < connectionLists->count())
list = &connectionLists->at(signal_index);
else
list = &connectionLists->allsignals;
do {
QObjectPrivate::Connection *c = list->first;
if (!c) continue;
// We need to check against last here to ensure that signals added
// during the signal emission are not emitted in this emission.
QObjectPrivate::Connection *last = list->last;
do {
if (!c->receiver)
continue;
QObject * const receiver = c->receiver;
const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId;
// determine if this connection should be sent immediately or
// put into the event queue
if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
|| (c->connectionType == Qt::QueuedConnection)) {
queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker);
continue;
#ifndef QT_NO_THREAD
} else if (c->connectionType == Qt::BlockingQueuedConnection) {
if (receiverInSameThread) {
qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
"Sender is %s(%p), receiver is %s(%p)",
sender->metaObject()->className(), sender,
receiver->metaObject()->className(), receiver);
}
QSemaphore semaphore;
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore);
QCoreApplication::postEvent(receiver, ev);
locker.unlock();
semaphore.acquire();
locker.relock();
continue;
#endif
}
QConnectionSenderSwitcher sw;//这个很牛逼的样子
if (receiverInSameThread) {//统一线程内
sw.switchSender(receiver, sender, signal_index);
}
const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction;
const int method_relative = c->method_relative;
if (c->isSlotObject) {
c->slotObj->ref();
QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj);
locker.unlock();
obj->call(receiver, argv ? argv : empty_argv);//调用
// Make sure the slot object gets destroyed before the mutex is locked again, as the
// destructor of the slot object might also lock a mutex from the signalSlotLock() mutex pool,
// and that would deadlock if the pool happens to return the same mutex.
obj.reset();
locker.relock();
} else if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
//we compare the vtable to make sure we are not in the destructor of the object.
locker.unlock();
const int methodIndex = c->method();
if (qt_signal_spy_callback_set.slot_begin_callback != 0)
qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv);
callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);//这里是默认的调用方式
if (qt_signal_spy_callback_set.slot_end_callback != 0)
qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex);
locker.relock();
} else {
const int method = method_relative + c->method_offset;
locker.unlock();
if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
qt_signal_spy_callback_set.slot_begin_callback(receiver,
method,
argv ? argv : empty_argv);
}
metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);//调用
if (qt_signal_spy_callback_set.slot_end_callback != 0)
qt_signal_spy_callback_set.slot_end_callback(receiver, method);
locker.relock();
}
if (connectionLists->orphaned)
break;
} while (c != last && (c = c->nextConnectionList) != 0);
if (connectionLists->orphaned)
break;
} while (list != &connectionLists->allsignals &&
//start over for all signals;
((list = &connectionLists->allsignals), true));//全部分发完!!!
}
if (qt_signal_spy_callback_set.signal_end_callback != 0)
qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
}
//上一步的call最终指向moc_widget::qt_static_metacall
void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
Widget *_t = static_cast<Widget *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->onSlotClicked(); break;
case 1: _t->onSlotClicked2(); break;
default: ;
}
}
Q_UNUSED(_a);
}
//最最终调用我们的代码实现
void Widget::onSlotClicked()
{
qDebug()<<"点击了按钮go-----";
}
再来:核心就是QMetaObject元对象!!!
//关于如何连接信号槽的,主要看这个吧!!!
//如果使用SIGNAL和SLOT宏
//见qobjectdefs.h
Q_CORE_EXPORT const char *qFlagLocation(const char *method);//核心的哦!!!
#ifndef QT_NO_META_MACROS
#ifndef QT_NO_DEBUG
# define QLOCATION "\0" __FILE__ ":" QT_STRINGIFY(__LINE__)
# ifndef QT_NO_KEYWORDS
# define METHOD(a) qFlagLocation("0"#a QLOCATION)
# endif
# define SLOT(a) qFlagLocation("1"#a QLOCATION)
# define SIGNAL(a) qFlagLocation("2"#a QLOCATION)
#else
# ifndef QT_NO_KEYWORDS
# define METHOD(a) "0"#a
# endif
# define SLOT(a) "1"#a
# define SIGNAL(a) "2"#a
#endif
//qobject.cpp中
const char *qFlagLocation(const char *method)
{
QThreadData *currentThreadData = QThreadData::current(false);//线程相关的!!!
if (currentThreadData != 0)
currentThreadData->flaggedSignatures.store(method);//应该就是注册相关的吧
return method;
}
//以下是moc_widget.cpp
#include "../../TestQt/widget.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'widget.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.6.3. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
struct qt_meta_stringdata_Widget_t {
QByteArrayData data[4];
char stringdata0[37];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_Widget_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_Widget_t qt_meta_stringdata_Widget = {
{
QT_MOC_LITERAL(0, 0, 6), // "Widget"
QT_MOC_LITERAL(1, 7, 13), // "onSlotClicked"
QT_MOC_LITERAL(2, 21, 0), // ""
QT_MOC_LITERAL(3, 22, 14) // "onSlotClicked2"
},
"Widget\0onSlotClicked\0\0onSlotClicked2"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_Widget[] = {
// content:
7, // revision
0, // classname
0, 0, // classinfo
2, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: name, argc, parameters, tag, flags
1, 0, 24, 2, 0x0a /* Public */,
3, 0, 25, 2, 0x0a /* Public */,
// slots: parameters
QMetaType::Void,
QMetaType::Void,
0 // eod
};
void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
Widget *_t = static_cast<Widget *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->onSlotClicked(); break;
case 1: _t->onSlotClicked2(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObject Widget::staticMetaObject = {
{ &QWidget::staticMetaObject, qt_meta_stringdata_Widget.data,
qt_meta_data_Widget, qt_static_metacall, Q_NULLPTR, Q_NULLPTR}
};
const QMetaObject *Widget::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *Widget::qt_metacast(const char *_clname)
{
if (!_clname) return Q_NULLPTR;
if (!strcmp(_clname, qt_meta_stringdata_Widget.stringdata0))
return static_cast<void*>(const_cast< Widget*>(this));
return QWidget::qt_metacast(_clname);
}
int Widget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 2)
qt_static_metacall(this, _c, _id, _a);
_id -= 2;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 2)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 2;
}
return _id;
}
QT_END_MOC_NAMESPACE