Qt自定义QWidget

130 篇文章 4 订阅
24 篇文章 1 订阅

实例1 电池

promotion.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = promotion
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
    main.cpp \
    widget.cpp \
    qmybattery.cpp

HEADERS += \
    widget.h \
    qmybattery.h

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[]) {
   QApplication a(argc, argv);

   Widget w;
   w.show();

   return a.exec();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QSlider>
#include <QVBoxLayout>

#include "qmybattery.h"

class Widget : public QWidget {
   Q_OBJECT
public:
   explicit Widget(QWidget *parent = 0);
private slots:
   void on_horizontalSlider_valueChanged(int value);
private:
   QmyBattery *battery;
   QSlider *horizontalSlider;
   QLabel *LabInfo;
   QVBoxLayout *mainLayout;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent){
    battery = new QmyBattery;
    horizontalSlider = new QSlider(Qt::Horizontal);
    horizontalSlider->setRange(0, 99);
    LabInfo = new QLabel;
    mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(battery, 1);
    mainLayout->addWidget(horizontalSlider);
    mainLayout->addWidget(LabInfo);

    connect(horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(on_horizontalSlider_valueChanged(int)));

    horizontalSlider->setValue(60);
}

void Widget::on_horizontalSlider_valueChanged(int value) {
    battery->setPowerLevel(value);
    QString  str = QStringLiteral("当前电量:")+QString::asprintf("%d%%", value);
    LabInfo->setText(str);
}

qmybatter.h

#ifndef WBATTERY_H
#define WBATTERY_H

#include <QWidget>
#include <QColor>

class QmyBattery : public QWidget {
    Q_OBJECT
	//自定义属性
    Q_PROPERTY(int powerLevel READ powerLevel WRITE setPowerLevel NOTIFY powerLevelChanged)
private:
    QColor  mColorBack = Qt::white;//背景颜色
    QColor  mColorBorder = Qt::black;//电池边框颜色
    QColor  mColorPower = Qt::green;//电量柱颜色
    QColor  mColorWarning = Qt::red;//电量短缺时的颜色

    int mPowerLevel = 60;//电量0-100
    int mWarnLevel = 20;//电量低警示阈值
protected:
    void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
public:
    explicit QmyBattery(QWidget *parent = 0);

    void setPowerLevel(int pow);//设置当前电量
    int powerLevel();

    void setWarnLevel(int warn);//设置电量低阈值
    int warnLevel();

    virtual QSize sizeHint() const Q_DECL_OVERRIDE;//报告缺省大小
signals:
    void powerLevelChanged(int);
};

#endif // WBATTERY_H

qmybatter.cpp

#include "qmybattery.h"

#include <QPainter>

void QmyBattery::paintEvent(QPaintEvent *event) { //界面组件的绘制
    Q_UNUSED(event);

    QPainter painter(this);
    QRect rect(0, 0, width(), height()); //viewport矩形区
    painter.setViewport(rect);//设置Viewport
    painter.setWindow(0, 0, 120, 50); // 设置窗口大小,逻辑坐标
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::TextAntialiasing);

    //绘制电池边框
    QPen pen;//设置画笔
    pen.setWidth(2); //线宽
    pen.setColor(mColorBorder); //划线颜色
    pen.setStyle(Qt::SolidLine);//线的类型,实线、虚线等
    pen.setCapStyle(Qt::FlatCap);//线端点样式
    pen.setJoinStyle(Qt::BevelJoin);//线的连接点样式
    painter.setPen(pen);

    QBrush brush;//设置画刷
    brush.setColor(mColorBack); //画刷颜色
    brush.setStyle(Qt::SolidPattern); //画刷填充样式
    painter.setBrush(brush);

    rect.setRect(1, 1, 109, 48);
    painter.drawRect(rect);//绘制电池边框

    brush.setColor(mColorBorder); //画刷颜色
    painter.setBrush(brush);
    rect.setRect(110, 15, 10, 20);
    painter.drawRect(rect); //画电池正极头

    //画电池柱
    if(mPowerLevel>mWarnLevel) {  //正常颜色电量柱
        brush.setColor(mColorPower); //画刷颜色
        pen.setColor(mColorPower); //划线颜色
    } else { //电量低电量柱
        brush.setColor(mColorWarning); //画刷颜色
        pen.setColor(mColorWarning); //划线颜色
    }
    painter.setBrush(brush);
    painter.setPen(pen);

    if (mPowerLevel>0) {
        rect.setRect(5, 5, mPowerLevel, 40);
        painter.drawRect(rect);//画电池柱
    }

    //绘制电量百分比文字
    QFontMetrics  textSize(this->font());
    QString powStr = QString::asprintf("%d%%", mPowerLevel);
    QRect textRect = textSize.boundingRect(powStr);//得到字符串的rect

    painter.setFont(this->font());
    pen.setColor(mColorBorder); //划线颜色
    painter.setPen(pen);

    painter.drawText(55-textRect.width()/2,
                     23+textRect.height()/2,
                     powStr);
}

