PyQt - Main 在 QThread 上挂起
PyQt - Main hangs on QThread
我有一个 Python QT 应用程序连接到 CG 服务器 (CasparCG)。 QT 应用程序触发一个 QThread,它使用模块 pynput 侦听热键 - 并向 CasparCG 发送命令以针对每个按下的键播放不同的视频文件。
在主 GUI 中,我可以将视频文件分配给热键列表,并从子菜单项触发热键侦听线程。
self.actionStart_Hotkeys = QtWidgets.QAction(MainWindow)
self.menuCasparCG.addAction(self.actionStart_Hotkeys)
self.actionStart_Hotkeys.triggered.connect(self.StartHotkeys)
主应用程序和 Ui_Window 代码很长并且没有问题 - 它可以正常运行。当按下按键激活热键时,视频也会像我预期的那样播放,但是在播放几个视频文件后应用程序的 Main window 冻结 - 我不确定为什么主 GUI 没有响应在 HotKey 线程启动后输入。
到目前为止的代码如下所示..
from pynput import keyboard
class HotKeys(QThread):
def __init__(self, parent):
QThread.__init__(self, parent)
self.COMBINATIONS = [
{keyboard.KeyCode(char='0')},
{keyboard.KeyCode(char='1')},
{keyboard.KeyCode(char='2')},
{keyboard.KeyCode(char='3')},
]
self.caspar = None
self.current = set()
self.Connect()
self.Listen()
def exit(self, i):
if not self.caspar == None:
self.caspar.close
sys.exit(i)
def Connect(self):
try:
self.caspar = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.caspar.connect(("127.0.0.1", 5250))
print("Connected to caspar")
except socket.error:
print("CasparCG not running, or incorrect settings.xml")
self.exit(0)
def execute(self, k=None): # k is videofile
movie = bytes("PLAY 1-20 {} \r\n".format(k), 'utf8')
self.caspar.send(movie)
def on_press(self, key):
if any([key in COMBO for COMBO in self.COMBINATIONS]):
self.current.add(key)
if any(all(k in self.current for k in COMBO) for COMBO in self.COMBINATIONS):
self.execute(key)
def on_release(self, key):
if any([key in COMBO for COMBO in self.COMBINATIONS]):
self.current.remove(key)
def Listen(self):
with keyboard.Listener(on_press=self.on_press, on_release=self.on_release) as listener:
listener.join()
我在应用程序的 Mainclass 中触发了这个热键 QThread,就像这样...
class Main(QMainWindow, Ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self) # from Ui_MainWindow class
def StartHotkeys(self):
hotkey_thread = HotKeys(self)
hotkey_thread.start()
和这样的应用程序...
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
gui = Main()
gui.show()
sys.exit(app.exec_())
那么为什么 Main 会冻结?
QThread
不是一个线程,它是一个线程处理程序,如果你想在另一个线程中执行任务你必须在run()
方法中执行,该方法是唯一的部分在另一个线程中执行。在您的情况下, Listen()
任务正在阻塞,您在构造函数中调用它,而 QThread
构造函数在 GUI 线程中运行,这就是您的 GUI 冻结的原因。解决方法是将Connect和Listen移到run()
方法:
class HotKeys(QThread):
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.COMBINATIONS = [
{keyboard.KeyCode(char='0')},
{keyboard.KeyCode(char='1')},
{keyboard.KeyCode(char='2')},
{keyboard.KeyCode(char='3')},
]
self.caspar = None
self.current = set()
def run(self):
self.Connect()
self.Listen()
def exit(self, i):
if self.caspar:
self.caspar.close()
sys.exit(i)
def Connect(self):
try:
self.caspar = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.caspar.connect(("127.0.0.1", 10000))
print("Connected to caspar")
except socket.error:
print("CasparCG not running, or incorrect settings.xml")
self.exit(0)
def execute(self, k=None): # k is videofile
if self.caspar:
movie = bytes("PLAY 1-20 {} \r\n".format(k), 'utf8')
self.caspar.send(movie)
def on_press(self, key):
if any([key in COMBO for COMBO in self.COMBINATIONS]):
self.current.add(key)
if any(all(k in self.current for k in COMBO) for COMBO in self.COMBINATIONS):
self.execute(key)
def on_release(self, key):
if any([key in COMBO for COMBO in self.COMBINATIONS]):
self.current.remove(key)
def Listen(self):
with keyboard.Listener(on_press=self.on_press, on_release=self.on_release) as listener:
listener.join()
我有一个 Python QT 应用程序连接到 CG 服务器 (CasparCG)。 QT 应用程序触发一个 QThread,它使用模块 pynput 侦听热键 - 并向 CasparCG 发送命令以针对每个按下的键播放不同的视频文件。
在主 GUI 中,我可以将视频文件分配给热键列表,并从子菜单项触发热键侦听线程。
self.actionStart_Hotkeys = QtWidgets.QAction(MainWindow)
self.menuCasparCG.addAction(self.actionStart_Hotkeys)
self.actionStart_Hotkeys.triggered.connect(self.StartHotkeys)
主应用程序和 Ui_Window 代码很长并且没有问题 - 它可以正常运行。当按下按键激活热键时,视频也会像我预期的那样播放,但是在播放几个视频文件后应用程序的 Main window 冻结 - 我不确定为什么主 GUI 没有响应在 HotKey 线程启动后输入。
到目前为止的代码如下所示..
from pynput import keyboard
class HotKeys(QThread):
def __init__(self, parent):
QThread.__init__(self, parent)
self.COMBINATIONS = [
{keyboard.KeyCode(char='0')},
{keyboard.KeyCode(char='1')},
{keyboard.KeyCode(char='2')},
{keyboard.KeyCode(char='3')},
]
self.caspar = None
self.current = set()
self.Connect()
self.Listen()
def exit(self, i):
if not self.caspar == None:
self.caspar.close
sys.exit(i)
def Connect(self):
try:
self.caspar = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.caspar.connect(("127.0.0.1", 5250))
print("Connected to caspar")
except socket.error:
print("CasparCG not running, or incorrect settings.xml")
self.exit(0)
def execute(self, k=None): # k is videofile
movie = bytes("PLAY 1-20 {} \r\n".format(k), 'utf8')
self.caspar.send(movie)
def on_press(self, key):
if any([key in COMBO for COMBO in self.COMBINATIONS]):
self.current.add(key)
if any(all(k in self.current for k in COMBO) for COMBO in self.COMBINATIONS):
self.execute(key)
def on_release(self, key):
if any([key in COMBO for COMBO in self.COMBINATIONS]):
self.current.remove(key)
def Listen(self):
with keyboard.Listener(on_press=self.on_press, on_release=self.on_release) as listener:
listener.join()
我在应用程序的 Mainclass 中触发了这个热键 QThread,就像这样...
class Main(QMainWindow, Ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self) # from Ui_MainWindow class
def StartHotkeys(self):
hotkey_thread = HotKeys(self)
hotkey_thread.start()
和这样的应用程序...
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
gui = Main()
gui.show()
sys.exit(app.exec_())
那么为什么 Main 会冻结?
QThread
不是一个线程,它是一个线程处理程序,如果你想在另一个线程中执行任务你必须在run()
方法中执行,该方法是唯一的部分在另一个线程中执行。在您的情况下, Listen()
任务正在阻塞,您在构造函数中调用它,而 QThread
构造函数在 GUI 线程中运行,这就是您的 GUI 冻结的原因。解决方法是将Connect和Listen移到run()
方法:
class HotKeys(QThread):
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.COMBINATIONS = [
{keyboard.KeyCode(char='0')},
{keyboard.KeyCode(char='1')},
{keyboard.KeyCode(char='2')},
{keyboard.KeyCode(char='3')},
]
self.caspar = None
self.current = set()
def run(self):
self.Connect()
self.Listen()
def exit(self, i):
if self.caspar:
self.caspar.close()
sys.exit(i)
def Connect(self):
try:
self.caspar = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.caspar.connect(("127.0.0.1", 10000))
print("Connected to caspar")
except socket.error:
print("CasparCG not running, or incorrect settings.xml")
self.exit(0)
def execute(self, k=None): # k is videofile
if self.caspar:
movie = bytes("PLAY 1-20 {} \r\n".format(k), 'utf8')
self.caspar.send(movie)
def on_press(self, key):
if any([key in COMBO for COMBO in self.COMBINATIONS]):
self.current.add(key)
if any(all(k in self.current for k in COMBO) for COMBO in self.COMBINATIONS):
self.execute(key)
def on_release(self, key):
if any([key in COMBO for COMBO in self.COMBINATIONS]):
self.current.remove(key)
def Listen(self):
with keyboard.Listener(on_press=self.on_press, on_release=self.on_release) as listener:
listener.join()