wx_dart 0.9.0 copy "wx_dart: ^0.9.0" to clipboard
wx_dart: ^0.9.0 copied to clipboard

Flutter backend of wxDart

wxDart #

A cross-platform GUI library to build native desktop apps, web apps and mobile apps from a single source using the Dart programming language.

Table of contents #

wxDart Flutter and wxDart Native #

wxDart consists of two separate libraries which offer the same API and can be used independently.

  • 'wxDart Flutter' uses the Flutter libary as its backend and is written in pure Dart.
  • 'wxDart Native' uses the wxWidgets C++ GUI library as its backend using FFI calls.

Note that both wxDart Native and wxDart Flutter support the main desktop architectures (Windows, macOS and Linux). When using wxDart Flutter (this package), your applications will have an identical look and feel across all desktop platforms (and on the web). With wxDart Native, your applications will have the native look and feel.

wxDart aims to provide Dart bindings to the wxWidgets library very similar to the hugely popular wxPython for Python, with additional support for mobile devices and web apps.

If you are coming from the Flutter world, consider wxDart a new toolkit based on the Flutter core (next to Material UI, Cupertino UI, MacOS UI or Fluent UI), but with a fully native twin brother library and a single code base for all of them.

Screenshot #

A screenshot showing the demo running side-by-side in a web browser (wxDart Flutter, in light mode) and running natively on macOS Tahoe (wxDart Native, in dark mode). There are more screenshots below and you can run the entire demo in the browser by clicking here.

Web vs macOS

Installation of wxDart Flutter #

To use wxDart Flutter, add wx_dart as a dependency in your pubspec.yaml file.

flutter pub add wx_dart

Import the package into your Dart file:

import 'package:wx_dart/wx_dart.dart';

Installation of wxDart Native #

wxDart Native can be downloaded from here. It consists of the wxDart Native library and the three bridge libraries (the Windows .dll, macOS .dynlib and Linux .so) as the interface to the respective platforms.

Licence #

'wxDart Flutter' is free software under the wxWindows licence. The wxWindows licence allows you to use 'wxDart Flutter' to create free and commercial software with no restrictions, but not to create a closed source competitor of the library itself. See the Licence in full.

'wxDart Native' is not open source.

Classes by Category #

wxDart uses the API from the wxWidgets library with only minimal adaptions to the Dart langauge.

Below you find a table of the main classes by category with links to both the documentation of the Dart classes as well as the C++ classes which wxDart Native uses internally.

Core data classes #

Dart C++
WxClass Any C++ class
WxObject wxObject
String wxString
List wxList
dynamic wxVariant
WxApp wxApp

Window classes #

Dart C++
WxWindow wxWindow
WxPanel wxPanel
WxScrolledWindow wxScrolledWindow
WxSplitterWindow wxSplitterWindow
WxTopLevelWindow wxTopLevelWindow
WxDialog wxDialog
WxFrame wxFrame

Book controls #

Dart C++
WxNotebook wxNotebook
WxTreebook wxTreebook
WxDataViewBook Only available in wxDart

Windows for mobile interfaces #

Dart C++
WxAdaptiveFrame Only available in wxDart
WxAppBar Only available in wxDart
WxNavigationCtrl Only available in wxDart

Common dialogs #

Dart C++
WxMessageDialog wxMessageDialog
WxFileDialog wxFileDialog
WxDirDialog wxDirDialog
Dart C++
WxMenuBar wxMenuBar
WxMenu wxMenu
WxMenuItem wxMenuItem
WxToolBar wxToolBar
WxStatusBar wxStatusBar

Misc classes #

Dart C++
WxUIAnimation Only available in wxDart
WxTimer wxTimer
WxStopWatch wxStopWatch
WxStandardPaths wxStandardPaths
WxSystemSettings wxSystemSettings

Graphics classes #

wxDC overview

Dart C++
WxPoint wxPoint
WxSize wxSize
WxRect wxRect
WxReadOnlyDC wxReadOnlyDC
WxDC wxDC
WxPaintDC wxPaintDC
WxMemoryDC wxMemoryDC
WxInfoDC wxInfoDC
WxPaintEvent wxPaintEvent
WxColour wxColour
WxCursor wxCursor
WxFont wxFont
WxPen wxPen
WxBrush wxBrush
WxBitmap wxBitmap
WxBitmapBundle wxBitmapBundle
WxImage wxImage
WxRendererNative wxRendererNative

