GUI toolkit notes
⌛ This hasn't been updated for a while, so could be outdated (particularly if it's about something that evolves constantly, such as software or research). |
Overview
High level / fuller-featured
Qt
- cross-platform (win, lin, osx)
- Comparable to GTK/Clutter in cleanliness and widget set.
- has its own widget set it draws; ignores native look, opting instead to look consistent across playforms (while trying to draw it as low-level as it can, for speed)
- comes with a a respectable class library (including networking, etc; this functionality can occasionally be a boon in crossplatform programming)
- commercial applications need a (paid) license, or choose to play by GPL.
GTK (formerly GTK+, GIMP Toolkit)
- originally developed to replace Motif backend that GIMP used at the time.
- became the basis of GNOME desktop
- cross-platform (win, lin, osx)
- LGPL license.
- Related:
WxWidgets
- cross-platform (win, lin, osx)
- Basically 'the third modern good choice'
- LGPL license
Lightweight
Tk [3]
- crossplatform (win, lin, osx)
- minimal, considered almost as dead in the water as (the X-only) Motif
- Comes with Python (tkinter wrapper), so if you use/teach python, Tk gives a quick-and-dirty GUI with a few lines and no further installs
- (Tk was also included with tcl, which is its own programming language, that you may have little use for)
FLTK [4]
- crossplatform (win, lin, osx)
- lightweight enough to be sensible to statically link
- Unrelated to tk(verify)
See also:
Web style
There are various frameworks that basically let you do HTML/JS/CSS style interfaces within a desktop app. Some of them are little more than standalone hosting, some of them also take care to make it easier to interface with more other code, like node stuff, or native code.
Electron
Java
Java, plus Swing, or AWT, or SWT, is one of the simplest options to get a GUI across many platforms, but is neither very fast or fancy, though that varies with which GUI choice you make, and it ties to you to only use Java code.
AWT (Abstract Widget Toolit)
- simple set of widgets (those present in all OS GUIs)
- ...so can be rendered natively by the OS (also meaning more allocation of OS resources rather than just java doing a bunch of drawing)
- has been in Java the longest(verify)
- http://en.wikipedia.org/wiki/Abstract_Window_Toolkit
Swing (by Sun)
- Richer set of widgets than AWT
- is rendered by Java2D
- http://en.wikipedia.org/wiki/Swing_(Java)
SWT (Standard Widget Toolkit) (by IBM)
- Richer set of widgets than AWT
- a competitor to Swing
- relies on JNI[5]
- http://en.wikipedia.org/wiki/Standard_Widget_Toolkit
SWT versus Swing:
- SWT can render faster, but its use of JNI may mean that larger-scale data transfer and/or frequent data updates incur more lag.
- SWT can be harder to extend (though this is not that commonly needed)
- Swing is part of Java, SWT is not (and since it relies on native code, it must be ported to every platform. It exists for all major platforms, of course)
Qt and PyQt notes
Models, Views and Delegates
Qt is a model-view type of system supported by event signaling.
- Models are classes that provide data to view,
- while views are GUI elements that mediate layout, painting, model editing.
- Delegates are the code that do the view's actual work.
- Communication between these elements is done via signals and slots.
Most of this is faily readable and easy to handle, though becomes slightly more code-intensive when you start writing your own models, view, slots and/or delegates.
Views may store selections (based on QItemSelectionModel), which are sensibly updated collections of model indices. The view-side selection model may be shared between views (note this may not always make so much visual sense with different types of and with custom views)
Models
You won't need abstract models when the provided models do what you want. If they don't, see creating new models. The basic model inheritance:
- QAbstractItemModel (inherits only from QObject)
- QStandardItemModel
- QAbstractListModel
- QStringListModel (list of QStrings)
- QDirModel (filesystem)
- QAbstractProxyModel
- QSortFilterProxyModel
- QAbstractTableModel
- QSqlQueryModel (read-only)
- QSqlTableModel (read-write)
- QSqlRelationalTableModel (supports foreign keys)
- QSqlTableModel (read-write)
- QSqlQueryModel (read-only)
Indices to items: accessing the Model
Model data (internally made of QVariant, a union of Qt types) is stored in a sparse, optionally nested structure that has conventions and functions to make it look like a list, table or tree (see [6]). For example:
toplevelthing = QModelIndex(0,0,QModelIndex()) //row 0, column 0, top-level
sub1 = QModelIndex(0,0,toplevelthing) //row 0, column 0 child of the thing indexed aboce
//this would likely representing a tree
//Or in this style:
sub2 = model->index(1,0,toplevelthing)
model->data(sub1); //get data. Optional role parameter defaults to DisplayRole
model->setData(sub2, value); //set data. Optional role parameter defaults to EditRole
A QModelIndex (introduced to separate view from the data; only the model needs to know how to access the data) may have a valid row(), column() or parent() yielding another QModelIndex. It will return an invalid index (also what QModelIndex() without parameters generates) to mean first or root element.
Note that if a model chooses to reorganize (will likely happen for a filesystem model), QModelIndex may refer to another item or become invalid (and therefore likely refer to a top item). In this case, you could wish to use QPersistentModelIndex which will last as long as the model. (Note that the view will change anyway)
Data contain a few types of state. They can for example be individually flagged (in the model) to be draggable and/or be drop targets (see also [7]).
Items will often be text, but be represented in the view with widgets like perhaps checkboxes, etc. ((verify) how).
Roles
An model's data items may contain information representable in multiple conceptual domains.
- minimal items have only a DisplayRole (the data viewed, often text), but items may may also include
- an EditRole (the data suited for the edit widget),
- Help details like a StatusTipRole, ToolTipRole and WhatsThisRole
- a DecorationRole (e.g. a color)
- GUI details like SizeHintRole, FontRole, FontColorRole, etc.
See [8] for a list.
Note: roles may refer to different parts of data, or be views on it.
Views
Those models can back the three main views. Data is fetched from an enumeration imposed on the data model, which separates data from GUI addressing (a good thing, really) and makes different data models minimally compatible (e.g. a tree model will show the top level elements in a list and table). The classes:
- QAbstractItemView
- HeaderView
- QListView
- (QListWidget (contains instantiations of QListWidgetItem))
- QTableView
- (QTableWidget (contains instantiations of QTableWidgetItem))
- QTreeView
- (QTreeWidget (contains instantiations of QTreeWidgetItem. See also QTreeWidgetItemIterator))
Avoid these *Widgets (and their respective *WidgetItems - though note model-view also talks about items of data); they are Qt3-style interfaces provided for easy forwards porting (reimplemented for Qt4-style model-view). They have more decisions than in views and as such are apparently not as flexibly linkable with models, nor as fast. (verify) Use Model-view for anything new you write.
Delegates
For read-only views:
- On change, model signals view that data changed.
- On need to paint, triggers delegate to do so.
- View will most likely trigger delegate to fetch data, and realize it needs to repaint
For editable views, also:
- On some event, trigger delegate to create temporary edit widget (note: cleaned by the view)
- On edit: trigger delegate, which changes model
Things have sensible default delegates. When you want custom behaviour, such as editing table elements, you subclass QItemDelegate (assuming you want some default functions, otherwise you can subclass QAbstractItemDelegate) to create an editable widget on-demand (automatically cleaned by the view).
Connections: Slots and signals
A connection is a one-way signal from one QObject to another QObject, that does not require an object to know details about the other object. Think event relayers, message handlers.
They also work between QThreads, but note they are are always executed in the calling thread.
Signals send messages, slots receive them.
They are connected with e.g.:
QObject::connect( quitButton, SIGNAL(clicked()),
app, SLOT(quit()) );
QObject::connect( scroll, SIGNAL(valueChanged(int)),
label, SLOT(setNum(int)) );
Connections are many-to-many in that
- a SIGNAL can connect to many SLOTs (called in an undefined order), and
- a slot can have multiple signals going to it.
connect returns false when the connection cannot be made.
The syntax, SIGNAL, SLOT, and the ability to define a signal: section (a la private: and public:) is not straight C++. You use an extra header preparser, moc.
Example code
Simple app (C++)
#include <QtCore/QDir.h>
#include <QtGui/QApplication.h>
#include <QtGui/QSplitter.h>
#include <QtGui/QDirModel.h>
#include <QtGui/QTreeView.h>
#include <QtGui/QListView.h>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QDirModel *dirModel = new QDirModel;
QSplitter *splitter = new QSplitter;
QTreeView *treeView = new QTreeView(splitter);
QListView *listView = new QListView(splitter);
treeView->setModel(dirModel);
listView->setModel(dirModel);
treeView->setRootIndex( dirModel->index( QDir::currentPath() ) );
listView->setRootIndex( dirModel->index( QDir::currentPath() ) );
splitter->setWindowTitle("A list and tree view of the current dir");
splitter->resize(600, 400);
app.setActiveWindow(splitter);
splitter->show();
return app.exec();
}
Link this with QtCore4 and QtGui4.
More complex example (PyQt)
Uses connections, multiple views on a single model, and synchronized selection between views.
import sys
from PyQt4.QtCore import Qt,QDir,QObject,QString,SIGNAL,SLOT
from PyQt4.QtGui import QApplication,QDirModel,QSplitter,QListView,QTreeView,QTableView,QPushButton
app = QApplication(sys.argv)
dirModel = QDirModel()
# Make something like:
# ____ ____ ____
# |view||view||view|
# |____||____||____|
# |__b_u_t_t_o_n___|
#
# Splits top-bottom first.
vsplitter=QSplitter()
vsplitter.setOrientation( Qt.Vertical )
#Top pane has the three views, split horizontally
hsplitter = QSplitter( vsplitter )
listView = QListView( hsplitter )
treeView = QTreeView( hsplitter )
tableView = QTableView( hsplitter )
# ...set all three to view the same directory model
listView.setModel( dirModel )
treeView.setModel( dirModel )
tableView.setModel( dirModel )
#(I forget exactly what this was for. Consistent item indexing, perhaps?)
treeView.setRootIndex( dirModel.index( QDir.currentPath() ) )
listView.setRootIndex( dirModel.index( QDir.currentPath() ) )
tableView.setRootIndex( dirModel.index( QDir.currentPath() ) )
#Synchronize *selection* between views as well
listView.setSelectionModel( treeView.selectionModel() );
tableView.setSelectionModel( treeView.selectionModel() );
#Bottom pane of the vertical split just has a big quit button
quit=QPushButton(QString("Quit"),vsplitter)
#The button executes the quit function
QObject.connect( quit,SIGNAL("clicked()") ,
app, SLOT("quit()") )
#Window details (vsplitter is effectively the window itself)
vsplitter.setWindowTitle("Three selection-synched views of the current dir")
vsplitter.resize(600, 400)
app.setActiveWindow(vsplitter) #this may be implied by not giving it a parent, verify.
vsplitter.show()
sys.exit( app.exec_() )
Note: You probably want to import a lot of classes instead of mentioning QtGui and QtCore all the time. Don't import *, though, it's rather bad style and slow)
Other notes
The basic object you need is a QApplication. Creating more than one is probably bad (in PyQt it's accessible as QtCore.qApp (if you forget the reference)) It is usual to make the main loop's result the process' return value. Since the main loop blocks, this tends to be the last line in the program.
GUI trees are constructed mentioning the parent in the widget's constructor. You mention a widget's parent widget in the constructor (0 in C++ and None in Python implies being/assigning a top?(verify). Interestingly, this means C++ memory management is made simpler: Deleting a widget (possibly any QObject-derivative(verify)) means all its children are recursively deleted - so you only need to keep track of your roots to clean up the Qt.
- A QObject's ->metaObject() (returns a QMetaObject) contains information like object name, property, signal, slot, and superclass information. See also 'The Qt object model'
Designing
The commercial version of Qt4 has Visual Studio integration [9], e.g. a designer and dynamic help.
Qt-aware (to some degree) IDEs you can use include eric3 (written in PyQt; should be crossplatform but seems to not yet play nice with PyQt4), KDevelop, and others.
In general it is assumed you want to build the forms separately from your usual coding environment. 'Qt Designer' (I prever its docked mode, by the way) is a form designer that outputs .ui files, which you can convert to C++ (using uic) and PyQt code (using pyuic) - code without real logic, of course.
You can actually let Qt process .ui files itself using QUiLoader (example ).
When you write from code in C++, you may likely use some Qt features like custom signals, introspection and macros like Q_OBJECT and properties, which means you have run moc (the Meta Object Compiler, a preprocessor) on headers with these features in your build step.
tr
Qt includes internationalization helpers. Instead of constructing widgets with fixed-text labels e.g.
QTableWidgetItem *things = new QTableWidgetItem(QString("Things")); #Instead do: QTableWidgetItem *things = new QTableWidgetItem(tr("Things"));
The tr function allows translation into the current(verify) language, based on provided translation data. The string you hand tr is basically a key for lookup - though it's obviously useful if you can read it.
TODO: Figure out what's behind this, exactly.
Rough sorting of core and GUI classes/interfaces
Not guaranteed to not contain strange misplaced items. Note that some naming changed in Qt4 and PyQt4. See also e.g.:
- Qt documentation (4.1)
- PyQt4 docs, class reference
- the class grouping here.
QtGui
Widgets, layouting, dialogues
- Concepts: QFrame QFocusFrame QDialog QWidget QWidgetItem QWorkspace QDesktopWidget QMainWindow
- Dialogs: QFileDialog QMessageBox QErrorMessage QInputDialog QTextEdit QTimeEdit QDateEdit QDateTimeEdit QProgressDialog QSplashScreen QTextBrowser
- Basic: QLabel QLineEdit QPushButton QComboBox QButtonGroup QCheckBox QRadioButton QSpinBox QDial QLCDNumber QProgressBar QSlider QDoubleSpinBox
- Item-based: QListView QMatrix QTableView QTableWidget QTableWidgetSelectionRange QListWidget QHeaderView QListWidgetItem QTableWidgetItem QTreeViewQTreeWidgetItemIterator QTreeWidget QTreeWidgetItem
- Layouting/structuring: QSpacerItem QSplitter QSplitterHandle QScrollBar QScrollArea QToolTip QWhatsThis QLayout QLayoutItem QBoxLayout QStackedLayout QStackedWidget QHBoxLayout QVBoxLayout QGridLayout QSizePolicy QTabWidget QTabBar QGroupBox QSizeGrip
- Also common: QDockWidget QMenu QMenuBar QStatusBar QAction QActionGroup QToolBar QToolBox QToolButton
Events, interaction
- Global or window events: QWindowStateChangeEvent QShowEvent QHideEvent QMoveEvent QResizeEvent QCloseEvent QFileOpenEvent QHelpEvent QStatusTipEvent QWhatsThisClickedEvent QContextMenuEvent QPaintEvent
- User events: QInputEvent QKeyEvent QKeySequence QTabletEvent QWheelEvent QMouseEvent QDragEnterEvent QDragLeaveEvent QDrag QDragMoveEvent QIconDragEvent QDropEvent QFocusEvent QHoverEvent QActionEvent QShortcut QShortcutEvent QInputMethodEvent
Graphics, audio
- Drawing, colors: QBrush QColor QGradient QColorDialog QRadialGradient QLinearGradient QConicalGradient QPaintDevice QPalette QPen QPolygon QPolygonF QPaintEngine QPaintEngineState QPainter QPainterPath qRgb qRgba qGreen qRed qGray qIsGray qAlpha qBlue
- Images, icons: QImage QImageReader QImageWriter QBitmap QPicture QPictureIO QPixmap QPixmapCache QIcon QIconEngine
- Fonts: QFont QFontDatabase QFontDialog QFontInfo QFontMetrics QFontMetricsF
- Audiovisual: QMovie QSound
Interfaces, Models
- QItemSelection QItemSelectionModel QItemSelectionRange QItemDelegate QItemEditorCreatorBase QItemEditorFactory QStandardItemModel
- QValidator QRegExpValidator QIntValidator QDoubleValidator
- QInputContext QAbstractItemDelegate QAbstractItemView QAbstractPrintDialog QAbstractProxyModel QAbstractScrollArea QAbstractSlider QAbstractSpinBox QAbstractTextDocumentLayout QDirModel QFileIconProvider QStringListModel
- QMimeSource QSessionManager QSortFilterProxyModel
QProxyModel
Look and feel
- QStyle QStyleFactory QStyleHintReturn QStyleHintReturnMask QStyleOption QStyleOptionButton QStyleOptionComboBox QStyleOptionComplex QStyleOptionDockWidget QStyleOptionFocusRect QStyleOptionFrame QStyleOptionFrameV2 QStyleOptionGroupBox QStyleOptionHeader QStyleOptionMenuItem QStyleOptionProgressBar QStyleOptionProgressBarV2 QStyleOptionRubberBand QStyleOptionSlider QStyleOptionSpinBox QStyleOptionTab QStyleOptionTabBarBase QStyleOptionTabV2 QStyleOptionTabWidgetFrame QStyleOptionTitleBar QStyleOptionToolBar QStyleOptionToolBox QStyleOptionToolButton QStyleOptionViewItem
General/Other/Unsorted
- QApplication QClipboard QSyntaxHighlighter QCursor QRegion QRubberBand QPageSetupDialog QPrintDialog QPrintEngine QPrinter
- qApp qDrawPlainRect qDrawShadeLine qDrawShadePanel qDrawShadeRect qDrawWinButton qDrawWinPanel
- QTextBlock QTextFormat QTextBlockFormat QTextBlockGroup QTextBlockUserData QTextCharFormat QTextFrameFormat QTextCursor QTextImageFormat QTextDocument QTextFragment QTextDocumentFragment QTextFrame QTextInlineObject QTextOption QTextLength
- QTextLayout QTextLine
- QTextItem QTextObject QTextList QTextListFormat
- QTextTable QTextTableCell QTextTableFormat
QtCore
Simple and complex types, files, and helpers
- QChar QString QStringList QStringMatcher QRegExp QLatin1Char QLatin1String QLocale QTextCodec QTranslator QTextDecoder QTextEncoder QTextStream QTextStreamManipulator
- QCString qstrcmp qstrcpy qstrdup qstricmp qstrlen qstrncmp qstrncpy qstrnicmp qSetPadChar
- QVector QBitArray QByteArray QByteArrayMatcher QBuffer QDataStream QMimeData qChecksum qCompress qUncompress
- qFuzzyCompare qRound qRound64 qSetRealNumberPrecision (floating point helpers)
- QFile QTemporaryFile QFileInfo QDir QIODevice QAbstractFileEngine QFSFileEngine QAbstractFileEngineHandler
- QUrl QUuid
- QTime QDate QDateTime
- QTimer QBasicTimer QTimerEvent
- QPoint QPointF QLine QLineF QRect QRectF QSize QSizeF
- QThread QWaitCondition QMutex QMutexLocker QSemaphore QReadLocker QWriteLocker QReadWriteLock QProcess
Unsorted
- QAbstractItemModel QAbstractListModel QAbstractTableModel
- QModelIndex QPersistentModelIndex
- QtMsgType QtCriticalMsg QtDebugMsg QtFatalMsg QtSystemMsg QtWarningMsg qDebug qWarning qErrnoWarning qCritical qFatal qInstallMsgHandler
- QEvent QEventLoop QChildEvent
QVariant QObject QObjectCleanupHandler QSignalMapper QAbstractEventDispatcher QSocketNotifier Qt QCoreApplication QLibrary QLibraryInfo QSysInfo QPluginLoader QSettings QMetaClassInfo QMetaEnum QMetaMethod QMetaObject QMetaProperty qIsNull qUnregisterResourceData qRegisterResourceData qSetFieldWidth qSharedBuild qVersion qAddPostRoutine qRemovePostRoutine MSG POINT QT_TRANSLATE_NOOP QT_TR_NOOP QT_VERSION QT_VERSION_STR SIGNAL SLOT
See also
WxWidgets notes
Web based and/or phone-targeted
Website UI frameworks
When this is not server-side "generate all the HTML for us" (which is entirely viable for simpler dynamic sites), this will almost always be JavaScript-based.
So see Javascript_notes_-_libraries_and_frameworks#Website_building.2FUI_frameworks
Web based on desktop only
Electron notes
Builds cross-platform desktop apps -- by actually having them effectively be locally hosted HTML+JS+CSS.
It's made mostly of
- Chromium for rendering
- node.js for its backend
- in part because acting like local apps requires escaping browser security
It doesn't do phones, yet there are some cases where the phone version shares a lot of code.
Web based on phone only
Ionic
(can be made to run on desktop too, but really wasn't aimed at it)
The first version was AngularJS and Cordova.
The second focuses on web components which makes it easier to use Angular, React, Vue.
Unsorted (web based)
Other mixes
Web based on desktop and mobile
There are a good number of platforms that are basically web server and web browser in one, so that you can shove the same codebase onto mobile and desktop.
While this is great for minimal apps, in terms of development time (particularly for people who fiddled with web but never on native GUIs), there are various applications where this will not only never be the fastest choice, but the difference can be fairly noticeable.
Most GUI toolkits mentioned here will be snappier, and if you care about mobile as a platform,
Compare with TODO: make list
Cordova (previously PhoneGap)
JavaFX
Windows, Linux, macOS, iOS, Android.
https://en.wikipedia.org/wiki/JavaFX
Unity
Flutter
you write Dart code, which can compile to native code (on phones?(verify)) or JS (on desktop)
NativeScript and similar
On mobile, have a JS VM controlling UI widgets instead of DOM+CSS, mainly to reuse some of the build steps and logic.
See NativeScript
Xamarin
.NET on Windows, Linux, Android, iOS and macOS(verify),
Xamarin can be seen as the continuation of Mono (which was .NET for Linux), extended to Android, then iOS.
It's seen a few purchases (Novell, AttachMate) and its future was unsure for a bit, but is now a Microsoft subsidiary, which is why you'll see it integrated into Visual Studio.