QChartView и QScatterSeries переопределяют метку QPointF

У меня есть QChartView, который отображает некоторые 2D точки, которые представляют каждую конкретный проект. Я хочу пометить каждую точку с именем проекта, а НЕ с его координатами x,y в качестве поведения по умолчанию

Есть ли способ добиться переопределения функции, которая создает или визуализирует метки?

1 ответ

Решение

Почему это может быть трудно достичь без изменения исходного кода Qt

  1. QXYSeries::setPointLabelsFormat не очень поможет вам. Это действительно позволяет вам изменять формат меток, но единственная переменная часть - это координаты точек.

  2. Все рисование сделано в приватной части классов Qt. Вот вся история:

Метки нарисованы в приватной части QXYSeries (painter->drawText(position, pointLabel);):

void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVector<QPointF> &points,
                                             const int offset)
{
    if (points.size() == 0)
        return;
    static const QString xPointTag(QLatin1String("@xPoint"));
    static const QString yPointTag(QLatin1String("@yPoint"));
    const int labelOffset = offset + 2;
    painter->setFont(m_pointLabelsFont);
    painter->setPen(QPen(m_pointLabelsColor));
    QFontMetrics fm(painter->font());
    // m_points is used for the label here as it has the series point information
    // points variable passed is used for positioning because it has the coordinates
    const int pointCount = qMin(points.size(), m_points.size());
    for (int i(0); i < pointCount; i++) {
        QString pointLabel = m_pointLabelsFormat;
        pointLabel.replace(xPointTag, presenter()->numberToString(m_points.at(i).x()));
        pointLabel.replace(yPointTag, presenter()->numberToString(m_points.at(i).y()));
        // Position text in relation to the point
        int pointLabelWidth = fm.width(pointLabel);
        QPointF position(points.at(i));
        position.setX(position.x() - pointLabelWidth / 2);
        position.setY(position.y() - labelOffset);
        painter->drawText(position, pointLabel);
    }
}

drawSeriesPointLabels вызывается из метода рисования ScatterChartItem (этот класс не включен в официальную документацию):

void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)
    if (m_series->useOpenGL())
        return;
    QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
    painter->save();
    painter->setClipRect(clipRect);
    if (m_pointLabelsVisible) {
        if (m_pointLabelsClipping)
            painter->setClipping(true);
        else
            painter->setClipping(false);
        m_series->d_func()->drawSeriesPointLabels(painter, m_points,
                                                  m_series->markerSize() / 2
                                                  + m_series->pen().width());
    }
    painter->restore();
}

В свою очередь ScatterChartItem создается в закрытой части QScatterSeries и не может быть заменен пользовательским классом:

void QScatterSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
{
    Q_Q(QScatterSeries);
    ScatterChartItem *scatter = new ScatterChartItem(q,parent);
    m_item.reset(scatter);
    QAbstractSeriesPrivate::initializeGraphics(parent);
}

Что вы можете попробовать

  1. Скрыть оригинальные ярлыки с setPointLabelsVisible(false); Этикетки будут нарисованы отдельно после этого.

  2. Подкласс QChartView и переопределить paintEventвызывая сначала QChartView::paintEvent а затем вызвать пользовательскую функцию (скажем, drawCustomLabels), который является модифицированной версией QXYSeriesPrivate::drawSeriesPointLabels, По телефону drawCustomLabels проходить:

    • местный художник рисует на портале MyChartView,
    • очки, возвращенные QXYSeries::points,
    • желаемое смещение.

Вот пример того, как drawCustomLabels может выглядеть так:

void MyChartView::drawCustomLabels(QPainter *painter, const QVector<QPointF> &points, const int offset)
{
    if (points.count() == 0)
        return;

    QFontMetrics fm(painter->font());
    const int labelOffset = offset + 2;

    painter->setFont(m_pointLabelsFont); // Use QXYSeries::pointLabelsFont() to access m_pointLabelsFont
    painter->setPen(QPen(m_pointLabelsColor)); // Use QXYSeries::pointLabelsColor() to access m_pointLabelsColor

    for (int n(0); n < points.count(); n++) {
        QString pointLabel = "..."; // Set the desired label for the n-th point of the series
        // Position text in relation to the point
        int pointLabelWidth = fm.width(pointLabel);
        QPointF position(points.at(n));
        position.setX(position.x() - pointLabelWidth / 2);
        position.setY(position.y() - labelOffset);
        painter->drawText(position, pointLabel);
    }
}
Другие вопросы по тегам