Как установить собственный формат меток точек для QLineSeries/QXYSeries?

Контекст: я пытаюсь отобразить QLineSeries на QChart, чтобы распечатать изменение значения во времени.
Следовательно, ось X (абсцисса) представляет собой QDateTimeAxis, а ось Y (ордината ) является QValueAxis.

Проблема: я хочу отобразить метки точек. Но я не могу найти, как установить нужный формат для даты и времени.
По умолчанию метки могут отображать только целые значения точки, что мне и нужно для значения ординаты.
Но для абсцисс (datetime), оно печатает количество миллисекунд, прошедших с последней эпохи (1970-01-01T00:00:00.000).
Я хочу изменить формат даты и времени чтобы соответствовать "чч:мм:сс" (это формат, который я использую для отображения делений на QDateTimeAxis).

Я знаю, что существует QXYSeries::setPointlabelsFormat(), который позволяет указать формат но он принимает только теги формата @xPoint и @yPoint (как вы можете видеть в документации).

  • Здесь вы можете найти изображение проблемы: введите здесь описание изображения

Как видите, я могу установить формат для QDateTimeAxis, но не для меток точек.

Образец кода, который создает этот вывод, основан на приведенном здесь. Я просто добавил больше точек и раскомментировал строку //ls->setPointLabelsVisible(true);.

Вопрос. Есть ли способ напечатать этикетки @xPoint в пользовательском формате (в идеале, чтобы они соответствовали QDateTime::toString("hh:mm:ss"))? Если да, то как?


person Fareanor    schedule 05.11.2019    source источник


Ответы (2)


Он не поддерживается QXYSeries. Вы можете создать новый класс из QAbstractSeries для вашего так называемое QXYDatetimeSeries после того же, что реализовано в QXYSeries просмотрев код. Вы также можете изменить исходный код QXYSeriesPrivate::drawSeriesPointLabels для поддержки своего поведения. Не забудьте отправить свои изменения в репозиторий Qt git, чтобы другие люди также могли его использовать.

person Soheil Armin    schedule 05.11.2019
comment
Спасибо за ответ, я уже думал об этом. Но я хотел избежать этого, если это возможно. Так что ответ - нет тогда. Я не буду изменять исходный код, потому что он должен быть переносимым и работать на другой платформе (на которой, очевидно, не будет моей модификации, если только Qt не примет возможный запрос на включение). Вместо этого я нарисую только @yPoint. Когда у меня будет время, я переопределю свой собственный класс серии. - person Fareanor; 06.11.2019

Как отмечает Soheim, формат меток точек, предоставляемый QtCharts, слишком ограничен для этого.

Если вы не хотите замарать руки внутренностями QtCharts, вы можете решить свою проблему другим способом: нарисовать текстовые метки самостоятельно.

Получите пользовательский графический элемент от QGraphicsObject:

class PointLabelsItem : public QGraphicsObject
{
    Q_OBJECT
public:
    PointLabelsItem(QtCharts::QChart *parent = nullptr);
    virtual QRectF boundingRect() const;
    virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);

public slots:
    void setRect(const QRectF &area);
    void setAxis(const QAbstractAxis *axis, Qt::Alignment alignment);
    // setter for either source Q*Series or points / point labels

protected:
    QRectF area;
    // const axes*
    // const series* or points/labels
};

В реализации:

PointLabelsItem::PointLabelsItem(QtCharts::QChart *parent)
    : QGraphicsObject(parent)
{
    setZValue(10); // put above series
    connect(parent, &QtCharts::QChart::plotAreaChanged,
        this, &PointLabelsItem::setRect);
}

QRectF PointLabelsItem::boundingRect() const
{
    return area;
}

void PointLabelsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    // translate between data coordinates and scene coordinates
    // by making use of `area` and the axes' ranges, OR via
    // qobject_cast<QtCharts::QChart>(parent())->mapToPosition()
    // then draw custom point label texts at the corresp. positions
}

void PointLabelsItem::setRect(const QRectF &newArea)
{
    area = newArea;
    update();
}

void setAxis(const QAbstractAxis *axis, Qt::Alignment alignment)
{
    disconnect(/* old axis member variable */);
    // set corresp. axis member variable here
    connect(axis, &QtCharts::QValueAxis::rangeChanged, this, [this] { update(); });
}

Снаружи:

auto pointLabels = new PointLabelsItem(chart);
// set axes, series

Это баребон.

Вы также можете решить, что QGRaphicsTextItem являются дочерними элементами ваших PointLabelsItem (т. е. участников, у которых this установлено как их parent). Таким образом, вы можете включить взаимодействие пользователя с метками.

person ypnos    schedule 12.11.2019
comment
Если я правильно понял, идея состоит в том, чтобы нарисовать еще один QGraphicsObject в QChart, который будет рисовать метки независимо. Звучит хороший обходной путь. Я предполагаю, что под RangeSelectItem (для объема реализации setRect()) вы подразумеваете PointLabelsItem. - person Fareanor; 12.11.2019
comment
Извините, это была ошибка копирования и вставки. Я изменил свой более конкретный класс для этого примера. - person ypnos; 12.11.2019