Was ist neu in Qt 6.10? Ein Überblick für Entwickler

Qt 6.10 ist ein klassisches „Framework‑Release“, das an vielen Stellen nachzieht, wo sich in den letzten Jahren Anforderungen und Best Practices geändert haben: moderneres UI‑Layouten mit Flexbox, stärkere Unterstützung für Vektoranimationen (SVG/Lottie), vereinfachte Datenanbindung zwischen C++ und QML, neue Hilfstypen für Modelle und Bindungen – und dazu ein spürbares Update bei Accessibility und Plattformintegration.

Im Folgenden ein Überblick über die wichtigsten Änderungen von Qt 6.10, auf Basis der offiziellen Release‑Informationen.

Accessibility: High Contrast und Screenreader werden ernster genommen

Qt 6.10 legt sichtbar mehr Wert auf Barrierefreiheit:

  • High‑Contrast‑Mode auf allen Plattformen:
  • Die eingebauten Styles orientieren sich stärker an den jeweiligen System‑Einstellungen für hohen Kontrast.
  • Ziel: Qt‑Apps sollen sich optisch nahtlos in die restliche Oberfläche einfügen und dabei besser lesbar sein.
  • Für dich als Entwickler bedeutet das: Ohne Codeänderung profitierst du von verbessertem Kontrast, wenn Nutzer das systemweit aktivieren.
  • Bessere Integration mit Assistive Technologies:
  • Qt Widgets und Qt Quick Controls wurden überarbeitet, damit Screenreader und andere Hilfsmittel sauberer angesprochen werden.
  • Besonders für WebAssembly gab es Verbesserungen in der Accessibility‑Implementierung.
  • Viele Änderungen fließen auch in LTS‑Branches zurück (Patch‑Releases), sofern du dort aktuell bleibst.

Unterm Strich: Qt 6.10 hilft dir bei der Einhaltung von Accessibility‑Vorgaben, ohne dass du an jeder Ecke Speziallogik schreiben musst.

Qt Quick: FlexboxLayout und moderne UI‑Bausteine

Qt Quick bleibt die Speerspitze für neue UI‑Konzepte. Mit Qt 6.10 kommen unter anderem:

FlexboxLayout (Tech Preview)

  • Neues Layout‑Element FlexboxLayout für Qt Quick, das sich an CSS Flexbox anlehnt.
  • Vorteile:
  • Besseres Verhalten bei unterschiedlich großen Screens und Aspect Ratios.
  • Weniger Custom‑Layoutcode für „responsive“ UIs.
  • Vertraut für alle, die bereits mit Web/CSS arbeiten.
  • Integration:
  • Bindet sich in das bestehende Layout‑System von Qt Quick ein (attached properties etc.).
  • Ist als Technologievorschau gekennzeichnet – API kann sich bis zum nächsten LTS noch ändern.

Animierte Vektorgrafiken (SVG & Lottie)

Qt 6.10 baut konsequent auf den SVG/Vektor‑Verbesserungen der vorherigen Versionen auf:

  • VectorImage (aus 6.8 bekannt) wird erweitert:
  • Unterstützung für animierte Vektorgrafiken in
    • SVG‑Format und
    • Lottie‑Format.
  • Qt Lottie‑Modul:
  • Deutlich verbesserte Unterstützung moderner Lottie‑Dateien.
  • Lottie‑Assets können jetzt als skalierbare, hardwarebeschleunigte Vektorgrafiken direkt im Qt‑Quick‑Scenegraph gerendert werden.

Für UI‑Designer bedeutet das: Aufwendige, aber leichtgewichtige Animationswelten lassen sich direkt aus Design‑Tools (Figma/After Effects → Lottie) in Qt übernehmen.

Neuer Quick Control: SearchField

  • Spezialisierter Eingabebaustein für Suchfelder.
  • Bringt:
  • nativen Look & Feel auf allen Plattformen (wie andere Qt Quick Controls),
  • integrierte Vorschlagsliste mit Modellanbindung.
  • Integration:
  • suggestionModel kann über die üblichen Mechanismen (QAbstractItemModel, Kontextobjekte, QML‑Modelle) befüllt werden.
  • Besonders interessant in Kombination mit den neuen Modell‑/Bindungswerkzeugen (siehe unten).

