使用“键盘”在失去焦点时打开新窗口

我正在尝试使用模块“键盘”跟踪我的按键,而 PySide2 小部件未处于焦点状态,效果很好。但是,当我尝试使用“键盘”快捷方式创建新的 Widget 时,程序崩溃了。按下按钮打开一个窗口工作正常。我也可以使用“键盘”调用非 UI 函数,例如。打印功能没有任何问题。


你知道解决这个问题的方法吗?使用“键盘”或任何其他方法打开一个新窗口,而 PySide2 窗口不在焦点上。在这个例子中,我想在“CTRL+D”上打开一个新窗口。PySide2 和 PyQt5 都存在该问题。


这是我的缩短代码:


import sys

import json

import os

import keyboard

from PySide2.QtWidgets import QApplication, QWidget, QGridLayout, QKeySequenceEdit, QLabel, QPushButton, QShortcut

from PySide2.QtCore import Qt, QObject, Signal, Slot # Qt.Key_W beispielsweise


#from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QKeySequenceEdit, QLabel, QPushButton, QShortcut

#from PyQt5.QtCore import Qt, QObject, pyqtSignal as Signal, pyqtSlot as Slot # Qt.Key_W beispielsweise



class ConfigWindow(QWidget):

    def __init__(self):

        super().__init__()

        self.initUi()

        self.init_shortcuts()

        self.show()


    def initUi(self):

        self.setGeometry(300,300, 400, 250)

        self.setWindowTitle("Settings")

        grid = QGridLayout()

        self.setLayout(grid)


        self.keyseq = QKeySequenceEdit("CTRL+D")

        grid.addWidget(self.keyseq, 0, 0)


        s_button = QPushButton("Safe")

        grid.addWidget(s_button, 1, 0)


        cl_button = QPushButton("Close")

        grid.addWidget(cl_button, 1, 1)

        cl_button.clicked.connect(self.close)


        open_button = QPushButton("openw")

        grid.addWidget(open_button, 2, 0)

        open_button.clicked.connect(self.call_item_parser)


    def keyPressEvent(self, event): #event:PySide2.QtGui.QKeyEvent

        if event.key() == Qt.Key_Escape:

            self.close()

慕森卡
浏览 119回答 1
1回答

蓝山帝景

