首页 > 解决方案 > 如何设置 QChart 纵横比

问题描述

我正在尝试实现一种算法来保持 QChart 纵横比。这是一种工作,但我想知道是否有人有更简单的解决方案。

下面是发生在调整大小事件上的代码

void TrainChartView::maintainAspectRatio(QSizeF eventSize) {

    int aspect = 8;
    QSizeF chartSize = m_chart->size();

    QValueAxis* axisX = qobject_cast<QValueAxis*>(m_chart->axisX());
    QValueAxis* axisY = qobject_cast<QValueAxis*>(m_chart->axisY());

    // get Min Max X-axis Value
    double minAxisX = axisX->min();
    double maxAxisX = axisX->max();
    double minAxisY = axisY->min();
    double maxAxisY = axisY->max();

    // Get Coordinates in scene of min and max X-axis value
    QPointF minAxisXPosition = m_chart->mapToPosition(QPointF(minAxisX, 0));
    QPointF maxAxisXPosition = m_chart->mapToPosition(QPointF(maxAxisX, 0));
    QPointF minAxisYPosition = m_chart->mapToPosition(QPointF(0, minAxisY));
    QPointF maxAxisYPosition = m_chart->mapToPosition(QPointF(0, maxAxisY));

    double axisXSize = abs(maxAxisXPosition.x() - minAxisXPosition.x());
    double axisYSize = abs(maxAxisXPosition.y() - minAxisYPosition.y());

    // get the size of axis x in the coordinate system
    double deltaAxisXSize = maxAxisXPosition.x() - minAxisXPosition.x();

    if (chartSize.width() != eventSize.width()) {
        QPointF maxAxisValue = m_chart->mapToValue(QPointF(0, (minAxisYPosition.y() - deltaAxisXSize)));
        axisY->setRange(minAxisY, maxAxisValue.y() / aspect);
    }

    if (chartSize.height() != eventSize.height() && m_chart->minimumSize().height() >= eventSize.height()) {
        double deltaHeight = eventSize.height() - chartSize.height();
        maxAxisYPosition.setY(maxAxisYPosition.y() - deltaHeight);
        QPointF maxAxisValue = m_chart->mapToValue(QPointF(maxAxisYPosition));

        axisY->setRange(minAxisY, maxAxisValue.y());

    }

标签: qtqt5qtchartsqchartqchartview

解决方案


我修改了你所做的一段代码,这就是我最终得到的:

在.h

//! \brief The QChartView_scaledAxis class extends the QChartView class but force the graph to be normalized
//! (i.e.) 1 pixel on the x-axis represent the same amount as 1 pixel on the y-axis.
class QChartView_scaledAxis : public QChartView {
public:
    void resizeEvent(QResizeEvent *event) override;
};

在.cpp

void QChartView_scaledAxis::resizeEvent(QResizeEvent *event) {
    QChartView::resizeEvent(event);

    // Get the axis of the graph
    QValueAxis* axisX = qobject_cast<QValueAxis*>(this->chart()->axes(Qt::Horizontal)[0]);
    QValueAxis* axisY = qobject_cast<QValueAxis*>(this->chart()->axes(Qt::Vertical)[0]);

    // Get the series displayed on the graph
    const QList<QAbstractSeries*> series = this->chart()->series();

    // get Min Max values (on X and Y) of all the points plotted on the graph
    float minX = std::numeric_limits<double>::max();
    float maxX = std::numeric_limits<double>::min();
    float minY = std::numeric_limits<double>::max();
    float maxY = std::numeric_limits<double>::min();
    for(QAbstractSeries *p_serie : series) { //iterate on all the series in the graph
        //Assuming all the series in the graph are QXYSeries...
        for(QPointF p : qobject_cast<QXYSeries*>(p_serie)->points()) { //iterate on each point of each serie
            minX = fmin(minX, p.x());
            maxX = fmax(maxX, p.x());
            minY = fmin(minY, p.y());
            maxY = fmax(maxY, p.y());
        }
    }

    // Get the points at both ends of the axis (will help to determine the plottable area in pixel)
    const QPointF minPosition = this->chart()->mapToPosition(QPointF(axisX->min(), axisY->min()));
    const QPointF maxPosition = this->chart()->mapToPosition(QPointF(axisX->max(), axisY->max()));

    // Ration between the size of the axis in pixel and in term of represented value
    const double axisX_PixToValue = (maxX - minX) / (maxPosition.x() - minPosition.x());
    const double axisY_PixToValue = (maxY - minY) / (maxPosition.y() - minPosition.y());

    // The smallest ratio must be 'kept' and applied to the other axis
    if(abs(axisX_PixToValue) > abs(axisY_PixToValue)) {
        axisY->setMin(minY);
        axisY->setMax(minY + (maxPosition.y() - minPosition.y()) * std::copysign(axisX_PixToValue, axisY_PixToValue));
    } else {
        axisX->setMin(minX);
        axisX->setMax(minX + (maxPosition.x() - minPosition.x()) * std::copysign(axisY_PixToValue, axisX_PixToValue));
    }
}

此代码适用于 1:1 的比例,但我确信它可以轻松修改为任何其他比例......


推荐阅读