Über dieses Handbuch
Dieses Projekt ergänzt die API-Dokumentation zur Qwt-Bibliothek und bietet sowas wie ein Programmiererhandbuch mit vielen Details zu den Internas der Bibliothek. Der Fokus liegt aber ganz klar auf der QwtPlot
Diagrammkomponente.
Das ist übrigends schon die 2. Auflage (komplett neu überarbeitet), weil es zum Zeitpunkt der ersten Ausgabe noch kein tolles AsciiDoc gab und ich irgendwie beim Textschreiben hängengeblieben bin.
Die Texte und Bilder stehen unter der Creative-Commons BY-NC Lizenz (siehe Lizenztext im Qwt Handbuch Repository https://github.com/ghorwin/QwtBook), können also frei verwendet, modifiziert und angepasst werden, aber bitte nicht publiziert oder zum Training von kommerziellen KI-Systemen benutzt werden. Alle Quelltextbeispiele, sowohl im Text, als auch in den herunterladbaren Tutorial/Beispiel-Quelltextarchiven, stehen unter der MIT-Lizenz und können damit in open-source wie auch kommerziellen Projekten genutzt werden.
Häufig wird das |
Viel Spaß bei der Lektüre - und falls noch Inhalte fehlen, einfach Geduld haben und später wiederkommen (oder im Github-Repo ein Issue anlegen). Und schaut Euch vielleicht auch meine anderen Tutorials unter https://schneggenport.de an!
— Andreas Nicolai
1. Überblick über die Qwt Bibliothek
Qwt - Qt Widgets for Technical Applications ist eine Open-Source Bibliothek für technische Anwendungen und stellt
bestimmte Widgets für Anzeigen und Kontrollkomponenten bereit. Die wohl wichtigste Komponente der Qwt Bibliothek ist das QwtPlot
,
eine sehr flexible und mächtige Diagrammkomponente.

Die Qwt Bibliothek steht unter einer Open-Source-Lizenz, wurde und wird aktiv vom Entwickler Uwe Rathmann gepflegt und wird auf SourceForge.net gehostet:
1.1. Entwicklungsgeschichte
-
die erste Version der Qwt-Bibliothek stammt noch aus dem Jahr 1997 von Josef Wilgen
-
seit 2002 wird die Bibliothek von Uwe Rathmann entwickelt und gepflegt
-
Version 5 ist wohl am weitesten verbreitet (erstes Release vom 26.02.2007)
-
Version 6 (erstes Release vom 15.04.2011, kein Qt3 Support mehr) enthält wesentliche API-Änderungen
-
aktuelle stabile Version 6.3.0 (Stand Mai 2025)
-
im trunk gibt es zum Teil bereits wesentlich mehr und fortgeschrittene Funktionen
1.1.1. Download der Bibliothek
Die Qwt Bibliothek kann von der Qwt SourceForge Projektseite als Quelltextarchiv geladen werden. Unter Linux wird Qwt bei vielen Distributionen als Paket gehalten. Genau genommen gibt es mehrere Pakete für die unterschiedlichen Qwt-Bibliotheksversionen bzw. Qt Versionen. Details zur Installation und Verwendung der Bibliothek gibt es im Kapitel 13.
1.2. Widget-Konzept und Erscheinungsbild
Die Qwt Bibliothek liefert Komponenten, welche analog zu den normalen Qt-Widgets in Desktopanwendungen verwendet werden können. Die Komponenten verwenden die Qt Palette, sodass die Qwt-Widgets in die jeweilige Oberfläche passen. Dadurch integrieren sich die Widgets nahtlos in Programmoberflächen. Einzelne Komponenten des QwtPlot
unterstützen auch Styles. So ermöglichen z.B. Abrundungseffekte beim Plot-Widget das Immitieren klassischer Anzeigen.

Details zum Styling und zur Anpassung des Erscheinungsbildes sind im Kapitel 10 zu finden.
1.3. Besitzer/Eigentümer-Konzept des QwtPlot-Widgets
Eine grundlegende Eigenschaft der QwtPlot
-Klasse ist die Besitzübername hinzugefügter Elemente. Dies gilt allgemein für alle Elemente des Plots (Linien, Marker, Legende, …). D.h. nach Übertragung der Eigentümerschaft kümmert sich das QwtPlot
um das Aufräumen des Speichers.
Einmal hinzugefügte Elemente werden nicht wieder losgelöst werden (bzw. nur über einen Trick, wie im Kapitel 12.1 beschrieben wird). Daher ist es sinnvoll, bei veränderlichen Diagrammelementen einen Mechanismus zur jeweiligen Neuerstellung eines Zeichenobjekts vorzusehen (Factory-Konzept).
1.4. Zeichenobjekte und deren Achsenabhängigkeit
Ein wesentliches Designmerkmal beim QwtPlot
ist die Möglichkeit, beliebige Zeichenobjekte (Kurven, Marker, Legende, …) dem Plot zu übergeben. Damit sich diese Zeichenobjekte (engl. PlotItem) am Koordinatengitter ausrichten können, wird ihnen eine Achsenabhängigkeit gegeben. Dadurch erhalten diese Zeichenobjekte eine Information, wann immer sich die Achsenskalierung ändert (durch Zoomen, oder Änderung der Wertebereiche etc.).
Diese Funktionalität definiert die zentrale Bedeutung der (bis zu) 4 Achsen im Diagramm. Deswegen sind diese auch fest im QwtPlot
verankert und werden nicht wie andere Zeichenobjekte beliebig hinzugefügt.
1.5. Vererbungskonzept
Grundsätzlich ist das QwtPlot
und die beteiligten Klassen auf maximale Anpassungsfähigkeit ausgelegt, d.h. es wird (fast) überall Polymorphie unterstützt. Wenn die eingebaute Funktionalität nicht zureichend ist, kann man einfach immer die entsprechende Klasse ableiten und die jeweils anzupassende Funktion re-implementieren und verändern. Dies wird anhand von Beispielen in den individuellen Kapiteln des Handbuchs beschrieben.
1.6. Verwendung der Designer Plugins
Die Qwt Bibliothek bringt Plugins für QtDesigner mit, welche das Einfügen von Qwt-Komponenten in ui-Dateien erleichtert. Es lassen sich jedoch keine QwtPlot-Eigenschaften festlegen oder Kurven hinzufügen. Die eigentliche Anpassung und Ausgestaltung des Plots erfolgt im Quelltext. Deswegen wird die Konfiguration und Anpassung des QwtPlot
in diesem Handbuch ausschließlich durch normale API-Aufrufe demonstriert.
Soll das |
Eine Beschreibung, wie die Designer-plugins erstellt und in Qt Creator/Designer integriert werden ist im Kapitel 13.3 beschrieben.
2. Erste Schritte und ein interaktives Diagramm
Um mit der Qwt-Bibliothek warm zu werden, erstellen wir in einem einfachen Beispiel ein interaktives Diagramm mit der QwtPlot
-Komponente.
Der komplette Beispielquelltext ist als 7z-Archiv herunterladbar: tutorial1.7z
2.1. Programmrohbau
2.1.1. QMake Projektdatei
Wir beginnen mit der qmake-Projektdatei, in der wir den Pfad für die Header-Dateien der Bibliothek und die zu linkende Bibliothek festlegen. Hier gehe ich davon aus, dass Qwt aus dem 6.3.0er Quelltextarchiv gebaut und lokal in die Standardverzeichnisse (C:\qwt-6.3.0
unter Windows und /usr/local/qwt-6.3.0
unter Linux/Mac) installiert wurde. Infos über das Compilieren der Bibliothek aus dem Quelltext und Installation gibt es in Kapitel 13.
TARGET = Tutorial1
QT += core gui widgets
CONFIG += c++11
win32 {
# Pfad zu den Qwt Headerdateien hinzufügen
INCLUDEPATH += C:/qwt-6.3.0/include
CONFIG(debug, debug|release) {
QWTLIB = qwtd
}
else {
QWTLIB = qwt
}
# Linkerpfad
LIBS += -LC://qwt-6.3.0/lib -l$$QWTLIB
}
else {
# Pfad zu den Qwt Headerdateien hinzufügen
INCLUDEPATH += /usr/local/qwt-6.3.0/include/
# Linkerpfad, unter Linux wird standardmäßig nur die release-Version der Lib gebaut und installiert
LIBS += -L/usr/local/qwt-6.3.0/lib -lqwt
}
SOURCES += main.cpp
Dies ist eine .pro
-Datei für eine Qwt-6.3.0-Installation aus dem Quelltext mit Standardeinstellungen (siehe Kapitel 13.2).
Beachte, dass die im Debug-Modus kompilierte Qwt-Bibliothek ein angehängtes d hat. Unter Linux wird standardmäßig nur die release-Version gebaut und installiert, daher braucht man hier die Fallunterscheidung nicht. |
2.1.2. Minimalistisches Hauptprogramm
Für die Verwendung des QwtPlot
braucht man nur eine sehr minimalistische main.cpp
.
#include <QApplication>
#include <QwtPlot>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QwtPlot plot;
plot.resize(800,500);
plot.show();
return a.exec();
}
Wenn man das Programm compiliert hat und ausführen will, beklagt sich Windows über eine fehlende DLL.
Dazu in den Projekteinstellungen, unter "Ausführen", im Abschnitt "Umgebung" die PATH-Variable bearbeiten und dort den Pfad |
Das Programm zeigt ein ziemlich langweiliges (und hässliches) Diagrammfenster (später wird das noch ansehnlicher gestaltet).

