12-1_Qt 5.9 C++开发指南_自定义插件和库-自定义Widget组件(提升法(promotion)创建自定义定制化组件)
当UI设计器提供的界面组件不满足实际设计需求时,可以从 QWidget 继承自定义界面组件。
有两种方法使用自定义界面组件:
-
一种是
提升法(promotion)
,例如在8.3 节将一个QGraphicsView组件提升为自定义的 QWGraphicsView 类,提升法用于界面可视化设计时不够直观,不能在界面上即刻显示自定义组件的效果; -
另一种是
为 UI 设计器设计自定义界面组件的 Widget 插件,直接安装到 UI设计器的组件面板里,如同 Qt 自带的界面设计组件一样使用,在设计时就能看到组件的实际显示效果,只是编译和运行时需要使用到插件的动态链接库 (Windows 平台上)
。
本章先介绍这两种自定义 Widget 组件的设计和使用方法,再介绍Qt编写和使用静态链接库和共享库(Windows 平台上就是动态链接库)的方法
文章目录
- 1. 自定义 Widget 子类QmyBattery
- 2. 自定义Widget组件的使用
- 3. 软件结构及源代码
- 3.1 软件结构
- 3.2 可视化UI设计
- 3.3 源码
1. 自定义 Widget 子类QmyBattery
Qt的 UI 设计器提供了很多 GUI 设计的界面组件,可以满足常见的界面设计需求。但是某些时候需要设计特殊的界面组件,而在 UI设计器的组件面板里根本没有合适的组件,这时就需要设计自定义的界面组件。
所有界面组件的基类是QWidget,要设计自定义的界面组件,可以从QWidget继承一个自定义的类,重定义其painEvent()事件,利用Qt的绘图功能会追组件外观,并实现所需的其他功能。
例如,假设需要设计一个如下图所示的电池电量显示组件,用于电池使用或充电时显示其电量,但是在 UI 设计器的组件面板里是没有这样一个现成的组件的。这就需要设计一个自定义的Widget 组件。
为此,设计一个从QWidget 继承的类QmyBattery。创建C++类,可以单击 Qt Creator 的“File”一“New File or Project”菜单项,在出现的对话框里选择 C++类组里的 C++ Class,在向导中设置类的名称,并选择基类为 QWidget。
定义QmyBattery类的qmybattery.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-100int 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:
};#endif // WBATTERY_H
在 private 部分定义了几个私有变量,主要是各种颜色的定义、当前电量值 mPowerLevel 和电量低阈值mWarLevel。
protected 部分重定义了 paintEvent()事件,在第8章中介绍过,QWidget 类的 paintEvent()事件用于界面绘制,在此事件里,可以使用 QPainter 的各种绘图功能绘制自己需要的界面。
public 部分定义了用于读取和设置当前电量值、电量低阈值的函数,还定义了 sizeHint()函数用于返回组件缺省大小。
定义了一个信号 powerLevelChanged(int),在当前电量值改变时发射该信号,使用QmyBattery类时可以设计槽函数对此信号做处理。
下面是 QmyBattery 类的实现代码,复杂一点的部分是 paintEvent()事件函数里绘制界面的功能实现,这里设置了窗口逻辑坐标,所以,当组件大小变化时,绘制的电池大小也会自动变化。QPainter 绘图的功能在第 8 章有详细介绍,这里不再详细解释。
#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);//设置Viewportpainter.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);//得到字符串的rectpainter.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;
}
2. 自定义Widget组件的使用
实现了QmyBattery 类之后,若是用代码创建QmyBattery 类对象,其使用与一般的组件类是一样的;若是在 UI设计器中使用 QmyBattery,则需要采用提升法(promotion)。
实例 samp12 1是一个基于 QWidegt 的应用程序,使用 UI 设计器设计主窗体时,在窗体上放置一个QWidegt 类组件,然后鼠标右键调出其快捷菜单,单击“Promote to”菜单项,会出现如下图所示的对话框。
此对话框里,在基类名称下拉列表框里选择 QWidget,将提升后的类名称设置为 QmyBattery,头文件名称会自动生成。可以将设置添加到已提升类的列表里,以便重复使用。
设置后,单击“Promote”按钮,就可以将此QWidget 组件提升为 QmyBattery 类。提升后,在 Property Editor 里会看到这个组件的类名称变为了 QmyBattery。然后,将其 objectName 更改为 battery。
虽然界面上放置的 QWidget 组件被提升为了 QmyBattery 类,但是在这个组件的“Go to slot’对话框里并没有QmyBattery 类的 powerLevelChanged(int) 信号,无法采用可视化方法生成信号的槽函数。
在主窗口上放置一个 QSlider 组件和一个 QLabel 组件。滑动标尺改变数值时,设置为 battery的当前电量值,其 valueChanged()信号的槽函数代码如下:
void Widget::on_horizontalSlider_valueChanged(int value)
{ui->battery->setPowerLevel(value);QString str=QStringLiteral("当前电量:")+QString::asprintf("%d %%",value);ui->LabInfo->setText(str);
}
battery 的各种参数采用其缺省的设置,battery 的当前电量值改变时,内部会调用 paintEvent()事件代码重新绘制电池显示效果。
3. 软件结构及源代码
3.1 软件结构
3.2 可视化UI设计
3.3 源码
(1)qmybattery.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-100int 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:
};#endif // WBATTERY_H
(2)qmybattery.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);//设置Viewportpainter.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);//得到字符串的rectpainter.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;
}
(3) widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}void Widget::on_horizontalSlider_valueChanged(int value)
{ui->battery->setPowerLevel(value);QString str=QStringLiteral("当前电量:")+QString::asprintf("%d %%",value);ui->LabInfo->setText(str);
}
相关文章:

12-1_Qt 5.9 C++开发指南_自定义插件和库-自定义Widget组件(提升法(promotion)创建自定义定制化组件)
当UI设计器提供的界面组件不满足实际设计需求时,可以从 QWidget 继承自定义界面组件。 有两种方法使用自定义界面组件: 一种是提升法(promotion),例如在8.3 节将一个QGraphicsView组件提升为自定义的 QWGraphicsView 类,提升法用…...

【软件测试学习】—软件测试的基本认识(一)
【软件测试学习】—软件测试的基本认识(一) 文章目录 【软件测试学习】—软件测试的基本认识(一)一、什么是软件测试二、软件测试的目的三、测试的原则四、测试的标准五、测试的基本要求六、bug的由来七、测试的流程八、开发模式九…...

Unity AI项目笔记
一、创建虚拟环境 在开始进行Unity AI项目之前,首先需要设置一个适当的虚拟环境。以下步骤将会指导你如何创建: 下载Python 3.7。下载Anaconda 2020.11。可以在清华大学开源软件镜像站找到镜像资源:https://mirrors.tuna.tsinghua.edu.cn/a…...

如何在地图上寻找峨眉山零公里的龙洞湖
爬峨眉山的需要,住在零公里附近。 据说这附近有个好玩的地方叫龙洞湖,我们住得远,想步行去看看。拿出地图,搜龙洞湖,尴尬了。搜不到具体位置。细想,人家整个村就叫龙洞村,地图上居然没有标识&a…...

cloudstack平台host加入后,显示CPU speed为0GHz
一、环境说明 操作系统:openEuler 22.03CPU:Kunpeng-920,arm v8cloudstack:4.18libvirtd:6.2.0 二、问题描述 cloudstack平台初始化完成后,第一次加入host,系统虚拟机一直无法正常创建&#…...

创新技术应用,提升企业图文档管理水平的新思路
信息爆炸和数字化发展的时代,企业图文档管理显得尤为重要。传统的纸质文件管理方式已经无法满足企业高效、安全、便捷管理的需求。因此,创新技术的应用成为了提升企业图文档管理水平的必然选择。PDM(产品数据管理)与BOM࿰…...

