说到自定义控件,我是感觉特别熟悉的几个字,本人亲自原创的自定义控件超过110个,都是来自各个行业的具体应用真实需求,而不是凭空捏造的,当然有几个小控件也有点凑数的嫌疑,在编写整个数据可视化大屏界面电子看板系统中,也用到了四五个自定义的控件,比如那个环形百分比图,多态进度条,合格率仪表盘,速度仪表盘等,这些控件在现有的类中是没有的,需要用QPainter这个牛逼的工具来绘制,类似于神笔马良似的,给我一个画笔,可以画出任意你想要的图形,好比我常说的心中有坐标,万物皆painter。
自定义控件为了适应整体换肤,需要用Q_PROPERTY类指定,类似于元对象,用Q_PROPERTY指定的东西,可以直接样式表控制,比如GaugePercent{qproperty-baseColor:#FF0000;}就可以对所有的GaugePercent类进行颜色更换,而且是动态更换,用Q_PROPERTY指定的东西还可以直接出现在Qtcreator的右侧属性栏,直接修改属性即可,所见即所得,非常方便。
电子看板是目视化管理的一种表现形式,即对数据的状况一目了然地表现,主要是对于管理项目,它通过利用形象直观而又色彩适宜的各种视觉感知信息来组织现场生产活动,目视管理依据人类的生理特征,在生产现场充分利用信号灯、标识牌、符号颜色等方式来发出视觉信号,鲜明准确地刺激人的神经末梢,快速地传递信息,形象直观地将潜在的问题和浪费现象都显现出来。以便任何人都可以及时掌握管理现状和必要的情报,从而能够快速制定并实施应对措施。因此,管理看板是发现问题、解决问题的非常有效且直观的手段,是优秀的现场管理必不可少的工具之一。
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();
}