Ein Hinweis zu den Header-Dateien der Qwt-Bibliothek. Analog zu Qt Klassen werden die Qwt-Klassen über den gleichnamigen Header eingebunden, also:
Diese Header-Dateien sind aber nur Wrapper um die eigentlichen Include-Dateien, mit dem Benennungsschema:
In früheren Versionen der Qwt-lib (auch der Debian-Paket-Version |
2.2. Diagrammelemente hinzufügen
2.2.1. Linie hinzufügen
Als erstes fügen wir eine Linie bzw. Diagrammkurve hinzu (Header QwtPlotCurve
bzw. qwt_plot_curve.h
):
#include <QApplication>
#include <QwtPlot>
#include <QwtPlotCurve>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QwtPlot plot;
plot.resize(500,300);
// etwas Abstand zwischen Rand und Achsentiteln
plot.setContentsMargins(8,8,8,8);
// Hintergrund der Zeichenfläche soll weiß sein
plot.setCanvasBackground( Qt::white );
// Daten zum Darstellen einlesen
QVector<double> x, y;
QFile f("spektrum.tsv"); // Datei enthält 2 Spalten
f.open(QFile::ReadOnly);
QTextStream strm(&f);
strm.readLine(); // Kopfzeile überspringen
while (!strm.atEnd()) {
double xval, yval;
strm >> xval >> yval;
x.append(xval);
y.append(yval);
}
QwtPlotCurve *curve = new QwtPlotCurve();
curve->setPen(QColor(180,40,20), 0);
curve->setTitle("Gamma-Spektrum");
curve->setRenderHint( QwtPlotItem::RenderAntialiased, true ); // Antialiasing verwenden
curve->setSamples(x, y);
curve->attach(&plot); // Plot takes ownership
plot.show();
return a.exec();
}
Im erweiterten Hauptprogramm wird zunächst der Header für die QwtPlotCurve
eingebunden. Das Kurvenobjekt selbst wird mit new
auf dem Heap erstellt. Die Daten der Kurve lesen wir aus einer Textdatei (2 Spalten, mit Kopfzeile) aus. Die Datei spektrum.tsv
ist im Archiv des Tutorialquelltextes enthalten.
Grundsätzlich gilt beim |
Attribute wie Linienfarbe, Titel (wird später in der Legende angezeigt), und Antialising werden gesetzt (im Kapitel 4 werden alle Eigenschaften von Linien im Detail erläutert).
Die Funktion setSamples()
setzt die Daten der Linie. Wichtig ist hier, dass die übergebenen Vectoren die gleiche Länge haben. Es handelt sich um eine parametrische Kurve, d.h. weder x noch y Werte müssen monoton sein oder sonstwelchen Regeln folgen. Jedes x,y Wertepaar definiert einen Punkt und diese Punkte werden mit der Linie verbunden.
Die Funktion attach()
fügt das QwtPlotCurve
-Objekt zum Diagramm hinzu.
Beim Hinzufügen der Linie mittels |
Zusätzlich zu dem Code, welcher die Linie hinzufügt, wurden noch 2 kleine Anpassungen am Erscheinungsbild vorgenommen:
-
Ränder wurden mittels
setContentsMargins()
hinzugefügt (siehe auchQWidgdet::setContentsMargins()
) -
der Hintergrund der Zeichenfläche (canvas) wurde weiß gefärbt.
Das Ergebnis sieht schon eher nach Diagramm aus.

