tim-dlang / dqt

D bindings for the Qt Toolkit
GNU Lesser General Public License v3.0
25 stars 4 forks source link
binding d dlang gui qt ui

DQt

DQt contains experimental bindings for using a subset of Qt with the D Programming Language. Qt is a library for writing cross-platform graphical user interfaces. Currently bindings exist for the Qt modules core, gui, widgets, qml and webenginewidgets.

Features

Limitations

License

The bindings are licensed under LGPL version 3. See file LICENSE.LGPL3.

For Qt itself see also Qt Licensing and Licenses Used in Qt.

The bindings also depend on dxml for parsing files generated by Qt Designer at compile time. See the license in the repository for dxml.

Building

Three example programs show how to use DQt. The program helloworld is a minimal program showing a window with label and button. Example program examplewidgets uses many widgets from Qt and shows them in a window with different tabs. It uses UI files created with Qt Designer for the layout, which are imported at compile time. Example program examplebrowser uses QWebEngine to show a simple web browser.

Linux

Install the libraries for Qt 5.15.2 using the package manager of the distribution or the installer from https://www.qt.io/. It was tested with dmd v2.103.1.

You can build and run the example programs using dub:

dub run :helloworld
dub run :examplewidgets
dub run :examplebrowser
dub run :exampleqml

Alternatively dmd can be used directly:

dmd -i -Icore -Igui -Iwidgets \
    -L-lQt5Core -L-lQt5Gui -L-lQt5Widgets -L-lstdc++ \
    -g -run examples/helloworld/main.d
dmd -i -Icore -Igui -Iwidgets -Iexamples -Idxml/source -Jexamples/examplewidgets \
    -L-lQt5Core -L-lQt5Gui -L-lQt5Widgets -L-lstdc++ \
    -g -run examples/examplewidgets/main.d

Windows

Install Qt 5.15.2 for MSVC 2019 32-bit or 64-bit (and not MinGW) using the installer from https://www.qt.io/. It was tested with dmd v2.103.1.

Windows 64-Bit

You can build and run the example programs using dub:

@set DFLAGS="-L/LIBPATH:C:\Qt\5.15.2\msvc2019_64\lib"
@set PATH=C:\Qt\5.15.2\msvc2019_64\bin;%PATH%
dub run --compiler=dmd --arch=x86_64 :helloworld --build-mode=allAtOnce
dub run --compiler=dmd --arch=x86_64 :examplewidgets --build-mode=allAtOnce
dub run --compiler=dmd --arch=x86_64 :examplebrowser --build-mode=allAtOnce
dub run --compiler=dmd --arch=x86_64 :exampleqml --build-mode=allAtOnce

Alternatively dmd can be used directly:

@set PATH=C:\Qt\5.15.2\msvc2019_64\bin;%PATH%
dmd -i -m64 -Icore -Igui -Iwidgets ^
    -L/LIBPATH:C:\Qt\5.15.2\msvc2019_64\lib ^
    Qt5Core.lib Qt5Gui.lib Qt5Widgets.lib ^
    -g -run examples\helloworld\main.d
dmd -i -m64 -Icore -Igui -Iwidgets -Iexamples -Idxml/source -Jexamples/examplewidgets ^
    -L/LIBPATH:C:\Qt\5.15.2\msvc2019_64\lib ^
    Qt5Core.lib Qt5Gui.lib Qt5Widgets.lib ^
    -g -run examples\examplewidgets\main.d

Windows 32-Bit

You can build and run the example programs using dub:

@set DFLAGS="-L/LIBPATH:C:\Qt\5.15.2\msvc2019\lib"
@set PATH=C:\Qt\5.15.2\msvc2019\bin;%PATH%
dub run --compiler=dmd --arch=x86_mscoff :helloworld --build-mode=allAtOnce
dub run --compiler=dmd --arch=x86_mscoff :examplewidgets --build-mode=allAtOnce
dub run --compiler=dmd --arch=x86_mscoff :exampleqml --build-mode=allAtOnce

Alternatively dmd can be used directly:

@set PATH=C:\Qt\5.15.2\msvc2019\bin;%PATH%
dmd -i -m32mscoff -Icore -Igui -Iwidgets ^
    -L/LIBPATH:C:\Qt\5.15.2\msvc2019\lib ^
    Qt5Core.lib Qt5Gui.lib Qt5Widgets.lib ^
    -g -run examples\helloworld\main.d
dmd -i -m32mscoff -Icore -Igui -Iwidgets -Iexamples -Idxml/source -Jexamples/examplewidgets ^
    -L/LIBPATH:C:\Qt\5.15.2\msvc2019\lib ^
    Qt5Core.lib Qt5Gui.lib Qt5Widgets.lib ^
    -g -run examples\examplewidgets\main.d

QObject

Many classes in Qt inherit from QObject. Those classes can define signals and slots, which are special member functions. Signals can be emitted by objects when something changes or happens. Slots allow to react to signals by connecting them. Slots can even run on a different thread than the thread emitting the signal.

Qt uses meta data about classes inheriting from QObject for signals, slots and other functionality. In C++ the classes have to use the macro Q_OBJECT, which declares prototypes for accessing the meta data. The Meta-Object Compiler will then scan the source code and generate the meta data as another source file. DQt uses the string mixins Q_OBJECT and Q_OBJECT_D instead. Q_OBJECT just declares the prototypes like the macro in C++. Q_OBJECT_D also generates the meta data itself using templates and CTFE, but this currently only contains a subset of meta data. Signals and slots are recognized using the UDAs QSlot and QSignal. Signals for classes implemented in D also need an implementation with the mixin Q_SIGNAL_IMPL_D.

Signals can be connected using different options. The first option is to connect a signal of one object to a slot of another object:

QObject.connect(pushButton.signal!"clicked", window.slot!"close");

Classes can also contain multiple signals or slots with the same name, but different parameter types. The connect function tries to find a unique pair of signal and slot with compatible parameter types. If multiple pairs are possible, the ambiguity can be resolved by providing the the parameter types as in obj.signal!("valueChanged", int).

It is also possible to connect a signal to a delegate:

QObject.connect(action.signal!"triggered", obj, (){
    ...
});

The second parameter obj is used to restrict the lifetime of the connection. Once obj is deleted, the connection will be removed. The caller has to ensure, that the GC does not free memory referenced by the delegate.

Signals and slots can also be connected automatically by name for layouts designed in Qt Designer.

Memory management

Objects can be created using normal new or cppnew from core.stdcpp.new. Qt will sometimes automatically delete objects. Those objects have to be created with cpp_new.

Objects created with new are freed by the GC, but the GC can not see references managed by Qt.

Qt Designer

Qt Designer is a program for designing graphical user interfaces for Qt Widgets. It is also integrated in the IDE Qt Creator. The layout is saved in XML files with the extension .ui. For C++ projects they are converted to C++ code as part of the built process. DQt contains the module qt.widgets.ui, which converts them to D code at compile time instead. The file is parsed at compile time with dxml.

The content of the .ui files is accessed using the import expression. It searches for the a file in directories provided with the dmd option -J. Struct UIStruct in module qt.widgets.ui is a template, which gets a filename as template argument. It contains members for all widgets in the .ui file. The member function setupUi initializes all members. As an alternative to UIStruct the function generateUICode can be used to generate D code for the layout, which can be used in a mixin. It is used by UIStruct internally.

Alternatives

For other libraries making Qt available in D see QtE5, dqml or QtD. You can also find other GUI libraries for D here: https://code.dlang.org/?sort=updated&category=library.gui