Qt自定义 Widget 组件

自定义 Widget 子类 QmyBattery

Qt 的 UI 设计器提供了很多 GUI 设计的界面组件,可以满足常见的界面设计需求。但是某些时候需要设计一些特殊的界面组件,而在 UI 设计器的组件面板里根本没有合适的组件,这时就需要设计自定义的界面组件。

所有界面组件的基类是 QWidget,要设计自定义的界面组件,可以从 QWidget 继承一个自定义的类,重定义其 paintEvent() 事件,利用 Qt 的绘图功能绘制组件外观,并实现需要的其他功能。

例如,假设需要设计一个如图所示的电池电量显示组件,用于电池使用或充电时显示电量,但是在 UI 设计器的组件面板没有现成的组件。这就需要设计一个自定义的 Widget 组件。

为此,设计一个从 QWidget 继承的类 QmyBattery。创建 C++类,可以单击 Qt Creator 的"File"->"New File or Project"菜单选项,在出现的对话框选择 C++组里面的 C++Class,在向导中设置类的名称,并选择基类为 QWidget。定义 QmyBattery 类的头文件如下:

cpp 复制代码
#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();

    QSize   sizeHint();//报告缺省大小

signals:
    void   powerLevelChanged(int );

public slots:
};

在 private 部分定义了几个私有变量,主要是各种颜色的定义,当前电量值 mPowerLevel 和电量低阈值 mWarnLevel;protected 部分重定义了 patinEvent() 事件;public 部分定义了用来读取和设置当前电量值、电量低阈值的好函数,还定义了 sizeHint() 函数,用于返回组件缺省大小。

定义了一个信号 powerLevelChanged(int),在当前电量值改变的时候发射该信号,使用 QmyBattery 类时可以设计槽函数对此信号做处理。下面是具体的实现代码,复杂的部分是 paintEvent() 事件函数里绘制界面功能实现,这里设置了窗口逻辑坐标,所以当组件大小变化时,绘制的电池大小也会自动变化。

cpp 复制代码
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)
{
//    setPalette(QPalette(mColorBack));
//    setAutoFillBackground(true);
//    this->resize(120,50);
}

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()
{//报告缺省大小,调整比例
    int H=this->height();
    int W=H*12/5;
    QSize   size(W,H);
    return size;
}

自定义 Widget 组件的使用

实现了自定义类后,如果是使用代码创建 QmyBattery 类对象,其使用与一般的组件类是一样的;如果是在 UI 设计器中使用 QmyBattery,则需要采用提升的方法(promotion)。

拖一个 QWidget 组件在窗口上,右击选择"提升为(Promote to)",就会出现如下所示对话框:

在基类名称的下来列表里选择 QWidget,将提升后的类名设置为 QmyBattery,头文件名会自动生成。可以将设置添加到已提升的列表里,以便重复使用。在提供组件之后,虽然 QWidget 已经被提升为 QmyBattery 类,但是在这个组件的"Go to slot"对话框没有 QmyBattery 类的 powerLevelChanged(int) 信号,无法采用可视化方法生成信号的槽函数。在主窗口上放置一个 QSlider 组件和一个 QLabel 组件。华东标尺改变数据时,设置为 battery 的当前电量,其 valueChanged()信号的槽函数代码如下:

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

下一篇文章说说如何创建 Qt Designer 的插件,可以直接在 UI 设计器中拖动使用。

参考资料:https://github.com/0voice

相关推荐
芒果爱编程3 小时前
MCU、ARM体系结构,单片机基础,单片机操作
开发语言·网络·c++·tcp/ip·算法
明明跟你说过3 小时前
【Go语言】从Google实验室走向全球的编程新星
开发语言·后端·go·go1.19
凌盛羽4 小时前
C#对Excel表csv文件的读写操作
开发语言·windows·物联网·microsoft·c#·excel
VBA63374 小时前
VBA高级应用30例应用在Excel中的ListObject对象:向表中添加注释
开发语言
Dontla4 小时前
Rust字节数组(Byte Array)Rust u8、Vec<u8>、数组切片、向量切片、字符串转字节数组转字符串、&[u8]类型:字节数组引用
开发语言·rust
走在考研路上6 小时前
Python错误处理
开发语言·python
数据小爬虫@6 小时前
Python爬虫:如何优雅地“偷窥”商品详情
开发语言·爬虫·python
CV大法好6 小时前
刘铁猛p3 C# 控制台程序引用System.Windows.Forms报错,无法引用程序集 解决方法
开发语言·c#
Days20506 小时前
uniapp小程序增加加载功能
开发语言·前端·javascript
朱小勇本勇7 小时前
Qt实现控件拖曳
开发语言·数据库·qt