You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Windows平台信息展示应用:Tkinter持久化占位问题与wxAppBar求助

How to Create a Persistent, Non-Intrusive Desktop Toolbar for Your Tkinter App on Windows

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_TOP to ABE_BOTTOM/LEFT/RIGHT if 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_GETSTATE and ABM_WINDOWPOSCHANGED messages)

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.Labelwx.StaticText, tk.Entrywx.TextCtrl)
  • The AppBar class handles Windows API integration under the hood, so you don't have to deal with ctypes directly
  • 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

火山引擎 最新活动