我正在创建Albert,Alfred或uLauncher风格的启动器。我的应用程序在后台运行,并在按下热键时显示。我pynput
过去常常听热键。我无法使用PyQt5热键的功能(不是吗?),因为我需要监听系统范围内的键盘事件,而不仅仅是应用程序范围。
按下快捷方式后,它将调用我的小部件的show()方法。唯一的问题是,我不能让我的窗口上,焦点回到尽管使用了raise_
,setFocus
和activateWindow
。
我发现了一个(丑陋的)解决方法,其中包括打开QMessageBox(+调整其外观以使其不可见,但没有在示例代码中添加它)并在之后立即将其关闭。
当我在Linux上工作时,该解决方法正在完成任务,而我准备忘记它在完成任务时有多丑。但是我切换到Windows(我的应用程序也必须在其上运行),现在这个厚脸皮的把戏似乎导致应用程序冻结然后崩溃。业力?当然。
无论如何,如果我的应用程序不能引起关注,那它就毫无用处,所以我问了两个问题,我很高兴只解决了一个问题。:)
这是一个示例代码。
非常感谢你 :)
编辑:我刚刚发现,即使停用QMessageBox解决方法,应用程序最终也会崩溃(在热键调用5、20、30之后)。因此,问题可能出在我将快捷方式绑定到GUI的方式上,我担心会出现线程问题,但这超出了我的了解:/
import sys
from PyQt5.QtWidgets import QLineEdit, QApplication, QMessageBox
from PyQt5.QtCore import QSize, Qt, QEvent
from pynput import keyboard
class Launcher(QLineEdit):
def __init__(self):
super().__init__()
self.setFixedSize(QSize(600, 50))
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setPlaceholderText('Search...')
self.installEventFilter(self)
self.set_shortcut('<ctrl>+`')
def set_shortcut(self, shortcut):
def for_canonical(f):
return lambda k: f(listener.canonical(k))
hotkey = keyboard.HotKey(
keyboard.HotKey.parse(shortcut),
self.wake_up)
listener = keyboard.Listener(
on_press=for_canonical(hotkey.press),
on_release=for_canonical(hotkey.release))
listener.start()
def wake_up(self):
print('Waking up')
self.show()
self.cheeky_focus_stealer()
def cheeky_focus_stealer(self):
self.setFocus()
self.raise_()
self.activateWindow()
# Working of linux, but causes freeze/crash on Windows 10
message_box = QMessageBox(self)
message_box.show()
message_box.hide()
def eventFilter(self, obj, event):
if obj is self and event.type() == QEvent.KeyPress:
if event.key() == Qt.Key_Escape:
self.hide()
return True
return super().eventFilter(obj, event)
def main():
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
window = Launcher()
window.show()
app.exec_()
if __name__ == "__main__":
main()
我发现了我的错误,所以我在这里发布了一段更新的代码,因为它可能对尝试将全局热键绑定到影响GUI的功能(也就是两个不同的线程通信)的人有所帮助。
我的错误确实是将热键触发的操作直接绑定到我的show()
方法,这意味着pynput
侦听器线程将尝试与进行通信QApplication
。
诀窍是使用pyqtSignal()
和要求它触发show()
方法。信号本身被热键触发。
在以一种干净的方式完成此操作之后,我cheeky_focus_stealer
再次工作,因为它是从GUI线程运行的。
import sys
from PyQt5.QtWidgets import QLineEdit, QApplication, QMessageBox
from PyQt5.QtCore import QSize, Qt, QEvent, QObject, pyqtSignal
from pynput import keyboard
class Forwarder(QObject):
signal = pyqtSignal()
class Launcher(QLineEdit):
def __init__(self):
super().__init__()
self.setFixedSize(QSize(600, 50))
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setPlaceholderText('Search...')
self.installEventFilter(self)
self.set_shortcut('<ctrl>+`')
def set_shortcut(self, shortcut):
# The forwarder must be parented to the Launcher
forwarder = Forwarder(parent=self)
forwarder.signal.connect(self.wake_up)
def for_canonical(f):
return lambda k: f(listener.canonical(k))
hotkey = keyboard.HotKey(
keyboard.HotKey.parse(shortcut),
forwarder.signal.emit)
listener = keyboard.Listener(
on_press=for_canonical(hotkey.press),
on_release=for_canonical(hotkey.release))
listener.start()
def wake_up(self):
print('Waking up')
self.show()
self.cheeky_focus_stealer()
def cheeky_focus_stealer(self):
self.setFocus()
self.raise_()
self.activateWindow()
# Working of linux, but causes freeze/crash on Windows 10
message_box = QMessageBox(self)
message_box.show()
message_box.hide()
def eventFilter(self, obj, event):
if obj is self and event.type() == QEvent.KeyPress:
if event.key() == Qt.Key_Escape:
self.hide()
return True
return super().eventFilter(obj, event)
def main():
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
window = Launcher()
window.show()
app.exec_()
if __name__ == "__main__":
main()
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句