问题是因为在键盘上注册的回调是在辅助线程中执行的,可以通过修改以下部分代码并打印来验证threading.current_thread()。在 Qt 中,禁止在另一个线程中创建任何小部件,因为它们不是线程安全的。def call_item_parser(self):&nbsp; &nbsp; print(threading.current_thread())&nbsp; &nbsp; self.h_w = ParseWindow()&nbsp; &nbsp; self.h_w.setWindowTitle("New Window")&nbsp; &nbsp; self.h_w.setGeometry(100, 100, 100, 100)&nbsp; &nbsp; self.h_w.show()print(threading.current_thread())app = QApplication(sys.argv)w = ConfigWindow()sys.exit(app.exec_())输出:<_MainThread(MainThread, started 140144979916608)>Binding _price_keyseq to ctrl+a<Thread(Thread-10, started daemon 140144220817152)>一种可能的解决方案是使用信号将信息发送到主线程,并在主线程中调用回调。import sysfrom functools import partialimport platformimport threadingimport keyboardfrom PySide2.QtCore import Qt, QObject, Signal, Slotfrom PySide2.QtGui import QKeySequencefrom PySide2.QtWidgets import (&nbsp; &nbsp; QApplication,&nbsp; &nbsp; QWidget,&nbsp; &nbsp; QGridLayout,&nbsp; &nbsp; QKeySequenceEdit,&nbsp; &nbsp; QPushButton,)class KeyBoardManager(QObject):&nbsp; &nbsp; activated = Signal(str)&nbsp; &nbsp; def __init__(self, parent=None):&nbsp; &nbsp; &nbsp; &nbsp; super().__init__(parent)&nbsp; &nbsp; &nbsp; &nbsp; self._callbacks = dict()&nbsp; &nbsp; &nbsp; &nbsp; self.activated.connect(self._handle_activated)&nbsp; &nbsp; @property&nbsp; &nbsp; def callbacks(self):&nbsp; &nbsp; &nbsp; &nbsp; return self._callbacks&nbsp; &nbsp; def register(self, shortcut, callback, *, args=(), kwargs=None):&nbsp; &nbsp; &nbsp; &nbsp; self.callbacks[shortcut] = (callback, args, kwargs or {})&nbsp; &nbsp; &nbsp; &nbsp; keyboard.add_hotkey(shortcut, partial(self.activated.emit, shortcut))&nbsp; &nbsp; @Slot(str)&nbsp; &nbsp; def _handle_activated(self, shortcut):&nbsp; &nbsp; &nbsp; &nbsp; values = self.callbacks.get(shortcut)&nbsp; &nbsp; &nbsp; &nbsp; if values is not None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback, args, kwargs = self._callbacks[shortcut]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback(*args, **kwargs)class ConfigWindow(QWidget):&nbsp; &nbsp; def __init__(self):&nbsp; &nbsp; &nbsp; &nbsp; super().__init__()&nbsp; &nbsp; &nbsp; &nbsp; self.initUi()&nbsp; &nbsp; &nbsp; &nbsp; self.init_shortcuts()&nbsp; &nbsp; &nbsp; &nbsp; self.show()&nbsp; &nbsp; def initUi(self):&nbsp; &nbsp; &nbsp; &nbsp; self.setGeometry(300, 300, 400, 250)&nbsp; &nbsp; &nbsp; &nbsp; self.setWindowTitle("Settings")&nbsp; &nbsp; &nbsp; &nbsp; grid = QGridLayout(self)&nbsp; &nbsp; &nbsp; &nbsp; self.keyseq = QKeySequenceEdit("CTRL+A")&nbsp; &nbsp; &nbsp; &nbsp; grid.addWidget(self.keyseq, 0, 0)&nbsp; &nbsp; &nbsp; &nbsp; s_button = QPushButton("Safe")&nbsp; &nbsp; &nbsp; &nbsp; grid.addWidget(s_button, 1, 0)&nbsp; &nbsp; &nbsp; &nbsp; cl_button = QPushButton("Close")&nbsp; &nbsp; &nbsp; &nbsp; grid.addWidget(cl_button, 1, 1)&nbsp; &nbsp; &nbsp; &nbsp; cl_button.clicked.connect(self.close)&nbsp; &nbsp; &nbsp; &nbsp; open_button = QPushButton("openw")&nbsp; &nbsp; &nbsp; &nbsp; grid.addWidget(open_button, 2, 0)&nbsp; &nbsp; &nbsp; &nbsp; open_button.clicked.connect(self.call_item_parser)&nbsp; &nbsp; def keyPressEvent(self, event):&nbsp; # event:PySide2.QtGui.QKeyEvent&nbsp; &nbsp; &nbsp; &nbsp; if event.key() == Qt.Key_Escape:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.close()&nbsp; &nbsp; # shortcuts are listened to, while program is running&nbsp; &nbsp; def init_shortcuts(self):&nbsp; &nbsp; &nbsp; &nbsp; self.keyboard_manager = KeyBoardManager()&nbsp; &nbsp; &nbsp; &nbsp; str_value = self.keyseq.keySequence().toString()&nbsp; &nbsp; &nbsp; &nbsp; if platform.system() == "Linux":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; str_value = str_value.lower()&nbsp; &nbsp; &nbsp; &nbsp; print("Binding _price_keyseq to {}".format(str_value))&nbsp; &nbsp; &nbsp; &nbsp; self.keyboard_manager.register(str_value, self.call_item_parser)&nbsp; &nbsp; def call_item_parser(self):&nbsp; &nbsp; &nbsp; &nbsp; print(threading.current_thread())&nbsp; &nbsp; &nbsp; &nbsp; self.h_w = ParseWindow()&nbsp; &nbsp; &nbsp; &nbsp; self.h_w.setWindowTitle("New Window")&nbsp; &nbsp; &nbsp; &nbsp; self.h_w.setGeometry(100, 100, 100, 100)&nbsp; &nbsp; &nbsp; &nbsp; self.h_w.show()class ParseWindow(QWidget):&nbsp; &nbsp; passdef main():&nbsp; &nbsp; print(threading.current_thread())&nbsp; &nbsp; app = QApplication(sys.argv)&nbsp; &nbsp; w = ConfigWindow()&nbsp; &nbsp; sys.exit(app.exec_())if __name__ == "__main__":&nbsp; &nbsp; main()输出:<_MainThread(MainThread, started 140037641176896)>Binding _price_keyseq to ctrl+a<_MainThread(MainThread, started 140037641176896)>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python