日志
2016.12.23 日志
2016-12-23 16:43
QWidget 键盘事件 焦点 (2012-11-29 15:17:50)
键盘事件派发给谁? 如何确定谁来接收键盘事件,不妨看一点点QApplication的源码: X11下 QETWidget *keywidget=0;bool grabbed=false;if (event->type==XKeyPress || event->type==XKeyRelease) {keywidget = (QETWidget*)QWidget::keyboardGrabber();if (keywidget) {grabbed = true;} else if (!keywidget) {if (d->inPopupMode()) // no focus widget, see if we have a popupkeywidget = (QETWidget*) (activePopupWidget()->focusWidget() ? activePopupWidget()->focusWidget() : activePopupWidget());else if (QApplicationPrivate::focus_widget)keywidget = (QETWidget*)QApplicationPrivate::focus_widget;else if (widget)keywidget = (QETWidget*)widget->window();}} Windows下 QWidget *g = QWidget::keyboardGrabber();if (g && qt_get_tablet_widget() && hwnd == qt_get_tablet_widget()->winId()) {// if we get an event for the internal tablet widget,// then don't send it to the keyboard grabber, but// send it to the widget itself (we don't use it right// now, just in case).g = 0;}if (g)widget = (QETWidget*)g;else if (QApplication::activePopupWidget())widget = (QETWidget*)QApplication::activePopupWidget()->focusWidget()? (QETWidget*)QApplication::activePopupWidget()->focusWidget(): (QETWidget*)QApplication::activePopupWidget();else if (QApplication::focusWidget())widget = (QETWidget*)QApplication::focusWidget();else if (!widget || widget->internalWinId() == GetFocus()) // We faked the message to go to exactly that widget.widget = (QETWidget*)widget->window(); 大致顺序:
在QWidget间切换焦点 在Qt键盘事件一文中我们提到这个和focusPolicy相关。我们可以通过Tab键或者鼠标单击来使得某个QWidget获得焦点。 问题:当我们按下Tab键(或者上下左右箭头键)时,下一个或获取焦点的QWidget是如何被确定的? 我们重新贴出上文最后贴出过的QWidget::event()的源码: 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); 老是觉得 QWidget::focusNextPrevChild() 这个函数有点名不符实(或者有点别扭),因为:bool QWidget::focusNextPrevChild(bool next){Q_D(QWidget);QWidget* p = parentWidget();bool isSubWindow = (windowType() == Qt::SubWindow);if (!isWindow() && !isSubWindow && p)return p->focusNextPrevChild(next);...} 当我们调用一个Widget该成员时,最终将递归调用到其所在窗口的focusNextPrevChild成员。(不过这是一个protected的虚函数,在派生类中可以覆盖它,从而控制派生类实例中的焦点移动。) prev/next QWidgetPrivate内有3个成员变量:class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate{...QWidget *focus_next;QWidget *focus_prev;QWidget *focus_child; 这3个变量可以分别用:
进行获取。 前两个可以用来构成一个focus链表。void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f){Q_Q(QWidget);focus_next = focus_prev = q;...void QWidgetPrivate::reparentFocusWidgets(QWidget * oldtlw){... 通过QWidget::setTabOrder()可以调整Widgets在focus链表中的顺序 Widget上放置大量按钮怎么样? 比如一个类似软键盘的东西,在一个QWidget上面放置了大量的QPushButton。此时,除了Tab/Shift+Tab外,上下左右箭头也都可以用来移动焦点。 这是因为:void QAbstractButton::keyPressEvent(QKeyEvent *e){bool next = true;switch (e->key()) {case Qt::Key_Up:case Qt::Key_Left:next = false;// fall throughcase Qt::Key_Right:case Qt::Key_Down:...focusNextPrevChild(next);} focus proxy
Manual中说的比较清楚:
简单列出源码:void QWidget::setFocus(Qt::FocusReason reason){QWidget *f = this;while (f->d_func()->extra && f->d_func()->extra->focus_proxy)f = f->d_func()->extra->focus_proxy;bool QWidget::hasFocus() const{const QWidget* w = this;while (w->d_func()->extra && w->d_func()->extra->focus_proxy)w = w->d_func()->extra->focus_proxy; 其他
设置可通过方向键来控制焦点进行上下左右的移动。 》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》 setfocus() 是让某个窗体获得焦点 setfocusPolicy 是设置窗体怎么获得焦点 he focus policy is Qt::TabFocus if the widget accepts keyboard focus by tabbing, Qt::ClickFocus if the widget accepts focus by clicking, Qt::StrongFocus if it accepts both, and Qt::NoFocus (the default) if it does not accept focus at all. void QWidget::setFocusProxy ( QWidget * w ) [virtual] 就是把窗体获得焦点时的处理,委托给窗体w处理 Sets this widget's focus proxy to w. If w is 0, this function resets this widget to not have any focus proxy. Some widgets, such as QComboBox, can "have focus," but create a child widget to actually handle the focus. QComboBox, for example, creates a QLineEdit. setFocusProxy() sets the widget which will actually get focus when "this widget" gets it. If there is a focus proxy, focusPolicy(), setFocusPolicy(), setFocus() and hasFocus() all operate on the focus proxy. See also focusProxy(). 将该widget的focus proxy设置给w。如果w为0,该函数将此widget设为没有任何focus proxy。 有些widget,比如QComboBox,可以“拥有focus”,但是它们会创建一个子的widget来实际地处理焦点。比如QComboBox创建的叫做QLineEdit。 setFocusProxy()用来指定当该widget获得焦点时实际上由谁来处理这个焦点。如果某个widget拥有focus proxy,focusPolicy(),setFocusPolicy(),setFocus()和hasFocus()都是对focus proxy进行操作。 原文链接:http://blog.sina.com.cn/s/blog_a401a1ea0101ec9z.html |