You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5使用pynput全局监听O键创建新窗口时Widget崩溃问题求解

问题原因

pynput的键盘监听器运行在独立的工作线程,而PyQt所有UI控件的创建、修改、显示操作都只允许在主线程(也就是运行QApplication事件循环的线程)执行,直接在监听器回调里创建QWidget属于跨线程操作UI,会触发未定义行为导致崩溃。

解决方案

使用Qt自带的线程安全的信号槽机制中转事件:工作线程监听到按键后只发射信号,主线程接收信号后再执行UI创建逻辑。

修复后完整代码

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtCore
from PyQt5.uic import loadUiType

import sys

from pynput import keyboard

class win(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        # self.setWindowFlag(Qt.FramelessWindowHint)

        self.btn = QPushButton('close', self)
        self.btn.clicked.connect(lambda: self.close())

    def initUI(self):
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Student log in screen')
        self.show()

class Main(QMainWindow):
    # 自定义信号,传递按下的按键名称
    key_pressed = pyqtSignal(str)
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.setGeometry(500, 500, 500, 400)
        self.start_btn = QPushButton('start', self)
        self.start_btn.clicked.connect(lambda : self.start())
        # 绑定信号到创建窗口的槽函数,槽函数默认运行在主线程
        self.key_pressed.connect(self.create_new_window)
        # 可选:如果需要保留多个窗口,用列表存储窗口实例,避免被回收
        # self.widget_list = []

    def copy(self):
        pya.hotkey('ctrl', 'c')
        time.sleep(.05)
        return pyperclip.paste()    

    def create_new_window(self, key):
        if key == 'o':
            print('you pressed o')
            self.widget = win()
            # 多窗口场景替换为下面两行
            # new_win = win()
            # self.widget_list.append(new_win)

    def test(self, key):
        try:
            k = key.char  # single-char keys
        except:
            k = key.name  # other keys
        # 工作线程只做信号发射,不触碰UI逻辑
        self.key_pressed.emit(k)

    def start(self):
        self.listener = keyboard.Listener(on_press=self.test)   
        self.listener.start() 

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Main()
    ex.show()
    sys.exit(app.exec_())

内容的提问来源于stack exchange,提问作者user15896474

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 10:36:02