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 XML : Sélectionner tout - Visualiser dans une fenêtre à part
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 C++ : Sélectionner tout - Visualiser dans une fenêtre à part
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 C++ : Sélectionner tout - Visualiser dans une fenêtre à part
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