2.2.2. Legende hinzufügen
Als nächstes wird eine Legende eingefügt (Header QwtLegend
bzw. qwt_legend.h
):
// Legende anzeigen
QwtLegend * legend = new QwtLegend();
QFont legendFont;
legendFont.setPointSize(8);
legend->setFont(legendFont);
plot.insertLegend( legend , QwtPlot::BottomLegend); // plot takes ownership
Auch hier wird oben wieder der Header für die Klasse QwtLegend
eingebunden.
Die Legende bekommt hier noch einen veränderten Font. Das weitere Anpassen der Legende wird in Kapitel 5 beschrieben.
Die Legende kann links, rechts, oberhalb oder unterhalb der Zeichenfläche liegen, oder in der Zeichenfläche selbst. Die Platzierung wird beim Aufruf von insertLegend()
festlegegt.
Das Plot nimmt beim Aufruf von insertLegend()
wiederum Besitz vom Legendenobjekt und kümmert sich um das Aufräumen des Speichers.
2.2.3. Diagrammtitel hinzufügen
// Titel hinzufügen
QwtText text("Gamma-Spektrum");
QFont titleFont;
titleFont.setBold(true);
titleFont.setPointSize(10);
text.setFont(titleFont);
plot.setTitle(text);
Die Klasse QwtText
(Header QwtText
bzw. qwt_text.h
) kapselt einen QString und ergänzt Funktionalität zum Rendern von mathematischen Symbolen mittels MathML (siehe Kapitel 8.1).
2.2.4. Diagrammraster hinzufügen
Gitterlinien werden durch das Zeichenobjekt QwtPlotGrid
gezeichnet (Header QwtPlotGrid
bzw. qwt_plot_grid.h
):
// Haupt- und Nebengitter anzeigen
QwtPlotGrid *grid = new QwtPlotGrid();
QPen gridPen(Qt::gray);
gridPen.setStyle(Qt::DashLine);
grid->setMajorPen(gridPen);
// Minor grid
grid->enableYMin( true );
gridPen.setColor(Qt::lightGray);
gridPen.setStyle(Qt::DotLine);
grid->setMinorPen(gridPen);
grid->attach( &plot ); // plot takes ownership
Das Raster selbst kann hinsichtlich der Stifts (QPen) für das Haupt- und Nebengitter angepasst werden. Die Funktion enableYMin()
schaltet das Nebengitter für die Y-Achse ein.
Wie auch bei den Plotkurven übergibt attach()
das QwtPlotGrid
Objekt an das QwtPlot
, welches sich dann um die Speicherverwaltung kümmert.
Ein Raster wird standardmäßig an eine x- und y-Achse gebunden, wobei man aber auch die Gitterlinien für eine der Achsen ausblenden kann. Wenn man z.B. ein Diagramm mit 2 y-Achsen hat und für jede ein Gitterraster anzeigen möchte (auch wenn das meistens verwirrend aussieht), dann braucht man zwei |
Inzwischen sieht das Diagramm schon ganz ansehnlich aus.