Control classes #

Dart C++
WxControl wxControl
WxStaticLine wxStaticLine
WxStaticBox wxStaticBox
WxStaticText wxStaticText
WxStaticBitmap wxStaticBitmap
WxButton wxButton
WxBitmapButton wxBitmapButton
WxToggleButton wxToggleButton
WxAnimationCtrl wxAnimationCtrl
WxCheckBox wxCheckBox
WxTextCtrl wxTextCtrl
WxChoice wxChoice
WxRadioButton wxRadioButton
WxRadioBox wxRadioBox
WxComboBox wxComboBox
WxListBox wxListBox
WxSlider wxSlider
WxGauge wxGauge
WxSpinCtrl wxSpinCtrl
WxSpinCtrlDouble wxSpinCtrlDouble
WxHyperlinkCtrl wxHyperlinkCtrl

Complex control classes #

Dart C++
WxTreeCtrl wxTreeCtrl
WxHeaderCtrl wxHeaderCtrl
WxHtmlWindow wxHtmlWindow
Dart C++
WxDataViewCtrl wxDataViewCtrl
WxDataViewModel wxDataViewModel
WxDataViewModelNotifier wxDataViewModelNotifier
WxDataViewIndexListModel wxDataViewIndexListModel
WxDataViewVirtualListModel wxDataViewVirtualListModel
WxDataViewColumn wxDataViewColumn

wxDataViewCtrl Renderers

Dart C++
WxDataViewRenderer wxDataViewRenderer
WxDataViewTextRenderer wxDataViewTextRenderer
WxDataViewChoiceRenderer wxDataViewChoiceRenderer
WxDataViewBitmapRenderer wxDataViewBitmapRenderer
WxDataViewProgressRenderer wxDataViewProgressRenderer
WxDataViewToggleRenderer wxDataViewToggleRenderer
WxDataViewTileRenderer Only available in wxDart

Predefined model and controls for tabular data

Dart C++
WxDataViewListStore wxDataViewListStore
WxDataViewListCtrl wxDataViewListCtrl
WxDataViewTileListCtrl Only available in wxDart

Predefined models and controls for tree data

Dart C++
WxDataViewTreeStore wxDataViewTreeStore
WxDataViewTreeCtrl wxDataViewTreeCtrl
WxDataViewBookStore Only available in wxDart
WxDataViewChapterRenderer Only available in wxDart
WxDataViewChapterCtrl Only available in wxDart

Layout classes #

WxSizer overview

Dart C++
WxSizer wxSizer
WxSizerItem wxSizerItem
WxBoxSizer wxBoxSizer
WxStaticBoxSizer wxStaticBoxSizer
WxFlexGridSizer wxFlexGridSizer
WxWrapSizer wxWrapSizer
WxTileSizer Only available in wxDart

Event classes #

Event handling overview

Dart C++
WxEvtHandler wxEvtHandler
WxEvent wxEvent
WxEventTableEntry Internal implementation detail.
WxCommandEventTableEntry Internal implementation detail.

System events (deriving from WxEvent directly)

Dart C++
WxEvtHandler wxEvtHandler
WxPaintEvent wxPaintEvent
WxMouseEvent wxMouseEvent
WxKeyEvent wxKeyEvent
WxSizeEvent wxSizeEvent
WxShowEvent wxShowEvent
WxIdleEvent wxIdleEvent
WxTimerEvent wxTimerEvent
WxCloseEvent wxCloseEvent
WxFocusEvent wxFocusEvent
WxScrollWinEvent wxScrollWinEvent
wxActivateEvent wxActivateEvent
WxDPIChangedEvent wxDPIChangedEvent
WxSysColourChangedEvent wxSysColourChangedEvent
WxInitDialogEvent wxInitDialogEvent
WxDialogValidateEvent Only available in wxDart
WxMenuEvent wxMenuEvent

Command events (deriving from WxCommandEvent)

Dart C++
WxCommandEvent wxCommandEvent
WxUpdateUIEvent wxUpdateUIEvent
WxNotifyEvent wxNotifyEvent
WxNotebookEvent wxNotebookEvent
WxTreeEvent wxTreeEvent
WxSplitterEvent wxSplitterEvent
WxDataViewEvent wxDataViewEvent
WxHtmlEvent wxHtmlEvent

Demo #

Here is a link to the demo app (written in wxDart) running in your browser.

Screenshots #

Several pages from the demo running on the iPhone emulator: iPhone

The demo running on Windows 11 in light mode Windows 11 light mode

The demo running on Windows 11 in dark mode Windows 11 dark mode

The demo running on Linux Ubuntu in light and dark mode Linux Ubuntu

For completeness: the demo running in the Android emulator Android

wxDart Native and wxDart Flutter showing a WxDataViewListCtrl on the desktop Native vs Flutter

Web app tutorials #

Here are samples from the tutorials that you can run in the window.

Screencasts from the demo #

Here are screencasts from the demo running on different platforms.

Hello world #

import 'package:wx_dart/wx_dart.dart';

// wxDart uses IDs to identify menu items, toolbar items, and sometimes controls.
const idAbout = 100;

// Every app needs a WxFrame as a main window.
class MyFrame extends WxFrame {
  MyFrame( WxFrame? parent) : super( parent, -1, "Hello World", size: WxSize(900, 700) ) 
  {
    // Create a menu bar
    final menubar = WxMenuBar();

    // Create a menu 
    final filemenu = WxMenu();
    // Create a menu item with short cuts and help text
    filemenu.appendItem( idAbout, "About\tAlt-A", help: "About Hello World" );
    filemenu.appendSeparator();
    filemenu.appendItem( wxID_EXIT, "Quit app\tCtrl-Q", help: "Run, baby, run!" );
    // Attach menu to menu bar
    menubar.append(filemenu, "File");

    // Attach menu bar to this frame
    setMenuBar(menubar);

    // Create status bar at the bottom
    createStatusBar();
    setStatusText( "Welcome to wxDart" );

    // Bind this function to idAbout ID menu item
    bindMenuEvent((_) {
      // Show a message dialog
      final dialog = WxMessageDialog( this, "Welcome to Hello World", caption: "wxDart" );
      dialog.showModal(null);
    }, idAbout );

    // Bind this function to wxID_EXIT 
    bindMenuEvent( (_) => close(false), wxID_EXIT );

    // Someone requested to close. 
    bindCloseWindowEvent( (event) { 
      // You didn't save your data? Veto!
      // event.veto( true ); 
      // return

      // otherwise, go ahead and quit
      destroy();
    } );
  }
}

// Every app needs an instance of WxApp
class MyApp extends WxApp {
  MyApp();

  @override
  bool onInit() {
    // create and show main window
    WxFrame myFrame = MyFrame( null );
    myFrame.show();

    return true;
  }
}

void main()
{
  final myApp = MyApp();
  myApp.run();
  myApp.dispose();
}

License of wxDart Flutter #

wxWindows Library Licence, Version 3.1
                ======================================

  Copyright (c) 1998-2026 Julian Smart, Robert Roebling et al

  Everyone is permitted to copy and distribute verbatim copies
  of this licence document, but changing it is not allowed.

                       WXWINDOWS LIBRARY LICENCE
     TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  This library is free software; you can redistribute it and/or modify it
  under the terms of the GNU Library General Public Licence as published by
  the Free Software Foundation; either version 2 of the Licence, or (at
  your option) any later version.

  This library is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library
  General Public Licence for more details.

  You should have received a copy of the GNU Library General Public Licence
  along with this software, usually in a file named COPYING.LIB.  If not,
  write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301 USA.

  EXCEPTION NOTICE

  1. As a special exception, the copyright holders of this library give
  permission for additional uses of the text contained in this release of
  the library as licenced under the wxWindows Library Licence, applying
  either version 3.1 of the Licence, or (at your option) any later version of
  the Licence as published by the copyright holders of version
  3.1 of the Licence document.

  2. The exception is that you may use, copy, link, modify and distribute
  under your own terms, binary object code versions of works based
  on the Library.

  3. If you copy code from files distributed under the terms of the GNU
  General Public Licence or the GNU Library General Public Licence into a
  copy of this library, as this licence permits, the exception does not
  apply to the code that you add in this way.  To avoid misleading anyone as
  to the status of such modified files, you must delete this exception
  notice from such code and/or adjust the licensing conditions notice
  accordingly.

  4. If you write modifications of your own for this library, it is your
  choice whether to permit this exception to apply to your modifications.
  If you do not wish that, you must delete the exception notice from such
  code and/or adjust the licensing conditions notice accordingly.

