一、前言
说到自定义控件,我是感觉特别熟悉的几个字,本人亲自原创的自定义控件超过110个,都是来自各个行业的具体应用真实需求,而不是凭空捏造的,当然有几个小控件也有点凑数的嫌疑,在编写整个数据可视化大屏界面电子看板系统中,也用到了四五个自定义的控件,比如那个环形百分比图,多态进度条,合格率仪表盘,速度仪表盘等,这些控件在现有的类中是没有的,需要用QPainter这个牛逼的工具来绘制,类似于神笔马良似的,给我一个画笔,可以画出任意你想要的图形,好比我常说的心中有坐标,万物皆painter。
自定义控件为了适应整体换肤,需要用Q_PROPERTY类指定,类似于元对象,用Q_PROPERTY指定的东西,可以直接样式表控制,比如GaugePercent{qproperty-baseColor:#FF0000;}就可以对所有的GaugePercent类进行颜色更换,而且是动态更换,用Q_PROPERTY指定的东西还可以直接出现在Qtcreator的右侧属性栏,直接修改属性即可,所见即所得,非常方便。
二、电子看板介绍
电子看板是目视化管理的一种表现形式,即对数据的状况一目了然地表现,主要是对于管理项目,它通过利用形象直观而又色彩适宜的各种视觉感知信息来组织现场生产活动,目视管理依据人类的生理特征,在生产现场充分利用信号灯、标识牌、符号颜色等方式来发出视觉信号,鲜明准确地刺激人的神经末梢,快速地传递信息,形象直观地将潜在的问题和浪费现象都显现出来。以便任何人都可以及时掌握管理现状和必要的情报,从而能够快速制定并实施应对措施。因此,管理看板是发现问题、解决问题的非常有效且直观的手段,是优秀的现场管理必不可少的工具之一。
三、功能特点
- 整体总共分三级界面,一级界面是整体布局,二级界面是单个功能模块,三级界面是单个控件。
- 子控件包括饼图+圆环图+曲线图+柱状图+柱状分组图+横向柱状图+横向柱状分组图+合格率控件+百分比控件+进度控件+设备状态面板+表格数据+地图控件(包括动态闪烁点+迁徙图等)+视频控件+其他控件等。
- 二级界面可以自由拖动悬浮,支持最小化最大化关闭,响应双击自定义标题栏。
- 数据源支持数据库采集(默认)、网络通信、网络请求等,可自由设定每个子界面的采集间隔即数据刷新频率。
- 采用纯QWidget编写,支持Qt4.6到Qt5.12.3任何版本,支持嵌入式linux比如树莓派、香橙派、全志、imx6等。
- 提供三个内核版本,自定义控件版本+qchart版本+echart版本。
- 内置多套配色风格样式,默认紫色,支持任何分辨率。
- 可设置标题+目标分辨率+布局方案,启动立即应用。
- 可设置主背景颜色+面板颜色+十字线游标颜色。
- 可设置多条曲线颜色,没有设置颜色的情况下内置15套精美颜色随机应用。
- 可设置标题栏背景颜色+文字颜色。
- 可设置曲线图表背景颜色+文字颜色+网格颜色。
- 可设置正常颜色+警戒颜色+报警颜色+禁用颜色+百分比进度颜色。
- 可分别设置各种字体大小,比如全局+软件名称+标题栏+子标题栏+加粗标签等。
- 可设置标题栏高度+表头高度+行高度。
- 曲线支持游标+悬停高亮数据点和显示值,柱状图支持顶部(可设置顶端+上部+中间+底部)显示数据,全部自适应计算位置。
- 主界面直接鼠标右键切换布局+配色方案+关闭开启某个二级窗体。
- 自动记忆所有子窗口的大小和位置,下次启动立即应用。
- 动态加载布局方案菜单,可以动态新建布局、恢复布局、保存布局、另存布局等,用户可以制造任意布局。
- 二级窗体,双击从主窗体分离出来浮动,可以自由调整大小。再次双击标题栏最大化,再次双击还原。
- 每个模块都可以自定义采集速度,如果是数据库采集会自动排队处理。
四、配置文件说明
(1)、基本配置参数
字段 |
描述 |
默认值 |
WorkMode |
工作模式 timer-模拟数据 db-数据库采集 tcp-网络采集 http-post请求 |
db |
MapStyle |
中间地图样式 image-静态图片 point-闪烁点 move-迁徙图 |
point |
Title |
软件标题,显示在软件中间顶部 |
数字化工厂信息中心 |
Ratio |
分辨率,目前无意义 |
4096*216 |
Layout |
布局方案,每次切换布局方案以后都会保存 |
完整布局 |
Theme |
配色方案,每次切换配色方案以后都会保存 |
紫色风格 |
VideoAddr |
视频流地址,视频模块播放的视频地址 |
凤凰卫视 |
AutoRun |
是否开机启动 |
false |
MoveEnable |
模块是否可以拖动,启用以后模块可以任意拖动 |
true |
CutLeftBottom |
底部布局左侧是否切掉 |
true |
CutRightBottom |
底部布局右侧是否切掉 |
true |
StaticLine |
是否绘制静态定位线,为假则绘制游标十字线 |
true |
ShowPercent |
Y轴是否显示百分比 |
true |
StepY |
Y轴大尺度步长 |
6 |
CursorHideTime |
用户不操作鼠标自动隐藏鼠标的时间间隔,单位秒 |
5 |
(2)、颜色配置参数
字段 |
描述 |
默认值 |
ColorMainBg |
主背景颜色 |
QColor(4, 7, 38) |
ColorPanelBg |
面板背景颜色 |
QColor(26, 29, 60) |
ColorLine |
十字线定位线颜色 |
QColor(255, 0, 0) |
ColorLine1 |
线条1颜色 |
QColor(0, 176, 180) |
ColorLine2 |
线条2颜色 |
QColor(32, 159, 223) |
ColorLine3 |
线条3颜色 |
QColor(255, 192, 0) |
ColorTitleBg |
标题栏背景颜色 |
QColor(48, 48, 85) |
ColorTitleText |
标题栏文字颜色 |
QColor(255, 255, 255) |
ColorChartBg |
曲线图表背景颜色 |
QColor(38, 41, 74) |
ColorChartText |
曲线图表文字颜色 |
QColor(250, 250, 250) |
ColorChartGrid |
曲线图表网格颜色 |
QColor(180, 180, 180) |
ColorOk |
正常颜色 |
QColor(0, 176, 180) |
ColorLow |
警戒颜色 |
QColor(255, 192, 0) |
ColorAlarm |
报警颜色 |
QColor(214, 77, 84) |
ColorDisable |
禁用背景颜色 |
QColor(210, 210, 210) |
ColorPercent |
环形百分比背景颜色 |
QColor(0, 254, 254) |
(3)、字体和尺寸配置参数
字段 |
描述 |
默认值 |
MainFont |
全局字号 |
微软雅黑,12 |
NameFont |
软件名称字号 |
19 |
LabFont |
加粗标签字号 |
12 |
DeviceFont |
设备面板字号 |
12 |
SubTitleFont |
模块子标题栏字号 |
13 |
TitleFont |
模块标题栏字号 |
15 |
TitleHeight |
模块标题栏高度 |
23 |
HeadHeight |
表格表头高度 |
28 |
RowHeight |
表格行高度 |
25 |
(4)、采集速度配置参数
字段 |
描述 |
默认值 |
IntervalModule1 |
模块1采集间隔 |
5000 |
IntervalModule2 |
模块2采集间隔 |
5000 |
IntervalModule3 |
模块3采集间隔 |
5000 |
IntervalModule4 |
模块4采集间隔 |
5000 |
IntervalModule5 |
模块5采集间隔 |
5000 |
IntervalModule6 |
模块6采集间隔 |
5000 |
IntervalModule7 |
模块7采集间隔 |
5000 |
IntervalModule8 |
模块8采集间隔 |
5000 |
(5)、本地数据库配置参数
字段 |
描述 |
默认值 |
LocalDBType |
本地数据库类型,Sqlite、Mysql等 |
Mysql |
LocalDBIP |
本地数据库主机地址 |
127.0.0.1 |
LocalDBPort |
本地数据库端口 |
3306 |
LocalDBName |
本地数据库名称 |
bigscreen |
LocalUserName |
本地数据库用户名 |
root |
LocalUserPwd |
本地数据库密码 |
root |
五、特别说明
- 可执行文件同级文件夹有layout+layout_1440+layout_1920,程序默认自动识别分辨率并加载对应的布局文件夹,比如1920分辨率则从layout_1920文件夹加载布局,并作为整体布局文件夹。
- 程序默认是模拟数据,如果需要从数据库采集则修改配置文件WorkMode=db即可。
- 如果发现布局拖动乱了,可以直接鼠标右键选择恢复布局即可,在保存布局以前。
- 在中间地图模块鼠标右键可以弹出菜单,切换布局和配色方案等。
- 在模块的标题栏上右键可以弹出默认的dock菜单,用来显示和隐藏各模块。
- 软件关闭过程中会自动保存布局,下次启动以后自动应用。
- 如果使用的默认的默认的配色方案比如紫色风格,则配置文件中的颜色全部无效,会自动应用代码中的颜色,如果需要启用自定义的颜色,则将配置文件的 Theme=x81eax5b9ax4e49x98cex683c 即可。此时打开软件会应用配置文件中的颜色。
- 右键菜单可以截图保存,默认命名为 配色方案名称_布局方案名称.png 保存在snap目录下。
- 如果是XP系统请先执行fixff.cmd,用来修复ffmpeg在XP上不可用的BUG。
- 在二级窗体的标题栏上右键弹出模块菜单,可以对单个模块打开关闭,其他地方右键全局菜单。
- 可执行文件下载地址:https://pan.baidu.com/s/1o97IGvZgTgDhlkuXQa4B0w 提取码:r2bv。
- 会不定期更新程序,欢迎各位提出批评和建议。
六、效果图
七、核心代码
void ProgressRing::paintEvent(QPaintEvent *)
{
int width = this->width();
int height = this->height();
int side = qMin(width, height);
//绘制准备工作,启用反锯齿,平移坐标轴中心,等比例缩放
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.translate(width / 2, height / 2);
painter.scale(side / 200.0, side / 200.0);
//绘制背景
drawBg(&painter);
//绘制进度
drawRing(&painter);
//绘制间隔,重新绘制一个圆遮住,产生间距效果
if (ringPadding > 0) {
drawPadding(&painter);
}
//绘制中间圆
drawCircle(&painter);
//绘制当前值
drawValue(&painter);
}
void ProgressRing::drawBg(QPainter *painter)
{
int radius = 99;
painter->save();
painter->setPen(Qt::NoPen);
//这里有个技巧,如果没有间距则设置成圆环的背景色
painter->setBrush(ringPadding == 0 ? ringBgColor : bgColor);
painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
painter->restore();
}
void ProgressRing::drawRing(QPainter *painter)
{
int radius = 99 - ringPadding;
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(ringColor);
QRectF rect(-radius, -radius, radius * 2, radius * 2);
//计算总范围角度,当前值范围角度,剩余值范围角度
double angleAll = 360.0;
double angleCurrent = angleAll * ((currentValue - minValue) / (maxValue - minValue));
double angleOther = angleAll - angleCurrent;
//如果逆时针
if (!clockWise) {
angleCurrent = -angleCurrent;
angleOther = -angleOther;
}
//动态设置当前进度颜色
QColor color = ringColor;
if (alarmMode == 1) {
if (currentValue >= ringValue3) {
color = ringColor3;
} else if (currentValue >= ringValue2) {
color = ringColor2;
} else {
color = ringColor1;
}
} else if (alarmMode == 2) {
if (currentValue <= ringValue1) {
color = ringColor1;
} else if (currentValue <= ringValue2) {
color = ringColor2;
} else {
color = ringColor3;
}
}
//绘制当前值饼圆
painter->setBrush(color);
painter->drawPie(rect, (startAngle - angleCurrent) * 16, angleCurrent * 16);
//绘制剩余值饼圆
painter->setBrush(ringBgColor);
painter->drawPie(rect, (startAngle - angleCurrent - angleOther) * 16, angleOther * 16);
painter->restore();
}
void ProgressRing::drawPadding(QPainter *painter)
{
int radius = 99 - ringWidth - ringPadding;
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(bgColor);
painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
painter->restore();
}
void ProgressRing::drawCircle(QPainter *painter)
{
//文字的区域要减去进度的宽度及间距
int radius = 99 - ringWidth - (ringPadding * 2);
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(circleColor);
painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
painter->restore();
}
void ProgressRing::drawValue(QPainter *painter)
{
//文字的区域要减去进度的宽度及间距
int radius = 99 - ringWidth - (ringPadding * 2);
painter->save();
painter->setPen(textColor);
QFont font;
int fontSize = radius - (showPercent ? 20 : 6);
font.setPixelSize(fontSize);
painter->setFont(font);
QRectF textRect(-radius, -radius, radius * 2, radius * 2);
QString strValue;
if (showPercent) {
double percent = (currentValue * 100) / (maxValue - minValue);
strValue = QString("%1%").arg(percent, 0, 'f', precision);
} else {
strValue = QString("%1").arg(currentValue, 0, 'f', precision);
}
//如果定义了显示的文字则优先显示
strValue = text.isEmpty() ? strValue : text;
painter->drawText(textRect, Qt::AlignCenter, strValue);
painter->restore();
}