QwtPlotZoomer et arrivée continue de données
Bonjour,
Je découvre Qwt (version 6.0.1) dans le but d'intégrer un Widget capable d'afficher une courbe en recevant des ordonnées (avancée sur les abscisses pixel par pixel). Je galère énormément.
Comportement :
L'axe des ordonnées est laissé libre (pour le moment) donc en autoscaling. L'axe des abscisses, lui, s'initialise de la taille du widget (car 1 pixel = 1 unité). Son pas, pour être lisible, est de disons 10 unités.
Les premiers points arrivent, on part de zéro. Lorsque la longueur est remplie, on décale d'un pas vers la gauche, et à partir de là ça décale régulièrement. Les valeurs affichées sont stockées dans un QVector, ce qui veut dire que lors du décalage, on efface les "pas" premières valeurs.
Problème : gestion d'un zoom
Pour gérer le zoom, j'ai choisi de garder en permanence un QRectF représentant la zoomBase. Ceci afin de ne pas dézoomer ou décaler l'affichage lors d'un décalage des données si l'écran est zoomé. Donc en dézoomant, on ne revient pas forcément à la vue avant le zoom, mais à la vue courante vu qu'entre temps il a pu y avoir des décalages.
Or, setZoomBase a un comportement inattendu et je n'y arrive tout simplement pas.
Voici le code : il s'agit de base d'un projet graphique "sample" basé sur un QWidget, et voici les Widget.h et Widget.cpp. L'arrivée de donnée est simulée avec un QTimer et un nombre aléatoire.
Widget.ui
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>564</width>
<height>377</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="reset">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui> |
Widget.h
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTimer>
namespace Ui {
class Widget;
}
class QwtPlot;
class QwtPlotGrid;
class QwtPlotCurve;
class QwtPlotZoomer;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
QVector<QPointF> points;
qreal curX;
QTimer timer;
QwtPlot* m_pPlot;
QwtPlotCurve* m_pCurve;
QwtPlotGrid* m_pGrid;
int stepSize;
QRectF m_BaseRec;
QwtPlotZoomer* m_pZoomer;
private slots:
void newValue();
void resetBottomAxis();
};
#endif // WIDGET_H |
Widget.cpp
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| #include "Widget.h"
#include "ui_Widget.h"
#include <QDebug>
#include <QTime>
#include <qwt_plot.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_canvas.h>
#include <qwt_plot_layout.h>
#include <qwt_plot_zoomer.h>
#include <qwt_plot_panner.h>
#include <qwt_plot_magnifier.h>
#include <qwt_plot_directpainter.h>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget),
curX(0),
stepSize(10),
m_pPlot( new QwtPlot(this) ),
m_pCurve(new QwtPlotCurve),
m_pGrid(new QwtPlotGrid)
{
ui->setupUi(this);
m_pPlot->canvas()->setPaintAttribute(QwtPlotCanvas::BackingStore, false);
m_pPlot->setCanvasBackground(Qt::black);
m_pCurve->setPen(QColor(Qt::green));
m_pCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
m_pGrid->setPen(QColor(Qt::white));
m_pPlot->plotLayout()->setAlignCanvasToScales(true);
m_pCurve->attach(m_pPlot);
m_pGrid->attach(m_pPlot);
m_pZoomer = new QwtPlotZoomer( m_pPlot->canvas() );
m_pZoomer->setRubberBandPen(QColor(Qt::red));
m_pZoomer->setTrackerPen(QColor(Qt::red));
m_pZoomer->setTrackerMode(QwtPlotZoomer::AlwaysOn);
m_pZoomer->setMousePattern( QwtEventPattern::MouseSelect2,
Qt::RightButton, Qt::ControlModifier );
m_pZoomer->setMousePattern( QwtEventPattern::MouseSelect3,
Qt::RightButton );
(void) new QwtPlotMagnifier( m_pPlot->canvas() );
connect(&timer, SIGNAL(timeout()), SLOT(newValue()));
connect(ui->reset, SIGNAL(clicked()), SLOT(resetBottomAxis()));
qsrand(QTime::currentTime().msec());
timer.start(200);
ui->verticalLayout->addWidget(m_pPlot);
m_BaseRec.setWidth(m_pPlot->canvas()->width());
m_BaseRec.setHeight(m_pPlot->canvas()->height());
resetBottomAxis();
}
Widget::~Widget()
{
delete m_pPlot;
delete ui;
}
void Widget::newValue()
{
qDebug() << m_BaseRec.top() << m_BaseRec.bottom();
points << QPointF(curX++, qrand()%201 - 100);
if (points.size() > m_BaseRec.width()) {
points.remove(0, stepSize);
m_pCurve->setSamples(points);
m_BaseRec.moveRight(m_BaseRec.right()+stepSize);
qDebug() << "**** APRES moveRight ****" << m_BaseRec;
qDebug() << "**** AVANT setZoomBase ****" << m_pZoomer->zoomBase();
m_pZoomer->setZoomBase(m_BaseRec);
qDebug() << "**** APRES setZoomBase ****" << m_pZoomer->zoomBase();
//if (m_pZoomer->zoomRectIndex() >= 1) {
resetBottomAxis();
m_pPlot->replot();
//}
} else {
m_pCurve->setSamples(points);
QwtPlotDirectPainter directPainter;
const double& d = m_pPlot->axisScaleDiv(QwtPlot::xBottom)->lowerBound();
directPainter.drawSeries(m_pCurve, curX-2-d, curX-1-d);
}
if (points.last().y() > m_BaseRec.bottom()) {
m_BaseRec.setBottom(points.last().y());
m_pZoomer->setZoomBase(m_BaseRec);
//if (m_pZoomer->zoomRectIndex() >= 1) {
m_pPlot->replot();
//}
} else if (points.last().y() < m_BaseRec.top()) {
m_BaseRec.setTop(points.last().y());
m_pZoomer->setZoomBase(m_BaseRec);
//if (m_pZoomer->zoomRectIndex() >= 1) {
m_pPlot->replot();
//}
}
qDebug() << m_pZoomer->zoomRectIndex() << " : " << m_pZoomer->zoomBase();
}
void Widget::resetBottomAxis() {
m_pPlot->setAxisScale(QwtPlot::xBottom, m_BaseRec.left(), m_BaseRec.right(), stepSize);
} |
Déjà je ne comprends pas pourquoi le m_pZoomer->zoomRectIndex() donne 1 tout le temps au lieu de 0 (clic droit pour dézoomer et on a 0 jusqu'au prochain changement de canvas où ça repasse à 1). Ensuite le setZoomBase force le zoomRectIndex à 1, alors que l'idée est juste de modifier la base (le 0 de la pile normalement) pendant qu'on est zoomé.
En espérant votre aide :)