Design overview #

Nomenclature #

Overall, wxDart uses the exact API and nomenclature of the wxWidgets C++ GUI library. Since Dart demands that all class names start with a capital letter, all wxDart related classes use the capitalized prefix "Wx":

  • wxWindow becomes WxWindow
  • wxBitmap becomes WxBitmap

All primitive types are matched to their respective equivalents in Dart.

  • wxString is mapped to String
  • bool remains bool
  • double remains double
  • all integer types are mapped to int
  • wxArrayInt is mapped to List<int>
  • wxArrayString is mapped to List<String>
  • wxClientDataObject and wxTreeItemData are mapped to dynamic
  • wxVariant is mapped to dynamic (not actually used yet)
  • wxVector<wxVariant> is mapped to List (not actually used yet)
  • wxPointList is mapped to List<WxPoint>

All constants and enums are mapped to "const int" with a non-capitalized prefix "wx". That - unfortunately - loses run-time type checking, but this cannot be avoided since wxWidgets uses enumns with concrete values.

  • wxALIGN_RIGHT stays wxALIGN_RIGHT
  • *wxBLUE becomes wxBLUE
  • *wxBLUE_PEN becomes wxBLUE_PEN
  • *wxNORMAL_FONT becomes wxNORMAL_FONT
  • wxID_OK stays wxID_OK
  • xxx::NO_IMAGE becomes wxNO_IMAGE
  • wxNullCursor becomes null
  • wxNullBitmap becomes null
  • wxNullFont becomes null
  • wxDefaultPosition and wxDefaultSize remain the same
  • wxTheApp stays wxTheApp

Some factory creators have become global functions

  • wxStandardPaths::Get() becomes wxGetStandardPaths()
  • wxRendererNative::Get() becomes wxGetRendererNative()
  • wxSystemSettings::Get() becomes wxGetSystemSettings()

The wxWidgets logging functions have been mapped to

  • wxLogError( String text );
  • wxLogWarning( String text );
  • wxLogMessage( String text );
  • wxLogStatus( WxFrame frame, String text );
  • setLogTarget( WxTextCtrl? textCtrl );

WxPoint and WxSize #

WxPoint and WxSize are implemented as const classes, so their values cannot be changed. This allows the use of wxDefaultPosition and wxDefaultSize in constructors as it is widely done in wxWidgets.

WxRect, however, is not a constant class and can be used and changed like its C++ counterpart. A noteworthy difference - valid for all of wxDart - is that Dart does reference counting for every instance of every class. Use WxRect.fromRect() to create a deep copy.

Deriving from wxWindow and wxSizer #

wxDart Native and wxDart Flutter allow the use of 'generic' classes, i.e. classes written neither using the Flutter backend nor the C++ backend, but written in pure wxDart. The entire wxDataViewCtrl group of classes is inplemented in pure wxDart, including its events, the data models, the header controls and the main control.

Such generic controls can then be used with both wxDart Flutter and wxDart Native - like it is done with wxDataViewCtrl.

Likewise, wxDart allows the creation of generic sizers by composing existing ones. The WxTileSizer is a simple example of this and works with both wxDart Native and wxDart Flutter.

Double buffering and background erasure #

The wxWidgets C++ library was created many years ago when double buffering of window content to avoid flicker was an expensive operation. In particular the Windows port still can show redraw flicker when not using a double buffering mechanism.

