Tkinter,Linux:如何在没有标题栏的windows任务栏中查看window?
Tkinter, Linux: How to view window in windows task bar which has no title bar?
我创建了一个 window:
root = Tk()
并删除了标题栏:
root.attributes("-type", "splash")
现在 window 不在任务栏上。如何在任务栏中显示它?
系统详情:
- Ubuntu: 21.04
- Python: 3.9.5
- Tcl 版本:8.6
<tk.Tk>._windowingsystem
: "x11"
这个问题已经回答 Windows
一种方法是直接使用 libX11
并告诉它不要像这样在正常的 tk.Tk()
window 上绘制标题栏:
# Mostly taken from: https://www.tonyobryan.com//index.php?article=9
# Inspired by: https://github.com/EDCD/EDMarketConnector/blob/main/theme.py
import tkinter as tk
import ctypes
# Defining types
CHAR = ctypes.c_char
UCHAR = ctypes.c_ubyte
BOOL = ctypes.c_bool
INT = ctypes.c_int
UINT = ctypes.c_uint
LONG = ctypes.c_long
PTR = ctypes.c_void_p
CHAR_PTR = ctypes.POINTER(CHAR)
UINT_PTR = ctypes.POINTER(UINT)
ULONG = ctypes.c_ulong
class HINTS(ctypes.Structure):
_fields_ = (("flags", ULONG),
("functions", ULONG),
("decorations", ULONG),
("inputMode", LONG),
("status", ULONG))
DISPLAY = PTR
ATOM = LONG
WINDOW = LONG
WINDOW_PTR = ctypes.POINTER(WINDOW)
HINTS_PTR = ctypes.POINTER(HINTS)
def _errcheck_not_zero(value, func, args):
if value == 0:
args_str = ", ".join(map(str, args))
raise OSError(f"{func.__name__}({args_str}) => {value}")
return args
def string_to_c(data:str) -> CHAR_PTR:
return ctypes.create_string_buffer(data.encode())
libx11 = ctypes.cdll.LoadLibrary("libX11.so.6")
# Constants
PropModeReplace = 0
XA_ATOM = 4
# Defining functions
XInternAtom = libx11.XInternAtom
XInternAtom.argtypes = (PTR, CHAR_PTR, BOOL)
XInternAtom.restype = ATOM
XInternAtom.errcheck = _errcheck_not_zero
XOpenDisplay = libx11.XOpenDisplay
XOpenDisplay.argtypes = (CHAR_PTR, )
XOpenDisplay.restype = DISPLAY
XOpenDisplay.errcheck = _errcheck_not_zero
XChangeProperty = libx11.XChangeProperty
XChangeProperty.argtypes = (DISPLAY, WINDOW, ATOM, ATOM, INT, INT, HINTS_PTR, INT)
XChangeProperty.restype = INT
XChangeProperty.errcheck = _errcheck_not_zero
XQueryTree = libx11.XQueryTree
XQueryTree.argtypes = (DISPLAY, WINDOW, WINDOW_PTR, WINDOW_PTR, WINDOW_PTR, UINT_PTR)
XQueryTree.restype = INT
XQueryTree.errcheck = _errcheck_not_zero
XFlush = libx11.XFlush
XFlush.argtypes = (DISPLAY, )
XFlush.restype = INT
XFlush.errcheck = _errcheck_not_zero
if __name__ == "__main__":
root = tk.Tk()
# This is needed:
root.update_idletasks()
# Get the handle of the window
handle:int = root.winfo_id()
# Get the default display
display = XOpenDisplay(None)
# Get the parent of the window
parent = WINDOW()
XQueryTree(display, handle, ctypes.byref(WINDOW()),
ctypes.byref(parent), ctypes.byref(WINDOW()),
ctypes.byref(UINT()))
# Change the motif hints of the window
motif_hints = XInternAtom(display, string_to_c("_MOTIF_WM_HINTS"), False)
hints = HINTS()
hints.flags = 2 # Specify that we're changing the window decorations.
hints.decorations = False
XChangeProperty(display, parent, motif_hints, XA_ATOM, 32,
PropModeReplace, ctypes.byref(hints), 5)
# Flush the changes
XFlush(display)
# Normal `tkinter` code can follow
root.mainloop()
它使用root.update_idletasks()
和XQueryTree(...)
来获取window 的句柄。然后它修改 "_MOTIF_WM_HINTS"
以便 x11
将删除所有 window 装饰,包括标题栏。
我创建了一个 window:
root = Tk()
并删除了标题栏:
root.attributes("-type", "splash")
现在 window 不在任务栏上。如何在任务栏中显示它?
系统详情:
- Ubuntu: 21.04
- Python: 3.9.5
- Tcl 版本:8.6
<tk.Tk>._windowingsystem
:"x11"
这个问题已经回答 Windows
一种方法是直接使用 libX11
并告诉它不要像这样在正常的 tk.Tk()
window 上绘制标题栏:
# Mostly taken from: https://www.tonyobryan.com//index.php?article=9
# Inspired by: https://github.com/EDCD/EDMarketConnector/blob/main/theme.py
import tkinter as tk
import ctypes
# Defining types
CHAR = ctypes.c_char
UCHAR = ctypes.c_ubyte
BOOL = ctypes.c_bool
INT = ctypes.c_int
UINT = ctypes.c_uint
LONG = ctypes.c_long
PTR = ctypes.c_void_p
CHAR_PTR = ctypes.POINTER(CHAR)
UINT_PTR = ctypes.POINTER(UINT)
ULONG = ctypes.c_ulong
class HINTS(ctypes.Structure):
_fields_ = (("flags", ULONG),
("functions", ULONG),
("decorations", ULONG),
("inputMode", LONG),
("status", ULONG))
DISPLAY = PTR
ATOM = LONG
WINDOW = LONG
WINDOW_PTR = ctypes.POINTER(WINDOW)
HINTS_PTR = ctypes.POINTER(HINTS)
def _errcheck_not_zero(value, func, args):
if value == 0:
args_str = ", ".join(map(str, args))
raise OSError(f"{func.__name__}({args_str}) => {value}")
return args
def string_to_c(data:str) -> CHAR_PTR:
return ctypes.create_string_buffer(data.encode())
libx11 = ctypes.cdll.LoadLibrary("libX11.so.6")
# Constants
PropModeReplace = 0
XA_ATOM = 4
# Defining functions
XInternAtom = libx11.XInternAtom
XInternAtom.argtypes = (PTR, CHAR_PTR, BOOL)
XInternAtom.restype = ATOM
XInternAtom.errcheck = _errcheck_not_zero
XOpenDisplay = libx11.XOpenDisplay
XOpenDisplay.argtypes = (CHAR_PTR, )
XOpenDisplay.restype = DISPLAY
XOpenDisplay.errcheck = _errcheck_not_zero
XChangeProperty = libx11.XChangeProperty
XChangeProperty.argtypes = (DISPLAY, WINDOW, ATOM, ATOM, INT, INT, HINTS_PTR, INT)
XChangeProperty.restype = INT
XChangeProperty.errcheck = _errcheck_not_zero
XQueryTree = libx11.XQueryTree
XQueryTree.argtypes = (DISPLAY, WINDOW, WINDOW_PTR, WINDOW_PTR, WINDOW_PTR, UINT_PTR)
XQueryTree.restype = INT
XQueryTree.errcheck = _errcheck_not_zero
XFlush = libx11.XFlush
XFlush.argtypes = (DISPLAY, )
XFlush.restype = INT
XFlush.errcheck = _errcheck_not_zero
if __name__ == "__main__":
root = tk.Tk()
# This is needed:
root.update_idletasks()
# Get the handle of the window
handle:int = root.winfo_id()
# Get the default display
display = XOpenDisplay(None)
# Get the parent of the window
parent = WINDOW()
XQueryTree(display, handle, ctypes.byref(WINDOW()),
ctypes.byref(parent), ctypes.byref(WINDOW()),
ctypes.byref(UINT()))
# Change the motif hints of the window
motif_hints = XInternAtom(display, string_to_c("_MOTIF_WM_HINTS"), False)
hints = HINTS()
hints.flags = 2 # Specify that we're changing the window decorations.
hints.decorations = False
XChangeProperty(display, parent, motif_hints, XA_ATOM, 32,
PropModeReplace, ctypes.byref(hints), 5)
# Flush the changes
XFlush(display)
# Normal `tkinter` code can follow
root.mainloop()
它使用root.update_idletasks()
和XQueryTree(...)
来获取window 的句柄。然后它修改 "_MOTIF_WM_HINTS"
以便 x11
将删除所有 window 装饰,包括标题栏。