2.2.5. Achsenkonfiguration
Das QwtPlot
hat 4 Achsen eingebaut, genannt:
-
QwtPlot::yLeft
undQwtPlot::yRight
-
QwtPlot::xBottom
undQwtPlot::xTop
Standardmäßig sind die Achsen xBottom
und yLeft
sichtbar, wie im bisher verwendeten Plot.
Jedes Zeichenelement im Plot (Kurven, Marker, …) wird einer oder mehrerer Achsen zugeordnet. In unserem Einführungsbeispiel verwendet die QwtPlotCurve
standardmäßig die Achsen xBottom
und yLeft
.
Die Achsen können wie folgt konfiguriert werden.
// Achsen formatieren
QFont axisFont;
axisFont.setPointSize(8);
axisFont.setBold(true);
QFont axisLabelFont;
axisLabelFont.setPointSize(8);
// X-Achse
QwtText axisTitle("Kanal");
axisTitle.setFont(axisFont);
// Titel Text und Font setzen
plot.setAxisTitle(QwtPlot::xBottom, axisTitle);
// Font für Achsenzahlen setzen
plot.setAxisFont(QwtPlot::xBottom, axisLabelFont);
// Y-Achse
axisTitle.setText("Ereignisse");
plot.setAxisTitle(QwtPlot::yLeft, axisTitle);
plot.setAxisFont(QwtPlot::yLeft, axisLabelFont);
Der Titel jeder Achse wird wiederum über ein QwtText
-Objekt (enthält Text und Font) gesetzt.
Der Font für die Zahlen an den Achsen selbst wird über setAxisFont()
geändert.
Die Achsen selbst lassen sich vielfältig anpassen, siehe Kapitel 7.

Die Achsen passen sich standardmäßig automatisch an den Wertebereich der angezeigten Kurven an. Das kann man natürlich auch ändern, siehe Kapitel 7.
2.2.6. Logarithmische Achsen
Das QwtPlot
kann auch logarithmische Achsen verwenden. Dazu muss man eine anderen Skalenberechnungsklasse einbinden, die QwtLogScaleEngine
(Header QwtLogScaleEngine
bzw. qwt_scale_engine.h
):
// Logarithmische Y-Achse
QwtLogScaleEngine * logScale = new QwtLogScaleEngine();
plot.setAxisScaleEngine(QwtPlot::yLeft, logScale); // plot takes ownership
// manuelle Achsenlimits festlegen, da autoscale bei log-Achsen nicht sinnvoll funktioniert
plot.setAxisScale(QwtPlot::yLeft, 1e-3,1000);
Beim Aufruf von setAxisScaleEngine()
nimmt das Plot wiederum das Objekt in Besitz und kümmert sich dann um das Speicheraufräumen.
Kapitel 7 beschreibt die Details der ScaleEngine und gibt weitere Beispiele.

2.2.7. Markierungslinien
Ein weiteres Zeichenelement, das man hin und wieder braucht, sind horizontale oder vertikale Markierungslinien. Beispielhaft fügen wir eine solche Linie mal dem Plot hinzu (Header QwtPlotMarker
bzw. qwt_plot_marker.h
):
// Vertikale, gestrichelte Plot-Markierung einfügen
QwtPlotMarker * marker = new QwtPlotMarker("207,50 keV");
marker->setLabelOrientation(Qt::Vertical); // Vertikale Linie
marker->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom); // Label unten und rechts von der Linie
marker->setValue(36, 0); // bei vertikalen Linien muss die x-Koordinate festgelegt werden
QPen markerPen(QColor(40,60,255));
markerPen.setStyle(Qt::SolidLine);
marker->setLinePen(markerPen);
marker->setLineStyle(QwtPlotMarker::VLine);
marker->setLabel(QwtText("207,50 keV"));
marker->attach(&plot); // plot takes ownership
Auch bei den Markern gibt es vielfältige Einstellungsmöglichkeiten, siehe Kapitel 6.