Einfachere Verbindung zwischen C++‑Daten und QML‑UIs

Ein klassischer Schmerzpunkt in Qt‑Projekten war die Verbindung zwischen C++‑Backend und QML‑UI. Qt 6.10 nimmt sich genau dieser Nähte an.

QRangeModel: C++‑Container direkt als Modell

  • QRangeModel ist eine schlanke QAbstractItemModel‑Implementierung, die C++‑Ranges (z.B. std::vector, std::array, beliebige iterierbare Container) direkt als Modell zur Verfügung stellt.
  • Eigenschaften:
  • Kann einfache Typen (int, QString, …) wie auch komplexe Typen (GADGETs, std::tuple) abbilden.
  • Modellrollen werden automatisch erzeugt.
  • Funktioniert gleichermaßen in Qt Widgets (Views) und in QML/Qt Quick.
  • Beispiel‑Anwendung:
  • std::vector<int> als Liste in einer QML‑ListView,
  • std::vector<MyGadget> als typ‑sicheres Modell in Delegates mit required property.

Damit entfällt für viele Anwendungsfälle das Schreiben eigener QAbstractItemModel‑Subklassen.

delegateModelAccess: Zurückschreiben in das Modell vereinfachen

Bisher war das Schreiben aus einem Delegate zurück in das Modell oft umständlich:

  • Entweder über model‑Objekte im Delegate
  • oder über Kontextproperties und eigene Signal‑Handler.

Mit Qt 6.10 kann eine View über delegateModelAccess: DelegateModel.ReadWrite explizit erlauben, dass required‑Properties im Delegate direkt zurück ins Modell schreiben. Das reduziert Boilerplate deutlich, insbesondere in größeren QML‑UIs.

Synchronizer: Zwei‑ und Mehrwege‑Bindungen

  • Neues Element Synchronizer (Tech Preview, Modul Qt.labs.synchronizer).
  • Zweck:
  • Mehrere Properties so synchron halten, dass sie (so weit möglich) denselben Wert haben, ohne klassische Bindungen zu „brechen“.
  • Funktioniert für Kombinationen von C++‑ und QML‑Eigenschaften.
  • Praxisnutzen:
  • Typische „Slider ↔ Modell‑Wert“‑Szenarien lassen sich deklarativ und ohne zusätzliche Signal‑Handler abbilden.

TreeModel für QML

  • Neues QML‑TreeModel, mit dem sich Baumdaten direkt in QML deklarieren lassen.
  • Zielgruppe:
  • Prototyping,
  • kleinere Datenmengen,
  • Szenarien, in denen ein kompletter C++‑Baummodell‑Layer Overkill wäre.

Zusammen genommen macht Qt 6.10 die Kante zwischen C++‑Backend und QML‑Frontend deutlich angenehmer.

Qt Graphs: FilledSurface und mehr

Qt Graphs wird auch in 6.10 weiter ausgebaut:

  • Neue Diagrammtypen und Anpassungen:
  • u.a. ein neuer „FilledSurface“‑Graph zur besseren Darstellung gefüllter Flächen.
  • Bessere Integration in Qt Quick und die neuen Layout‑/Vektorfeatures.

Wenn du bereits mit Qt Graphs arbeitest, lohnt sich ein Blick in die konkreten Release Notes für dieses Modul.

Sonstige Verbesserungen und Plattform‑Updates

Wie bei jedem Qt‑Release gibt es eine Reihe weiterer Verbesserungen:

  • Plattformintegration:
  • Qt 6.10 richtet sich nach den jeweils aktuellen Versionen der großen Desktop‑, Mobile‑ und Embedded‑Plattformen (siehe Release Note und Wiki‑Seite).
  • Bugfixes und Feinschliff:
  • Dutzende Fehlerkorrekturen in den Untermodulen (Widgets, Quick, Network, etc.).
  • Viele Details lassen sich in den detaillierten Release Notes (6.10.0–6.10.2) nachlesen.

Fazit

