QPaint绘制自定义坐标轴组件01

#ifndef MYCHART_H
#define MYCHART_H

#include <QWidget>
#include <QPainter>
#include <QString>

struct DataNode
{
    int value;
    QString key;
};

// MyChart继承自QWidget类,是一个窗口小部件。
class MyChart : public QWidget
{
    Q_OBJECT
public:
    // `explicit` 是 C++ 中的一个关键字,用于修饰类的构造函数,表示该构造函数只能用于显式地创建对象,不能被隐式地调用。
    // 只能通过MyChart painter = MyChart(parent)的方式显式地创建一个 `MyChart` 对象:
    // `parent` 参数的默认值为 `nullptr`,这表示如果没有提供父部件的指针,那么 `MyChart` 就没有父部件,即它是一个独立的窗口部件。
    explicit MyChart(QWidget *parent = nullptr);
    ~MyChart();
    void updateValue(const DataNode &node);
    // 创建坐标轴
    void AxisCreate();
    void AxisCurvesUpdate(const QList<QPoint> & pointList);

protected:
    void paintEvent(QPaintEvent *event);

private:
    QPainter *m_painter;
    QPoint m_pointZero;
    QPoint m_pointEndX;
    QPoint m_pointEndY;
    QPoint m_pointEndA;
    //坐标轴其实结束点
    int m_axisStartX;
    int m_axisStartY;
    int m_axisEndX;
    int m_axisEndY;
    // 高度
    int m_lenY;
    // 长度
    int m_lenX;
    // 每个刻度之间间隔的长度
    int m_PeriodX;
    int m_PeriodY;

    // 刻度间隔数
    int m_durationX = 100;
    int m_durationY = 10;

    int yMaxValue = 10;
    int maxNodeNum = 110;
    QList<DataNode> listDataNode;
};

#endif // MYCHART_H

#include "mychart.h"

MyChart::MyChart(QWidget *parent) : QWidget(parent)
{
    m_painter = new QPainter(this);
}

MyChart::~MyChart()
{
    delete m_painter;
}

// 数据刷新
void MyChart::updateValue(const DataNode &node)
{
    // 如果当前列表中的数据节点数量已经达到了最大值 `maxNodeNum`,
    // 先删除队列头部的元素,即最早加入的元素(使用 `removeFirst()` 函数)。
    if(listDataNode.size() >= maxNodeNum) {
        listDataNode.removeFirst();
    }
    // 然后,将数据节点 `node` 添加到当前列表的末尾,使用 `append()` 函数实现。
    listDataNode.append(node);
    // 最后,将整个图表更新,调用 `update()` 函数。
    // `update()` 函数是用来触发 `paintEvent()` 函数的信号的。
    // 当窗口或控件需要更新或重绘自己时,它们会同时发射一个 `update()` 信号。
    // 这个信号会被 Qt 的事件循环机制捕获,最终调用 `paintEvent()` 函数进行绘图。
    // 因此,如果不调用 `update()` 函数,`paintEvent()` 函数就不会被调用,也就不会更新图表的显示内容。
    update();
}

// 创建坐标轴
void MyChart::AxisCreate()
{
    m_painter->setRenderHint(QPainter::Antialiasing);
    QPen pen;
    pen.setWidth(2);
    pen.setColor(QColor(100, 200, 100));
    m_painter->setPen(pen);

    m_axisStartX = 30;
    m_axisEndX = this->width() - 30;
    m_axisStartY = this->height() - 30;
    m_axisEndY = 30;
    // 坐标轴高度
    m_lenX = m_axisEndX - m_axisStartX + 1;
    // 坐标轴长度
    m_lenY = m_axisStartY - m_axisEndY + 1;
    // 坐标端点设置
    m_pointZero = QPoint(m_axisStartX, m_axisStartY);
    m_pointEndX = QPoint(m_axisEndX, m_axisStartY);
    m_pointEndY = QPoint(m_axisStartX, m_axisEndY);
    m_pointEndA = QPoint(m_axisEndX, m_axisEndY);
    // x轴线
    m_painter->drawLine(m_pointZero, m_pointEndX);
    // 左侧y轴线
    m_painter->drawLine(m_pointZero, m_pointEndY);
    // 右侧y轴线
    m_painter->drawLine(m_pointEndX, m_pointEndA);

    // 绘制刻度
    // 每个刻度之间间隔的长度
    m_PeriodX = m_lenX / m_durationX - 1;
    m_PeriodY = m_lenY / m_durationY - 1;
    // 绘制坐标轴上的刻度和数字,用以标示坐标轴上每个刻度对应的数值
    for (int i = 0; i < m_durationX; ++i) {
        // 绘制表示x轴刻度的垂直线段
        m_painter->drawLine(QPoint(m_pointZero.x() + i * m_PeriodX, m_pointZero.y() + 5), QPoint(m_pointZero.x() + i * m_PeriodX, m_pointZero.y() - 5));
    }
    // 左侧y轴刻度
    for (int i = 0; i <= m_durationY; ++i) {
        // 绘制表示y轴刻度的水平线段
        m_painter->drawLine(QPoint(m_pointZero.x() - 5, m_pointZero.y() - i * m_PeriodY), QPoint(m_pointZero.x() + 5, m_pointZero.y() - i * m_PeriodY));
        QString value = QString::number(i * 2);
        // 绘制刻度数值
        m_painter->drawText(QPoint(m_pointZero.x() - 25, m_pointZero.y() - i * m_PeriodY + 5), value);
    }
    // 右侧y轴刻度
    for (int i = 0; i <= m_durationY; ++i) {
        // 绘制表示y轴刻度的水平线段
        m_painter->drawLine(QPoint(m_pointEndX.x() - 1, m_pointEndX.y() - i * m_PeriodY), QPoint(m_pointEndX.x() + 5, m_pointEndX.y() - i * m_PeriodY));
        QString value = QString::number(i * 2);
        // 绘制刻度数值
        m_painter->drawText(QPoint(m_pointEndX.x() - 25, m_pointEndX.y() - i * m_PeriodY + 5), value);
    }
}

