How to prevent zooming of QChartView into negative x or y axis values

934 Views Asked by At

I want to prevent zooming of a QChartView into negative x or y axis values. So I'm trying to intercept the mouseReleaseEvent in my subclass of QChartView and then modify the coordinates of the rubberBandRect before performing the zoom. But it seems the rubberBandRect coordinates are always zero after mouse release, so I think I'm not working with the correct rubberBandRect.

I'm trying to adapt based on the documentation for QChartView (emphasis added):

void QChartView::mouseReleaseEvent(QMouseEvent *event)

If the left mouse button is released and the rubber band is enabled, the event event is accepted and the view is zoomed into the rectangle specified by the rubber band.

When I tried looked at the actual values in the rubberBandRect in the code snippet below, the x/y and height/width values of the rectangle are always zero no matter how I zoomed with the cursor.

I also looked at the answer to this question: Qt How to connect the rubberBandChanged signal but in that case, they wanted the behavior in the main window, which is not what I want. Thanks!

class MyQChartView : public QtCharts::QChartView
{
    Q_OBJECT
public:
    MyQChartView(QWidget *parent = 0);
    //...
protected:
    void mouseReleaseEvent(QMouseEvent *event);
    void keyPressEvent(QKeyEvent *event);

};


void MyQChartView::mouseReleaseEvent(QMouseEvent *event)
{
    
    //always shows zeroes for the x and y position
    if(event->button() == Qt::LeftButton){
        std::cout << "x: " << this->rubberBandRect().x() << " y: " << this->rubberBandRect().y() << std::endl;
        
        QChartView::mouseReleaseEvent(event);
    }
    
    //any other event
    QChartView::mouseReleaseEvent(event);
}
1

There are 1 best solutions below

0
On

After extensive experiments, I think I found the best workaround. It was necessary to make a rubberBand pointer and then findChild to get to the actual rubberband. Then after mouse release, I get the plot area coordinates as well as the rubberband coordinates. Then I made a bounding box (bounded_geometry) and limited its values if the rubberband went out of bounds. Then I zoomIn to the bounded geometry box. It won't work to just modify the rubberband because those coordinates are not floating point and rounding errors cause wrong zooming.

class MyQChartView : public QtCharts::QChartView
{
    Q_OBJECT
public:
    MyQChartView(QWidget *parent = 0):
    QChartView(parent)
    {
        myChart = new QtCharts::QChart();
        setRubberBand(QtCharts::QChartView::RectangleRubberBand);
        rubberBandPtr = this->findChild<QRubberBand *>();
        this->setChart(myChart);
        //...other things
    }
    //...
protected:
    void mouseReleaseEvent(QMouseEvent *event);
    void keyPressEvent(QKeyEvent *event);
private:
    QRubberBand * rubberBandPtr;
    QtCharts::QChart * myChart;
};


void MyQChartView::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        //first get the plot area and save the needed values (could change each time)
        QRectF plotArea = myChart->plotArea();
        qreal xbound = plotArea.x(); //values < xbound are out of bounds on x axis
        qreal ybound = plotArea.y() + plotArea.height(); // !!! note that values > ybound are out of bounds (i.e. negative y values)
        
        QPointF rb_tl = rubberBandPtr->geometry().topLeft();
        QPointF rb_br = rubberBandPtr->geometry().bottomRight();
        
        QRectF bounded_geometry = rubberBandPtr->geometry();
        
        if(rb_tl.x() < xbound){
            bounded_geometry.setX(xbound);
        }
        if(rb_br.y() > ybound){ //note that values > ybound are out of bounds
            bounded_geometry.setBottom(ybound);
        }
        
        myChart->zoomIn(bounded_geometry);        
        rubberBandPtr->close();

        return;
    }
    
    //any other event
    QChartView::mouseReleaseEvent(event);
}