小部件中的键盘焦点

Qt 的控件以已成为图形用户界面(GUI)中的一种常规方式处理键盘焦点。

基本问题是用户的按键可以指向屏幕上多个窗口的任意一个,以及目标窗口内的多个控件中的任意一个。当用户按下按键时,他们期望它到达正确的位置,而软件必须努力满足这种期望。系统必须确定哪个应用程序接收按键,该应用程序中的哪个窗口,以及窗口内的哪个控件。

焦点运动

发展而来的将键盘焦点指向特定控件的习惯包括这些

  1. 用户按下Tab(或Shift+Tab)。
  2. 用户点击一个控件。
  3. 用户按下快捷键。
  4. 用户使用鼠标滚轮。
  5. 用户将焦点移动到一个窗口,应用程序必须确定该窗口中的哪个控件应该获得焦点。

这些运动机制各不相同,只有一些控件在这些机制中才能获得焦点。我们将逐一介绍它们。

Tab 或 Shift+Tab

按下Tab是使用键盘移动焦点最普遍的方法。(有时在数据输入应用程序中,Enter 与Tab的作用相同;这可以通过在 Qt 中实现事件过滤器轻松实现。)

在当今广泛使用的所有窗口系统中,按下Tab都将键盘焦点移动到一个特定窗口圆周列表中的下一个控件。 Tab沿着圆周列表的方向移动焦点,而Shift+Tab则相反。按下Tab使控件之间的移动顺序称为标签顺序。

您可以使用QWidget::setTabOrder()自定义标签顺序。(如果您不这样做,Tab通常按控件构造的顺序移动焦点。)Qt Designer提供了一种直观修改标签顺序的方式。

由于按下Tab非常常见,几乎所有可能获得焦点的控件都应该支持标签焦点。主要的例外是很少使用且存在一些键盘加速器或错误处理程序来移动焦点的控件。

例如,在数据输入对话框中,可能有在所有情况下仅1%的情况下才必要的字段。在这种情况下,Tab可以跳过该字段,对话框可以使用以下这些机制之一

  1. 如果程序可以确定字段是否必要,它可以在用户完成输入并在按下OK或在其他字段完成输入后按下 Enter 时将焦点移到该字段。或者,将字段包含在标签顺序中但禁用它。如果根据用户在其他字段中设置的值适宜,则启用它。
  2. 字段的标签可以包括一个键盘快捷键,用于将焦点移至这个字段。

对于支持制表符插入的文本输入小部件,不支持Tab是另一个异常情况;几乎所有文本编辑器都属于这一类。Qt将Ctrl+Tab视为Tab,并将Ctrl+Shift+Tab视为Shift+Tab,此类小部件可以重新实现QWidget::event(),并在调用QWidget::event()之前处理Tab键,以便获取其他所有键的正常处理。然而,由于一些系统将Ctrl+Tab用于其他目的,并且许多用户甚至不了解Ctrl+Tab,这不是一个完整的解决方案。

用户点击了一个小部件

这可能比在具有鼠标或其他指针设备的计算机上按下Tab键更为常见。

点击以移动焦点比Tab键强大一些。虽然它将焦点移动到小部件,对于编辑器小部件,它还会将文本光标(小部件的内部焦点)移动到鼠标点击的位置。

由于它如此常见且人们已经习惯了它,所以为大多数小部件提供支持是个好主意。然而,也有一个重要原因要避免它:您可能不希望移除最初的小部件焦点。

例如,在一个字处理程序中,当用户点击'B'(粗体)工具按钮时,键盘焦点应该发生什么?它应该保持在原地,几乎肯定在编辑小部件中,或者应该移动到'B'按钮处?

我们建议支持支持文本输入的小部件的单击焦点,并避免为大多数鼠标点击有不同效果的小部件提供单击焦点。(对于按钮,我们也建议添加键盘快捷键:QAbstractButton及其子类使这变得非常简单。)

在Qt中,只有QWidget::setFocusPolicy()函数会影响单击焦点。

用户按下键盘快捷键

键盘快捷键移动焦点并不罕见。这可能通过打开模式对话框隐式地发生,也可能通过使用焦点加速器例如QLabel::setBuddy()、QGroupBoxQTabBar显式地发生。

您的应用程序可以支持用户可能希望跳转到所有小部件的快捷键焦点。例如,标签对话框可以为每个页面提供键盘快捷键,因此用户可以按下例如Alt+P移至打印页面。记住,过度使用这个问题很容易发生,因为可用的键很少,同时也非常重要为命令提供键盘快捷键。请参考您目标平台的用户界面指南,例如Microsoft的键盘用户界面设计指南或Apple的焦点和选择指南

用户旋转鼠标滚轮

在Microsoft Windows上,鼠标滚轮的使用始终由有键盘焦点的小部件处理。在macOS和X11上,它由获得其他鼠标事件的控件处理。

Qt处理此平台差异的方式是让控件在滚轮使用时移动键盘焦点。有了每个小部件的正确焦点策略,Windows、macOS和X11上的应用程序可以正确地使用习惯用语。

用户将焦点移至此窗口

在这种情况下,应用程序必须确定窗口内哪个小部件应该接收焦点。

这可能很简单:如果焦点以前在这个窗口中,那么最后获得焦点的小部件应该恢复焦点。Qt会自动这样做。

如果焦点以前从未在这个窗口中,并且你知道焦点应该从哪里开始,在你调用 QWidget::setFocus() 之前,请调用该应该获得焦点的控件上的QWidget::setFocus(),然后再调用 QWidget::show()。如果不这样做,Qt将选择一个合适的控件。

© 2024 Qt公司。包含在本中的文档贡献属于各自所有者的版权。提供的文档是根据由自由软件基金会发布并受GNU自由文档许可证版本1.3的条款所许可的。Qt和相应的商标是芬兰及其它世界各地的Qt公司的商标。所有其他商标均为其各自所有者的财产。