statistics: do resizing in UI thread, not render thread

The updatePaintNode() function, which is run on the render
thread detected a geometry change and initiated recalculation
of the chart layout.

This means that plotAreaChanged() was called in two different
thread contexts, which is questionable. Instead, hook into
the geometryChanged() function and recalculate the chart items
there.

This fixes a rendering bug, because the old code would first
delete unneeded items and then rerender the chart. Thus, old
grid and tick items were still visible.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-01-20 23:13:54 +01:00 committed by Dirk Hohndel
parent 913bed19bb
commit 54ff31f5c1
2 changed files with 17 additions and 8 deletions

View file

@ -31,6 +31,7 @@ static const double sceneBorder = 5.0; // Border between scene edges and stati
static const double titleBorder = 2.0; // Border between title and chart static const double titleBorder = 2.0; // Border between title and chart
StatsView::StatsView(QQuickItem *parent) : QQuickItem(parent), StatsView::StatsView(QQuickItem *parent) : QQuickItem(parent),
backgroundDirty(true),
highlightedSeries(nullptr), highlightedSeries(nullptr),
xAxis(nullptr), xAxis(nullptr),
yAxis(nullptr), yAxis(nullptr),
@ -125,11 +126,9 @@ QSGNode *StatsView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNod
} }
deletedItems.clear(); deletedItems.clear();
QRectF rect = boundingRect(); if (backgroundDirty) {
if (plotRect != rect) { rootNode->backgroundNode->setRect(plotRect);
plotRect = rect; backgroundDirty = false;
rootNode->backgroundNode->setRect(rect);
plotAreaChanged(plotRect.size());
} }
for (ChartItem *item = dirtyItems.first; item; item = item->next) { for (ChartItem *item = dirtyItems.first; item; item = item->next) {
@ -232,6 +231,16 @@ QRectF StatsView::plotArea() const
return plotRect; return plotRect;
} }
void StatsView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
plotRect = QRectF(QPointF(0.0, 0.0), newGeometry.size());
backgroundDirty = true;
plotAreaChanged(plotRect.size());
// Do we need to call the base-class' version of geometryChanged? Probably for QML?
QQuickItem::geometryChanged(newGeometry, oldGeometry);
}
void StatsView::plotAreaChanged(const QSizeF &s) void StatsView::plotAreaChanged(const QSizeF &s)
{ {
double left = sceneBorder; double left = sceneBorder;
@ -393,7 +402,7 @@ void StatsView::plot(const StatsState &stateIn)
state = stateIn; state = stateIn;
plotChart(); plotChart();
updateFeatures(); // Show / hide chart features, such as legend, etc. updateFeatures(); // Show / hide chart features, such as legend, etc.
plotAreaChanged(boundingRect().size()); plotAreaChanged(plotRect.size());
update(); update();
} }

View file

@ -64,12 +64,12 @@ public:
private slots: private slots:
void replotIfVisible(); void replotIfVisible();
private: private:
bool resetChart;
// QtQuick related things // QtQuick related things
bool backgroundDirty;
QRectF plotRect; QRectF plotRect;
QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override; QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
void plotAreaChanged(const QSizeF &size); void plotAreaChanged(const QSizeF &size);
void reset(); // clears all series and axes void reset(); // clears all series and axes
void setAxes(StatsAxis *x, StatsAxis *y); void setAxes(StatsAxis *x, StatsAxis *y);