Nun ist das Diagramm selbst fertig und wir widmen uns der Nutzerinteraktion.
2.3. Interaktion mit dem Diagramm
Das QwtPlot
bietet die üblichen Interaktionsmöglichkeiten für den Anwender, wie z.B. Herein- und Herauszoonmen, oder Verschieben des Plotausschnitts.
2.3.1. Zoomfunktionalität mit QwtPlotZoomer
Die Zoom-Funktionalität wird über die Klasse QwtPlotZoomer
hinzugefügt (Header QwtPlotZoomer
bzw. qwt_plot_zoomer.h
):
// Zoomer hinzufügen
// Achtung: NICHT QwtPlot selbst als 3 Argument übergeben, sonder das canvas()
QwtPlotZoomer * zoomer = new QwtPlotZoomer(QwtPlot::xBottom, QwtPlot::yLeft, plot.canvas()); // plot takes ownership
zoomer->setTrackerMode( QwtPlotPicker::AlwaysOn ); // Kurvenvwerte unterm Cursor anzeigen
Wenn man mit der Maus über das Diagramm fährt, sieht man bereits einen veränderten Cursor und dank des Aufrufs setTrackerMode(QwtPlotPicker::AlwaysOn)
sieht man nun auch die x- und y-Werte (des Achsen xBottom
und yLeft
) unter dem Cursor.
Hineinzoomen kann man, indem man die Linke Maustaste gedrückt hält, und ein Zoom-Rechteck aufzieht. Das kann man auch mehrmals hintereinander machen. Das QwtPlot
merkt sich intern diese Zoomstufen. Herauszoomen kann durch Klick auf die rechte Maustaste, wobei immer eine Zoomstufe hinausgezoomt wird.
Die äußerste Zoomstufe wird im Konstruktor der |
Im Quelltext gibt es noch eine Besonderheit. Während die bisherigen Plotelemente immer mit Memberfunktionen der QwtPlot
-Klasse hinzugefügt wurde, bzw. mittels attach()
, wird das Zoomerobjekt analog zu Qt Klassen als Kindobjekt der Zeichenfläche gegeben und registriert sich darüber als interaktives Element bei Plot.
Es ist wichtig darauf zu achten, dass man beim Konstruktor der Klasse Im Konstruktor der |
Damit der Zoomer weiß, welche Achsen beim Zoom manipuliert werden sollen, muss man die x- und y-Achse im Konstruktor angeben. Möchte man z.B. beide y-Achsen gleichzeitig zoomen, braucht man zwei QwtPlotZoomer
-Objekte.

2.3.2. Plotausschnitt verschieben mit QwtPlotPanner
Wenn man Ausschnitt eines hineingezoomten Plots interaktiv verschieben möchte, kann man den QwtPlotPanner
hinzufügen (Header QwtPlotZoomer
bzw. qwt_plot_zoomer.h
):
// Panner hinzufügen, wie auch beim PlotZoomer muss das Canvas-Objekt als Argument übergeben werden
QwtPlotPanner * panner = new QwtPlotPanner(plot.canvas()); // plot takes ownership
panner->setMouseButton(Qt::MidButton); // Mittlere Maustaste verschiebt
Wie beim QwtPlotZoomer
wird das Objekt als Kindobjekt des Canvas-Widgets hinzugefügt. Üblich ist das Verschieben von Bildschirminhalten mit gedrückter mittlerer Maustaste, also legt man das mit setMouseButton()
fest.
Damit ist das Einstiegstutorial beendet. Mit dem QwtPlot
kann man bereits mit wenigen Handgriffen ein voll funktionsfähiges und interaktives Diagramm erstellen. In diesem Tutorial war das QwtPlot
gleichzeitig das Anwendungs-Widget. Wenn man das QwtPlot
aber in bestehende Designer-Formularklassen einfügen will, gibt es verschiedene Techniken:
-
die Verwendung von Platzhalter-Widgets
-
die Einbindung von Qt Designer Plugins für die Qwt Bibliothek
Diese Methoden sind in Kapitel 13.5 beschrieben.
3. QWT Widgets und Eingabekomponenten
Neben dem QwtPlot
gibt es in der Qwt-Bibliothek noch eine Reihe anderer Eingabekomponenten, die in diesem Kapitel kurz vorgestellt werden.
Viele dieser Komponenten sind klassischen Anzeigen und Einstellrädern in wissenschafltlich/technischen Geräten nachempfunden.
Für die Anzeige der Skalen verwenden die nachfolgend vorgestellten Komponenten intern zur Darstellung der Skalen die in [sec::axisScales] näher beschriebenen Skalenberechnungs- und -zeichenklassen.
3.1. Schieberegler (Slider)
Die Klasse QwtSlider
erlaubt die Darstellung verschiedener Schieberegler, welche mit der Maus oder Tastatur (Cursortasten) bedient werden können. Im Gegensatz zur QSlider
Klasse können die Skalen viel flexibler und auch nichtlinear definiert werden.