Qt 6.10 ist kein „großer Sprung“ im Sinne völlig neuer Konzepte, sondern ein Release, das viele typischen Alltagsbaustellen adressiert:

  • Accessibility wird ernst genommen (High Contrast, Screenreader‑Integration).
  • Qt Quick bekommt mit FlexboxLayout, animierten Vektorgrafiken und SearchField Werkzeuge, die aktuelle UI‑Designs besser abbilden.
  • Die Verbindung zwischen C++‑Daten und QML‑UIs wird durch QRangeModel, delegateModelAccess, Synchronizer und TreeModel deutlich entschärft.

Wer bereits auf Qt 6.x unterwegs ist, sollte Qt 6.10 vor allem dann in Betracht ziehen, wenn:

  • Accessibility und regulatorische Vorgaben eine Rolle spielen,
  • moderne, animierte UIs (Vektor/Lottie) benötigt werden,
  • oder die Brücke zwischen C++‑Backend und QML‑Frontend bislang viel Handarbeit erfordert.

Quellen

  • Qt Blog: Qt 6.10 Released! – https://www.qt.io/blog/qt-6.10-released
  • Qt Wiki: Qt 6.10 Release – https://wiki.qt.io/Qt_6.10_Release
  • Qt Doku: New Features in Qt 6.10 – https://doc.qt.io/qt-6.10/whatsnew610.html

KooKooK: App für neurodivergente Menschen als Testballon

Vor einiger Zeit wollte ich mich mit QML näher auseinandersetzen und suchte nach einer Projektidee. Als Domain hatte ich noch „kookook.org“ bei mir registriert und dachte, dass ich einfach damit was mache. Bei der Projektidee ging es, allen voran, darum, dass ich mich mit dieser Technik auseinandersetzen und mich vor allem auf mobile Plattformen (iOS, Android) konzentrieren wollte.

Ich habe mich entschieden, an einer App für neurodivergente Menschen zu arbeiten, um ein Ziel vor Augen zu haben. Herausgekommen ist jetzt eine kleine App, mit der man seine Stimmungen und Reize tracken kann. Das Programm kann noch nicht viel, aber vielleicht interessiert es jemanden.

Hier sind ein paar Screenshots:

Es gibt auch eine Android-Version, die ist im Google Play Store allerdings noch nicht freigegeben, da ich dafür erst 12 Tester benötige und mir dazu gerade die Zeit fehlt. Wer Lust hat: Gerne per E-Mail an mich, ich schalte die Version dann frei.

Die App ist kostenlos und benötigt keine Internetverbindung.

Unterschiede zwischen Qt und wxWidgets

Qt und wxWidgets sind zwei beliebte Frameworks für die Entwicklung von Benutzeroberflächen, die sich in technischen und Lizenzunterschieden unterscheiden. Technisch gesehen basiert Qt auf einer objektorientierten Architektur mit einem eigenen Meta-Objekt-System (MOC), das Funktionen wie Signale und Slots für die Ereignisbehandlung bietet. Im Gegensatz dazu verwendet wxWidgets eine Wrapper-Architektur, die die nativen APIs der Zielplattform nutzt, was zu Anwendungen führt, die sich stärker an das native Look-and-Feel anpassen. In Bezug auf Programmiersprachen unterstützt Qt hauptsächlich C++, bietet aber auch Bindings für Sprachen wie Python (PyQt/PySide). wxWidgets ist primär für C++ konzipiert, hat aber ebenfalls Bindings für Python (wxPython) und Perl. Beim GUI-Design kommt Qt mit dem leistungsstarken Qt Designer zur visuellen Gestaltung von Benutzeroberflächen, während wxWidgets oft manuelles Codieren der GUI oder den Einsatz von Drittanbieter-Tools erfordert. In Bezug auf die Plattformunterstützung deckt Qt Windows, macOS, Linux sowie Embedded-Systeme und mobile Plattformen (Android, iOS) ab. wxWidgets unterstützt ebenfalls Windows, macOS und Linux, hat aber eingeschränkte Unterstützung für mobile Geräte.

