【发布时间】:2021-08-12 22:12:47
【问题描述】:
我正在尝试为 Windows 开发一个由全局键绑定触发的覆盖弹出窗口,一旦按下键绑定,它应该将焦点捕获到 QLineEdit 中。问题是,如果它被聚焦一次,但我点击外部有效地移除了焦点,之后就无法重新获得焦点。
这是我试图用来强制键盘焦点在 QLineEdit 上的代码的简化版本:
from PySide6 import QtCore, QtWidgets, QtGui
from pynput import keyboard
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.input = QtWidgets.QLineEdit()
self.layout = QtWidgets.QVBoxLayout(self)
self.layout.addWidget(self.input)
self.input.setWindowModality(QtCore.Qt.ApplicationModal)
self.setWindowState(QtCore.Qt.WindowActive)
self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
@QtCore.Slot()
def toggle_visible(self):
if self.isVisible():
print("Hiding popup")
self.hide()
else:
print("Showing popup")
self.show()
self.activateWindow()
self.input.grabKeyboard()
self.input.setFocus()
class KeybindPressed(QtCore.QObject):
keybind_pressed = QtCore.Signal()
def __call__(self):
self.keybind_pressed.emit()
if __name__ == "__main__":
app = QtWidgets.QApplication([])
pressed = KeybindPressed()
with keyboard.GlobalHotKeys({"<alt>+<space>": pressed}):
widget = MyWidget()
pressed.keybind_pressed.connect(widget.toggle_visible)
widget.resize(800, 600)
widget.show()
app.exec()
这是一段记录,显示焦点停留在其他应用程序中而不是在显示时返回窗口的不良行为。
【问题讨论】:
-
请提供minimal reproducible example,而不是外部链接
-
@eyllanesc 完成。
-
不幸的是,在 Windows 上,这种行为是“设计使然”。如docs for activateWindow 中所述,操作系统会主动防止焦点窃取。 Qt 提供了QWindowsWindowFunctions.setWindowActivationBehavior 作为解决此问题的方法,但是 PyQt 和 PySide 都没有实现
QWindowsWindowFunctions类。 -
看起来可以使用 win32api 推出您自己的解决方案。我在 Linux 上(没有这个问题),所以我无法测试任何这些,但 an article here 有一个可能的解决方案。如果这不起作用,您可以尝试移植 Qt 的 QWindowsWindow::requestActivateWindow 函数。
-
@ekhumoro 谢谢你,做到了!我现在可以强制集中注意力。现在写答案。