QwtSlider
Das Beispiel im Screenshot oben ist in der Qwt-Bibliothek als Beispiel controls
enthalten.
3.2. Drehräder/Einstellräder und
Die Klasse QwtWheel
zeigt ein horizontales oder vertikales Einstellrad. Die Klasse QwtThermo
zeigt eine Balkenanzeige, allerdings mit einer flexibel hinterlegbaren Farbtabelle. Dies erlaubt z.B. Farbverläufe oder Farbsprünge bei Übersteigen bestimmter Schwellwerte.
Qt selbst bietet für eine Balkenanzeige die Klasse QProgressBar
an, welches sich aber im Erscheinungsbild an den jeweiligen Plattformstil für Fortschrittsbalken orientiert und auch keine Skalen bietet.

QwtWheel
und QwtThermo
Das Beispiel im Screenshot oben ist in der Qwt-Bibliothek als Beispiel controls
enthalten.
3.3. Drehknöpfe
Die Klasse QwtKnob
zeigt einen Drehknopf, mit ebenso flexibel konfigurierbaren Skaleneinheiten. Die Qt-Klasse QDial
bietet ebenso ein Einstellrad, jedoch wiederum viel simpler und mit weniger Einstellungsmöglichkeiten hinsichtlich der Skalendarstellung und -skalierung.

QwtKnob
Das Beispiel im Screenshot oben ist in der Qwt-Bibliothek als Beispiel controls
enthalten.
3.4. Analoge Zeiger-Anzeigen
Die Klasse QwtDial
zeichnet analoge Zeigeranzeigen, die aber auch mit der Maus/Tastatur verändert werden können (wenn man das aktiviert). Die Anzeigen lassen sich farblich sehr individuell konfigurieren.

QwtDial
Das Beispiel im Screenshot oben ist in der Qwt-Bibliothek als Beispiel controls
enthalten.
Bemerkenswert ist vielleicht noch, dass die Anzeigenadel selbst unabhängig von der Klasse QwtDial
durch eine separate Klasse implementiert wird. Als Standard wird hier QwtDialSimpleNeedle
verwendet, wie im Screenshot oben. Man kann sich hier aber auch austoben, und selber beliebige Anzeigenadeln entwerfen und integrieren.
4. Liniendiagramme
5. Legende
6. Markierungslinien
7. Plotachsen
Die Achsen/Skalen eines Plots (insgesamt 4, open, unten, links und rechts) können bereits in den mitgeliferten Klassenimplementierungen vielfältig angepasst und verändert werden. Und natürlich können die beteiligten Klassen auch abgeleitet und so beliebig modifiziert/geändert werden.
Die wichtigsten Klassen in Bezug auf die Achsen sind:
-
QwtAxis
-
QwtAbstractScaleDraw
und die SpezialisierungenQwtScaleDraw
undQwtDateScaleDraw
-
QwtScaleEngine`und die Spezialisierungen `QwtLinearScaleEngine`und `QwtLogScaleEngine
7.1. Allgemeine Achsenformatierung
7.2. Skalen
8. QwtText und Sonderformatierungen
8.1. MathML
9. Interaktiver Zoom und Verschieben von Diagrammausschnitten
10. Anpassung/Styling der Qwt Komponenten
10.1. Allgemeines zu Farbpaletten
Die Qwt-Komponenten verwenden die Qt Palette und deren Farbrollen für die Einfärbung.
10.2. Rahmen und Zeichenfläche des Diagramms
Beim QwtPlot können verschiedene Elemente angepasst werden. Nachfolgend ist ein QwtPlot zu sehen, welches in einem äußeren Widget (dunkelgrau) eingebettet ist. Die hellgraue Fläche ist das eigentliche QwtPlot
:

Im Screenshot sind die wichtigsten Attribute markiert:
-
Innenabstand (siehe
QWidget::setContentsMargins()
) -
Rahmen (hauptsächlich für den Druck wichtig)
-
Hintergrund des Plot-Widgets
-
Zeichenfläche (engl. Canvas) (betrifft Hintergrundfarbe und Rahmen)
10.2.1. Farbe und Rahmen des Plots
Die Farbe des äußeren Bereichs des Plots wird über die Paletteneigenschaft des QwtPlot
kontrolliert. Standardmäßig wird der äußere Rand des Plot-Widgets transparant gezeichnet, d.h. die Farbe des darunterliegenden Widgets ist sichtbar. Um eine eigene Farbe zu setzen, muss daher ```setAutoFillBackground(true)``` aufgerufen werden:
QPalette pal = plot.palette();
// Die QPalette::Window Farbrolle definiert die Einfärbung
// des äußeren Plotbereichs
pal.setColor(QPalette::Window, QColor(196,196,220));
plot->setPalette(pal);
// die Eigenschaft "autoFillBackground" muss dafür eingeschaltet sein
plot->setAutoFillBackground(true);