网络安全 Day22-mariadb数据库用户管理
数据库用户管理 1. mariadb数据库用户管理2. mariadb数据库用户授权3. 用户回收授权4. 使客户端连接数据库 1. mariadb数据库用户管理 用户的格式: 用户主机范围 合起来才算一个用户授权主机范围 只能从本机访问: localhost或127.0.0.1或10.0.0.166(指定IP)授权整个网段: 授权…...

SERDES关键技术
目录 一、SERDES介绍 二、SERDES关键技术 2.1 多重相位技术 2.2 线路编解码技术 2.2.1 8B/10B编解码 2.2.2 控制字符(Control Characters) 2.2.3 Comma检测 2.2.4 扰码(Scrambling) 2.2.5 4B/5B与64B/66B编解码技术 2.3 包传…...

小程序如何上传商品图片
了解如何在小程序商城中上传商品图片是非常重要的,因为商品图片的质量和展示效果直接影响到用户对商品的购买决策。下面,我将介绍怎么在小程序上传产品图片的方法和注意事项。 1. 图片准备:在上传商品图片之前,首先要准备好商品图…...

vue中人员导出功能实现
大纲: 1、导出定义的export.js文件 代码展示 import axios from axios //导出一 export const exportExcel (url, params, name, type post) > {// url url路径 params 查询参数 name 文件名 type 请求方式axios[type](url, params, {responseType: blob,}).t…...

【微信小程序】引入第三方库poke对GZIP压缩数据进行解压
使用 npm 包管理工具: 首先,在小程序的根目录下执行 npm init 初始化项目,生成 package.json 文件。然后,通过 npm 安装 pako:npm install pako。接下来,在小程序的根目录下创建一个名为 miniprogram_npm 的…...

Pandas操作Excel
Pandas 是 Python 语言的一个扩展程序库,用于数据分析。 菜鸟教程:https://www.runoob.com/pandas/pandas-tutorial.html 读取Excel pd.read_excel(path,sheet_name,header) path:excel文件路径sheet_name:读取的sheet࿰…...

leetcode 712. Minimum ASCII Delete Sum for Two Strings(字符串删除字母的ASCII码之和)
两个字符串s1, s2, 删除其中的字母使s1和s2相等。 问删除字母的最小ASCII码之和是多少。 思路: DP 先考虑极端的情况,s1为空,那么要想达到s2和s1相等,就要把s2中的字母删完, ASCII码之和就是s2中所有字母的ASCII码之…...

Springboot -- 按照模板生成docx、pdf文件,docx转pdf格式
使用 poi-tl 根据模板生成 word 文件。 使用 xdocreport 将 docx 文件转换为 pdf 文件。 xdocreport 也支持根据模板导出 word ,但是 poi-tl 的功能更齐全,操作更简单,文档清晰。 poi-tl 、xdocreport 内部均依赖了 poi ,要注意两…...

UE5.1.1 创建C++项目失败
因一直使用Unity开发环境,安装Unreal后,并未详细配置过其开发环境,默认创建蓝图工程无异常,但创建UE C项目时总共遇到两个错误: 错误一 Running /Epic/UE/UE_5.1/Engine/Build/BatchFiles/Build.bat -projectfiles -…...

windows进行端口映射
windows进行端口映射 1. 查询端口映射情况 netsh interface portproxy show v4tov42. 查询某一个IP的所有端口映射情况 netsh interface portproxy show v4tov4 | find "[IP]" # 例: netsh interface portproxy show v4tov4 | find "192.168.1.1&quo…...

Python 异常处理
Python 异常处理 python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。你可以使用该功能来调试python程序。 异常处理: 本站Python教程会具体介绍。断言(Assertions):本站Python教程会具体介绍。 python标准异常 异常名称描述BaseException所有异常的…...

C++ 类的静态成员
在结构化程序设计中程序模块的基本单位是函数,因此模块间对内存中数据的共享是通过函数与和函数之间的数据共享来实现的,其中包括两个途径——参数传递和全局变量。 面向对象的程序设计方法兼顾数据的共享和保护,将数据与操作数据的函数封装…...