QmyBattery::QmyBattery(QWidget *parent) : QWidget(parent) {
}

void QmyBattery::setPowerLevel(int pow) { //设置当前电量值
    mPowerLevel = pow;
    emit powerLevelChanged(pow); //触发信号
    repaint();
}

int QmyBattery::powerLevel() { //读取当前电量值
    return mPowerLevel;
}

void QmyBattery::setWarnLevel(int warn) {//设置电量低阈值
    mWarnLevel = warn;
    repaint();
}

int QmyBattery::warnLevel() {//读取电量低阈值
    return  mWarnLevel;
}

QSize QmyBattery::sizeHint() const {//报告缺省大小,调整比例
    int H = height();
    int W = H*12/5;
    return QSize(W, H);
}

实例2 plot绘图

Plot.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = Plot
TEMPLATE = app

SOURCES += main.cpp \
    widget.cpp

HEADERS  += widget.h

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    Widget w;
    w.show();

    return a.exec();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMargins>

class Widget : public QWidget {
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
protected:
    void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
private:
    void iniData();//初始化数据
    void drawGrid(QPainter& p, QRect &windRect);//绘制网格底图
    void preparePoints(QRect &windRect);//准备画点的数据
    void drawCurve(QPainter& p);//绘制曲线

    const int m_count = 1000;
    const qreal m_intv = 0.01;
    const int m_XTicks = 10;
    const int m_YTicks = 4;

    QMargins m_margins;//边距
    QVector<QPointF> m_dataF;//实际数据
    QVector<QPoint> m_points;//数据点,像素点

    qreal m_xmin = 0;
    qreal m_xmax = 10;
    qreal m_xspan = m_xmax-m_xmin;

    qreal m_ymin = -2;
    qreal m_ymax = 2;
    qreal m_yspan=m_ymax-m_ymin;

    //单位数值是对应像素点
    qreal m_xRatio;
    qreal m_yRatio;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include <QtMath>
#include <QPainter>
#include <QFontMetrics>

Widget::Widget(QWidget *parent) : QWidget(parent) {
    setPalette(QPalette(Qt::white));
    setAutoFillBackground(true);

    m_margins.setLeft(80);
    m_margins.setTop(50);
    m_margins.setRight(50);
    m_margins.setBottom(50);

    iniData();
}

void Widget::paintEvent(QPaintEvent *) {
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing, true);
    p.setRenderHint(QPainter::TextAntialiasing, true);

    int W = width();
    int H = height();

    QRect WindRect(0, 0, W, H);

    m_xRatio = (W-m_margins.left()-m_margins.right())/m_xspan;
    m_yRatio = (H-m_margins.top()-m_margins.bottom())/m_yspan;

    drawGrid(p, WindRect);
    preparePoints(WindRect);
    drawCurve(p);
}

void Widget::iniData() {//生成实际数据
    for (int i=0; i<m_count; i++){
        qreal t = m_intv*i;
        m_dataF.append(QPointF(t, qSin(4*t)));
    }
}

