【问题标题】:Tkinter customization on high level高级别的 Tkinter 定制
【发布时间】:2021-10-17 09:46:09
【问题描述】:

我想完全自定义我的应用程序,所以我创建了一个标题栏并想出了一种方法来拖动它,但现在我的问题是它缺少一些功能,比如调整大小和各种动画,我想知道是否有可能只是摆脱一些图书馆的标题栏?或者也许可以恢复一些功能并让我不必在每次我想隐藏窗口时都使用 overrideredirect?

第一个选项更好,我确实使用ctypes.windll 让窗口回到任务栏,但它似乎也不是最实用的解决方案。

目前的代码如下所示:

import tkinter as tk
from ctypes import windll


GWL_EXSTYLE = -20
WS_EX_APPWINDOW = 0x00040000
WS_EX_TOOLWINDOW = 0x00000080
WS_BORDER = 0x00800000


class Application(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.overrideredirect(True)
        self.after(10, self.setup_window)

        self.geometry('1000x500+500+250')

        self.app_hidden = False
        self.bind('<Expose>', self.show_app)


    # for full customization im using different widgets as buttons
    # lets assume its on the custom title bar

        text = tk.Label(self, width=10, height=2,
                    bg='blue', text='close', foreground='white')
        text.pack()
        text.bind('<ButtonPress-1>', self.hide_app)

    # taken from another post
    def setup_window(self, t: int = 10):
        hwnd = windll.user32.GetParent(self.winfo_id())
        style = windll.user32.GetWindowLongPtrW(hwnd, GWL_EXSTYLE)
        style = style & ~WS_EX_TOOLWINDOW
        style = style | WS_EX_APPWINDOW
        res = windll.user32.SetWindowLongPtrW(hwnd, GWL_EXSTYLE, style)
        self.wm_withdraw()
        self.after(t, self.wm_deiconify)

    def hide_app(self):
        if not self.app_hidden:
            self.overrideredirect(False)
            self.iconify()
            self.app_hidden = True

    def show_app(self, event):
        if self.app_hidden:
            self.overrideredirect(True)
            self.setup_window()
            self.app_hidden = False


if __name__ == '__main__':

    app = Application()
    app.mainloop()

我想要的是能够回到边界,我尝试通过添加来做到这一点

WS_BORDER = 0x00800000
...
def setup_window(self):
    ...
    style = style | WS_BORDER
    ...

但它没有用,而且我也希望没有已经存在的不必要的绑定,所以主要问题是是否可以在没有 overrideredirect 的情况下使用 overrideredirect,如果那里有一些可以使用的库与高级别的默认窗口管理器交互?

【问题讨论】:

  • overrideredirect without overrideredirect 我相信你在这里看到了问题。所以答案是否定的,要么您自己进行窗口管理,要么将其绑定到可用选项。此外,还有一些示例如何使用overrideredirect 拖放窗口。

标签: python python-3.x windows tkinter customization


【解决方案1】:

正如我在评论中所说,据我所知,tkinter 没有任何扩展可以为您完成这项工作。您必须自己进行窗口管理。无论如何,您可能想要这样的东西:

import win32con
import win32api
import win32gui
import tkinter as tk

def override(event):
    hwnd = win32gui.GetParent(root.winfo_id())
    style= win32api.GetWindowLong(hwnd, win32con.GWL_STYLE)
    style&= ~win32con.WS_MINIMIZEBOX
    style&= ~win32con.WS_MAXIMIZEBOX
    style&= ~win32con.WS_SYSMENU
    style&= ~win32con.WS_CAPTION
    #style&= ~win32con.WS_SIZEBOX
    valid= win32api.SetWindowLong(hwnd, win32con.GWL_STYLE, style)
    root.bind('<Map>', None)
    

root = tk.Tk()
root.bind('<Map>', override)
root.mainloop()

如果您使用这些选项,您可以获得各种窗口样式,如下所示。

WS_MINIMIZEBOX:

WS_MAXIMIZEBOX:

WS_MINIMIZEBOX & WS_MAXIMIZEBOX:

WS_SYSMENU:

WS_CAPTION:

WS_CAPTION & SIZEBOX:

Ctypes 解决方案

import tkinter as tk
from ctypes import windll, wintypes

GWL_STYLE = -16
WS_SYSMENU = 0x00080000

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

GetWindowLong = windll.user32.GetWindowLongW
SetWindowLong = windll.user32.SetWindowLongW
SetWindowPos = windll.user32.SetWindowPos

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.hwnd = int(self.wm_frame(), 16)
        tk.Button(self, text="Remove buttons", command=self.remove_buttons).pack()
        tk.Button(self, text="Add buttons", command=self.add_buttons).pack()

    def remove_buttons(self):
        old_style = GetWindowLong(self.hwnd, GWL_STYLE)
        new_style = old_style & ~WS_SYSMENU
        SetWindowLong(self.hwnd, GWL_STYLE, new_style)
        SetWindowPos(self.hwnd, 0, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)

    def add_buttons(self):
        old_style = GetWindowLong(self.hwnd, GWL_STYLE)
        new_style = old_style | WS_SYSMENU
        res = SetWindowLong(self.hwnd, GWL_STYLE, new_style)
        res = SetWindowPos(self.hwnd, 0, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)

if __name__ == "__main__":
    app = App()
    app.mainloop()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多