wxWidgets

Cross-platform GUI library for C++. Uses native APIs for each platform to achieve OS-standard appearance and feel. Lightweight, fast, and commercially usable license. Provides stable API over long periods.

desktopC++cross-platformGUInativemulti-platform

GitHub Overview

wxWidgets/wxWidgets

Cross-Platform C++ GUI Library

Stars6,702
Watchers254
Forks1,826
Created:May 18, 2011
Language:C++
License:-

Topics

c-plus-pluscocoacross-platformcross-platform-desktopdesktopgtkguigui-frameworklinuxmacosportablewin32windowswxwidgetsx11

Star History

wxWidgets/wxWidgets Star History
Data as of: 7/15/2025, 10:54 PM

Desktop Framework

wxWidgets

Overview

wxWidgets is a cross-platform GUI library written in C++. It provides native look and feel and runs on Windows, macOS, Linux (GTK), and many other platforms. Developed since 1992, it has a reputation for stability and compatibility.

Details

wxWidgets uses native APIs directly on each platform, enabling natural appearance and usability specific to each OS. It uses Win32 API on Windows, Cocoa on macOS, and GTK on Linux, allowing you to build truly cross-platform applications. It provides rich UI controls and layout management features, making it suitable for enterprise-level application development.

Features

  • Native appearance: Native look and behavior on each platform
  • Wide platform support: Windows, macOS, Linux, FreeBSD, Solaris, etc.
  • Rich controls: Buttons, lists, trees, grids, menus, etc.
  • Open source: Available under the wxWindows Library License
  • Long-term stability: Over 30 years of development experience
  • Python bindings: Also available from Python via wxPython

Architecture

  • MVC support: Document/View architecture support
  • Event-driven: Event-based design rather than callbacks
  • Memory management: Automatic memory management and resource cleanup
  • Internationalization: Unicode support and multilingual support
  • Printing: High-quality printing functionality

Pros and Cons

Pros

  • Native appearance that integrates naturally with the OS
  • Extremely stable library with expected long-term support
  • Rich documentation and sample code
  • Large community and ecosystem
  • Track record in enterprise applications
  • Python bindings (wxPython) also available

Cons

  • High learning cost with complex API
  • Not suitable for modern UI/UX design
  • C++ specific complexity (memory management, compiler dependencies)
  • Slow response to new UI trends
  • Bundle size tends to be large

Reference Pages

Code Examples

Hello World

#include <wx/wx.h>

class MyApp : public wxApp
{
public:
    bool OnInit() override;
};

class MyFrame : public wxFrame
{
public:
    MyFrame();
    
private:
    void OnExit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
};

wxIMPLEMENT_APP(MyApp);

bool MyApp::OnInit()
{
    MyFrame *frame = new MyFrame();
    frame->Show(true);
    return true;
}

MyFrame::MyFrame()
    : wxFrame(nullptr, wxID_ANY, "Hello wxWidgets")
{
    CreateStatusBar();
    SetStatusText("Welcome to wxWidgets!");
}

Windows and Controls

class MainFrame : public wxFrame
{
public:
    MainFrame() : wxFrame(nullptr, wxID_ANY, "wxWidgets App")
    {
        // Menu bar
        wxMenuBar* menuBar = new wxMenuBar();
        wxMenu* fileMenu = new wxMenu();
        fileMenu->Append(wxID_EXIT, "&Exit");
        menuBar->Append(fileMenu, "&File");
        SetMenuBar(menuBar);
        
        // Main panel
        wxPanel* panel = new wxPanel(this);
        wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
        
        // Controls
        wxStaticText* label = new wxStaticText(panel, wxID_ANY, "Hello World!");
        wxTextCtrl* textCtrl = new wxTextCtrl(panel, wxID_ANY, "");
        wxButton* button = new wxButton(panel, wxID_ANY, "Click Me");
        
        // Layout
        sizer->Add(label, 0, wxALL, 5);
        sizer->Add(textCtrl, 0, wxALL | wxEXPAND, 5);
        sizer->Add(button, 0, wxALL, 5);
        
        panel->SetSizer(sizer);
        
        // Event handler
        button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, 
                    [this](wxCommandEvent&) {
                        wxMessageBox("Button clicked!", "Info");
                    });
    }
};

Event Handling and Dialogs

class EventFrame : public wxFrame
{
public:
    EventFrame() : wxFrame(nullptr, wxID_ANY, "Event Handling")
    {
        wxPanel* panel = new wxPanel(this);
        wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
        
        wxButton* dialogBtn = new wxButton(panel, wxID_ANY, "Show Dialog");
        wxButton* fileBtn = new wxButton(panel, wxID_ANY, "Open File");
        wxButton* exitBtn = new wxButton(panel, wxID_ANY, "Exit");
        
        sizer->Add(dialogBtn, 0, wxALL, 5);
        sizer->Add(fileBtn, 0, wxALL, 5);
        sizer->Add(exitBtn, 0, wxALL, 5);
        
        panel->SetSizer(sizer);
        
        // Event binding
        dialogBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &EventFrame::OnDialog, this);
        fileBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &EventFrame::OnOpenFile, this);
        exitBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &EventFrame::OnExit, this);
    }
    