wxDart hides this and provides built-in double buffering on all platforms (Windows, macOS, Linux and Flutter). As a consequence of that, wxDart does not need a separate event or function to clear the background (like it is done in the C++ library with the wxEraseEvent).

When drawing in an paint event handler, the background (i.e. the backing store) gets automatically cleared to the window background. This may be a single colour or a more complex background depending on the system, user setting, dark vs. light mode and the particular window. You can overwrite this with e.g. pure white, a colour gradient or a bitmap in the paint handler.

2D and 3D drawing support #

wxDart currently uses the original drawing API from the wxDC group of classes and it uses the GDI backend under Windows which provides fastest drawing for simple geometries and text.

wxWidgets has support for a modern path based drawing API from the wxGraphicsContext group of classes. These are not available in wxDart yet. Once done, it will use the Direct2D backend under Windows, CoreGraphics on MacOS, Cairo on Linux and Impellar when using the Flutter backend.

There is no 3D support in wxDart yet. Ideal would be a port of ThreeJS on all platforms.

Main loop #

A key technical difference between wxDart Native and wxDart Flutter is that wxDart Native uses the native system's main event loop while wxDart Flutter uses a specialized hybrid Dart/native main loop. This makes no difference when executing synchronous code, but using the native event loop in wxDart Native means that you cannot run any asynchronous Dart code in wxDart Native. Put differently, wxDart Flutter supports the async await paradigm, but wxDart Native currently does not.

Eventually, the goal is to enable asynchronous code execution in wxDart Native, as well, but currently no asynchronous Dart operations are supported in wxDart Native (but they are fully supported in wxDart Flutter) including streams and asynchronous file operations or web transfer.

As written above, wxDart Native does not currently support the async await paradigm of Dart, but Flutter requires it to show dialogs modally (i.e. blocking input to all other windows on screen). Therefore, wxDart uses a slightly different API compared to the API of wxWidgets: the return value from WxDialog.showModal() is retrieved through a callback function.

    void showSomeDialog()
    {
      final dialog = MyDialog(this);
      dialog.showModal( (ret, data) {
        if (ret == wxID_OK) {
          // Pressed OK
        } else {
          // Cancelled dialog
        }
      });
    }

If the return value is not relevant, you can pass null to WxDialog.showModal():

    void showSomeDialog()
    {
      final dialog = MyDialog(this);
      dialog.showModal(null);
    }

WxDialog.showModal() will also destroy the dialog, so you cannot call WxDialog.showModal() twice.

Resources or assets #

Flutter and wxWidgets have the notion of assets or resources, i.e. files that will be used by the application during execution, such as image files or HTML text. Flutter loads assets asynchronously - potentially from a web server when using the Web variant - while wxWidgets loads them directly. wxDart either hides this difference on the level of controls or uses callbacks (which might get called sooner or later).

In wxDart, resource or asset files need to be in the lib/assets directory and the Flutter build system needs to be informed about them by adding them to the project's pubspec.yaml file. If README.md and flutter.svg need to be used, they have to be declared in the pubspec.yaml file of your project like this:

  # To add assets to your application, add an assets section, like this:
  assets:
     - lib/assets/README.md
     - lib/assets/flutter.svg

Such code is then needed to load the text file:

  void loadReadMe()
  {
    wxLoadStringFromResource( "README.md", (text) {
      // here is the text
      final readme = text;
    } );
  }

Note that for wxDart Native under OSX, the asset files need to be copied into the Resources directory of the app package. For Linux, they need to be installed as by the Linux standard.

Layout mechanism #

The system for laying out windows or controls on screen in wxWidgets is based on so called sizers deriving from the wxSizer base class (see wxSizer overview). The most often used sizers are wxBoxSizer, wxFlexGridSizer and wxStaticBoxSizer. Flutter has its own, very similar system where e.g. a Row corresponds to a wxBoxSizer(wxHORIZONTAL) in wxWidgets.

Therefore, all wxDart sizer classes have been implemented to internally use the corresponding Flutter classes in wxDart Flutter, whereas they use the C++ wxSizer classes in wxDart Native. Both wxDart Flutter and wxDart Native lay out the controls automatically when the parent (e.g. a dialog) is shown on screen.

A very subtle difference is that Flutter's layout classes automatically re-layout when they are changed also after they have been shown on screen (e.g. by adding a control or by changing text with a different length). In wxWidgets, you then need to call wxDialog::Layout() for the controls to be laid out correctly again.

In practice, you should call WxDialog.layout() in wxDart which will do nothing in wxDart Flutter (as Flutter does the layout for you) and will call the C++ layout algorithm in wxDart Native.

Using sizers within a scrolled window #

On the desktop, sizers are typically used to determine the size of dialog window, which usually do not use scrolling. On mobile devices with limited space, but also on desktop interfaces, the classical modal dialog is use less frequently now and vertical scrolling is used to layout controls.

Therefore, WxScrolledWindow in both wxDart Flutter and wxDart Native has been adapted to re-size the scrolling area (virtual area) to the size the sizers ask for and enable vertical scrolling automatically. This is slightly different from the semantics in the C++ library, but very convenient.

WxBitmapBundle #

Like the wxWidgets C++ library, wxDart supports resolution independent bitmaps through the WxBitmapBundle interface, i.e. a concrete WxBitmap can be constructed from e.g. two different PNG files (16x16 and 32x32) or from a single SVG file (which gets scaled to whatever resolution is needed).

Material icons #

wxDart Flutter and wxDart Native have built-in support for more than 2000 scalable icons from Google's Material icon set. The data is included automatically in wxDart Native and is part of wxDart Flutter as well.

Dark and Light mode and accent colour #

Both wxDart Native and wxDart Flutter support dark and light modes. Only wxDart Flutter additionally supports setting an accent colour programmatically to use a specfic main branding colour in your application. The default is light blue.

Event handling #

C++ event handling overview

A key feature of the wxDart event handling system is that it allows you to override a base class behaviour as the derived class's event handler will be called first. If you want the base class to then execute its original code, you need to call WxEvent.skip(). This is particularly important when overriding the WxSizeEvent handler from the base class.

wxDart implements the "bind" interface of the wxWidgets event handling in both wxDart Native and wxDart Flutter. You can bind any class deriving from WxEvtHandler to any event (even if that class does not emit that event). If you want to react to the event from a WxButton, you will typically call

button.bindButtonEvent( (event)=>doSomething(), -1 );

You can also fully write out the event handler like this:

button.bindButtonEvent( onButton, -1 );

void onButton( WxCommandEvent event )
{
  // do something
}

System events like WxPaintEvent, WxKeyEvent and WxMouseEvent are only sent to the actual window where they occur - which is why they don't need any ID. It is very common to derive a new class if you handle these events

// in the constructor
bindPaintEvent( onPaint );

void onPaint( WxPaintEvent event )
{
  final dc = WxPaintDC( this );
  dc.drawLine(10,10,100,100);
}

Command events (all events deriving from WxCommandEvent) are propagated to their parent windows (if not intercepted before) until they finally reach a top-level window such a s WxDialog or a WxFrame.

One usage case for propagating events up to parent windows is that you might want to design a dialog in an external GUI builder, then load the controls into your dialog and react to events in that parent dialog. But propagation of command events to parent windows is useful in many other situations.

When intercepting command events in parent windows, such as a WxDialog, a unique id has to be assigned to the control and then used in the call to bind().

const int idTextCtrl = 300;

final dialog = WxDialog( parent, -1, "Dialog", size: WxSize( 500,600) );
final textctrl = WxTextCtrl( dialog, idTextCtrl );
dialog.bindTextEvent( (event) {
    // do something
},idTextCtrl);

If the event is intercepted in the control itself, then the default id of -1 is fine.

final textctrl = WxTextCtrl( parent, -1 );
textctrl.bindTextEvent( (event) {
    // do something
},-1);

Command events are typically sent from a control when the user e.g. clicked on a button, entered text in a text field or chose an item in a tree control. Command events are not sent by controls when their content or selection is changed programmatically. This includes those cases where the events are being sent in the original C++ library (wxNotebook::SetSelection() and wxTextCtrl::SetValue()) - these two cases have been changed and corrected in wxDart Flutter and wxDart Native.