如何控制QWidgetAction的子窗口小部件的焦点?

时间:2013-12-04 02:23:58

标签: qt pyqt pyside

对于我的应用程序我正在尝试将登录控制放入QMenu并且正在努力控制焦点策略。 这是我的自定义登录小部件:

class LoginWidget(QWidget):

    def __init__(self, parent=None):

        super(LoginWidget, self).__init__(parent)
        mainLayout = QVBoxLayout()
        layoutH = QHBoxLayout()
        nameField = QLineEdit()
        pwdField = QLineEdit()
        pwdField.setEchoMode(QLineEdit.EchoMode(2))
        btnSubmit = QPushButton('log in')
        btnSubmit.setIcon(IconCache.getIcon('login'))

        for w in (nameField, pwdField):
            layoutH.addWidget(w)
        mainLayout.addLayout(layoutH)
        mainLayout.addWidget(btnSubmit)
        self.setLayout(mainLayout)

然后我将上面的小部件添加到我的菜单中:

app = QApplication([])

menu = QMenu()
settingsAction = QAction('settings', menu)
loginAction = QWidgetAction(menu)
loginAction.setDefaultWidget(LoginWidget())
menu.addAction(settingsAction)    
menu.addAction(loginAction)

btn = QToolButton()
btn.setText('menu button')
btn.setMenu(menu)
btn.setPopupMode(QToolButton.InstantPopup)

btn.show()
sys.exit(app.exec_())

问题是,当您打开菜单时,单击名称字段以填写用户名,然后按Tab键,焦点跳转到“设置”操作而不是LoginWidget内的密码窗口小部件。 我在LoginWidget上尝试了setFocusPolicy(Qt.StrongFocus)以及它的pwdField,但无济于事。

可以这样做吗?

提前致谢, 坦率

2 个答案:

答案 0 :(得分:1)

http://qt-project.org/doc/qt-4.8/qwidget.html#setTabOrder

http://qt-project.org/doc/qt-4.8/focus.html#tab-or-shift-tab

  

Tab或Shift + Tab

     

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

     

在今天常用的所有窗口系统中按Tab键,将键盘焦点移动到每个窗口循环列表中的下一个窗口小部件。选项卡沿圆形列表向一个方向移动焦点,Shift + Tab在另一个方向上移动焦点。 Tab按下从小部件移动到小部件的顺序称为Tab顺序。

     

您可以使用QWidget :: setTabOrder()自定义Tab键顺序。 (如果不这样做,Tab通常会按小部件构造的顺序移动焦点。)Qt Designer提供了一种可视化更改Tab键顺序的方法。

     

由于按下Tab非常常见,因此大多数可以拥有焦点的小部件都应该支持tab焦点。主要的例外是很少使用的小部件,并且有一些键盘加速器或错误处理程序可以移动焦点。

     

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

     

如果程序可以确定是否需要该字段,则当用户完成输入并按OK时,或者当用户在完成其他字段后按Enter键时,它可以将焦点移动到那里。或者,在选项卡顺序中包含该字段但禁用它。如果根据用户在其他字段中设置的内容而变得合适,则启用它。

     

字段的标签可以包含将焦点移动到此字段的键盘快捷键。

     

Tab支持的另一个例外是必须支持插入标签的文本输入小部件;几乎所有的文本编辑都属于这个类。 Qt将Ctrl + Tab视为Tab,Ctrl + Shift + Tab视为Shift + Tab,这样的小部件可以重新实现QWidget :: event()并在调用QWidget :: event()之前处理Tab以获得所有其他键的正常处理。但是,由于某些系统将Ctrl + Tab用于其他目的,并且许多用户无论如何都不知道Ctrl + Tab,这不是一个完整的解决方案。

所以你可能会想要使用:

QWidget.setTabOrder( nameField, pwdField )
QWidget.setTabOrder( pwdField, btnSubmit )

或类似的东西。

希望有所帮助。

答案 1 :(得分:1)

QMenu对Tab / Backtab进行了特殊处理,有效地将它们转换为向上/向下箭头键按下。

然而,问题行为的真正根源是focusNextPrevChild方法,它会将焦点强制回到菜单。幸运的是,这个方法是虚方法的,因此它可以在子类中重写,如下所示:

class Menu(QtGui.QMenu):
    def focusNextPrevChild(self, next):
        return QtGui.QWidget.focusNextPrevChild(self, next)

这将恢复子窗口小部件之间的正常标签。

要启用从子窗口小部件到常规菜单项的键盘导航,请确保LoginWidget具有focus proxy,如下所示:

class LoginWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        ...
        self.setFocusPolicy(QtCore.Qt.TabFocus)
        self.setFocusProxy(nameField)