首页 > 解决方案 > 键模拟器始终在顶部/前景(tkinter)

问题描述

我试图找出我如何总是将窗口放在前台。如果我单击另一个区域,则该窗口处于“非活动状态”并且我无法再访问它(这不是真正的问题)。例如,当我打开浏览器或游戏时,我希望它位于前台,即使我单击其他表面也是如此。“-topmost”已经可用,该窗口只对其他活动消失。

我发布代码是为了更好地概述我的意思(但我自己认为如果有一个小解决方案,就会有一个小解决方案)

from tkinter import *
from tkinter import ttk


class MainWindow(Tk):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.style = ttk.Style()
        self.style.theme_use("clam")
        self.style.configure("TButton", background="red",  borderwidth=0, focuscolor="none")
        self.style.configure("TONE.TButton", background="#1e2224", font=("Unispace", 12), borderwidth=1,
                             foreground="#a1e0ff", bordercolor="lime", darkcolor="lime", lightcolor="lightgreen")

        self.bgFrame = []
        for x in range(5):
            frm = Frame(self, bg="red")
            frm.pack(fill="x", ipady=30)
            self.bgFrame.append(frm)

        Button(self.bgFrame[0], text="\u26cc", bg="red", bd=0, command=self.destroy).pack(side="right", anchor="ne")

        self.firstRow = []
        x1 = 0
        width1 = [80, 80, 80, 80, 80, 80]
        for x in range(6):
            firstRow = ttk.Button(self.bgFrame[0])
            firstRow.place(x=x1, y=0, width=width1[x], height=60)
            self.firstRow.append(firstRow)
            x1 += 80

        self.secondRow = []
        x2 = [0, 100, 180, 260, 340, 420, 500]
        width2 = [100, 80, 80, 80, 80, 80]
        for x in range(6):
            secondRow = ttk.Button(self.bgFrame[1])
            secondRow.place(x=x2[x], y=0, width=width2[x], height=60)
            self.secondRow.append(secondRow)

        x3 = [0, 120, 200, 280, 360, 440, 520]
        width3 = [120, 80, 80, 80, 80, 80]
        self.thirdRow = []
        for x in range(6):
            thirdRow = ttk.Button(self.bgFrame[2])
            thirdRow.place(x=x3[x], y=0, width=width3[x], height=60)
            self.thirdRow.append(thirdRow)

        self.fourthRow = []
        x4 = [0, 100, 180, 260, 340, 420, 500]
        width4 = [100, 80, 80, 80, 80, 80]
        for x in range(6):
            fourthRow = ttk.Button(self.bgFrame[3])
            fourthRow.place(x=x4[x], y=0, width=width4[x], height=60)
            self.fourthRow.append(fourthRow)

        x5 = 0
        width5 = [100, 100, 100, 300]
        self.fithRow = []
        for x in range(4):
            fithRow = ttk.Button(self.bgFrame[4])
            fithRow.place(x=x5, y=0, width=width5[x], height=60)
            self.fithRow.append(fithRow)
            x5 += 100

        self.bind("<Key>", self.keyBind)
        self.bind("<KeyRelease>", self.keyRelease)

    def keyBind(self, event):
        for i, num in enumerate(range(5), 1):
            if event.char == str(i).upper() or event.char == str(i).lower():
                self.firstRow[i].config(text=event.char.upper(), style="TONE.TButton")
        for i, txt in enumerate(["q", "w", "e", "r", "t"], 1):
            if event.char == str(txt).upper() or event.char == str(txt).lower():
                self.secondRow[i].config(text=event.char.upper(), style="TONE.TButton")
        for i, txt in enumerate(["a", "s", "d", "f", "g"], 1):
            if event.char == str(txt).upper() or event.char == str(txt).lower():
                self.thirdRow[i].config(text=event.char.upper(), style="TONE.TButton")
        for i, txt in enumerate(["<", "y", "x", "c", "v"], 1):
            if event.char == str(txt).upper() or event.char == str(txt).lower():
                self.fourthRow[i].config(text=event.char.upper(), style="TONE.TButton")
        if event.keysym == "Tab":
            self.secondRow[0].config(text="\u2B7E", style="TONE.TButton")
        if event.keysym == "Shift_L":
            self.fourthRow[0].config(text="\u21E7", style="TONE.TButton")
        if event.keysym == "Control_L":
            self.fithRow[0].config(text="STRG", style="TONE.TButton")
        if event.keysym == "Alt_L":
            self.fithRow[2].config(text="ALT", style="TONE.TButton")
        if event.keysym == "space":
            self.fithRow[3].config(text="SPACE", style="TONE.TButton")

    def keyRelease(self, event):
        for i in range(6):
            self.firstRow[i].config(text="", style="TButton")
        for i in range(6):
            self.secondRow[i].config(text="", style="TButton")
        for i in range(6):
            self.thirdRow[i].config(text="", style="TButton")
        for i in range(6):
            self.fourthRow[i].config(text="", style="TButton")
        for i in range(4):
            self.fithRow[i].config(text="", style="TButton")


