Diagrammgalerie
Galerie mit Balken-, Streu- und Flächendiagrammen.
Die Diagrammgalerie veranschaulicht alle drei Diagrammtypen und einige ihrer besonderen Merkmale. Die Diagramme verfügen in der Anwendung über eigene Registerkarten.

Ausführen des Beispiels
Sie können das Beispiel wie folgt ausführen:
- Qt Creator
Öffnen Sie den Modus „ Welcome “ und wählen Sie das Beispiel unter „ Examples “ aus. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
- Qt Extension for Visual Studio Code
Führen Sie den Befehl „ Qt: Open Qt examples “ über „ Command Palette “ aus und wählen Sie das Beispiel aus der Liste aus. Weitere Informationen finden Sie unter Qt Extension for Visual Studio Code: Tutorial: Erstellen und Ausführen.
Balkendiagramm
Erstellen Sie auf der Registerkarte „ Bar Graph “ mithilfe von „Q3DBarWidgetItem“ ein 3D-Balkendiagramm und kombinieren Sie verschiedene Widgets, um verschiedene Eigenschaften des Balkendiagramms anzupassen. Das Beispiel zeigt, wie Sie:
- Erstellen einer Anwendung mit „Q3DBarWidgetItem“ und einigen Steuerelementen
- QBar3DSeries und QBarDataProxy verwenden, um Daten für das Diagramm festzulegen
- einige Diagramm- und Reiheneigenschaften mithilfe von Widget-Steuerelementen anzupassen
- eine Zeile oder Spalte durch Klicken auf eine Achsenbeschriftung auswählen
- Erstellen eines benutzerdefinierten Proxys zur Verwendung mit „Q3DBarWidgetItem“
Informationen zur Interaktion mit dem Diagramm finden Sie auf dieser Seite.
Erstellen der Anwendung
- Instanziieren Sie in „
bargraph.cpp“ die Klassen „ QQuickWidget “ und „ Q3DBarsWidgetItem “ und legen Sie die Instanz „ QQuickWidget “ als Widget für „ Q3DBarsWidgetItem “ fest:m_quickWidget = new QQuickWidget(); m_barGraph = new Q3DBarsWidgetItem(this); m_barGraph->setWidget(m_quickWidget); - Erstellen Sie ein Container-Widget sowie ein horizontales und ein vertikales Layout. Fügen Sie das Diagramm und das vertikale Layout dem horizontalen Layout hinzu:
m_container = new QWidget(); auto *hLayout = new QHBoxLayout(m_container); QSize screenSize = m_quickWidget->screen()->size(); m_quickWidget->setMinimumSize(QSize(screenSize.width() / 2, screenSize.height() / 1.75)); m_quickWidget->setMaximumSize(screenSize); m_quickWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_quickWidget->setFocusPolicy(Qt::StrongFocus); hLayout->addWidget(m_quickWidget, 1); auto *vLayout = new QVBoxLayout(); hLayout->addLayout(vLayout); - Erstellen Sie eine weitere Klasse, um das Hinzufügen von Daten und andere Interaktionen mit dem Diagramm zu verwalten:
m_modifier = new GraphModifier(m_barGraph, this);
Einrichten des Balkendiagramms
- Richten Sie das Diagramm im Konstruktor der Klasse „
GraphModifier“ ein:GraphModifier::GraphModifier(Q3DBarsWidgetItem *bargraph, QObject *parent) : QObject(parent) , m_graph(bargraph) - Erstellen Sie die Achsen und die Reihen als Member-Variablen, um deren Änderung zu ermöglichen:
, m_temperatureAxis(new QValue3DAxis) , m_yearAxis(new QCategory3DAxis) , m_monthAxis(new QCategory3DAxis) , m_primarySeries(new QBar3DSeries) , m_secondarySeries(new QBar3DSeries) - Legen Sie einige visuelle Eigenschaften für das Diagramm fest:
m_graph->setShadowQuality(QtGraphs3D::ShadowQuality::SoftMedium); m_graph->setMultiSeriesUniform(true); // These are set through the active theme m_graph->activeTheme()->setPlotAreaBackgroundVisible(false); m_graph->activeTheme()->setLabelFont(QFont("Times New Roman", m_fontSize)); m_graph->activeTheme()->setLabelBackgroundVisible(true); - Richten Sie die Achsen ein und legen Sie sie als aktive Achsen des Diagramms fest:
m_temperatureAxis->setTitle("Average temperature"); m_temperatureAxis->setSegmentCount(m_segments); m_temperatureAxis->setSubSegmentCount(m_subSegments); m_temperatureAxis->setRange(m_minval, m_maxval); m_temperatureAxis->setLabelFormat(u"%.1f "_s + m_celsiusString); m_temperatureAxis->setLabelAutoAngle(30.0f); m_temperatureAxis->setTitleVisible(true); m_yearAxis->setTitle("Year"); m_yearAxis->setLabelAutoAngle(30.0f); m_yearAxis->setTitleVisible(true); m_monthAxis->setTitle("Month"); m_monthAxis->setLabelAutoAngle(30.0f); m_monthAxis->setTitleVisible(true); m_graph->setValueAxis(m_temperatureAxis); m_graph->setRowAxis(m_yearAxis); m_graph->setColumnAxis(m_monthAxis); - Weisen Sie den Achsenbeschriftungen einen kleinen Autodrehwinkel zu:
m_yearAxis->setLabelAutoAngle(30.0f);Dies geschieht, um sie leicht in Richtung der Kamera auszurichten, was die Lesbarkeit der Achsenbeschriftungen bei extremen Kamerawinkeln verbessert.
- Initialisieren Sie die visuellen Eigenschaften der Reihen. Beachten Sie, dass die zweite Reihe zunächst nicht sichtbar ist:
m_primarySeries->setItemLabelFormat(u"Oulu - @colLabel @rowLabel: @valueLabel"_s); m_primarySeries->setMesh(QAbstract3DSeries::Mesh::BevelBar); m_primarySeries->setMeshSmooth(false); m_secondarySeries->setItemLabelFormat(u"Helsinki - @colLabel @rowLabel: @valueLabel"_s); m_secondarySeries->setMesh(QAbstract3DSeries::Mesh::BevelBar); m_secondarySeries->setMeshSmooth(false); m_secondarySeries->setVisible(false); - Fügen Sie die Reihen zum Diagramm hinzu:
m_graph->addSeries(m_primarySeries); m_graph->addSeries(m_secondarySeries); - Stellen Sie den Kamerawinkel ein, indem Sie dieselbe Methode aufrufen, die auch die Schaltfläche zur Änderung des Kamerawinkels in der Benutzeroberfläche verwendet, um zwischen verschiedenen Kamerawinkeln zu wechseln:
changePresetCamera(); - Die neue Kameravoreinstellung wird im Diagramm festgelegt:
static int preset = int(QtGraphs3D::CameraPreset::Front); m_graph->setCameraPreset((QtGraphs3D::CameraPreset) preset); if (++preset > int(QtGraphs3D::CameraPreset::DirectlyBelow)) preset = int(QtGraphs3D::CameraPreset::FrontLow);
Daten zum Diagramm hinzufügen
Rufen Sie am Ende des Konstruktors eine Methode auf, die die Daten einrichtet:
resetTemperatureData();Diese Methode fügt Daten zur entsprechenden Reihe hinzu, indem sie Proxys der beiden Reihen verwendet:
// Set up data
static const float tempOulu[8][12] = {
{-7.4f, -2.4f, 0.0f, 3.0f, 8.2f, 11.6f, 14.7f, 15.4f, 11.4f, 4.2f, 2.1f, -2.3f}, // 2015
{-13.4f, -3.9f, -1.8f, 3.1f, 10.6f, 13.7f, 17.8f, 13.6f, 10.7f, 3.5f, -3.1f, -4.2f}, // 2016
...
QBarDataArray dataSet;
QBarDataArray dataSet2;
dataSet.reserve(m_years.size());
for (qsizetype year = 0; year < m_years.size(); ++year) {
// Create a data row
QBarDataRow dataRow(m_months.size());
QBarDataRow dataRow2(m_months.size());
for (qsizetype month = 0; month < m_months.size(); ++month) {
// Add data to the row
dataRow[month].setValue(tempOulu[year][month]);
dataRow2[month].setValue(tempHelsinki[year][month]);
}
// Add the row to the set
dataSet.append(dataRow);
dataSet2.append(dataRow2);
}
// Add data to the data proxy (the data proxy assumes ownership of it)
m_primarySeries->dataProxy()->resetArray(dataSet, m_years, m_months);
m_secondarySeries->dataProxy()->resetArray(dataSet2, m_years, m_months);Steuerung des Diagramms mithilfe von Widgets
Fügen Sie anschließend einige Widgets unter „ bargraph.cpp “ hinzu.
- Fügen Sie einen Schieberegler hinzu:
- Verwenden Sie den Schieberegler, um das Diagramm zu drehen, anstatt nur die Maus oder den Touchscreen zu nutzen. Fügen Sie ihn dem vertikalen Layout hinzu:
- Verbinden Sie ihn mit einer Methode in „
GraphModifier“: - Erstellen Sie in „
GraphModifier“ einen Slot für die Signalverbindung. Geben Sie die tatsächliche Kameraposition entlang der Umlaufbahn um den Mittelpunkt an, anstatt einen voreingestellten Kamerawinkel festzulegen:void GraphModifier::rotateX(int angle) { m_xRotation = angle; m_graph->setCameraPosition(m_xRotation, m_yRotation); }
Sie können nun den Schieberegler verwenden, um die Grafik zu drehen.
Fügen Sie dem vertikalen Layout weitere Widgets hinzu, um Folgendes zu steuern:
- Diagrammrotation
- Beschriftungsstil
- Kamera-Voreinstellung
- Sichtbarkeit des Hintergrunds
- Sichtbarkeit des Rasters
- Glättung der Balkenschattierung
- Sichtbarkeit der zweiten Balkenreihe
- Richtung der Werteachse
- Sichtbarkeit und Drehung des Achsenbeschriftung
- Anzuzeigender Datenbereich
- Balkenstil
- Auswahlmodus
- Design
- Schattenqualität
- Schriftart
- Schriftgröße
- Drehung der Achsenbeschriftung
- Datenmodus
Einige Widget-Steuerelemente sind im Datenmodus „ Custom Proxy Data “ absichtlich deaktiviert.
Auswahl einer Zeile oder Spalte durch Klicken auf eine Achsenbeschriftung
Die Auswahl über Achsenbeschriftungen ist die Standardfunktion für Balkendiagramme. Sie können beispielsweise Zeilen auswählen, indem Sie wie folgt auf eine Achsenbeschriftung klicken:
- Wechseln Sie in den Auswahlmodus
Row - Klicken Sie auf eine Jahresbezeichnung
- Die Zeile mit dem angeklickten Jahr wird ausgewählt
Die gleiche Methode funktioniert auch mit den Flags „ Slice “ und „ Item “, sofern zusätzlich entweder „ Row “ oder „ Column “ gesetzt ist.
Zoomen auf die Auswahl
Als Beispiel für die Anpassung des Kameraziels implementieren Sie eine Animation, bei der durch Drücken einer Schaltfläche auf die Auswahl gezoomt wird. Die Initialisierung der Animation erfolgt im Konstruktor:
m_defaultAngleX = m_graph->cameraXRotation();
m_defaultAngleY = m_graph->cameraYRotation();
m_defaultZoom = m_graph->cameraZoomLevel();
m_defaultTarget = m_graph->cameraTargetPosition();
m_animationCameraX.setTargetObject(m_graph);
m_animationCameraY.setTargetObject(m_graph);
m_animationCameraZoom.setTargetObject(m_graph);
m_animationCameraTarget.setTargetObject(m_graph);
m_animationCameraX.setPropertyName("cameraXRotation");
m_animationCameraY.setPropertyName("cameraYRotation");
m_animationCameraZoom.setPropertyName("cameraZoomLevel");
m_animationCameraTarget.setPropertyName("cameraTargetPosition");
int duration = 1700;
m_animationCameraX.setDuration(duration);
m_animationCameraY.setDuration(duration);
m_animationCameraZoom.setDuration(duration);
m_animationCameraTarget.setDuration(duration);
// The zoom always first zooms out above the graph and then zooms in
qreal zoomOutFraction = 0.3;
m_animationCameraX.setKeyValueAt(zoomOutFraction, QVariant::fromValue(0.0f));
m_animationCameraY.setKeyValueAt(zoomOutFraction, QVariant::fromValue(90.0f));
m_animationCameraZoom.setKeyValueAt(zoomOutFraction, QVariant::fromValue(50.0f));
m_animationCameraTarget.setKeyValueAt(zoomOutFraction,
QVariant::fromValue(QVector3D(0.0f, 0.0f, 0.0f)));Die Funktion „ GraphModifier::zoomToSelectedBar() “ enthält die Zoom-Funktionalität. „ QPropertyAnimation “ und „ m_animationCameraTarget “ beziehen sich auf die Eigenschaft „ cameraTargetPosition “, die einen auf den Bereich (-1, 1) normierten Wert annimmt.
Ermitteln Sie, wo sich der ausgewählte Balken relativ zu den Achsen befindet, und verwenden Sie dies als Endwert für ` m_animationCameraTarget`:
QVector3D endTarget;
float xMin = m_graph->columnAxis()->min();
float xRange = m_graph->columnAxis()->max() - xMin;
float zMin = m_graph->rowAxis()->min();
float zRange = m_graph->rowAxis()->max() - zMin;
endTarget.setX((selectedBar.y() - xMin) / xRange * 2.0f - 1.0f);
endTarget.setZ((selectedBar.x() - zMin) / zRange * 2.0f - 1.0f);
...
m_animationCameraTarget.setEndValue(QVariant::fromValue(endTarget));Drehen Sie anschließend die Kamera so, dass sie am Ende der Animation immer ungefähr auf die Mitte des Diagramms zeigt:
qreal endAngleX = 90.0 - qRadiansToDegrees(qAtan(qreal(endTarget.z() / endTarget.x())));
if (endTarget.x() > 0.0f)
endAngleX -= 180.0f;
float barValue = m_graph->selectedSeries()
->dataProxy()
->itemAt(selectedBar.x(), selectedBar.y())
.value();
float endAngleY = barValue >= 0.0f ? 30.0f : -30.0f;
if (m_graph->valueAxis()->reversed())
endAngleY *= -1.0f;Modellproxy für Daten
Wenn Sie den Datenmodus „ Model Proxy Data “ aktivieren, verwendet das Diagramm im Beispiel einen auf einem Elementmodell basierenden Datensatz und den entsprechenden Proxy.
RainfallData
Die Klasse „ RainfallData “ richtet einen „ QItemModelBarDataProxy “ zusammen mit den Zeitreihen und Achsen ein.
- Wir verwenden ein „
std::array<double, 12>“, um die Werte eines Jahres, indiziert nach Monaten, zu speichern. Die statische Hilfsfunktion „readData()“ liest die Daten ein und gibt ein „ QList “ zurück, das nach Jahren indiziert ist:using YearlyData = std::array<double, 12>; using ModelData = QList<YearlyData>; static ModelData readData(const QString&fileName, int *firstYear) { ModelData result; *firstYear =-1; // Daten aus einer Datendatei in die Datenelementliste einlesen QFile dataFile(fileName); if (!dataFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Unable to open data file:" << dataFile.fileName() << dataFile.errorString(); return result; } QTextStream stream(&dataFile); int lastYear =-1; while (!stream.atEnd()) { QString line = stream.readLine(); if (line.startsWith(u'#')) // Kommentare ignorieren continue; const auto strList = QStringView{line}.split(',', Qt::SkipEmptyParts); // Jede Zeile enthält drei Datenelemente: Jahr, Monat und Niederschlagswert if (strList.size() < 3) { qWarning() << "Invalid row read from data:" << line; continue; } // Jahr und Monat als int speichern, Niederschlagswert als double bool yearOk{}; bool monthOk{}; bool valueOk{}; const int year = strList.at(0).trimmed().toInt(&yearOk); const int month = strList.at(1).trimmed().toInt(&monthOk); const double value = strList.at(2).trimmed().toDouble(&valueOk); if (!yearOk|| !monthOk|| month < 1|| month > 12|| !valueOk) { qWarning() << "Invalid row values:" << line; weiter; } if (Jahr != letztesJahr) { if (letztesJahr==-1) { *erstesJahr = Jahr; } else if (Jahr != letztesJahr + 1) { qWarning() << "Non-consecutive years" << year << lastYear; return {}; } lastYear = year; result.emplace_back(YearlyData{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); } result.back()[month - 1] = value; } return result; } ... - Das „ QList “ stellt ein zweidimensionales Array dar, das jeweils nach Jahr und Monat indiziert ist. Daraus füllen wir ein „ QRangeModel “ und übergeben es an ein „QItemModelBarDataProxy()“ in der Klasse „
RainfallData“:int firstYear{}; auto data = readData(":/data/raindata.txt"_L1, &firstYear); Q_ASSERT(!data.isEmpty()); updateYearsList(firstYear, firstYear + int(data.size()) - 1); auto *model = new QRangeModel(data, this); m_proxy = new QItemModelBarDataProxy(model); m_proxy->setUseModelCategories(true); m_series = new QBar3DSeries(m_proxy); - Fügen Sie abschließend eine Funktion hinzu, um die erstellte Reihe zur Anzeige abzurufen:
QBar3DSeries *customSeries() { return m_series; }
Streudiagramm
Erstellen Sie auf der Registerkarte „ Scatter Graph “ mithilfe von Q3DScatterWidgetItem ein 3D-Streudiagramm. Das Beispiel zeigt, wie Sie:
- Einrichten eines „ Q3DScatterWidgetItem “-Diagramms
- QScatterDataProxy verwenden, um Daten in das Diagramm einzufügen
- Erstellen und Hinzufügen eines benutzerdefinierten Eingabehandlers
Informationen zur Erstellung einer einfachen Anwendung finden Sie unter „Balkendiagramm“.
Einrichten des Streudiagramms
- Legen Sie im Konstruktor von „
ScatterDataModifier“ einige visuelle Eigenschaften für das Diagramm fest:m_graph->setShadowQuality(QtGraphs3D::ShadowQuality::SoftHigh); m_graph->setCameraPreset(QtGraphs3D::CameraPreset::Front); m_graph->setCameraZoomLevel(80.f); // These are set through active theme m_graph->activeTheme()->setTheme(QGraphsTheme::Theme::MixSeries); m_graph->activeTheme()->setColorScheme(QGraphsTheme::ColorScheme::Dark);Keine dieser Einstellungen ist zwingend erforderlich, sie dienen jedoch dazu, die Standardeinstellungen des Diagramms zu überschreiben. Um das Erscheinungsbild mit den voreingestellten Standardwerten zu betrachten, kann der obige Block auskommentiert werden.
- Erstellen Sie ein ` QScatterDataProxy ` und das zugehörige ` QScatter3DSeries`. Legen Sie ein benutzerdefiniertes Beschriftungsformat und eine Gitterglättung für die Reihe fest und fügen Sie diese dem Diagramm hinzu:
auto *proxy = new QScatterDataProxy; auto *series = new QScatter3DSeries(proxy); series->setItemLabelFormat(u"@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel"_s); series->setMeshSmooth(m_smooth); m_graph->addSeries(series);
Hinzufügen von Streudaten
- Fügen Sie im Konstruktor von `
ScatterDataModifier` Daten zum Diagramm hinzu:addData(); - Das eigentliche Hinzufügen der Daten erfolgt in der Methode `
addData()`. Konfigurieren Sie zunächst die Achsen:m_graph->axisX()->setTitle("X"); m_graph->axisY()->setTitle("Y"); m_graph->axisZ()->setTitle("Z");Dies könnte man auch im Konstruktor von `
ScatterDataModifier` tun. Wenn man es hier tut, bleibt der Konstruktor einfacher und die Konfiguration der Achsen befindet sich in der Nähe der Daten. - Erstellen Sie ein Datenarray und füllen Sie es:
QScatterDataArray dataArray; dataArray.reserve(m_itemCount); ... const float limit = qSqrt(m_itemCount) / 2.0f; for (int i = -limit; i < limit; ++i) { for (int j = -limit; j < limit; ++j) { const float x = float(i) + 0.5f; const float y = qCos(qDegreesToRadians(float(i * j) / m_curveDivider)); const float z = float(j) + 0.5f; dataArray.append(QScatterDataItem(x, y, z)); } } - Weisen Sie den Proxy schließlich an, die von uns bereitgestellten Daten zu verwenden:
m_graph->seriesList().at(0)->dataProxy()->resetArray(dataArray);
Nun enthält das Diagramm die Daten und ist einsatzbereit. Informationen zum Hinzufügen von Widgets zur Steuerung des Diagramms finden Sie unter „Verwenden von Widgets zur Steuerung des Diagramms“.
Ersetzen der Standard-Eingabeverarbeitung
Um den Standardmechanismus zur Eingabeverarbeitung zu ersetzen, legen Sie die neuen Eingabehandler für ` Q3DScatterWidgetItem` fest, die das benutzerdefinierte Verhalten implementieren:
connect(m_graph,
&Q3DGraphsWidgetItem::selectedElementChanged,
this,
&ScatterDataModifier::handleElementSelected);
connect(m_graph, &Q3DGraphsWidgetItem::dragged, this, &ScatterDataModifier::handleAxisDragging);
m_graph->setDragButton(Qt::LeftButton);Erweiterung der Mausereignisbehandlung
Implementieren Sie einen neuen Ereignis-Handler für ` drag `. Dieser liefert die Mausbewegungsdistanz für die Berechnung des Achsen-Draggings (Einzelheiten finden Sie unter „Implementierung des Achsen-Draggings“ ):
connect(m_graph,
&Q3DGraphsWidgetItem::selectedElementChanged,
this,
&ScatterDataModifier::handleElementSelected);
connect(m_graph, &Q3DGraphsWidgetItem::dragged, this, &ScatterDataModifier::handleAxisDragging);
m_graph->setDragButton(Qt::LeftButton);Implementierung des Achsenverschiebens
- Beginnen Sie damit, das Auswahlsignal des Diagramms zu überwachen. Führen Sie dies im Konstruktor durch und verknüpfen Sie es mit der Methode „
handleElementSelected“:connect(m_graph, &Q3DGraphsWidgetItem::selectedElementChanged, this, &ScatterDataModifier::handleElementSelected); connect(m_graph, &Q3DGraphsWidgetItem::dragged, this, &ScatterDataModifier::handleAxisDragging); m_graph->setDragButton(Qt::LeftButton); - Überprüfen Sie in `
handleElementSelected` den Typ der Auswahl und legen Sie den internen Zustand entsprechend fest:switch (type) { case QtGraphs3D::ElementType::AxisXLabel: m_state = StateDraggingX; break; case QtGraphs3D::ElementType::AxisYLabel: m_state = StateDraggingY; break; case QtGraphs3D::ElementType::AxisZLabel: m_state = StateDraggingZ; break; default: m_state = StateNormal; break; } - Die eigentliche Drag-Logik ist in der Methode `
handleAxisDragging` implementiert, die vom Ereignis `drag` aufgerufen wird:void ScatterDataModifier::handleAxisDragging(QVector2D delta) - Rufen Sie in `
handleAxisDragging` zunächst die Szenenausrichtung der aktiven Kamera ab:// Get scene orientation from active camera float xRotation = m_graph->cameraXRotation(); float yRotation = m_graph->cameraYRotation(); - Berechne die Modifikatoren für die Mausbewegungsrichtung basierend auf der Ausrichtung:
// Calculate directional drag multipliers based on rotation float xMulX = qCos(qDegreesToRadians(xRotation)); float xMulY = qSin(qDegreesToRadians(xRotation)); float zMulX = qSin(qDegreesToRadians(xRotation)); float zMulY = qCos(qDegreesToRadians(xRotation)); - Berechnen Sie die Mausbewegung und passen Sie sie entsprechend der y-Rotation der Kamera an:
// Get the drag amount QPoint move = delta.toPoint(); // Flip the effect of y movement if we're viewing from below float yMove = (yRotation < 0) ? -move.y() : move.y(); - Wende die Verschiebungsdistanz auf die richtige Achse an:
// Adjust axes QValue3DAxis *axis = nullptr; switch (m_state) { case StateDraggingX: axis = m_graph->axisX(); distance = (move.x() * xMulX - yMove * xMulY) / m_dragSpeedModifier; axis->setRange(axis->min() - distance, axis->max() - distance); break; case StateDraggingZ: axis = m_graph->axisZ(); distance = (move.x() * zMulX + yMove * zMulY) / m_dragSpeedModifier; axis->setRange(axis->min() + distance, axis->max() + distance); break; case StateDraggingY: axis = m_graph->axisY(); distance = move.y() / m_dragSpeedModifier; // No need to use adjusted y move here axis->setRange(axis->min() + distance, axis->max() + distance); break; default: break; }
Oberflächendiagramm
Erstellen Sie auf der Registerkarte „ Surface Graph “ mithilfe von „ Q3DSurfaceWidgetItem “ ein 3D-Oberflächendiagramm. Das Beispiel zeigt, wie Sie dabei vorgehen:
- ein einfaches „ QSurfaceDataProxy “ einrichten und Daten dafür festlegen.
- QHeightMapSurfaceDataProxy zur Darstellung von 3D-Höhenkarten verwendet.
- topografische Daten zur Erstellung von 3D-Höhenkarten nutzen.
- Drei verschiedene Auswahlmodi zur Untersuchung des Diagramms nutzen.
- Verwenden Sie Achsenbereiche, um ausgewählte Abschnitte des Diagramms anzuzeigen.
- Legen Sie einen benutzerdefinierten Oberflächengefällewert fest.
- Fügen Sie mit „ QCustom3DItem “ und „ QCustom3DLabel “ benutzerdefinierte Elemente und Beschriftungen hinzu.
- Verwenden Sie einen benutzerdefinierten Eingabe-Handler, um Zoomen und Verschieben zu ermöglichen.
- Heben Sie einen Bereich der Oberfläche hervor.
Informationen zur Erstellung einfacher Anwendungen finden Sie unter „Balkendiagramm“.
Einfache Oberfläche mit generierten Daten
- Erstellen Sie zunächst eine neue Instanz von „ QSurfaceDataProxy “ und fügen Sie diese einem neuen „ QSurface3DSeries “ hinzu:
m_sqrtSinProxy = new QSurfaceDataProxy(); m_sqrtSinSeries = new QSurface3DSeries(m_sqrtSinProxy); - Füllen Sie den Proxy mit einfachen Quadratwurzel- und Sinuswellen-Daten. Erstellen Sie eine „
QSurfaceDataArray“-Instanz und fügen Sie ihr „QSurfaceDataRow“-Elemente hinzu. Legen Sie das erstellte „QSurfaceDataArray“ als Datenarray für den „ QSurfaceDataProxy “ fest, indem Sie „resetArray()“ aufrufen.QSurfaceDataArray dataArray; dataArray.reserve(sampleCountZ); for (int i = 0; i < sampleCountZ; ++i) { QSurfaceDataRow newRow; newRow.reserve(sampleCountX); // Keep values within range bounds, since just adding step can cause minor // drift due to the rounding errors. float z = qMin(sampleMax, (i * stepZ + sampleMin)); for (int j = 0; j < sampleCountX; ++j) { float x = qMin(sampleMax, (j * stepX + sampleMin)); float R = qSqrt(z * z + x * x) + 0.01f; float y = (qSin(R) / R + 0.24f) * 1.61f; newRow.append(QSurfaceDataItem(x, y, z)); } dataArray.append(newRow); } m_sqrtSinProxy->resetArray(dataArray);
Höhenkartendaten mit mehreren Serien
Erstellen Sie die Höhenkarte, indem Sie eine ` QHeightMapSurfaceDataProxy `-Instanz mit einem ` QImage ` instanziieren, das die Höhendaten enthält. Verwenden Sie ` QHeightMapSurfaceDataProxy::setValueRanges()` zur Definition des Wertebereichs der Karte. Im Beispiel bezieht sich die Karte auf einen fiktiven Standort zwischen 34,0° N und 40,0° N sowie zwischen 18,0° O und 24,0° O. Diese Werte werden verwendet, um die Karte auf den Achsen zu positionieren.
// Create the first surface layer
QImage heightMapImageOne(":/data/layer_1.png");
m_heightMapProxyOne = new QHeightMapSurfaceDataProxy(heightMapImageOne);
m_heightMapSeriesOne = new QSurface3DSeries(m_heightMapProxyOne);
m_heightMapSeriesOne->setItemLabelFormat(u"(@xLabel, @zLabel): @yLabel"_s);
m_heightMapProxyOne->setValueRanges(34.f, 40.f, 18.f, 24.f);Fügen Sie die anderen Oberflächenebenen auf die gleiche Weise hinzu, indem Sie für diese mithilfe von Höhenkartenbildern einen Proxy und eine Reihe erstellen. -
Topografische Kartendaten
Die topografischen Daten stammen vom finnischen Landesvermessungsamt. Dieses stellt ein Produkt namens „ Elevation Model 2 m “ zur Verfügung, das für dieses Beispiel geeignet ist.
Die topografischen Daten stammen vom Levi-Fjell. Da die Genauigkeit der Daten die Anforderungen bei weitem übersteigt, werden sie komprimiert und in eine PNG-Datei kodiert. Der Höhenwert der ursprünglichen ASCII-Daten wird mithilfe eines Multiplikators in das RGB-Format kodiert, wie im folgenden Code-Beispiel gezeigt. Der Multiplikator wird berechnet, indem der größte 24-Bit-Wert durch den höchsten Punkt in Finnland geteilt wird.
QHeightMapSurfaceDataProxy konvertiert nur Ein-Byte-Werte. Um die höhere Genauigkeit der Daten des finnischen Landesvermessungsamtes zu nutzen, lesen Sie die Daten aus der PNG-Datei und dekodieren Sie sie in ein „ QSurface3DSeries “.
- Definieren Sie den Kodierungsmultiplikator:
// Value used to encode height data as RGB value on PNG file const float packingFactor = 11983.f; - Führen Sie die eigentliche Dekodierung durch:
QImage heightMapImage(file); uchar *bits = heightMapImage.bits(); int imageHeight = heightMapImage.height(); int imageWidth = heightMapImage.width(); int widthBits = imageWidth * 4; float stepX = width / float(imageWidth); float stepZ = height / float(imageHeight); QSurfaceDataArray dataArray; dataArray.reserve(imageHeight); for (int i = 0; i < imageHeight; ++i) { int p = i * widthBits; float z = height - float(i) * stepZ; QSurfaceDataRow newRow; newRow.reserve(imageWidth); for (int j = 0; j < imageWidth; ++j) { uchar aa = bits[p + 0]; uchar rr = bits[p + 1]; uchar gg = bits[p + 2]; uint color = uint((gg << 16) + (rr << 8) + aa); float y = float(color) / packingFactor; newRow.append(QSurfaceDataItem(float(j) * stepX, y, z)); p += 4; } dataArray.append(newRow); } dataProxy()->resetArray(dataArray);
Nun kann ein Surface Graph die Daten über den Proxy abrufen.
Auswahl des Datensatzes
Um verschiedene Proxys zu veranschaulichen, verfügt der „ Surface Graph “ über drei Optionsfelder zum Wechseln zwischen den Reihen.
Bei „ Sqrt & Sin “ ist die einfach generierte Reihe aktiviert.
- Legen Sie die Darstellungsoptionen fest, z. B. das Aktivieren des Rasters für die Oberfläche und die Auswahl des Flachschattierungsmodus.
- Legen Sie das Format der Achsenbeschriftungen und die Wertebereiche fest. Aktivieren Sie die automatische Drehung der Beschriftungen, um deren Lesbarkeit bei niedrigen Kamerawinkeln zu verbessern.
- Stellen Sie sicher, dass die richtige Serie zum Diagramm hinzugefügt wurde und die anderen nicht.
m_sqrtSinSeries->setDrawMode(QSurface3DSeries::DrawSurfaceAndWireframe);
m_sqrtSinSeries->setShading(QSurface3DSeries::Shading::Flat);
m_graph->axisX()->setLabelFormat("%.2f");
m_graph->axisZ()->setLabelFormat("%.2f");
m_graph->axisX()->setRange(sampleMin, sampleMax);
m_graph->axisY()->setRange(0.f, 2.f);
m_graph->axisZ()->setRange(sampleMin, sampleMax);
m_graph->axisX()->setLabelAutoAngle(30.f);
m_graph->axisY()->setLabelAutoAngle(90.f);
m_graph->axisZ()->setLabelAutoAngle(30.f);
m_graph->removeSeries(m_heightMapSeriesOne);
m_graph->removeSeries(m_heightMapSeriesTwo);
m_graph->removeSeries(m_heightMapSeriesThree);
m_graph->removeSeries(m_topography);
m_graph->removeSeries(m_highlight);
m_graph->addSeries(m_sqrtSinSeries);Mit „ Multiseries Height Map “ werden die Höhenkartenreihen aktiviert und die anderen deaktiviert. Die automatische Anpassung des Y-Achsenbereichs funktioniert gut für die Höhenkartenoberfläche; stellen Sie daher sicher, dass diese Option aktiviert ist.
m_graph->axisY()->setAutoAdjustRange(true);Bei „ Textured Topography “ ist die topografische Reihe aktiviert und die anderen sind deaktiviert. Aktivieren Sie einen benutzerdefinierten Eingabehandler für diese Reihe, um Bereiche darin hervorheben zu können:
m_graph->setDragButton(Qt::LeftButton);
QObject::connect(m_graph,
&Q3DGraphsWidgetItem::dragged,
this,
&SurfaceGraphModifier::handleAxisDragging);
QObject::connect(m_graph,
&Q3DGraphsWidgetItem::wheel,
this,
&SurfaceGraphModifier::onWheel);
m_graph->setZoomEnabled(false);Informationen zum benutzerdefinierten Eingabe-Handler für diesen Datensatz finden Sie unter „Benutzerdefinierten Eingabe-Handler verwenden, um Zoomen und Schwenken zu aktivieren “.
Auswahlmodi
Die drei von „ Q3DSurfaceWidgetItem “ unterstützten Auswahlmodi können mit Optionsfeldern verwendet werden. Um den ausgewählten Modus zu aktivieren oder zu deaktivieren, fügen Sie die folgenden Inline-Methoden hinzu:
void toggleModeNone() { m_graph->setSelectionMode(QtGraphs3D::SelectionFlag::None); }
void toggleModeItem() { m_graph->setSelectionMode(QtGraphs3D::SelectionFlag::Item); }
void toggleModeSliceRow()
{
m_graph->setSelectionMode(QtGraphs3D::SelectionFlag::ItemAndRow
| QtGraphs3D::SelectionFlag::Slice
| QtGraphs3D::SelectionFlag::MultiSeries);
}
void toggleModeSliceColumn()
{
m_graph->setSelectionMode(QtGraphs3D::SelectionFlag::ItemAndColumn
| QtGraphs3D::SelectionFlag::Slice
| QtGraphs3D::SelectionFlag::MultiSeries);
}Um die gleichzeitige Auswahl von Ausschnitten für alle sichtbaren Reihen im Diagramm zu ermöglichen, fügen Sie die Flags „ QtGraphs3D::SelectionFlag::Slice “ und „ QtGraphs3D::SelectionFlag::MultiSeries “ für die Zeilen- und Spaltenauswahlmodi hinzu.
Achsenbereiche zur Untersuchung des Diagramms
Das Beispiel enthält vier Schieberegler zum Anpassen der Minimal- und Maximalwerte für die X- und Z-Achsen. Bei Auswahl des Proxys werden diese Schieberegler so angepasst, dass sie den Achsenbereichen des aktuellen Datensatzes entsprechen:
// Reset range sliders for Sqrt & Sin
m_rangeMinX = sampleMin;
m_rangeMinZ = sampleMin;
m_stepX = (sampleMax - sampleMin) / float(sampleCountX - 1);
m_stepZ = (sampleMax - sampleMin) / float(sampleCountZ - 1);
m_axisMinSliderX->setMinimum(0);
m_axisMinSliderX->setMaximum(sampleCountX - 2);
m_axisMinSliderX->setValue(0);
m_axisMaxSliderX->setMinimum(1);
m_axisMaxSliderX->setMaximum(sampleCountX - 1);
m_axisMaxSliderX->setValue(sampleCountX - 1);
m_axisMinSliderZ->setMinimum(0);
m_axisMinSliderZ->setMaximum(sampleCountZ - 2);
m_axisMinSliderZ->setValue(0);
m_axisMaxSliderZ->setMinimum(1);
m_axisMaxSliderZ->setMaximum(sampleCountZ - 1);
m_axisMaxSliderZ->setValue(sampleCountZ - 1);Um die Einstellung des X-Bereichs über die Widget-Steuerelemente im Diagramm zu ermöglichen, fügen Sie Folgendes hinzu:
void SurfaceGraphModifier::setAxisXRange(float min, float max)
{
m_graph->axisX()->setRange(min, max);
}Fügen Sie die Unterstützung für den Z-Bereich auf die gleiche Weise hinzu.
Benutzerdefinierte Oberflächenverläufe
Mit dem Datensatz „ Sqrt & Sin “ können benutzerdefinierte Oberflächenverläufe über zwei Schaltflächen verwendet werden. Definieren Sie den Verlauf mit ` QLinearGradient`, wobei die gewünschten Farben festgelegt werden. Ändern Sie außerdem den Farbstil auf `Q3DTheme::ColorStyle::RangeGradient`, um den Verlauf zu verwenden.
QLinearGradient gr;
gr.setColorAt(0.f, Qt::black);
gr.setColorAt(0.33f, Qt::blue);
gr.setColorAt(0.67f, Qt::red);
gr.setColorAt(1.f, Qt::yellow);
m_sqrtSinSeries->setBaseGradient(gr);
m_sqrtSinSeries->setColorStyle(QGraphsTheme::ColorStyle::RangeGradient);Hinzufügen benutzerdefinierter Meshes zur Anwendung
So fügen Sie benutzerdefinierte Meshes zur Anwendung hinzu:
- Bei einem CMake-Build fügen Sie die Mesh-Dateien zu „
CMakeLists.txt“ hinzu:set(graphgallery_resource_files ... "data/oilrig.mesh" "data/pipe.mesh" "data/refinery.mesh" ... ) qt6_add_resources(widgetgraphgallery "widgetgraphgallery" PREFIX "/" FILES ${graphgallery_resource_files} ) - Bei einem qmake-Build: Fügen Sie die Mesh-Dateien in die qrc-Ressourcendatei ein:
<RCC> <qresource prefix="/"> ... <file>data/refinery.mesh</file> <file>data/oilrig.mesh</file> <file>data/pipe.mesh</file> ... </qresource> </RCC>
Hinzufügen eines benutzerdefinierten Elements zu einem Diagramm
Mit dem Datensatz „ Multiseries Height Map “ werden benutzerdefinierte Elemente in das Diagramm eingefügt und können über Kontrollkästchen ein- oder ausgeschaltet werden. Weitere visuelle Änderungen lassen sich ebenfalls über eine weitere Reihe von Kontrollkästchen steuern, darunter die Transparenz der beiden obersten Ebenen und eine Hervorhebung der untersten Ebene.
- Erstellen Sie ein kleines „ QImage “. Füllen Sie es mit einer einzigen Farbe, die als Farbe für das benutzerdefinierte Objekt verwendet werden soll:
- Legen Sie die Position des Elements in einer Variablen fest. Die Position kann dann verwendet werden, um das richtige Element aus dem Diagramm zu entfernen:
QVector3D positionOne = QVector3D(39.f, 77.f, 19.2f); - Erstellen Sie ein neues „ QCustom3DItem “ mit allen Parametern:
auto *item = new QCustom3DItem(":/data/oilrig.mesh", positionOne, QVector3D(0.0125f, 0.0125f, 0.0125f), QQuaternion::fromAxisAndAngle(0.f, 1.f, 0.f, 45.f), color); - Fügen Sie das Element zum Diagramm hinzu:
m_graph->addCustomItem(item);
Hinzufügen einer benutzerdefinierten Beschriftung zu einem Diagramm
Das Hinzufügen einer benutzerdefinierten Beschriftung erfolgt ähnlich wie das Hinzufügen eines benutzerdefinierten Elements. Für die Beschriftung ist kein benutzerdefiniertes Mesh erforderlich, sondern lediglich eine „ QCustom3DLabel “-Instanz:
auto *label = new QCustom3DLabel();
label->setText("Oil Rig One");
label->setPosition(positionOneLabel);
label->setScaling(QVector3D(1.f, 1.f, 1.f));
m_graph->addCustomItem(label);Entfernen eines benutzerdefinierten Elements aus einem Diagramm
Um ein bestimmtes Element aus dem Diagramm zu entfernen, rufen Sie ` removeCustomItemAt() ` mit der Position des Elements auf:
m_graph->removeCustomItemAt(positionOne);Hinweis: Durch das Entfernen eines benutzerdefinierten Elements aus dem Diagramm wird auch das Objekt gelöscht. Um das Element zu erhalten, verwenden Sie stattdessen die Methode „ releaseCustomItem() “.
Textur für eine Oberflächenreihe
Erstellen Sie mit dem Datensatz „ Textured Topography “ eine Kartentextur, die mit der topografischen Höhenkarte verwendet werden soll.
Legen Sie mit ` QSurface3DSeries::setTextureFile()` ein Bild fest, das als Textur auf einer Oberfläche verwendet werden soll. Fügen Sie ein Kontrollkästchen hinzu, um zu steuern, ob die Textur festgelegt ist oder nicht, sowie einen Handler, der auf den Status des Kontrollkästchens reagiert:
void SurfaceGraphModifier::toggleSurfaceTexture(bool enable)
{
if (enable)
m_topography->setTextureFile(":/data/maptexture.jpg");
else
m_topography->setTextureFile("");
}Das Bild in diesem Beispiel wird aus einer JPG-Datei gelesen. Durch Festlegen einer leeren Datei mit dieser Methode wird die Textur gelöscht, und die Oberfläche verwendet die Farbverläufe oder Farben aus dem Design.
Verwenden Sie einen benutzerdefinierten Eingabe-Handler, um Zoomen und Verschieben zu aktivieren
Erstellen Sie mit dem Datensatz „ Textured Topography “ einen benutzerdefinierten Eingabe-Handler, um die Auswahl im Diagramm hervorzuheben und das Verschieben des Diagramms zu ermöglichen.
Die Umsetzung des Verschiebens ähnelt der in „Implementierung des Achsenziehens“ gezeigten. Der Unterschied besteht darin, dass Sie in diesem Beispiel nur die X- und Z-Achsen verfolgen und das Ziehen der Oberfläche außerhalb des Diagramms nicht zulassen. Um das Ziehen zu begrenzen, halten Sie sich an die Grenzen der Achsen und führen Sie keine Aktion aus, wenn der Bereich des Diagramms verlassen wird:
case StateDraggingX:
distance = (move.x() * xMulX - move.y() * xMulY) * m_speedModifier;
m_axisXMinValue -= distance;
m_axisXMaxValue -= distance;
if (m_axisXMinValue < m_areaMinValue) {
float dist = m_axisXMaxValue - m_axisXMinValue;
m_axisXMinValue = m_areaMinValue;
m_axisXMaxValue = m_axisXMinValue + dist;
}
if (m_axisXMaxValue > m_areaMaxValue) {
float dist = m_axisXMaxValue - m_axisXMinValue;
m_axisXMaxValue = m_areaMaxValue;
m_axisXMinValue = m_axisXMaxValue - dist;
}
m_graph->axisX()->setRange(m_axisXMinValue, m_axisXMaxValue);
break;Zum Zoomen fangen Sie das Ereignis „ wheelEvent “ ab und passen Sie die Bereiche der X- und Y-Achse entsprechend dem Delta-Wert unter „ QWheelEvent “ an. Passen Sie die Y-Achse so an, dass das Seitenverhältnis zwischen der Y-Achse und der XZ-Ebene gleich bleibt. Dadurch wird verhindert, dass ein Diagramm entsteht, in dem die Höhe übertrieben dargestellt wird:
void SurfaceGraphModifier::onWheel(QWheelEvent *event)
{
float delta = float(event->angleDelta().y());
m_axisXMinValue += delta;
m_axisXMaxValue -= delta;
m_axisZMinValue += delta;
m_axisZMaxValue -= delta;
checkConstraints();
float y = (m_axisXMaxValue - m_axisXMinValue) * m_aspectRatio;
m_graph->axisX()->setRange(m_axisXMinValue, m_axisXMaxValue);
m_graph->axisY()->setRange(100.f, y);
m_graph->axisZ()->setRange(m_axisZMinValue, m_axisZMaxValue);
}Fügen Sie anschließend einige Begrenzungen für den Zoomfaktor hinzu, damit dieser nicht zu nah an die Oberfläche heranrückt oder sich zu weit davon entfernt. Wenn beispielsweise der Wert für die X-Achse unter die zulässige Grenze fällt, d. h. der Zoom zu weit geht, wird der Wert auf den zulässigen Mindestwert gesetzt. Wenn der Bereich unter das Bereichsminimum fällt, werden beide Enden der Achse so angepasst, dass der Bereich an der Grenze bleibt:
if (m_axisXMinValue < m_areaMinValue)
m_axisXMinValue = m_areaMinValue;
if (m_axisXMaxValue > m_areaMaxValue)
m_axisXMaxValue = m_areaMaxValue;
// Don't allow too much zoom in
if ((m_axisXMaxValue - m_axisXMinValue) < m_axisXMinRange) {
float adjust = (m_axisXMinRange - (m_axisXMaxValue - m_axisXMinValue)) / 2.f;
m_axisXMinValue -= adjust;
m_axisXMaxValue += adjust;
}Einen Bereich der Oberfläche hervorheben
Um eine Hervorhebung auf der Oberfläche anzuzeigen, erstellen Sie eine Kopie der Reihe und fügen Sie dem y-Wert einen Versatz hinzu. In diesem Beispiel implementiert die Klasse „ HighlightSeries “ die Erstellung der Kopie in ihrer Methode „ handlePositionChange “.
Übergeben Sie zunächst der Klasse „ HighlightSeries “ den Zeiger auf die ursprüngliche Reihe und beginnen Sie dann, das Signal „ QSurface3DSeries::selectedPointChanged “ abzuhören:
void HighlightSeries::setTopographicSeries(TopographicSeries *series)
{
m_topographicSeries = series;
m_srcWidth = m_topographicSeries->dataArray().at(0).size();
m_srcHeight = m_topographicSeries->dataArray().size();
QObject::connect(m_topographicSeries,
&QSurface3DSeries::selectedPointChanged,
this,
&HighlightSeries::handlePositionChange);
}Wenn das Signal ausgelöst wird, prüfen Sie, ob die Position gültig ist. Berechnen Sie anschließend die Bereiche für den kopierten Bereich und stellen Sie sicher, dass diese innerhalb der Grenzen liegen. Füllen Sie schließlich das Datenarray der „highlight“-Reihe mit dem Bereich aus dem Datenarray der „topography“-Reihe:
void HighlightSeries::handlePositionChange(const QPoint &position)
{
m_position = position;
if (position == invalidSelectionPosition()) {
setVisible(false);
return;
}
int halfWidth = m_width / 2;
int halfHeight = m_height / 2;
int startX = position.x() - halfWidth;
if (startX < 0)
startX = 0;
int endX = position.x() + halfWidth;
if (endX > (m_srcWidth - 1))
endX = m_srcWidth - 1;
int startZ = position.y() - halfHeight;
if (startZ < 0)
startZ = 0;
int endZ = position.y() + halfHeight;
if (endZ > (m_srcHeight - 1))
endZ = m_srcHeight - 1;
const QSurfaceDataArray &srcArray = m_topographicSeries->dataArray();
QSurfaceDataArray dataArray;
dataArray.reserve(endZ - startZ);
for (int i = startZ; i < endZ; ++i) {
QSurfaceDataRow newRow;
newRow.reserve(endX - startX);
QSurfaceDataRow srcRow = srcArray.at(i);
for (int j = startX; j < endX; ++j) {
QVector3D pos = srcRow.at(j).position();
pos.setY(pos.y() + m_heightAdjustment);
newRow.append(QSurfaceDataItem(pos));
}
dataArray.append(newRow);
}
dataProxy()->resetArray(dataArray);
setVisible(true);
}Ein Farbverlauf zur „Highlight“-Serie
Da es sich bei der „ HighlightSeries “ um eine „ QSurface3DSeries “ handelt, stehen alle Dekorationsmethoden zur Verfügung, die eine Serie haben kann. Fügen Sie in diesem Beispiel einen Farbverlauf hinzu, um die Höhenlage hervorzuheben. Da der geeignete Farbverlaufsstil vom Bereich der Y-Achse abhängt und wir diesen Bereich beim Zoomen ändern, müssen die Positionen der Farbverlaufsfarben an die Änderungen des Bereichs angepasst werden. Definieren Sie dazu proportionale Werte für die Positionen der Farbverlaufsfarben:
const float darkRedPos = 1.f;
const float redPos = 0.8f;
const float yellowPos = 0.6f;
const float greenPos = 0.4f;
const float darkGreenPos = 0.2f;Die Anpassung des Farbverlaufs erfolgt in der Methode ` handleGradientChange `, verbinden Sie diese daher so, dass sie auf Änderungen an der Y-Achse reagiert:
QObject::connect(m_graph->axisY(),
&QValue3DAxis::maxChanged,
m_highlight,
&HighlightSeries::handleGradientChange);Wenn sich der Maximalwert der Y-Achse ändert, berechnen Sie die neuen Farbpositionen des Farbverlaufs:
void HighlightSeries::handleGradientChange(float value)
{
float ratio = m_minHeight / value;
QLinearGradient gr;
gr.setColorAt(0.f, Qt::black);
gr.setColorAt(darkGreenPos * ratio, Qt::darkGreen);
gr.setColorAt(greenPos * ratio, Qt::green);
gr.setColorAt(yellowPos * ratio, Qt::yellow);
gr.setColorAt(redPos * ratio, Qt::red);
gr.setColorAt(darkRedPos * ratio, Qt::darkRed);
setBaseGradient(gr);
setColorStyle(QGraphsTheme::ColorStyle::RangeGradient);
handleZoomChange(ratio);
}Beispielinhalt
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.