Windows平台信息展示应用:Tkinter持久化占位问题与wxAppBar求助
Hey KeithW, I get where you're coming from—Tkinter is great for building functional apps quickly, but it doesn't have native support for Windows' Application Desktop Toolbars (the feature that lets apps like taskbars or desktop widgets reserve screen space and stay on top without blocking user interactions). Let's cover two practical ways to solve this, one that builds on your existing Tkinter code, and another using wxAppBar with minimal wx experience needed.
Option 1: Extend Your Tkinter App with Windows API via ctypes
You can directly call Windows' shell32 and user32 APIs from Tkinter using Python's built-in ctypes module. This way you don't have to learn a whole new framework. Here's a stripped-down example to get you started:
First, define the core AppBar functions and structures:
import ctypes from ctypes import wintypes user32 = ctypes.WinDLL('user32', use_last_error=True) shell32 = ctypes.WinDLL('shell32', use_last_error=True) # Define Windows API structures class APPBARDATA(ctypes.Structure): _fields_ = [ ("cbSize", wintypes.DWORD), ("hWnd", wintypes.HWND), ("uCallbackMessage", wintypes.UINT), ("uEdge", wintypes.UINT), ("rc", wintypes.RECT), ("lParam", wintypes.LPARAM) ] # Constants for AppBar edges ABE_LEFT = 0 ABE_TOP = 1 ABE_RIGHT = 2 ABE_BOTTOM = 3 # Register and unregister AppBar SHAppBarMessage = shell32.SHAppBarMessage SHAppBarMessage.argtypes = [wintypes.UINT, ctypes.POINTER(APPBARDATA)] SHAppBarMessage.restype = wintypes.HRESULT
Then, integrate this with your Tkinter window:
import tkinter as tk class PersistentToolbar(tk.Tk): def __init__(self): super().__init__() self.title("Persistent Info Toolbar") self.geometry("800x60") # Adjust size based on your needs self.overrideredirect(True) # Remove window borders # Get Tkinter window handle self.hwnd = wintypes.HWND(self.winfo_id()) # Register as AppBar (top edge in this example) self.register_appbar(ABE_TOP) # Add your existing info display widgets here label = tk.Label(self, text="Your Info Display Here", font=("Arial", 12), bg="#333", fg="white") label.pack(fill=tk.BOTH, expand=True) def register_appbar(self, edge): abd = APPBARDATA() abd.cbSize = ctypes.sizeof(APPBARDATA) abd.hWnd = self.hwnd abd.uEdge = edge # Register the AppBar SHAppBarMessage(0, ctypes.byref(abd)) # ABM_NEW # Set the size and position monitor = user32.MonitorFromWindow(self.hwnd, 0) monitor_rect = wintypes.RECT() user32.GetMonitorInfoW(monitor, ctypes.byref(monitor_rect)) if edge == ABE_TOP: abd.rc = monitor_rect abd.rc.bottom = abd.rc.top + self.winfo_height() # Add other edge cases if needed (left, right, bottom) SHAppBarMessage(3, ctypes.byref(abd)) # ABM_SETPOS # Make the window stay on top user32.SetWindowPos(self.hwnd, wintypes.HWND(-1), 0, 0, 0, 0, 0x0001 | 0x0002) # HWND_TOPMOST if __name__ == "__main__": app = PersistentToolbar() app.mainloop()
Notes for this approach:
- This reserves screen space at the top of the monitor (adjust
ABE_TOPtoABE_BOTTOM/LEFT/RIGHTif needed) - The
overrideredirect(True)removes window decorations, making it look like a native toolbar - You'll want to add logic to handle window resizing or monitor changes later (use
ABM_GETSTATEandABM_WINDOWPOSCHANGEDmessages)
Option 2: Use wxAppBar with Minimal wxPython Knowledge
If you want to use wxAppBar instead, you don't need to master the entire wx framework—just a few basics. Here's a simple template you can adapt:
First, install wxPython:
pip install wxpython
Then, create a minimal app with wxAppBar:
import wx from wx.lib.appbar import AppBar class InfoAppBar(AppBar): def __init__(self, parent): super().__init__(parent, style=wx.TB_HORIZONTAL | wx.NO_BORDER) self.SetPosition(wx.DefaultPosition) self.SetSize(wx.Size(wx.DisplaySize()[0], 60)) # Full width, 60px height # Add your info display here (use wx widgets instead of Tkinter) info_label = wx.StaticText(self, label="Your Info Display Here", style=wx.ALIGN_CENTER) info_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) info_label.SetForegroundColour(wx.WHITE) self.SetBackgroundColour(wx.Colour(51,51,51)) # Set the AppBar to stay on top and reserve space self.SetWindowStyle(wx.STAY_ON_TOP) self.EnableAutoHide(False) self.SetPosition(wx.Point(0,0)) # Top-left corner class MyApp(wx.App): def OnInit(self): frame = wx.Frame(None, wx.ID_ANY, "") self.appbar = InfoAppBar(frame) frame.Show(False) # Hide the main frame, only show the AppBar return True if __name__ == "__main__": app = MyApp() app.MainLoop()
Tips for adapting your Tkinter content:
- Convert your Tkinter widgets to wx equivalents (e.g.,
tk.Label→wx.StaticText,tk.Entry→wx.TextCtrl) - The
AppBarclass handles Windows API integration under the hood, so you don't have to deal withctypesdirectly - Use
wx.DisplaySize()to get monitor dimensions for full-width/height toolbars
Both approaches will let your app reserve screen space, stay visible, and not interfere with user interactions. If you're more comfortable sticking with Tkinter, the ctypes method is the way to go—you can keep your existing code and just add the AppBar registration logic.
内容的提问来源于stack exchange,提问作者KeithW