private:
    void OnDialog(wxCommandEvent& event)
    {
        wxMessageDialog dlg(this, "This is a message dialog", "Information", 
                           wxOK | wxICON_INFORMATION);
        dlg.ShowModal();
    }
    
    void OnOpenFile(wxCommandEvent& event)
    {
        wxFileDialog dlg(this, "Choose a file", "", "", 
                        "Text files (*.txt)|*.txt|All files (*.*)|*.*",
                        wxFD_OPEN | wxFD_FILE_MUST_EXIST);
                        
        if (dlg.ShowModal() == wxID_OK)
        {
            wxString path = dlg.GetPath();
            wxMessageBox("Selected: " + path, "File Selected");
        }
    }
    
    void OnExit(wxCommandEvent& event)
    {
        Close(true);
    }
};

Lists and Grids

class ListFrame : public wxFrame
{
public:
    ListFrame() : wxFrame(nullptr, wxID_ANY, "List and Grid")
    {
        wxPanel* panel = new wxPanel(this);
        wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
        
        // List control
        wxListCtrl* listCtrl = new wxListCtrl(panel, wxID_ANY, 
                                             wxDefaultPosition, wxDefaultSize,
                                             wxLC_REPORT | wxLC_SINGLE_SEL);
        
        // Add columns
        listCtrl->AppendColumn("Name", wxLIST_FORMAT_LEFT, 100);
        listCtrl->AppendColumn("Age", wxLIST_FORMAT_RIGHT, 60);
        listCtrl->AppendColumn("City", wxLIST_FORMAT_LEFT, 120);
        
        // Add data
        long index = listCtrl->InsertItem(0, "John Doe");
        listCtrl->SetItem(index, 1, "30");
        listCtrl->SetItem(index, 2, "New York");
        
        index = listCtrl->InsertItem(1, "Jane Smith");
        listCtrl->SetItem(index, 1, "25");
        listCtrl->SetItem(index, 2, "Los Angeles");
        
        // Grid (requires wxGrid include)
        wxGrid* grid = new wxGrid(panel, wxID_ANY);
        grid->CreateGrid(5, 3);
        grid->SetColLabelValue(0, "Product");
        grid->SetColLabelValue(1, "Price");
        grid->SetColLabelValue(2, "Stock");
        
        // Grid data
        grid->SetCellValue(0, 0, "Laptop");
        grid->SetCellValue(0, 1, "$999");
        grid->SetCellValue(0, 2, "10");
        
        sizer->Add(listCtrl, 1, wxALL | wxEXPAND, 5);
        sizer->Add(grid, 1, wxALL | wxEXPAND, 5);
        
        panel->SetSizer(sizer);
    }
};

Multithreading and Timers

class TimerFrame : public wxFrame
{
public:
    TimerFrame() : wxFrame(nullptr, wxID_ANY, "Timer Example"),
                   timer(this, wxID_ANY)
    {
        wxPanel* panel = new wxPanel(this);
        wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
        
        timeLabel = new wxStaticText(panel, wxID_ANY, "00:00:00");
        wxButton* startBtn = new wxButton(panel, wxID_ANY, "Start Timer");
        wxButton* stopBtn = new wxButton(panel, wxID_ANY, "Stop Timer");
        
        sizer->Add(timeLabel, 0, wxALL | wxCENTER, 10);
        sizer->Add(startBtn, 0, wxALL, 5);
        sizer->Add(stopBtn, 0, wxALL, 5);
        
        panel->SetSizer(sizer);
        
        // Event binding
        startBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &TimerFrame::OnStart, this);
        stopBtn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &TimerFrame::OnStop, this);
        timer.Bind(wxEVT_TIMER, &TimerFrame::OnTimer, this);
        
        startTime = wxDateTime::Now();
    }
    
private:
    wxTimer timer;
    wxStaticText* timeLabel;
    wxDateTime startTime;
    
    void OnStart(wxCommandEvent& event)
    {
        startTime = wxDateTime::Now();
        timer.Start(1000); // 1 second interval
    }
    
    void OnStop(wxCommandEvent& event)
    {
        timer.Stop();
    }
    
    void OnTimer(wxTimerEvent& event)
    {
        wxDateTime now = wxDateTime::Now();
        wxTimeSpan diff = now - startTime;
        timeLabel->SetLabel(diff.Format("%H:%M:%S"));
    }
};

Custom Drawing

class DrawingPanel : public wxPanel
{
public:
    DrawingPanel(wxFrame* parent) : wxPanel(parent)
    {
        Bind(wxEVT_PAINT, &DrawingPanel::OnPaint, this);
        Bind(wxEVT_LEFT_DOWN, &DrawingPanel::OnMouseDown, this);
    }
    
private:
    std::vector<wxPoint> points;
    
    void OnPaint(wxPaintEvent& event)
    {
        wxPaintDC dc(this);
        
        // Clear background
        dc.Clear();
        
        // Gradient
        wxRect rect = GetClientRect();
        dc.GradientFillLinear(rect, wxColour(200, 200, 255), 
                             wxColour(100, 100, 200), wxSOUTH);
        
        // Draw circles and lines
        dc.SetPen(wxPen(wxColour(255, 0, 0), 3));
        dc.SetBrush(wxBrush(wxColour(0, 255, 0, 128)));
        
        for (size_t i = 0; i < points.size(); ++i)
        {
            dc.DrawCircle(points[i], 20);
            if (i > 0)
            {
                dc.DrawLine(points[i-1], points[i]);
            }
        }
        
        // Draw text
        dc.SetTextForeground(wxColour(0, 0, 0));
        dc.DrawText(wxString::Format("Points: %zu", points.size()), 10, 10);
    }
    
    void OnMouseDown(wxMouseEvent& event)
    {
        points.push_back(event.GetPosition());
        Refresh(); // Trigger redraw
    }
};