写在前面
该部分代码主要是构建的自定义控件库中的一个控件,主要是通过painterEvent绘制的一个饼状图,主要是使用QChart无法在自定义控件库中无法加载,所以参考网上的一些程序做的一个自定义的饼状图。在原有的基础上添加了点击后突出显示的功能,因为颜色链表初始化使用的颜色不太符合美观,所以显示效果偏差,可以通过调整颜色链表来调整饼状图的显示效果。
控件效果
程序
#ifndef CUSTOMPIE_H
#define CUSTOMPIE_H
#include <QWidget>
#include <QMouseEvent>
#ifdef yu //自己的控件库名
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
class QDESIGNER_WIDGET_EXPORT CustomPie : public QWidget
#else
class CustomPie : public QWidget// 自定义饼状图
#endif
{
Q_OBJECT
Q_PROPERTY(bool showPercent READ getShowPercent WRITE setShowPercent)
Q_PROPERTY(bool explodedAll READ getExplodedAll WRITE setExplodedAll)
Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor) //设置饼状图文字的颜色
Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor) //设置饼状图的颜色
Q_PROPERTY(QString Label READ getLabel WRITE setLabel)
Q_PROPERTY(QString Value READ getValue WRITE setValue)
public:
CustomPie(QWidget *parent = nullptr);
~CustomPie();
void setExplodedIndex(int index);
//设置默认大小
QSize sizeHint() const;
QSize minimumSizeHint() const;
protected:
void paintEvent(QPaintEvent *); //绘图事件
void drawPie(QPainter *painter); //绘制饼图
void mousePressEvent(QMouseEvent *event);
private:
bool explodedAll; //是否全部展开
int explodedIndex; //展开的索引
bool showPercent; //是否显示百分比
double holeSize; //空心占比,暂时未使用
QColor textColor; //文字颜色
QColor borderColor; //边框颜色
QList<QColor> colors; //颜色集合,专门用于渲染用的
QList<QString> labels; //标签集合
QList<double> values; //值集合
QString Label;
QString Value;
private:
//获取总值
double getSumValue();
//根据偏移值获取偏移点坐标
QPoint getOffsetPoint(double angel, int offset = 6);
public:
QColor getTextColor() const;
QColor getBorderColor() const;
bool getShowPercent() const;
bool getExplodedAll() const;
QString getLabel() const;
QString getValue() const;
public Q_SLOTS:
//设置是否全部展开+展开的索引
void setExplodedAll(bool explodedAll);
void setShowPercent(bool showPercent);
//设置文字颜色+边框颜色
void setTextColor(const QColor &textColor);
void setBorderColor(const QColor &borderColor);
void setLabel(QString label);
void setValue(QString value);
public:
//设置颜色集合
void setColors(const QList<QColor> &colors);
public:
//设置空心占比
void setHoleSize(double holeSize);
};
#include "custompie.h"
#include <QPainter>
#include <math.h>
#include <QDebug>
CustomPie::CustomPie(QWidget *parent):
QWidget(parent)
{
explodedAll=false;
explodedIndex=1;
showPercent=true;
holeSize=30;
textColor=QColor(0,0,0); //文字颜色
borderColor=QColor(0,0,0); //边框颜色
Label="标签1;标签2;标签3;标签4";
Value="3;4;5;6";
colors<<QColor(255,0,0)<<QColor(0,255,0)<<QColor(0,0,255)<<QColor(255,255,0)<<QColor(0,255,255)<<QColor(255,0,255)<<QColor(0,0,0)<<QColor(222,184,135)<<QColor(192,192,192)<<QColor(46,139,87);
labels=Label.split(";");
QStringList Values=Value.split(";");
for(int i=0;i<Values.size();i++)
{
values<<Values.at(i).toDouble();
}
}
CustomPie::~CustomPie()
{
}
void CustomPie::mousePressEvent(QMouseEvent *event)
{
int x=event->pos().x()-width()/2;
int y=event->pos().y()-height()/2;
double angle=-atan2(x,-y)* 180 / 3.1415926+90;
if(angle<0)
angle+=360;
qDebug()<<angle<<endl;
double sum=getSumValue();
double value=0;
for(int i=0;i<values.size();i++)
{
value+=values.at(i);
if(angle/360.0<value/sum)
{
explodedIndex=i;
update();
break;
}
}
}
void CustomPie::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);
//绘制饼图
drawPie(&painter);
}
void CustomPie::drawPie(QPainter *painter)
{
painter->save();
int radius = 93;
QRect rect(-radius, -radius, radius * 2, radius * 2);
double startAngle = 0;
double sum = getSumValue();
//逐个取出值并绘制饼图区域和对应的文字
int count = labels.count();
for (int i = 0; i < count; ++i) {
//取出值并计算当前值占比面积
double value = values.at(i);
double arcLength = value / sum * 360;
double percent = value / sum * 100;
QRect pieRect = rect;
//如果当前区域展开则需要设置边框
painter->setPen(Qt::NoPen);
if (explodedIndex == i || explodedAll) {
painter->setPen(borderColor);
QPoint center = pieRect.center();
int mid = startAngle + arcLength / 2;
center += getOffsetPoint(mid);
pieRect.moveCenter(center);
}
//从颜色集合中取出颜色
painter->setBrush(colors.at(i));
painter->drawPie(pieRect, startAngle * 16, arcLength * 16);
QString strValue = labels.at(i);
if (showPercent && percent > 7) {
strValue = QString("%1%2%3%").arg(strValue).arg(strValue.isEmpty() ? "" : "\n").arg(QString::number(percent, 'f', 0));
}
int mid = startAngle + arcLength / 2;
int offset = 60;
if (percent >= 50) {
offset = 45;
} else if (percent >= 30) {
offset = 55;
} else if (percent >= 15) {
offset = 60;
}
QPoint p = getOffsetPoint(mid, offset);
QRect textRect;
textRect.setX(p.x() - 40);
textRect.setY(p.y() - 30);
textRect.setWidth(80);
textRect.setHeight(60);
painter->setPen(Qt::black);
//painter->drawRect(textRect);
QFont font;
font.setPixelSize(strValue.isEmpty() ? 20 : 17);
painter->setFont(font);
painter->setPen(textColor);
painter->drawText(textRect, Qt::AlignCenter, strValue);
startAngle += arcLength;
}
painter->restore();
}
double CustomPie::getSumValue()
{
double value=0;
for(int i=0;i<values.size();i++)
{
value+=values.at(i);
}
return value;
}
QColor CustomPie::getTextColor() const
{
return textColor;
}
QColor CustomPie::getBorderColor() const
{
return borderColor;
}
bool CustomPie::getShowPercent() const
{
return showPercent;
}
bool CustomPie::getExplodedAll() const
{
return explodedAll;
}
void CustomPie::setShowPercent(bool showPercent)
{
this->showPercent=showPercent;
}
void CustomPie::setExplodedAll(bool explodedAll)
{
this->explodedAll=explodedAll;
}
void CustomPie::setExplodedIndex(int index)
{
explodedIndex=index;
}
void CustomPie::setTextColor(const QColor &textColor)
{
this->textColor=textColor;
}
void CustomPie::setBorderColor(const QColor &borderColor)
{
this->borderColor=borderColor;
}
void CustomPie::setColors(const QList<QColor> &colors)
{
this->colors=colors;
update();
}
void CustomPie::setHoleSize(double holeSize)
{
this->holeSize=holeSize;
update();
}
QString CustomPie::getLabel() const
{
return Label;
}
QString CustomPie::getValue() const
{
return Value;
}
void CustomPie::setLabel(QString label)
{
Label=label;
labels=Label.split(";");
}
void CustomPie::setValue(QString value)
{
Value=value;
QStringList Values=Value.split(";");
for(int i=0;i<Values.size();i++)
{
values<<Values.at(i).toDouble();
}
}
最后说明
有3个函数是被删掉的,一个涉及到饼状图位置,还有两个涉及到控件大小,难度并不大可以自己写。自定义控件一般是不在*.ui文件上绘制的,因为要确保控件中的各种事件不会失效,特别是需要拖拽那中抽象类型的控件。另外使用自定义控件库真的可以大大地降低后续的界面设计使用的时间,也能大大地提高UI界面的美观性。