In Bezug auf die Lizenzierung ist Qt unter GPL, LGPL und kommerziellen Lizenzen lizenziert. Die GPL erfordert die Offenlegung des Quellcodes von abgeleiteten Werken, während die LGPL eine flexiblere Nutzung ermöglicht, insbesondere für proprietäre Software, wenn dynamische Verlinkung verwendet wird. Unternehmen können auch eine kommerzielle Lizenz erwerben, um diese Einschränkungen zu umgehen. wxWidgets wird unter der wxWidgets-Lizenz veröffentlicht, die sehr liberal ist und ähnlich wie die LGPL funktioniert. Sie erlaubt die Entwicklung von sowohl Open-Source- als auch proprietärer Software, ohne die Notwendigkeit, den Quellcode offenzulegen.

Zusammenfassung der Unterschiede

  • Architektur:
    • Qt: Objektorientiert mit MOC, Signale und Slots.
    • wxWidgets: Wrapper-Architektur, nutzt native APIs.
  • Programmiersprachen:
    • Qt: Hauptsächlich C++, Bindings für Python und andere.
    • wxWidgets: Primär C++, Bindings für Python und Perl.
  • GUI-Design:
    • Qt: Qt Designer für visuelle Gestaltung.
    • wxWidgets: Oft manuelles Codieren oder Drittanbieter-Tools.
  • Plattformunterstützung:
    • Qt: Windows, macOS, Linux, Embedded, mobile (Android, iOS).
    • wxWidgets: Windows, macOS, Linux, eingeschränkte mobile Unterstützung.
  • Lizenz:
    • Qt: GPL, LGPL, kommerziell.
    • wxWidgets: Liberale wxWidgets-Lizenz, ähnlich LGPL.

Bald neue Videos

Viele haben mir geschrieben, dass ich doch weitere Videos bzw. Tutorials machen soll. Das freut mich sehr.

Zur Zeit nimmt mich die neue Arbeitstelle und meine Familie gut ein, ich habe aber schon die nächsten Videos geplant (Themen: wxWidgets, Qt und auch FreeBSD) und freue mich, sie bald machen und veröffentlichen zu können. Es dauert allerdings noch ein paar Tage. Aber: Es wird mit den Tutorials weiter gehen.

Wenn ihr Vorschläge für bestimmte Themen habt, gerne her damit.

KooKooK (Update 4): Die Authentifizierung im Einzelnen

Vielleicht interessiert es den ein oder anderen, wie ich die Authentifizierung durchführe. Mich würde unbedingt Eure Meinungen interessieren.

Ziel war es, dass man nicht Benutzername und Kennwort über die Leitung zum Server zur Verifizierung überträgt, da ich das für unsicher halte. Ich habe es erst einmal so gelöst:

  1. Client verbindet sich zum Server
  2. TLS-Handshake
  3. Server sendet Welcome-Message an Client. Die Welcome-Message besteht aus der Versionsnummer des Servers sowie einer UUID, getrennt mit einem Doppelpunkt (1.0.1:8234-234-234-234)
  4. Der Client trennt die empfangene Versionsnummer von der UUID anhand des Doppelpunkts
  5. Der Benutzer hat am Client den Benutzernamen und das Kennwort eingegeben
    1. Das Kennwort wird mit MD5 gehasht
    2. Benutzername, UUID und gehashtes Kennwort wird als Bytearray zusammengefasst und mit Keccak_512 gehasht
    3. Daraus entsteht dann das Bytearray, was zum Server geschickt werden soll
  6. Das gehashte Bytearray mit vorangestelltem Benutzername@ wird zum Server geschickt (ausgedachtes Beispiel: thorsten@ljdf08asdflu0dsa98foklj234ASDF)
  7. Der Server hat jetzt den unverschlüsselten Benutzernamen, der eindeutig in der Datenbank ist und zieht das Kennwort, fügt auch alles zusammen und hasht dann das Bytearray
  8. Der Server vergleicht, ob das empfangene Bytearray gleich dem selbst generiertem Bytearray ist. Ja = Der Benutzer ist eingeloggt, Nein = Der Benutzer ist nicht eingeloggt

