Library Guide

wxPython

Native OS widgets on every platform โ€” your app looks like it belongs on Windows, macOS or Linux.

Native widgets Desktop-focused

What Is wxPython?

wxPython is a set of Python bindings for the C++ wxWidgets library. Unlike Qt or Kivy, which draw their own widgets, wxWidgets maps each control to the host operating system's native API โ€” Win32/UWP on Windows, Cocoa on macOS, GTK on Linux. The result: your app genuinely looks and behaves like a native application on each platform.

wxPython has been around since 1998 and powers many long-lived desktop tools. Its API is more verbose than tkinter but offers significantly richer widgets and better platform integration (system tray, native file dialogs, accessibility).

Architecture & Core Concepts

  • wx.App โ€” application object; call MainLoop() to start.
  • wx.Frame โ€” top-level window; contains panels and controls.
  • wx.Panel โ€” container inside a frame; groups related controls.
  • Sizers โ€” BoxSizer, GridSizer, FlexGridSizer handle layout (similar to Qt layouts).
  • Event binding โ€” widget.Bind(wx.EVT_BUTTON, handler) connects events to functions.
  • wxPython Phoenix โ€” the modern Python 3 branch; always use Phoenix (wx 4.x).

Common widgets

ClassPurpose
wx.ButtonClickable action
wx.TextCtrlSingle or multi-line text
wx.ListCtrlLists and tables
wx.TreeCtrlTree views
wx.NotebookTabbed pages
wx.MenuBar / wx.ToolBarMenus and toolbars
wx.FileDialogNative open/save dialogs

Installation

shell
pip install wxPython

# Verify:
python -c "import wx; print(wx.version())"

# Demo apps ship with wx:
python -m wx.lib.inspection

Example 1 โ€” Button with message box

python
import wx

app = wx.App()
frame = wx.Frame(None, title="wxPython demo", size=(300, 160))
panel = wx.Panel(frame)
btn = wx.Button(panel, label="Say hi", pos=(20, 20))
btn.Bind(wx.EVT_BUTTON, lambda e: wx.MessageBox("Hello!"))
frame.Show()
app.MainLoop()

Example 2 โ€” Form with sizers (recommended layout)

python
import wx

class FormFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="Contact", size=(360, 200))
        panel = wx.Panel(self)
        grid = wx.FlexGridSizer(3, 2, 8, 8)
        self.name  = wx.TextCtrl(panel)
        self.email = wx.TextCtrl(panel)
        grid.AddMany([(wx.StaticText(panel, label="Name:"),  0), (self.name,  1, wx.EXPAND),
                      (wx.StaticText(panel, label="Email:"), 0), (self.email, 1, wx.EXPAND)])
        grid.AddGrowableCol(1)
        btn = wx.Button(panel, label="Save")
        btn.Bind(wx.EVT_BUTTON, self.on_save)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(grid, 1, wx.ALL | wx.EXPAND, 12)
        sizer.Add(btn, 0, wx.ALIGN_RIGHT | wx.ALL, 12)
        panel.SetSizer(sizer)
    def on_save(self, event):
        wx.MessageBox(f"{self.name.GetValue()} / {self.email.GetValue()}")

app = wx.App()
FormFrame().Show()
app.MainLoop()

Example 3 โ€” Tabbed notebook

python
import wx

app = wx.App()
frame = wx.Frame(None, title="Tabs")
nb = wx.Notebook(frame)
page1 = wx.Panel(nb)
page2 = wx.Panel(nb)
nb.AddPage(page1, "Settings")
nb.AddPage(page2, "About")
wx.StaticText(page1, label="Configure here", pos=(20, 20))
frame.Show()
app.MainLoop()

Practical advice

  • Always use sizers instead of absolute pos= coordinates for resizable layouts.
  • Subclass wx.Frame or wx.Panel for reusable UI components.
  • Use wx.CallAfter() to update the UI from background threads safely.
  • wx.glcanvas and wx.lib provide OpenGL and extended widgets.
  • wxPython apps bundle cleanly with PyInstaller; wx is auto-detected on most platforms.

Real-world use cases

  • Desktop apps where native OS appearance is mandatory
  • Cross-platform tools for Windows and macOS users
  • Scientific and engineering utilities
  • Replacement for legacy wxWidgets C++ apps with Python scripting

โœ“ Strengths

  • Truly native look & feel per OS
  • Large, mature widget collection
  • Permissive license, good for commercial apps
  • Native dialogs, menus, and accessibility

โœ— Weaknesses

  • More verbose API than tkinter
  • Occasionally tricky to install on exotic platforms
  • Smaller community than Qt/tkinter today
  • No mobile deployment path
Use it when

Native platform appearance is a priority and you target traditional desktop OSes. A strong alternative to Qt when you want native widgets without Qt's licensing concerns.