if __name__ == '__main__':
    mw = MainWindow()
    mw.geometry("700x340+0+0")

    mw["bg"] = "red"
    mw.overrideredirect(1)
    mw.wm_transient()
    mw.attributes("-transparentcolor", "red")
    mw.attributes("-topmost", True)

    mw.mainloop()

标签: pythontkinter

解决方案


尝试这样的事情:

from tkinter import ttk
import tkinter as tk
import keyboard


class MainWindow(tk.Tk):
    # Some constants:
    CHARACTERS_ROW_1 = tuple("qwertyuiop")
    CHARACTERS_ROW_2 = tuple("asdfghjkl")
    CHARACTERS_ROW_3 = tuple("zxcvbnm")
    CHARACTERS = (CHARACTERS_ROW_1, CHARACTERS_ROW_2, CHARACTERS_ROW_3)

    def __init__(self):
        super().__init__()

        self.event_queue = []
        self.alive = True

        self.style = ttk.Style()
        self.style.theme_use("clam")
        self.style.configure("TButton", background="red", borderwidth=0, focuscolor="none", font=("Unispace", 12))
        self.style.configure("TONE.TButton", background="#1e2224", font=("Unispace", 12), borderwidth=1,
                             foreground="#a1e0ff", bordercolor="lime", darkcolor="lime", lightcolor="lightgreen")

        self.buttons = {} # A dictionary of all of the buttons

        for row, characters in enumerate(self.CHARACTERS):
            for column, character in enumerate(characters):
                button = ttk.Button(self, style="TButton")
                button.grid(row=row, column=column)
                self.buttons.update({character: button})

        # Add a global system binding:
        keyboard.hook(self.hook)

        # Start the loop:
        self.handle_events_loop()

        # An easy way to escape the program:
        super().bind("<Escape>", lambda e: self.destroy())

    def destroy(self) -> None:
        self.alive = False
        super().destroy()

    def hook(self, event:keyboard.KeyboardEvent) -> None:
        if self.alive:
            self.event_queue.append(event)

    def handle_events_loop(self) -> None:
        if len(self.event_queue) > 0:
            # Get the first event:
            event = self.event_queue.pop(0)
            if event.name not in self.buttons.keys():
                return None
            if event.event_type == "down":
                self.show_key(event.name)
            elif event.event_type == "up":
                self.hide_key(event.name)
        # After 10 ms call `self.handle_events_loop` again
        super().after(10, self.handle_events_loop)

    def show_key(self, character:str) -> None:
        button = self.buttons[character]
        button.config(text=character, style="TONE.TButton")

    def hide_key(self, character:str) -> None:
        button = self.buttons[character]
        button.config(text="", style="TButton")


if __name__ == '__main__':
    root = MainWindow()

    # Removed for debugging
    # root.overrideredirect(True)
    root.transient()
    root.attributes("-topmost", True)
    root.attributes("-transparentcolor", "red")
    root.config(bg="red")

    root.mainloop()

我用keyboard.hook钩住了所有系统范围的键盘事件。然后我使用带有tkinter循环的队列来处理事件。


推荐阅读