Hinweis: In Abschnitt [Gradient als Plot-Hintergrund](customization/#gradient-als-plot-hintergrund) wird beschrieben, wie man einen Farbverlauf im Plothintergrund umsetzt, und diesen bei Größenänderung entsprechend anpasst.
Der Rahmen wird wie bei einem normalen Widget angepasst:
plot->setFrameStyle(QFrame::Box | QFrame::Sunken);
Normalerweise ist ein solcher Rahmen nicht notwendig für die Bildschirmdarstellung oder für das Einbetten des QwtPlot in eine Programmoberfläche. Der Rahmen ist jedoch häufig beim [Export/Druck](export) des Widgets sinnvoll.
10.2.2. Zeichenfläche
Die Zeichenfläche kann eingefärbt werden:
plot->setCanvasBackground(Qt::darkGray);

Der Randabstand zwischen Achsenbeschriftung und Titel zum Rand kann definiert werden:
plot->setContentsMargins(15,10,35,5);

Die Rahmen um die Zeichenfläche kann durch Anpassen des Zeichenflächenobjekts (QwtPlotCanvas
) verändert werden. QwtPlotCanvas
ist von QFrame abgeleitet, wodurch es entsprechend angepasst werden kann. Es wird einfach neues Objekt erstellt, konfiguriert und dem Plot übergeben (das QwtPlot wird neuer Besitzer des Zeichenflächenobjekts):
QwtPlotCanvas * canvas = new QwtPlotCanvas(&plot);
canvas->setPalette(Qt::white);
canvas->setFrameStyle(QFrame::Box | QFrame::Plain );
canvas->setLineWidth(1);
plot->setCanvas(canvas);

Einfacher geht es durch Setzen des Stylesheets für das Canvas-Widget (siehe Qt-Widgets Dokumentation, welche Attribute unterstützt werden):
plot->canvas()->setStyleSheet(
"border: 1px solid Black;"
"border-radius: 15px;"
"background-color: qlineargradient( x1: 0, y1: 0, x2: 0, y2: 1,"
"stop: 0 LemonChiffon, stop: 1 PaleGoldenrod );"
);

11. Exportieren und Drucken
Neben der Anzeige auf dem Bildschirm ist das Speichern schicker Diagramme und Verwendung dieser in Berichten eine nicht unwichtige Aufgabe. Allerdings ist es nicht trivial, gute Diagramme mit sinnvollen Schriftgrößen zu exportieren. Grundsätzlich muss hier zwischen Pixelgrafik-Export und Vektorgrafik unterschieden werden.
11.1. Exportieren des Plots als Pixelgrafik
Der naheliegenste Export des Plots ist eine 1-zu-1 Kopie in die Zwischenablage oder in eine Bitmapdatei (jpg, gif, png,…).
11.1.1. Erstellen einer 1-zu-1 Kopie des Plotwidgets
Jedes QWidget kann direkt in eine QPixmap gezeichnet werden. Und dieses kann dann in eine Datei gespeichert werden.
// Plot in Pixmap rendern
QPixmap p = plot.grab();
// Pixmap in Datei speichern
p.save("diagramm_screenshot.png");
11.1.2. Kopie in die Zwischenablage
Statt das Pixmap in eine Datei zu speichern, kann man das auch einfach in die Zwischenablage kopieren. Dazu QClibBoard
und QApplication
einbinden und:
// Plot in Pixmap rendern
QPixmap p = plot.grab();
// Pixmap in Zwischenablage kopieren
qApp->clipboard()->setImage(p.toImage());
11.1.3. QwtPlot mit anderer Auflösung abspeichern
Wenn das QwtPlot mit einer anderen Auflösung/Pixelgröße als angezeigt auf dem Bildschirm abgespeichert werden soll, so verwendet man die QwtPlotRenderer
:
// Render-Objekt erstellen
QwtPlotRenderer renderer;
// Statt der versenkten Box wird ein Rahmen mit Skalenstrichen gezeichnen
renderer.setLayoutFlag(QwtPlotRenderer::FrameWithScales);
// Zielgröße festlegen
QRect imageRect( 0.0, 0.0, 1200, 600 );
// Bildobjekt in der entsprechenden Größe erstellen...
QImage image( imageRect.size(), QImage::Format_ARGB32 );
// und mit weißem Hintergrund füllen
image.fill(Qt::white);
// Das Diagramm in das QImage zeichnen
QPainter painter( &image );
renderer.render( &plot, &painter, imageRect );
painter.end();
// QImage zurück in Pixmap konvertieren
QPixmap plotPixmap( QPixmap::fromImage(image) );
plotPixmap.save("diagram.png");
Das Diagramm aus dem Tutorial 1 (Kapitel 2) sieht dann z.B. so aus:

11.1.4. Diagrammelemente skalieren (DPI ändern)
TODO
11.2. Exportieren des Plots als Vektorgrafik
TODO
11.3. Drucken
TODO
12. Fortgeschrittene Themen
Die nachfolgend vorgestellten Themen greifen in die internen Datenstrukturen der Qwt-Bibliotheksklassen ein und diese könnten sich in zukünftigen Bibliotheksversionen sicher nocheinmal deutlich ändern. Daher sind diese Techniken mit Vorsicht zu genießen!
12.1. Objekte aus dem QwtPlot loslösen
Die API des QwtPlot
geht davon aus, dass Objekt beim Hinzufügen/Ersetzen existierender Plotelemente das Plot als neuen Eigentümer erhalten. Sobald ein Plotelement ein vorheriges Plotelement ersetzt, löscht das QwtPlot
das alte Objekt automatisch. Es gibt keine release-Funktionen, wie man die von shared pointer-Implementierungen kennt. Daher kann man einmal hinzugefügte Objekte nicht entfernen, anpassen und wieder neu hinzufügen.
Die empfohlene Methode ist:
-
Plotelement neu erstellen
-
anpassen
-
das bisherige PlotElement ersetzen
Mitunter ist dies aber nicht praktikabel und man hätte gerne eine Methode, um ein existierendes Objekt loszulösen. Man kann das aber mit einem Trick dennoch machen.
TODO… erklären
13. Download/Installation/Erstellung der Qwt Bibliothek
13.1. Download fertiger Pakete
13.1.1. Linux
Unter Linux kann man auf die Pakete des Paketmanagers zurückgreifen.
Debian/Ubuntu
# Paket mit Headern für die Entwicklung
sudo apt install libqwt-qt5-dev
Headerdatei-Pfad: /usr/include/qwt
13.2. Erstellung aus dem Quelltext
13.2.1. Windows
-
Release
qwt-6.3.0.zip
herunterladen und entpacken. -
Datei
qwtconfig.pri
bearbeiten und Optionen ein-/ausschalten -
Kommandozeile mit Qt Umgebungsvariablen öffnen: Startmenu → Qt 5.15.2 (MinGW 8.1.0 64-bit)
-
Ins Verzeichnis mit der
qwt.pro
wechseln
13.2.2. Windows - MinGW32
Es wird eine MinGW32 Installation mit mingw32-make
im PATH erwartet.
:: Makefile erstellen
qmake qwt.pro
:: Bibliothek und Plugin/Beispiele bauen
mingw32-make -j8
:: Biblithek installieren
mingw32-make install
Die |
Sofern nicht in der Datei qwtconfig.pri
ein anderer Installationspräfix in der Variable QWT_INSTALL_PREFIX
eingestellt wurde, ist die Bibliothek nun unter c:\Qwt-6.3.0
installiert:
c:\Qwt-6.3.0\include - Header-Dateien c:\Qwt-6.3.0\lib - Bibliothek/DLLs c:\Qwt-6.3.0\doc\html - API Dokumentation (`index.html` in diesem Verzeichnis öffnen)
13.2.3. Linux/Mac
13.3. Qt Designer Plugins
-
wie erstellt man die Designerplugins und bekommt die in die Komponentenpalette…
13.4. Verwendung des Plots in eigenen Programmen
13.4.1. Windows
13.4.2. Linux/Mac
13.5. Das QwtPlot in eine Designer-Oberfläche/ui-Datei integrieren
Wenn man mittels Qt Designer eine Programmoberfläche baut, möchte man da vielleicht auch ein QwtPlot
einbetten. Das kann man auf zwei verschiedene Arten machen:
-
ein QWidget als Platzhalter einfügen und zu einem Platzhalterwidget für das
QwtPlot
machen, oder -
die Qwt-Designer-Plugins verwenden.
13.5.1. Definition eines Platzhalterwidgets
Zur Erklärung wird im Qt Designer ein einfaches Widget entworfen:

Unter der Spinbox wurde ein QWidget
eingefügt. Dieses soll nun als Platzhalter für das QwtPlot
dienen. Dazu im Kontextmenü des Widgets die Option "Als Platzhalter für benutzerdefinierte Klasse festlegen…" auswählen:

Und im Dialog eine neue Platzhalterklasse wie folgt definieren:

Die Eingabe mit "Hinzufügen" bestätigen und dann auf "Anwenden" klicken, um das Platzhalter-Widget in das QwtPlot
zu wandeln. Wir benennen das noch in plot um, und füge das horizontale Layout und das Plotwidget in ein vertikales Layout ein:

Damit sich das Plotwidget den ganzen vertikalen Platz schnappt, wählt man das Top-Level Widget aus und scrollt in der Eigenschaftsleiste bis nach unten zu den Einstellungen für das vertikale Layout. Dort gibt man bei den Stretch-Faktoren "0,1" ein, wodurch sich das 2. Widget im Layout (das Plot) komplett ausdehnt.
13.5.2. Verwendung der Designer-Plugins
Dazu muss man die QtDesigner-Plugins zunächst erstellen und integrieren.
TODO :
Wenn man die erstmal installiert hat, kann man ein QwtPlot
direkt aus der Komponentenpalette in den Entwurf zeihen und ist fertig.
14. Über den Autor
-
später, siehe https://schneggenport.de