Anmerkungen: In der Implementierung werden weitere Fehler behandelt und zurückgeliefert. Beispielsweise, ob der Benutzer überhaupt vorhanden ist, ob der Hash gebildet wurde, usw. Was noch fehlt ist, ob der Benutzer auch (in der Datenbank) auf aktiv steht.

Ihr könnt das in folgenden Dateien nachvollziehen:

Mitunter sollte man weitergehen und zum Beispiel auch den Benutzernamen nicht im Klartext senden?

KooKooK (Update 3): Umbauten und weitere Informationen

Ich habe mich doch entschieden, einige Umbauten durchzuführen. Zunächst wollte ich den Server eigentlich pro Verbindung mit einem Thread laufen lassen. Das hat direkt, für ein Hobbyprojekt mit wenig Zeit, viele Probleme aufgeworfen.

Von Threads

Vor allem sind die Dateideskriptoren auf unterschiedlichen Betriebssystemen unterschiedlich konfiguriert, aber doch teils sehr limitiert. Ich wollte auf meinem Mac mal eben 500 Verbindungen aufbauen, bei 80 oder so war Schluss. Man kann das Limit zwar höher schrauben, aber man ist natürlich durchaus limitiert.

Dann gab es noch Probleme mit dem Verschieben von Objekten innerhalb von Qt zu Threads. Neue erstellte Objekte liefen nicht im Thread, sondern Hauptthread. Das kann man alles recht problemlos fixen, indem man mit Workerprozessen arbeitet, aber ich wollte da nicht weiter herumbauen (zeitliche Einschränkung), da ich vorwärts kommen wollte. Aber interessant: Ich habe mal 500 Konnektierungen gleichzeitig startet (so gleichzeitig, wie es nur geht). Das hat auf meinem Mac 200ms (etwas darunter) benötigt, um auf 500 Verbindungen ein „Hallo Welt“ über das Loopback-Device zu senden. War zwar nur Loopback, aber ich war doch erstaunt, wie schnell es geht, so viele Threads zu öffnen, was zu schicken und wieder zu schließen.

Keine Threads mehr

Dann habe ich einfach mit generellen nonblocking Sockets herumgespielt (im Thread waren sie auch nonblocking!) und festgestellt, dass es von der Geschwindigkeit her für einige hundert Verbindungen ausreichen sollte, zumal man nicht sonderlich viele Informationen senden muss und diese ja auch noch komprimieren kann. Also habe ich alles umgebaut.

Benutzerauthentifizierung

Ich habe das tatsächlich so ähnlich, wie im vorherigen Blogeintrag, implementiert. Letztlich ist es so: Der Client macht eine Authentifizierungsanforderung an den Server. Der Server kennt den Benutzernamen und schickt eine UUID. Dann werden die Benutzerinformationen mit der UUID zusammengefasst und gehasht, zurückgeschickt, der Server macht das selbe und vergleicht beide Ergebnisse. Sind sie gleich, gilt der Benutzer als eingeloggt.

Weiteres

Weiterhin habe ich noch Datenbankabstraktionen implementiert für MySQL, PostgreSQL und SQLite, damit man Benutzer speichern kann. Ein Logging habe ich implementiert und dem Server kann man Signale schicken, um ihn zu beenden oder sonst was zu tun. Es gibt einen Testclient unter resources/sslclient, mit dem man mit dem Server ein wenig spielen kann.

Hier geht es übrigens zum GitHub-Repo.

KooKooK (Update 2): Überlegungen zur Benutzerauthentifizierung

Benutzer sollen sich am System anmelden können. Ich dachte mir, die speichern wir einfach in einer relationalen Datenbank, da Qt dafür schon Bibliotheken mitbringen (MySQL, PostgreSQL, SQLite). Welches DBMS wir nehmen, weiß ich noch nicht.

Dennoch muss die Benutzerauthentifizierung ja implementiert werden. Naiv könnte man das so machen:

  1. Client schickt Benutzernamen und Kennwort an Server
  2. Server prüft per Datenbank Benutzernamen und Kennwort
  3. Server gibt OK oder NK zurück

