小部件中的键盘焦点#

键盘焦点管理和处理。

Qt的小部件以在GUI中逐渐成为习惯的方式处理键盘焦点。

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

焦点移动#

`将键盘焦点定位到特定小部件的习俗如下:

  1. 用户按下Tab(或Shift+Tab)。

  2. 用户点击一个小部件。

  3. 用户按下一个键盘快捷键。

  4. 用户使用鼠标滚轮。

  5. 用户将焦点移动到一个窗口,应用程序必须确定窗口内的小部件中应该获得焦点的是哪一个。

这些动作机制各不相同,不同类型的小部件只在其中的一些中接收焦点。我们将依次介绍每个。

Tab或Shift+Tab#

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

按下Tab可在所有广泛使用的当前窗口系统中,将键盘焦点移动到每个窗口内的循环列表中下一个小部件。Tab按循环列表的一个方向移动焦点,Shift+Tab按另一个方向。Tab按下从一个小部件移动到另一个小部件的顺序称为标签顺序。

您可以使用setTabOrder()来自定义标签顺序。(如果您不这样做,Tab通常按小部件构造顺序移动焦点。)Qt Designer提供了一种视觉上改变标签顺序的方法。

由于按下Tab非常常见,因此大多数可能具有焦点的小部件应支持标签焦点。一个主要的例外是很少使用的小部件,以及有某些键盘加速器或错误处理器可以移动焦点的小部件。

例如,在一个数据输入对话框中,可能有一个只在所有情况中一的百分之一情况下必需的字段。在这样的对话框中,Tab可以跳过这个字段,对话框可以使用以下这些机制之一:

  1. 如果程序可以确定字段是否需要,则当用户完成输入并按OK键时,或者当用户在完成其他字段后按Enter键时,移动焦点到该字段。或者,包括该字段在标签顺序中,但禁用它。如果根据用户在其他字段中的设置变得适当,则启用它。

  2. 该字段的标签可以包括一个键盘快捷键,将焦点移动到此字段。

Tab支持的一个例外是必须支持插入tab的文本输入控件;几乎所有的文本编辑器都属于这个类别。Qt将Ctrl+Tab视为Tab键,将Ctrl+Shift+Tab视为Shift+Tab,并且这样的控件可以重写event()并在调用event()之前处理Tab键,以获得其他所有键的正常处理。然而,由于一些系统使用Ctrl+Tab用于其他目的,而且许多用户实际上并不了解Ctrl+Tab,这并不是一个完美的解决方案。

用户点击一个控件#

这可能在比使用鼠标或指针设备在计算机上按下Tab键更为常见。

点击以移动焦点比Tab键更强大。它不仅可以移动焦点一个控件,对于编辑器控件,它还将文本光标(控件的内部焦点)移动到鼠标点击的位置。

由于其非常常见,并且人们已经习惯了这种方式,因此为大多数控件支持它是个不错的想法。然而,避免它也有一个重要的原因:你可能不希望从当前位置移除焦点。

例如,在文字处理程序中,当用户点击“B”(粗体)工具按钮时,键盘焦点应该怎么办?它应该保持在原来的位置,几乎肯定是在编辑控件中,还是应该移动到“B”按钮上?

我们建议为支持文本输入的控件启用点击焦点,而对于大多数鼠标点击会产生不同效果的控件应避免使用。对于按钮,我们还建议添加键盘快捷键:QAbstractButton及其子类使这变得非常容易。

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

用户按下键盘快捷键#

键盘快捷键移动焦点并不罕见。这可以通过打开模态对话框隐式发生,也可以通过使用诸如setBuddy()QGroupBoxQTabBar等提供的焦点加速器来实现。

您可以使用快捷键为用户可能想要跳转到的所有控件提供焦点支持。例如,对话框标签页可以为每一页提供键盘快捷键,因此用户可以按下例如Alt+P来转到打印页面。请注意,过度使用此功能也很容易,因为可用的键不多,且为命令提供键盘快捷键也非常重要。请参考目标平台的界面设计指南,例如Microsoft的键盘用户界面设计指南或Apple的焦点和选择指南。

用户旋转鼠标滚轮#

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

Qt处理平台差异的方式是通过允许小部件在拖动滚轮时移动键盘焦点。通过在各个小部件上设置正确的焦点策略,应用程序可以正确地在Windows、macOS和X11上工作。

用户将焦点移动至此窗口#

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

这可以是简单的:如果焦点之前已经在该窗口中,则最后获得焦点的那个小部件应该重新获得焦点。Qt会自动完成这项操作。

如果焦点从未在该窗口中出现,且你知道焦点应该从哪里开始,请在调用setFocus()之前,将其应用于应获得焦点的小部件。如果不这样做,Qt将选择一个合适的小部件。