【问题标题】:Qt menu shortcuts preempt child widget KeyPressEventsQt 菜单快捷方式抢占子小部件 KeyPressEvents
【发布时间】:2025-12-26 04:20:09
【问题描述】:

我有一个主窗口,我在其中建立标准的编辑 > 剪切/复制/粘贴操作,菜单操作链接到作为主窗口子窗口的 QTextEdit 的相关插槽。

主窗口有一个不同的子窗口(在拆分器的另一侧),它显示一个 TableView。此小部件具有单击焦点和 KeyPressEvent 处理程序的焦点策略。当这个孩子获得焦点时,它的 KeyPressEvent 方法会拦截所有击键事件(我知道是因为它会在控制台上打印出来)除了 ctl-c、ctl-v 以及分配给编辑或文件菜单操作的任何其他键序列.这些击键进入菜单并在没有焦点的 QTextEdit 中生效。

我希望能够在表格视图中捕获 ^c 以复制表格选择的值,但键序列永远不会到达那里。

如何使 ^c 操作对具有焦点的小部件可见?

【问题讨论】:

    标签: python pyqt keyboard-shortcuts


    【解决方案1】:

    创建编辑操作后,将WidgetShortcut 上下文和add them 分配给它们要关联的小部件:

    copyAction.setShortcutContext(Qt.WidgetShortcut)
    editor.addAction(copyAction)
    

    请注意,以这种方式配置的操作快捷方式不会覆盖相关小部件可能具有的任何内置快捷方式。

    编辑

    这是一个简单的演示。请注意,当 text-edit 具有键盘焦点时,'Ctrl+P' 将触发处理程序,但 'Ctrl+C' 不会,因为它是内置快捷键。当 table 有键盘焦点时,'Ctrl+C' 将照常复制所选项目,但 'Ctrl+P' 不会做任何事情。

    from PyQt4 import QtGui, QtCore
    
    class Window(QtGui.QMainWindow):
        def __init__(self):
            QtGui.QMainWindow.__init__(self)
            widget = QtGui.QWidget(self)
            self.setCentralWidget(widget)
            layout = QtGui.QVBoxLayout(widget)
            self.edit = QtGui.QTextEdit(self)
            self.edit.setText('text')
            self.table = Table(self)
            layout.addWidget(self.edit)
            layout.addWidget(self.table)
            menu = self.menuBar().addMenu('&File')
            def add_action(text, shortcut):
                action = menu.addAction(text)
                action.setShortcut(shortcut)
                action.triggered.connect(self.handleAction)
                action.setShortcutContext(QtCore.Qt.WidgetShortcut)
                self.edit.addAction(action)
            add_action('&Copy', 'Ctrl+C')
            add_action('&Print', 'Ctrl+P')
    
        def handleAction(self):
            print ('Action!')
    
    class Table(QtGui.QTableWidget):
        def __init__(self, parent):
            QtGui.QTableWidget.__init__(self, parent)
            self.setRowCount(4)
            self.setColumnCount(2)
            self.setItem(0, 0, QtGui.QTableWidgetItem('item'))
    
        def keyPressEvent(self, event):
            print ('keyPressEvent: %s' % event.key())
            QtGui.QTableWidget.keyPressEvent(self, event)
    
    if __name__ == '__main__':
    
        import sys
        app = QtGui.QApplication(sys.argv)
        window = Window()
        window.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 谢谢,但它似乎不起作用。我在阅读这篇文章时意识到,我的所有菜单操作都被赋予了主窗口的父级,所以我改变了这一点,以便特别是 Edit>Cut/Copy/Paste 动作被赋予 QTextEdit 小部件的父级(它本身就是主窗口的子级) .同样对于这些动作,我按照您的建议做了 setShortcutContext 。但是,cmd-C 仍然会进入编辑菜单,并且不会被其他小部件的 keyPressEvent 拦截。
    • 对于临时解决方法,我将在表格小部件中使用 cmd-shift-c,keyPressEvent 可以看到它。但我当然希望弄清楚这一点。再次感谢。
    • @user405。在 Linux 上对我来说非常好用。我在我的答案中添加了一个简单的演示供您尝试。你在哪个平台上?
    • 一段时间后我又回到了这里。再次感谢演示,它实际上很好地说明了我的问题。永远不可能拦截 ^C keyEvent (无论焦点在哪里,都不会为 ^C 输入 keyPressEvent)。您的表格小部件将执行复制提供,一个人已经双击一个单元格,调出单元格委托编辑器,选择文本。但是,我想要做的是在表格单元格或 CELLS 仅被选中(单击、ctl-click、shift-click)时获得控制,并将其所有文本作为字符串复制到应用剪贴板。做不到。
    • @user405。我在 Linux 和 WinXP 上都对此进行了测试,它对我来说非常好用。也就是说,如果我在编辑器中选择文本并按 Ctrl+C,“文本”将被复制到剪贴板。如果我选择(而不是编辑)表格中的左上角单元格并执行 Ctrl+C,“项目”将被复制到剪贴板。此外,当表格获得焦点时,将打印所有keyPressEvents(包括 Ctrl+C)。所以问题一定出在你自己的代码上(你没有显示),而不是我的例子。