Jetzt will ich aber, wenn auch verschlüsselt, keinen Benutzernamen und kein Kennwort einfach durch die Gegend schicken. Meine Idee war folgende:

  1. Auf dem Server sind Benutzername und Kennwort in der Datenbank hinterlegt, wobei das Kennwort gehasht ist
  2. Client meldet sich bei Server, dass er sich authentifizieren will
  3. Server schickt einen einfache String (z.B. eine UUID) an den Client
  4. Der Client hasht sein Kennwort in der selben Weise, wie der Server, und fügt im String Benutzernamen und Kennwort zusammen (thorstenAdsfjlksudSDFAalsj)
  5. Mit dem zusammengefügten Benutzernamen und gehashten Kennwort verschlüsseln wir den vom Server geschickten String (z.B. die UUID)
  6. Den verschlüsselten String schicken wir an den Server zurück
  7. Der Server prüft den verschlüsselten String mit seinem eigenen (er macht das selbe online)
  8. Der Server gibt OK oder NK zurück

Was haltet ihr davon? Eine gute Idee? Hat jemand eine bessere?

KooKooK (Update 1): Ein paar Implementierungen ohne Video

Ich habe überlegt: ich kann leider nicht alles zu dem Projekt aufnehmen. Ich habe noch ein paar Erweiterungen gemacht. Was alles, seht ihr im GitHub-Projekt.

Hier eine Liste:

  • Über die Server.ini kann man den Server jetzt teils konfigurieren
  • Einfaches Logging wurde eingebaut
  • Threads können beendet werden
  • Kompilierungsscript wurde erweitert
  • Unix-Signal-Handling wurde implementiert (TERM und HUP)

Schreibt mir gerne bei Fragen und Anregungen.

Qt-Tutorial 041: Settings (Konfigurationsdateien speichern und laden)

Dieses Video zeigt, wie einfach es ist, mit Qt Konfigurationsdateien zu speichern und zu laden. Dazu benutze ich QSettings.

Settings (Konfigurationen)
Settings (Konfigurationen)

Hier der Beispielcode:

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QSettings>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
	: QMainWindow(parent)
	, ui(new Ui::MainWindow)
{
	ui->setupUi(this);

	QCoreApplication::setApplicationName("YouTube-Tutorial");
	QCoreApplication::setOrganizationName("DynSoft");
	QCoreApplication::setOrganizationDomain("dynsoft.com");
}

MainWindow::~MainWindow()
{
	delete ui;
}

void MainWindow::log()
{
	ui->logPlainTextEdit->appendPlainText("");
}

void MainWindow::log(const QString &message)
{
	ui->logPlainTextEdit->appendPlainText(message);
}

void MainWindow::log(const QString &prefix, const QString &message)
{
	ui->logPlainTextEdit->appendPlainText(prefix + ": " + message);
}


void MainWindow::on_savePushButton_clicked()
{
	//QSettings settings("C:\\Users\\thorsten\\Desktop\\Tutorial.ini", QSettings::IniFormat);
	//QSettings settings("DynSoft", "QtTutorialSettings");
	QSettings settings;

	settings.setValue("Window/PositionX", pos().x());
	settings.setValue("Window/PositionY", pos().y());
	settings.setValue("Window/Width", size().width());
	settings.setValue("Window/Height", size().height());
	settings.setValue("Window/Size", size());

	settings.beginGroup("UserSettings");
	settings.setValue("Username", "Thorsten");
	settings.endGroup();
}


void MainWindow::on_loadPushButton_clicked()
{
	//QSettings settings("C:\\Users\\thorsten\\Desktop\\Tutorial.ini", QSettings::IniFormat);
	//QSettings settings("DynSoft", "QtTutorialSettings");
	QSettings settings;

	log("Window");
	log("PositionX", settings.value("Window/PositionX").toString());
	log("PositionY", settings.value("Window/PositionY").toString());
	log("Width", settings.value("Window/Width").toString());
	log("Height", settings.value("Window/Height").toString());
	qDebug() << settings.value("Window/Size").toSize();

	log();

	log("UserSettings");
	settings.beginGroup("UserSettings");
	log("Username", settings.value("Username").toString());
	settings.endGroup();
}

Hier geht es zum Video.