360T7路由器进行WiFi无线中继教程
360T7路由器进行WiFi中继教程 1. 概述2. 360T7路由器进行WiFi中继实现教程2.1 登录路由器管理界面2.2 选择上网方式2.3 搜索WiFi2.4 连接WiFi2.5 点击确认2.6 在主页面查看网络 1. 概述 中继路由系统由一组中继路由器组成,为不能交换路由信息的路由域提供中继路由。…...

主成分分析
主成分分析 相关概念方差协方差协方差矩阵特征值和特征向量 主成分分析数据降维主成分分析原理主成分分析过程sklearn库中的PCA主成分分析实现案例 相关概念 方差 方差是一个用来衡量一组数据离散程度的统计量,它是各样本与样本均值的差的平方和的平均值。方差越大…...

笙默考试管理系统-MyExamTest(26)
笙默考试管理系统-MyExamTest(26) 目录 一、 笙默考试管理系统-MyExamTest 二、 笙默考试管理系统-MyExamTest 三、 笙默考试管理系统-MyExamTest 四、 笙默考试管理系统-MyExamTest 五、 笙默考试管理系统-MyExamTest 笙默考试管理系统-MyEx…...

重新理解 RocketMQ Commit Log 存储协议
最近突然感觉:很多软件、硬件在设计上是有 root reason 的,不是 by desgin 如此,而是解决了那时、那个场景的那个需求。一旦了解后,就会感觉在和设计者对话,了解他们的思路,学习他们的方法,思维…...

ES6基础知识十:你是怎么理解ES6中 Decorator 的?使用场景?
一、介绍 Decorator,即装饰器,从名字上很容易让我们联想到装饰者模式 简单来讲,装饰者模式就是一种在不改变原类和使用继承的情况下,动态地扩展对象功能的设计理论。 ES6中Decorator功能亦如此,其本质也不是什么高大…...

接口/Web自动化测试如何做?框架如何搭建封装?
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 自动化测试怎么做…...

Linux怎么从网络上下载文件
wget命令用于从网络上下载文件 下载文件: wget [URL]使用wget命令加上要下载的文件的URL,可以将文件下载到当前目录。 指定保存的文件名: wget -O [保存的文件名] [URL]使用-O选项后跟保存的文件名,可以指定下载的文件保存的名称…...

Flutter携带JSON参数post请求
在Flutter中发送带有JSON参数的网络请求,你可以使用HTTP库(如http或dio)来实现。以下是使用http库发送网络请求并携带JSON参数的示例: import package:http/http.dart as http; import dart:convert;// 创建参数Map Map<Strin…...

【vue】vue-image-lazy图片懒加载使用与介绍【超详细+npm包源代码】
简介 当前插件是基于vue3,写的一个图片懒加载,文章最下方是npm包的源码,你可以自己拿去研究和修改,如有更好的想法可以留言,如果对你有帮助,可以点赞收藏和关注,谢谢。 后续会添加图片放大和切…...

MFC第二十四天 使用GDI对象画笔和画刷来开发控件(分页控件选择态的算法分析、使用CToolTipCtrl开发动静态提示)
文章目录 GDI对象画笔和画刷来开发控件梯形边框的按钮控件CMainDlg.hCMainDlg.cppCLadderCtrl.hCLadderCtrl.cpp 矩形边框的三态按钮控件 CToolTipCtrl开发动静态提示CMainDlg.hCMainDlg.cppCLadderCtrl.hCLadderCtrl.cpp: 实现文件 矩形边框的三态按钮控件 CToolTipCtrl开发动…...

【NLP-新工具】语音转文本与OpenAI的用途
一、说明 OpenAI最近2022发布了一个名为Whisper的新语音识别模型。与DALLE-2和GPT-3不同,Whisper是一个免费的开源模型。它的主要功能就是将语音翻译成文本。本文将介绍如何使用这个重要应用库。 二、 Whisper概念 2.1 Whisper是啥? Whisper 是一种自动…...

try-catch-finally的字节码原理
Java 中有一个非常重要的内容是 try-catch-finally 的执行顺序和返回值问题,其中 finally 一定会执行,但是为什么会这样? 下面看下 try-catch-finally 背后的实现原理 try-catch public class Test {public static void main(String[] args)…...