自定义的Qt仿示波器控件

此控件主要用来显示波形图。当用户不断向控件push数值时,图表中的波形逐渐向左移动。此类用法简单。先创建类实例,然后调用setLimit函数设置数据范围,调用setMaxCount函数设置控件显示数据的最大数量,最后不断向其push数据就行了。这个控件在VS2015和Qt5.9上测试通过。下面是控件的效果图,分别是数据未满和数据已满的截图:

下面上代码,头文件:

class MOscil : public QWidget
{
    Q_OBJECT

public:
    MOscil(QWidget* parent = nullptr);
    void setLimit(qreal min, qreal max);
    void setMaxCount(int count);
    void push(qreal value);

private:
    void paintEvent(QPaintEvent *event) override;

private:
    int maxCount;
    qreal minValue;
    qreal maxValue;
    QQueue<qreal> datas;
};

CPP文件:

MOscil::MOscil(QWidget* parent) : 
    QWidget(parent)
{
    minValue = 0;
    maxValue = 100;
    maxCount = 10;
}

void MOscil::setLimit(qreal min, qreal max)
{
    minValue = min;
    maxValue = max;
    update();
}

void MOscil::setMaxCount(int count)
{
    int dataCount = (int)datas.size();
    if (count < dataCount)
    {
        const int delta = dataCount - count;
        for (int i = 0; i < delta; i++)
        {
            datas.pop_front();
        }
    }
    maxCount = count;
    update();
}

void MOscil::push(qreal value)
{
    datas.append(value);
    if (datas.size() > maxCount)
    {
        datas.pop_front();
    }
    update();
}

void MOscil::paintEvent(QPaintEvent *event)
{
    const int textPad = 20;
    const QMargins chartm(40, 20, 20, 20);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    int xLeft = chartm.left();
    int xRight = width() - chartm.right();
    int yTop = chartm.top();
    int yBottom = height() - chartm.bottom();

    /* 画矩形外框 */
    painter.setBrush(Qt::NoBrush);
    painter.setPen(QColor(32, 243, 32));
    painter.drawRect(xLeft, yTop, xRight - xLeft, yBottom - yTop);

    /* 画中间横竖虚线 */
    painter.setPen(QPen(QColor(32, 173, 32), 1, Qt::DashLine));
    for (int i = 0; i < 3; i++)
    {
        qreal y = yTop + (yBottom - yTop) / 4.0 * (i + 1);
        QPointF h1(xLeft, y);
        QPointF h2(xRight, y);
        painter.drawLine(h1, h2);

        qreal x = xLeft + (xRight - xLeft) / 4.0 * (i + 1);
        QPointF v1(x, yTop);
        QPointF v2(x, yBottom);
        painter.drawLine(v1, v2);
    }

    /* 画刻度数值 */
    painter.setPen(Qt::black);
    QFontMetrics fm = painter.fontMetrics();
    for (int i = 0; i <= 4; i++)
    {
        int y = yTop + (yBottom - yTop) / 4 * i;
        QString text = QString::number(maxValue + (minValue - maxValue) / 4 * i, 'g', 3);
        QPoint tpos(xLeft - textPad, y);
        QSize tsz = fm.size(0, text);
        painter.drawText(QRect(QPoint(tpos.x() - tsz.width() / 2, tpos.y() - tsz.height() / 2), tsz), text);
    }

    /* 画数据 */
    int count = (int)datas.size();
    qreal step = (xRight - xLeft) / (maxCount - 1.0);
    qreal startx = xLeft + step * (maxCount - count);
    painter.setPen(Qt::blue);
    for (int i = 1; i < count; i++)
    {
        qreal y1scr = yBottom + (yTop - yBottom) * (datas[i - 1] - minValue) / (maxValue - minValue);
        qreal y2scr = yBottom + (yTop - yBottom) * (datas[i] - minValue) / (maxValue - minValue);
        QPointF p1(startx, y1scr);
        QPointF p2(startx + step, y2scr);
        painter.drawLine(p1, p2);
        startx += step;
    }
}

 

posted @ 2022-11-12 16:28  兜尼完  阅读(367)  评论(0编辑  收藏  举报