void MyChart::AxisCurvesUpdate(const QList<QPoint> & pointList)
{
    QPen pen;

    // 折线线条宽度
    pen.setWidth(3);
    // 折现线条颜色
    pen.setColor(Qt::green);
    m_painter->setPen(pen);
    // 遍历并连接个数据节点,绘制折线
    for(int i = 0; i < pointList.size(); i++) {
        if((i+1) < pointList.size()) {
            // 连接个数据点,绘制折线
            m_painter->drawLine(pointList.at(i), pointList.at(i+1));
        }
    }
}

void MyChart::paintEvent(QPaintEvent *event)
{
    (void)event;
    m_painter->begin(this);

    // 创建坐标轴
    AxisCreate();

#if 1

    // 更新数据
    QList<QPoint> pointList;
    QList<QPoint> pointList2;

    for(int i = 0; i < listDataNode.size(); i++) {
        DataNode node = listDataNode.at(i);
        QString key = node.key;
        int value = node.value;
        // 当前数据在x轴位置对应的刻度值
        int xOffset = m_pointZero.x() + i * m_PeriodX;
        // 当前数据在y轴位置对应的刻度值
        int yOffset = value * m_lenY / yMaxValue;
        // 像数据列表中添加数据转换后对应的坐标点
        pointList << QPoint(xOffset, m_pointZero.y() - yOffset);
        pointList2 << QPoint(xOffset - 25,  m_pointZero.y() - yOffset - 25);
        // 使用 `QTransform` 类对绘制坐标文本的位置和方向进行变换
        QTransform transform;
        transform.translate(xOffset + 5, m_pointZero.y() - 7);
        transform.rotate(-45);
        m_painter->setTransform(transform);
        m_painter->drawText(0, 5, key);
        m_painter->resetTransform();
    }
    QPen pen;

    // 折线线条宽度
    pen.setWidth(3);
    // 折现线条颜色
    pen.setColor(Qt::red);
    m_painter->setPen(pen);
    // 遍历并连接个数据节点,绘制折线
    for(int i = 0; i < pointList.size(); i++) {
        if((i+1) < pointList.size()) {
            // 连接个数据点,绘制折线
            m_painter->drawLine(pointList.at(i), pointList.at(i+1));
        }
    }

    AxisCurvesUpdate(pointList2);
#endif

    m_painter->end();
}



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
InteractiveDataDisplay.WPF是一款用于可视化数据的开源图形库,它提供了许多功能强大且易于使用的功能。在该库中,我们可以自定义坐标轴以满足特定的需求。 要自定义坐标轴,我们可以使用以下步骤: 1. 创建一个新的自定义坐标轴类,继承自`AxisBase`类。 2. 在自定义坐标轴类中,重写必要的方法和属性,比如`CreateTicksProvider`用于生成刻度值、`TickFactory`用于生成刻度标签等。 3. 在自定义坐标轴类中,根据需要实现其他自定义功能,比如添加自定义网格线、刻度线样式等。 4. 将自定义坐标轴类与要显示的图形绑定,通过调用`Plotter.AddAxes`方法将其添加到绘图器中。 例如,我们可以用以下代码实现一个自定义的对数坐标轴: ```csharp public class CustomLogarithmicAxis : AxisBase { protected override ITicksProvider CreateTicksProvider() { // 创建对数刻度提供器 return new LogarithmicTicksProvider(); } protected override void DrawTicks(DrawingContext dc, double[] ticksLength) { // 自定义刻度线绘制逻辑 // ... } protected override void DrawLabels(DrawingContext dc, Plots.AxisPosition position) { // 自定义刻度标签绘制逻辑 // ... } } // 使用自定义坐标轴 var plotter = new Plotter(); plotter.AddAxes(new CustomLogarithmicAxis(), new CustomLogarithmicAxis()); ``` 通过以上步骤,我们可以按照自己的需求创建具有特定功能的自定义坐标轴,并将其添加到InteractiveDataDisplay.WPF的绘图器中显示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值