void Widget::drawGrid(QPainter &p, QRect &windRect) {
    QRect rect(windRect.left()+m_margins.left(),
               windRect.top()+m_margins.top(),
               windRect.width()-m_margins.left()-m_margins.right(),
               windRect.height()-m_margins.top()-m_margins.bottom());
    if (!rect.isValid())
        return;

    QPen penDot(Qt::DotLine);
    penDot.setColor(Qt::gray);

    QPen penSolid(Qt::SolidLine);
    penSolid.setColor(Qt::black);

    p.setPen(penSolid);
    p.drawRect(rect.adjusted(0, 0, -1, -1));

    int Xpos;
    qreal Xvalue;
    QString xlab;
    QFontMetrics textSize(this->font());
    QRect textRect;
    for(int i=0; i<=m_XTicks; i++) {
        Xpos = rect.left()+i*m_xRatio; //
        Xvalue = m_xmin+i*m_xspan/m_XTicks;//
        p.setPen(penDot);
        p.drawLine(Xpos, rect.top(), Xpos, rect.bottom());
        p.setPen(penSolid);
        p.drawLine(Xpos, rect.bottom(), Xpos, rect.bottom()+5);

        xlab = QString::asprintf("%.1f", Xvalue);
        textRect = textSize.boundingRect(xlab);//得到字符串的rect
        p.drawText(Xpos-textRect.width()/2,
                   rect.bottom()+5+textRect.height(),
                   xlab);
    }

    xlab = "time(sec)";
    textRect = textSize.boundingRect(xlab);//得到字符串的rect
    p.drawText(rect.left()+(rect.width()-textRect.width())/2,
               windRect.bottom()-textRect.height()/2,
               xlab);

    xlab = "曲线绘图";
    textRect = textSize.boundingRect(xlab);//得到字符串的rect
    p.drawText(rect.left()+(rect.width()-textRect.width())/2,
               (m_margins.top()-textRect.height())/2+textRect.height(),
               xlab);

    int Ypos;
    qreal Yvalue;
    QString ylab;
    for(int i=0;i<=m_YTicks;i++) {
        Ypos = rect.bottom()-i*m_yRatio; //
        Yvalue = m_ymin+i*m_yspan/m_YTicks;//
        p.setPen(penDot);
        p.drawLine(rect.left(), Ypos, rect.right(), Ypos);
        p.setPen(penSolid);
        p.drawLine(rect.left()-5, Ypos, rect.left(), Ypos);

        ylab = QString::asprintf("%.1f", Yvalue);
        textRect = textSize.boundingRect(ylab);//得到字符串的rect

        p.drawText(rect.left()-10-textRect.width(),
                   Ypos+textRect.height()/2,
                   ylab);
    }

    ylab = "函数值";
    textRect = textSize.boundingRect(ylab);//得到字符串的rect
    p.save();
    p.translate(0, windRect.height()/2); //平移到左侧中心
    p.rotate(-90);//逆时针旋转90度,变成正北为X轴,正东为Y轴

    p.drawText(-textRect.width()/2,
               (m_margins.left()-textRect.height())/2,
               ylab);
    p.restore();
}

void Widget::preparePoints(QRect &windRect) {
    m_points.clear();
    int xPos, yPos;
    qreal x, y;
    for (int i=0; i<m_count; i++) {
        x = m_dataF[i].x(); //实数
        y = m_dataF[i].y();//实数
        xPos = m_xRatio*(x-m_xmin);
        xPos = m_margins.left()+xPos;

        yPos = m_yRatio*(y-m_ymin);
        yPos = windRect.height()-m_margins.bottom()-yPos;

        m_points.append(QPoint(xPos, yPos));
    }
}

void Widget::drawCurve(QPainter &p) {
    QPolygon curve(m_points.count());

    for(int i=0; i<m_points.count(); i++)
        curve[i] = m_points[i];

    QPen pen(Qt::SolidLine);
    pen.setColor(Qt::blue);
    pen.setWidth(2);
    p.setPen(pen);

    p.drawPolyline(curve);
}

实例3 plot按比例绘图

Plot.pro

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = Plot
TEMPLATE = app

SOURCES += main.cpp \
    widget.cpp

HEADERS  += widget.h

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    Widget w;
    w.show();

    return a.exec();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMargins>

class Widget : public QWidget {
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
protected:
    void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
private:
    qreal x_min = 0.0;
    qreal x_max = 10.0;
    qreal y_min = -2.0;
    qreal y_max = 2.0;
    qreal top_margin = 0.1;
    qreal bottom_margin = 0.1;
    qreal left_margin = 0.1;
    qreal right_margin = 0.1;

    qreal x_range = x_max-x_min;
    qreal y_range = y_max-y_min;
    qreal ratio = x_range/y_range; //w/h

    int tick_length = 5;
    QFont title_font;
    QFont label_font;
    QString title = tr("曲线绘图");
    QString x_label = tr("time(sec)");
    QString y_label = tr("函数值");
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include <QtMath>
#include <QPainter>
#include <QFontMetrics>

Widget::Widget(QWidget *parent) : QWidget(parent) {
    setPalette(QPalette(Qt::white));
    setAutoFillBackground(true);

    title_font.setPixelSize(18);
    label_font.setPixelSize(10);
}

void Widget::paintEvent(QPaintEvent *) {
    //窗口中央按比例ratio绘制图像
    int W = width();
    int H = height();
    int w = W;
    int h = H;
    if(H*ratio>W){
        h = W/ratio;
    } else {
        w = H*ratio;
    }
    //单位数值对应像素点个数
    qreal x_ratio = w*(1.0-left_margin-right_margin)/x_range;
    qreal y_ratio = h*(1.0-top_margin-bottom_margin)/y_range;

    QRect rect((W-w)/2, (H-h)/2, w, h);
    if (!rect.isValid())
        return;

    //绘图中央区域
    QRect centerRect = rect.adjusted(w*left_margin, h*top_margin, -w*right_margin, -h*bottom_margin);

    //虚线
    QPen penDot;
    penDot.setStyle(Qt::DotLine);
    penDot.setColor(Qt::gray);

    //实线
    QPen penSolid;
    penSolid.setStyle(Qt::SolidLine);
    penSolid.setColor(Qt::black);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::TextAntialiasing, true);

