简体   繁体   English

Python GUI窗口不显示焦点

[英]Python GUI window stay on top without focus

I am trying to write my own on screen keyboard in python modeled after the messagease keyboard which combines swipes and taps to input characters. 我试图用模仿messagease键盘 (结合滑动和点击输入字符)的python编写自己的屏幕键盘。 I plan to use it on windows but would like to try and keep it cross platform if possible. 我计划在Windows上使用它,但如果可能的话,希望尝试使其跨平台。

Currently I am trying to find a way to keep the window on top and yet keep the cursor/focus in the previous window so that when I emulate key presses (using pyautogui) they will appear in the correct window. 当前,我正在尝试找到一种方法,将窗口保持在顶部,但将光标/焦点保持在上一个窗口中,以便当我模拟按键(使用pyautogui)时,它们将出现在正确的窗口中。

With tkinter I can keep the window on top with this line of code but I don't know how to keep the previous window in focus. 使用tkinter,我可以使用此行代码将窗口保持在顶部,但是我不知道如何保持上一个窗口的焦点。

root.wm_attributes("-topmost", 1)

And to send key presses, I am using pyautogui: 为了发送按键,我正在使用pyautogui:

pyautogui.typewrite("characters to write")

I don't have much experience in writing a gui in python so if it is easier to accomplish in a different framework I'm willing to switch. 我没有用python编写gui的经验,因此,如果在其他框架中更容易完成,我愿意切换。

So the base of my question is this: 所以我的问题的基础是这样的:

How do I make a gui window that can be interacted with (touch, swipes, etc) but that does not take the keyboard focus away from another window/application? 如何制作可以与之交互(触摸,滑动等)但不会使键盘焦点从另一个窗口/应用程序移开的gui窗口?

this is windows only, but to set the style of a window with python to not get focus you can use ctypes: 这仅是Windows,但是要使用python设置窗口样式以不引起焦点,可以使用ctypes:

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()

you need to use the right Get/Set functions depending on the applications environment. 您需要根据应用程序环境使用正确的Get / Set函数。 for 32 bit windows it seems you need to use either: 对于32位窗口,您似乎需要使用以下任一方法:
GetWindowLongW and SetWindowLongW GetWindowLongWSetWindowLongW
or 要么
GetWindowLongA and SetWindowLongA GetWindowLongASetWindowLongA

but 64 bit needs: 但64位需求:
GetWindowLongPtrW and SetWindowLongPtrW GetWindowLongPtrWSetWindowLongPtrW
or 要么
GetWindowLongPtrA and SetWindowLongPtrA GetWindowLongPtrASetWindowLongPtrA
see this 看到这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM