123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653 |
-
- #include "VPieChart.h"
- #include <qmath.h>
- #include "GvlManager.h"
- // 默认的分块数
- #define DEFAULT_PEICHART_SLICE_COUNT 3
- VPieChart::VPieChart(
- QWidget *parent,
- const QPoint& pos,
- const QSize& size,
- CONTROL_PROPERTY* pProperty,
- CONTROL_PROPERTY_EX* pPropertyEx
- )
- : QWidget(parent)
- , VControlObject(pProperty)
- {
- // 设置控件指针
- m_pWidget = this;
- // 设置控件类型
- m_Type = VALUE_TYPE::Control_PieChart;
- // 初始化UI风格
- this->initStyle();
- // 设置尺寸
- if (size == DEFAULT_CONTROL_SIZE)
- {
- this->resize(DEFAULT_PIE_SIZE);
- }
- else
- {
- this->resize(size);
- }
- // 设置中心点坐标
- QPoint tempPos;
- tempPos.setX(pos.x() - width() / 2);
- tempPos.setY(pos.y() - height() / 2);
- // 设置位置
- this->move(tempPos);
- // 初始化扩展属性
- if (pPropertyEx == nullptr)
- {
- // 初始化饼图的分块数
- this->m_Property.m_nSliceCount = DEFAULT_PEICHART_SLICE_COUNT;
-
- // 初始化扩展属性
- this->initPropertyEx();
- // 重新绘制预览饼图
- this->update();
- }
- else
- {
- this->m_PropertyEx = *pPropertyEx;
- // 根据分块数量先设置一个默认显示的Value
- for (int i = 0; i < m_Property.m_nSliceCount; i++)
- {
- // 初始化一下Value的预览数值(全为1)
- m_Values << 1.0;
- }
- // 重新绘制预览饼图
- this->update();
- }
- }
- VPieChart::~VPieChart()
- {
- }
- void VPieChart::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);
- }
- /// <summary>
- /// 初始化UI风格
- /// </summary>
- void VPieChart::initStyle()
- {
- explodedIndex = -1;
- explodedAll = false;
- showPercent = false;
- holeSize = 0.0;
- // 设置基础属性
- this->setTextColor(m_Property.m_clrText);
- this->setBorderColor(m_Property.m_clrBorder);
- // 备用颜色集合(按分块顺序赋值)
- m_defaultColors << QColor(0, 176, 180)
- << QColor(255, 192, 0)
- << QColor(0, 113, 193)
- << QColor(72, 103, 149)
- << QColor(185, 87, 86)
- << QColor(0, 177, 125)
- << QColor(214, 77, 84)
- << QColor(71, 164, 233)
- << QColor(34, 163, 169)
- << QColor(40, 45, 48)
- << QColor(162, 121, 197)
- << QColor(72, 202, 245)
- << QColor(0, 150, 121)
- << QColor(111, 9, 176)
- << QColor(250, 170, 20);
- }
- /// <summary>
- /// 核心函数:绘制饼图
- /// </summary>
- /// <param name="painter"></param>
- void VPieChart::drawPie(QPainter *painter)
- {
- painter->save();
- int radius = 93;
- QRect rect(-radius, -radius, radius * 2, radius * 2);
- double startAngle = 0;
- double sum = getSumValue();
- //逐个取出值并绘制饼图区域和对应的文字
- int count = this->m_Property.m_nSliceCount;
- for (int i = 0; i < count; ++i)
- {
- // 取出当前属性值用于绘制
- const PROPERTY_EX_SUBGROUP& subGroup = m_PropertyEx.m_groups[GROUP_INDEX_PIE].subGroups[i];
- //取出值并计算当前值占比面积
- double value = m_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(m_BorderColor);
- QPoint center = pieRect.center();
- int mid = startAngle + arcLength / 2;
- center += getOffsetPoint(mid);
- pieRect.moveCenter(center);
- }
- // 从颜色集合中取出颜色(按照索引顺序依次获取)
- painter->setBrush(subGroup.color);
- painter->drawPie(pieRect, startAngle * 16, arcLength * 16);
- QString strValue = subGroup.strValue;
- 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(m_TextColor);
- painter->drawText(textRect, Qt::AlignCenter, strValue);
- // 递增角度
- startAngle += arcLength;
- }
- painter->restore();
- }
- /// <summary>
- /// 初始化扩展属性
- /// </summary>
- void VPieChart::initPropertyEx()
- {
- // 扩展属性的总名称
- m_PropertyEx.m_strTitle = PIE_PROPERTY_EX_NAME;
- // 用于触发刷新的数据链接
- m_PropertyEx.m_refreshLink.title = PIE_PROPERTY_EX_REFRESHLINK_NAME;
- // 强制设置
- m_PropertyEx.m_refreshLink.bForce = true;
- //// 默认值(暂不使用)
- //m_PropertyEx.m_refreshLink.defaultValue = new VARIABLE("",
- // false, m_PropertyEx.m_refreshLink.title, "int", DEFAULT_DATALINK_VALUE_0, "");
- // 初始化每一个扩展属性组(Pie控件只有一个属性组)
- PROPERTY_EX_GROUP group;
- // 列信息属性
- group.strTitle = PIE_PROPERTY_EX_GROUP_NAME;
- group.strRelationKey = PIE_SLICE_COUNT_NAME;
- //初始化列信息每一个子分组
- for (int i = 0; i < m_Property.m_nSliceCount; i++)
- {
- PROPERTY_EX_SUBGROUP subGroup;
- this->initSubGroup(subGroup, i, GROUP_INDEX_PIE);
- // 保存子分组
- group.subGroups.push_back(subGroup);
- // 顺便初始化一下Value的预览数值(全为1)
- m_Values << 1.0;
- }
- // 保存本子分组定义信息
- m_PropertyEx.m_groups.push_back(group);
- //// 2022-9-11 为刷新链接绑定默认值(系统的执行次数)
- //this->bindDefaultRefreshDataLink();
- }
- /// <summary>
- /// 初始化一个扩展属性组
- /// </summary>
- /// <param name="subItem"></param>
- void VPieChart::initSubGroup(PROPERTY_EX_SUBGROUP& subGroup, int nIndex, int nSubGroupID)
- {
- if (nSubGroupID == GROUP_INDEX_PIE)
- {
- QString idx = QString::number(nIndex + 1);
- // 子分组名称
- subGroup.strTitle = PIE_PROPERTY_EX_SUBGROUP_NAME + idx;
- // 列名称 + 数值
- subGroup.strValueName = PIE_PROPERTY_EX_VALUE_NAME + idx;
- subGroup.strValue = PIE_PROPERTY_EX_VALUE_NAME + idx;
- // 分块颜色名称 + 数值
- subGroup.strColorName = PIE_PROPERTY_EX_COLOR_NAME + idx;
- // 按顺序给一个默认值(可能会越界)
- if (nIndex < m_defaultColors.size())
- {
- subGroup.color = m_defaultColors.at(nIndex);
- }
- else
- {
- subGroup.color = m_defaultColors.at(nIndex - m_defaultColors.size());
- }
- // 数据链接名称
- DataLink dataLink;
- dataLink.title = PIE_PROPERTY_EX_LINK_NAME + idx;
- dataLink.defaultValue = g_pGvlManager->getDefaultValueByName(DEFAULT_VALUE_NULLSTRING);
- subGroup.dataLinks.push_back(dataLink);
- }
- }
- /// <summary>
- /// 获取文字颜色
- /// </summary>
- /// <returns></returns>
- QColor VPieChart::getTextColor() const
- {
- return this->m_TextColor;
- }
- /// <summary>
- /// 获取边界颜色
- /// </summary>
- /// <returns></returns>
- QColor VPieChart::getBorderColor() const
- {
- return this->m_BorderColor;
- }
- /// <summary>
- /// 设置块数
- /// </summary>
- /// <param name="count"></param>
- void VPieChart::setSliceCount(const int& count)
- {
- if (this->m_Property.m_nSliceCount != count)
- {
- this->m_Property.m_nSliceCount = count;
- this->update();
- }
- }
- /// <summary>
- /// 获取当前块数
- /// </summary>
- int VPieChart::getSliceCount()
- {
- return this->m_Property.m_nSliceCount;
- }
- /// <summary>
- /// 设置分块文字
- /// </summary>
- /// <param name="newValue"></param>
- /// <param name="nIndex"></param>
- void VPieChart::updateSliceTitle(const QString& newValue, const int nIndex)
- {
- // 更新分块文字
- QString& strValue = m_PropertyEx.m_groups[GROUP_INDEX_PIE].subGroups[nIndex].strValue;
- if (strValue != newValue)
- {
- strValue = newValue;
- this->update();
- }
- qDebug() << "VPieChart::updateColTitle - update ["
- << m_PropertyEx.m_groups[GROUP_INDEX_PIE].subGroups[nIndex].strValueName << "] to [" << newValue << "]";
- }
- /// <summary>
- /// 设置分块颜色
- /// </summary>
- /// <param name="newValue"></param>
- /// <param name="nIndex"></param>
- void VPieChart::updateSliceColor(QColor newValue, const int nIndex)
- {
- QColor& color = m_PropertyEx.m_groups[GROUP_INDEX_PIE].subGroups[nIndex].color;
- if (color != newValue)
- {
- color = newValue;
- this->update();
- }
- qDebug() << "VPieChart::updateSliceColor - update ["
- << m_PropertyEx.m_groups[GROUP_INDEX_PIE].subGroups[nIndex].strColorName
- << "] to [" << newValue << "]";
- }
- /// <summary>
- /// 设置分块数值
- /// </summary>
- /// <param name="newValue"></param>
- /// <param name="nIndex"></param>
- void VPieChart::updateSliceValue(const int& newValue, const int nIndex)
- {
- if (newValue != m_Values[nIndex])
- {
- m_Values[nIndex] = newValue;
- this->update();
- }
- qDebug() << "VPieChart::updateSliceValue - update m_Values["
- << nIndex << "] to [" << newValue << "]";
- }
- /// <summary>
- /// 调整块属性数量(虚函数)
- /// </summary>
- /// <param name="fixCount"></param>
- void VPieChart::updateExPropertyCount(const int fixCount, const QString& strPropName)
- {
- // 获取属性的当前数量
- int curCount = this->getExPropertyCountByName(strPropName);
- // 子分组编号
- int curGroup = this->getGroupIDByName(strPropName);
- // 检查有效性
- if (curGroup < 0)
- {
- qDebug() << "[Error] VTableControl::updateExPropertyCount - nGroupID in invalid: " << curGroup;
- return;
- }
- // 如果需要增加
- if (fixCount > 0)
- {
- int nEnd = curCount + fixCount;
- for (int i = curCount; i < nEnd; i++)
- {
- PROPERTY_EX_SUBGROUP subItem;
- this->initSubGroup(subItem, i, curGroup);
- m_PropertyEx.m_groups[curGroup].subGroups.push_back(subItem);
- // 2022-1-5 顺便初始化一下Value的预览数值(全为1)
- m_Values << 1.0;
- }
- }
- // 如果需要减少
- else if (fixCount < 0)
- {
- for (int i = 0; i < qAbs(fixCount); i++)
- {
- // 去掉对应的数据结构信息
- m_PropertyEx.m_groups[curGroup].subGroups.pop_back();
- // 同时去掉预览数值
- m_Values.pop_back();
- }
- }
- }
- /// <summary>
- /// 修改扩展属性(虚函数)
- /// </summary>
- /// <param name="strValueTile"></param>
- /// <param name="newValue"></param>
- void VPieChart::changeExProperties(QString strValueTitle, const QVariant& newValue)
- {
- // 如果改变了分块标题
- if (strValueTitle.contains(PIE_PROPERTY_EX_VALUE_NAME))
- {
- // 获取修改属性的索引
- int nIndex = strValueTitle.remove(PIE_PROPERTY_EX_VALUE_NAME).toInt() - 1;
-
- // 如果索引值有效,则对应更新
- if (nIndex >= 0)
- {
- // 修改对应Pie的数据结构内容
- this->updateSliceTitle(newValue.toString(), nIndex);
- }
- }
- // 如果改变了分块颜色
- else if (strValueTitle.contains(PIE_PROPERTY_EX_COLOR_NAME))
- {
- // 获取修改属性的索引
- int nIndex = strValueTitle.remove(PIE_PROPERTY_EX_COLOR_NAME).toInt() - 1;
- // 如果索引值有效,则对应更新
- if (nIndex >= 0)
- {
- // 修改对应Pie的数据结构内容
- this->updateSliceColor(newValue.value<QColor>(), nIndex);
- }
- }
- // 如果改变了数据链接(此处应该不需要手工更新)
- else if (strValueTitle.contains(PIE_PROPERTY_EX_REFRESHLINK_NAME)
- || strValueTitle.contains(PIE_PROPERTY_EX_LINK_NAME)
- )
- {
-
- }
- // Error:不应该执行到这里
- else
- {
- qWarning() << "[Error]: VPieChart::changeExProperties - invalid strValueTitle: " << strValueTitle;
- }
- }
- void VPieChart::setExplodedAll(bool explodedAll)
- {
- if (this->explodedAll != explodedAll)
- {
- this->explodedAll = explodedAll;
- this->update();
- }
- }
- void VPieChart::setExplodedIndex(int explodedIndex)
- {
- if (this->explodedIndex != explodedIndex)
- {
- this->explodedIndex = explodedIndex;
- this->update();
- }
- }
- void VPieChart::setDefaultColor(bool defaultColor)
- {
- Q_UNUSED(defaultColor);
- }
- void VPieChart::setTextColor(const QColor &textColor)
- {
- if (this->m_TextColor != textColor)
- {
- this->m_TextColor = textColor;
- this->update();
- }
- }
- void VPieChart::setBorderColor(const QColor &borderColor)
- {
- if (this->m_BorderColor != borderColor)
- {
- this->m_BorderColor = borderColor;
- this->update();
- }
- }
- void VPieChart::setColors(const QVector<QColor> &colors)
- {
- this->m_defaultColors = colors;
- this->update();
- }
- void VPieChart::initPie()
- {
- }
- /// <summary>
- /// 设置显示百分比
- /// </summary>
- void VPieChart::loadPercent()
- {
- showPercent = true;
- this->update();
- }
- ///// <summary>
- ///// 清空饼图
- ///// </summary>
- //void VPieChart::clearPie()
- //{
- // m_Titles.clear();
- // m_Values.clear();
- //}
- void VPieChart::setHoleSize(double holeSize)
- {
- if (this->holeSize != holeSize) {
- this->holeSize = holeSize;
- this->update();
- }
- }
- //=========================================================
- //
- // 辅助函数
- //
- //=========================================================
- double VPieChart::getSumValue()
- {
- double sum = 0;
- for (int i = 0; i < m_Values.count(); i++)
- {
- sum += m_Values.at(i);
- }
- if (sum == 0.0)
- {
- sum = 1;
- }
- return sum;
- }
- QPoint VPieChart::getOffsetPoint(double angel, int offset)
- {
- int wl = 0;
- int hl = 0;
- double ang = (angel)*M_PI / 180;
- wl = offset * qCos(ang);
- hl = offset * qSin(ang);
- if (angel > 90 && angel < 270)
- {
- wl = qAbs(wl) * -1;
- }
- else {
- wl = qAbs(wl);
- }
- if (angel < 180)
- {
- hl = qAbs(hl) * -1;
- }
- else {
- hl = qAbs(hl);
- }
- return QPoint(wl, hl);
- }
|