    QFontMetrics textSize(this->font());
    QRect textRect;
    QString x_tick;
    QString y_tick;
    int x1, y1;
    int x2, y2;
    int x_h=0, y_w=0;

    //x轴网格线,刻度和标签
    y1 = centerRect.top();
    y2 = centerRect.bottom();
    for(int x_value=x_min; x_value<=x_max; x_value++) {
        x1 = x2 = centerRect.left() + x_ratio*(x_value-x_min);

        painter.setPen(penDot);
        painter.drawLine(x1, y1, x1, y2);

        painter.setPen(penSolid);
        painter.drawLine(x1, y2, x1, y2+5);

        x_tick = QString::number(x_value, 'f', 1);
        textRect = textSize.boundingRect(x_tick);
        if(textRect.height()>x_h)
            x_h = textRect.height();
    }
    for(int x_value=x_min; x_value<=x_max; x_value++) {
        x2 = centerRect.left() + x_ratio*(x_value-x_min);
        x_tick = QString::number(x_value, 'f', 1);
        textRect = textSize.boundingRect(x_tick);
        textRect.moveCenter(QPoint(x2, y2+tick_length+x_h/2));

        painter.setPen(penSolid);
        painter.drawText(textRect, Qt::AlignCenter, x_tick);
    }

    //y轴网格线,刻度和标签
    x1 = centerRect.left();
    x2 = centerRect.right();
    for(int y_value=y_min; y_value<=y_max; y_value++) {
        y1 = y2 = centerRect.top() + y_ratio*(y_value-y_min);

        painter.setPen(penDot);
        painter.drawLine(x1, y1, x2, y2);

        painter.setPen(penSolid);
        painter.drawLine(x1-tick_length, y1, x1, y2);

        y_tick = QString::number(y_value, 'f', 1);
        textRect = textSize.boundingRect(y_tick);
        if(textRect.width()>y_w)
            y_w = textRect.width();
    }
    for(int y_value=y_min; y_value<=y_max; y_value++) {
        y1 = centerRect.top() + y_ratio*(y_value-y_min);
        y_tick = QString::number(y_value, 'f', 1);
        textRect = textSize.boundingRect(y_tick);
        textRect.moveCenter(QPoint(x1-tick_length-y_w/2, y1));

        painter.setPen(penSolid);
        painter.drawText(textRect, Qt::AlignCenter, y_tick);
    }

    //矩形框
    painter.setPen(penSolid);
    painter.drawRect(centerRect);

    //title
    painter.setFont(title_font);
    QFontMetrics titleSize(title_font);

    textRect = titleSize.boundingRect(title);
    textRect.moveCenter(QPoint(centerRect.center().x(), (rect.top()+centerRect.top())*0.5));
    painter.drawText(textRect, Qt::AlignCenter, title);

    //x_label
    painter.setFont(label_font);
    QFontMetrics labelSize(label_font);

    textRect = labelSize.boundingRect(x_label);
    textRect.moveCenter(QPoint(centerRect.center().x(), (rect.bottom()+tick_length+x_h+centerRect.bottom())*0.5));
    painter.drawText(textRect, Qt::AlignCenter, x_label);

    //y_label
    textRect = labelSize.boundingRect(y_label);
    painter.save();
    painter.translate(QPoint((rect.left()+centerRect.left()-tick_length-y_w)*0.5, centerRect.center().y()));
    painter.rotate(-90);//逆时针旋转90度,变成正北为X轴,正东为Y轴
    textRect.moveCenter(QPoint(0, 0));
    painter.drawText(textRect, Qt::AlignCenter, y_label);
    painter.restore();

    //数据线
    QPolygon curve(1001);
    for (int i=0; i<=1000; i++) {
        qreal x = 0.01*i;
        qreal y = 2.0*qSin(4*x);
        x = centerRect.left() + x_ratio*(x-x_min);
        y = centerRect.bottom() + y_ratio*(y-y_max);
        curve[i] = QPoint(x, y);
    }
    penSolid.setColor(Qt::blue);
    penSolid.setWidth(2);
    painter.setPen(penSolid);
    painter.drawPolyline(curve);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值