python - PYQT5:窗口没有获得焦点

标签 python python-3.x pyqt5 user32

我想创建自己的虚拟键盘。但是,按下按钮或打开窗口后,总是会发生焦点从另一个窗口移走的情况。 我该如何解决这个问题?

My goal

下面我创建了一个小示例,您可以使用它来重现该问题。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot


class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'Keyboard'
        self.left = 10
        self.top = 10
        self.width = 320
        self.height = 200
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        button = QPushButton('1', self)
        button.move(100, 70)
        button.clicked.connect(self.on_click)

        self.show()

    @pyqtSlot()
    def on_click(self):
        print('PyQt5 button click')


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

到目前为止,我已经尝试更改按钮 button.setFocusPolicy(Qt.NoFocus) 的焦点设置。 以及设置窗口标志或属性:

self.setWindowFlags(Qt.WindowDoesNotAcceptFocus|Qt.WindowStaysOnTopHint).
self.setAttribute(Qt.WA_ShowWithoutActivating)

我可能还需要 User32 dll 来解决问题 (https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowlonga)。我如何获得窗口句柄 (=hwnd)?

达到我的目标的最好和最简单的方法是什么?也许这已经集成在 PYQT5 中,但我找不到任何相关信息。

对于 tkinter,我发现了以下内容。我正在用 Pyqt5 尝试完全相同的事情!

import tkinter as tk
from ctypes import windll, wintypes

GWL_STYLE = -16
GWL_EXSTYLE = -20
WS_CHILD = 0x40000000
WS_EX_APPWINDOW = 0x00040000
WS_EX_TOOLWINDOW = 0x00000080
WS_EX_NOACTIVATE = 0x08000000

SWP_FRAMECHANGED = 0x0020
SWP_NOACTIVATE = 0x0010
SWP_NOMOVE = 0x0002
SWP_NOSIZE = 0x0001

# write short names for functions and specify argument and return types
GetWindowLong = windll.user32.GetWindowLongW
GetWindowLong.restype = wintypes.ULONG
GetWindowLong.argtpes = (wintypes.HWND, wintypes.INT)

SetWindowLong = windll.user32.SetWindowLongW
SetWindowLong.restype = wintypes.ULONG
SetWindowLong.argtpes = (wintypes.HWND, wintypes.INT, wintypes.ULONG)

SetWindowPos = windll.user32.SetWindowPos

def find_root_window(win): # takes tkinter window ref
    w_id = win.winfo_id() # gets handle
    style = GetWindowLong(w_id, GWL_STYLE) # get existing style
    newstyle = style & ~WS_CHILD # remove child style
    res = SetWindowLong(w_id, GWL_STYLE, newstyle) # set new style
    res = SetWindowPos(w_id, 0, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)
    hwnd = int(root.wm_frame(), 16) # find handle of parent
    res = SetWindowLong(w_id, GWL_STYLE, style) # set back to old style
    res = SetWindowPos(w_id, 0, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)
    return hwnd # return parents handle

def set_no_focus(hwnd):
    style = GetWindowLong(hwnd, GWL_EXSTYLE) # get existing style
    style = style & ~WS_EX_TOOLWINDOW # remove toolwindow style
    style = style | WS_EX_NOACTIVATE | WS_EX_APPWINDOW
    res = SetWindowLong(hwnd, GWL_EXSTYLE, style)
    res = SetWindowPos(hwnd, 0, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)

def push_me():
    print('you pushed me!')

def focus_me(event):
    root.focus_force()

root = tk.Tk()
root.wm_attributes("-topmost", 1)
tk.Button(root, text="Push me", command=push_me).pack()
e = tk.Entry(root)
e.pack()
e.bind('<Button-1>', focus_me) # if we have a widget that must have focus it needs to be bound
root.update() # for some reason, window style is messed with after window creation, update to get past this
hwnd = find_root_window(root)
if hwnd:
    set_no_focus(hwnd)
root.mainloop()

最佳答案

我通过 User32.dll 禁用窗口解决了 Windows 中的问题。为此,我只需将“HWND”处理程序传递给“SetWindowLongW”函数,然后设置新的扩展窗口样式。 所有信息都可以在以下链接中看到:

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlongw

更新:下面是工作示例:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot,Qt
import ctypes
User32 = ctypes.WinDLL('User32.dll')

class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'Keyboard'
        self.left = 10
        self.top = 10
        self.width = 320
        self.height = 200
        self.initUI()
        self.setWindowFlags(Qt.WindowDoesNotAcceptFocus | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_ShowWithoutActivating)
        print(int(self.winId()))
        self.update()
        self.show()
        print(User32.SetWindowLongW(int(self.winId()), -20, 134217728))

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        button = QPushButton('1', self)
        button.move(100, 70)
        button.clicked.connect(self.on_click)

        self.show()

    @pyqtSlot()
    def on_click(self):
        print('PyQt5 button click')


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

关于python - PYQT5:窗口没有获得焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71458741/

相关文章:

python - Keras 中的损失函数与类比函数不匹配

javascript - 如何在Selenium中获取JS生成的文本?

python - Pylint UnicodeDecodeError utf-8 无法解码字节

python-3.x - 使用 PyQt5,如何使 QComboBox 可搜索?

python - Python/OpenCV/OSX 中的鼠标回调事件标志?

python - OSX swift 没有名为 6 的模块

python - Google Scrape with Python 中的结果数量错误

python - 尝试使用 stdin : io. UnsupportedOperation 时在 Python 中出现错误:fileno

python - 不显示图标

python - PyQt5:Gtk-CRITICAL **:IA__gtk_widget_style_get:断言 'GTK_IS_WIDGET (widget)' 失败