#include "dpBarsChart.h" #include "dataManager.h" CustomBars::CustomBars(QCPAxis* keyAxis, QCPAxis* valueAxis) : QCPBars(keyAxis, valueAxis), m_textVisible(false), m_textAlignment(Qt::AlignCenter), m_spacing(5), m_font(QFont(QLatin1String("sans serif"), 12)) {} void CustomBars::setTextVisible(bool visible) { m_textVisible = visible; } void CustomBars::setTextAlignment(Qt::Alignment alignment) { m_textAlignment = alignment; } void CustomBars::setSpacing(double spacing) { m_spacing = spacing; } void CustomBars::setFont(QFont font) { m_font = font; } void CustomBars::draw(QCPPainter* painter) { ///源码拷贝 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } if (mDataContainer->isEmpty()) return; QCPBarsDataContainer::const_iterator visibleBegin, visibleEnd; getVisibleDataBounds(visibleBegin, visibleEnd); // loop over and draw segments of unselected/selected data: QList selectedSegments, unselectedSegments, allSegments; getDataSegments(selectedSegments, unselectedSegments); allSegments << unselectedSegments << selectedSegments; for (int i=0; i= unselectedSegments.size(); QCPBarsDataContainer::const_iterator begin = visibleBegin; QCPBarsDataContainer::const_iterator end = visibleEnd; mDataContainer->limitIteratorsToDataRange(begin, end, allSegments.at(i)); if (begin == end) continue; for (QCPBarsDataContainer::const_iterator it=begin; it!=end; ++it) { // check data validity if flag set: #ifdef QCUSTOMPLOT_CHECK_DATA if (QCP::isInvalidData(it->key, it->value)) qDebug() << Q_FUNC_INFO << "Data point at" << it->key << "of drawn range invalid." << "Plottable name:" << name(); #endif // draw bar: if (isSelectedSegment && mSelectionDecorator) { mSelectionDecorator->applyBrush(painter); mSelectionDecorator->applyPen(painter); } else { painter->setBrush(mBrush); painter->setPen(mPen); } applyDefaultAntialiasingHint(painter); painter->drawPolygon(getBarRect(it->key, it->value)); ///---自定义逻辑-start--- //draw text if(m_textVisible) { QRectF barRect = getBarRect(it->key, it->value); painter->setFont(m_font); QString text = QString::number(it->value, 'g', 2); //获取当前value值,保留两位精度 QRectF textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip | m_textAlignment, text); //计算文字占用大小 if(mKeyAxis.data()->orientation() == Qt::Horizontal) //水平轴为keyAxis { if(mKeyAxis.data()->axisType() == QCPAxis::atTop) //上轴,文字放到柱图下方 textRect.moveTopLeft(barRect.bottomLeft() + QPointF(0, m_spacing)); else //下轴,文字放到柱图上方 textRect.moveBottomLeft(barRect.topLeft() - QPointF(0, m_spacing)); textRect.setWidth(barRect.width()); } else //垂直轴为keyAxis { if(mKeyAxis.data()->axisType() == QCPAxis::atLeft) //左轴,文字放到柱图右侧 textRect.moveTopLeft(barRect.topRight() + QPointF(m_spacing, 0)); else //右轴,文字放到柱图左侧 textRect.moveTopRight(barRect.topLeft() - QPointF(m_spacing, 0)); textRect.setHeight(barRect.height()); } painter->drawText(textRect, Qt::TextDontClip | m_textAlignment, text); } ///---自定义逻辑-end--- } } ///源码拷贝 // draw other selection decoration that isn't just line/scatter pens and brushes: if (mSelectionDecorator) mSelectionDecorator->drawDecoration(painter, selection()); } dpBarsChart::dpBarsChart(QWidget* parent) :dpBaseChart(parent) { setAttribute(Qt::WA_TranslucentBackground,true); m_pCustomPlot = new QCustomPlot(this); /* m_pBarsGroup = new QCPBarsGroup(m_pCustomPlot); m_pBarsGroup->setSpacingType(QCPBarsGroup::stAbsolute); m_pBarsGroup->setSpacing(2); */ initQCP(); QBoxLayout* mainLayout = new QBoxLayout(QBoxLayout::LeftToRight); mainLayout->setContentsMargins(0, 1, 0, 0); mainLayout->addWidget(m_pCustomPlot); setLayout(mainLayout); m_updateData = false; connect(DataManager::instance(), &DataManager::dataUpdated, this, &dpBarsChart::onSignal_dataUpdated); } dpBarsChart::~dpBarsChart() { } void dpBarsChart::initQCP() { m_chartStyle.bgColor = Qt::transparent; m_chartStyle.axisColor = QColor(87, 100, 120); m_chartStyle.labelColor = QColor(250, 250, 250); m_chartStyle.labelFont = QFont("黑体", 12); m_chartStyle.tickColor = QColor(87, 100, 120); m_chartStyle.tickLabelColor = QColor(250, 250, 250); m_chartStyle.tickLabelFont = QFont("黑体", 12); m_chartStyle.gridPen = QPen(QColor(87, 100, 120), 1, Qt::DotLine); m_pCustomPlot->setInteractions(QCP::iNone); /*m_pCustomPlot->axisRect()->setRangeDrag(Qt::Horizontal); //只允许x轴方向的拖拽 double zoomFactor = m_pCustomPlot->axisRect()->rangeZoomFactor(Qt::Horizontal); m_pCustomPlot->axisRect()->setRangeZoomFactor(zoomFactor, 1); //只做x轴的缩放*/ //m_pCustomPlot->xAxis->setTicks(false); m_pCustomPlot->xAxis->setSubTicks(false); //m_pCustomPlot->yAxis->setTicks(false); m_pCustomPlot->yAxis->setSubTicks(false); //m_pCustomPlot->yAxis->setVisible(false); //m_pCustomPlot->yAxis2->setTicks(false); m_pCustomPlot->yAxis2->setSubTicks(false); m_pCustomPlot->yAxis2->setVisible(false); //背景颜色 m_pCustomPlot->setBackground(QBrush(m_chartStyle.bgColor)); //坐标轴颜色 m_pCustomPlot->xAxis->setBasePen(m_chartStyle.axisColor); m_pCustomPlot->xAxis2->setBasePen(m_chartStyle.axisColor); m_pCustomPlot->yAxis->setBasePen(m_chartStyle.axisColor); m_pCustomPlot->yAxis2->setBasePen(m_chartStyle.axisColor); //坐标刻度颜色 m_pCustomPlot->xAxis->setTickPen(QPen(m_chartStyle.tickColor)); m_pCustomPlot->yAxis->setTickPen(QPen(m_chartStyle.tickColor)); m_pCustomPlot->yAxis2->setTickPen(QPen(m_chartStyle.tickColor)); //坐标刻度Label颜色 m_pCustomPlot->xAxis->setTickLabels(false); m_pCustomPlot->xAxis->setTickLabelColor(m_chartStyle.tickLabelColor); m_pCustomPlot->xAxis->setTickLabelFont(m_chartStyle.tickLabelFont); m_pCustomPlot->yAxis->setTickLabels(false); m_pCustomPlot->yAxis->setTickLabelColor(m_chartStyle.tickLabelColor); m_pCustomPlot->yAxis->setTickLabelFont(m_chartStyle.tickLabelFont); m_pCustomPlot->yAxis2->setTickLabelColor(m_chartStyle.tickLabelColor); m_pCustomPlot->yAxis2->setTickLabelFont(m_chartStyle.tickLabelFont); //网格线颜色 m_pCustomPlot->xAxis->grid()->setVisible(false); m_pCustomPlot->xAxis->grid()->setPen(m_chartStyle.gridPen); m_pCustomPlot->xAxis->grid()->setZeroLinePen(m_chartStyle.gridPen); //m_pCustomPlot->xAxis2->grid()->setPen(m_chartStyle.gridPen); m_pCustomPlot->yAxis->grid()->setVisible(false); m_pCustomPlot->yAxis->grid()->setPen(m_chartStyle.gridPen); m_pCustomPlot->yAxis->grid()->setZeroLinePen(m_chartStyle.gridPen); m_pCustomPlot->yAxis2->grid()->setPen(m_chartStyle.gridPen); //Legend m_pCustomPlot->legend->setBrush(QBrush(QColor(255,255,255,12))); //背景透明 m_pCustomPlot->legend->setBorderPen(QPen(QColor(255,255,255,0))); //边框透明 m_pCustomPlot->legend->setFont(m_chartStyle.labelFont); m_pCustomPlot->legend->setTextColor( m_chartStyle.labelColor); } void dpBarsChart::setTimeRange(TimeUnit unit) {} void dpBarsChart::setDateTime(const QDateTime& dateTime) { if(m_updateData) { for(auto it = m_bars.begin(); it != m_bars.end(); ++it) DataManager::instance()->requestData(it.key(), this); m_pCustomPlot->replot(); } } void dpBarsChart::viewHistoricalData(const QDateTime& dateTime) {} void dpBarsChart::synchronizeConfigData(const configurationResults& cfg) { m_updateData = false; //停止更新数据 //先清除现有图形(直方图不像曲线一样有连续的过程展现,所以不采用动态更新,每次都清除、重新创建) //m_pBarsGroup->clear(); m_pCustomPlot->clearPlottables(); m_bars.clear(); m_barsGroups.clear(); bool groupByType = cfg.groupByType; //设定朝向 QCPAxis* keyAxis = nullptr; QCPAxis* valueAxis = nullptr; if(cfg.barOrientataion == Vertical) { keyAxis = m_pCustomPlot->xAxis; valueAxis = m_pCustomPlot->yAxis; } else { keyAxis = m_pCustomPlot->yAxis; valueAxis = m_pCustomPlot->xAxis; } if(!keyAxis || !valueAxis) return; QVector ticks; int tick = 0; QVector tickLabels; QHash> groupedBars; //按数据类型对bar进行分组,以实现可以按组放置以及设置颜色等操作 for(int i = 0; i < cfg.m_pModel_dataSource->rowCount(); i++) { QString itemText = cfg.m_pModel_dataSource->item(i, 0)->text(); QString stationID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_stationID).toString(); QString compoentID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_componentID).toString(); QString pointID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_pointID).toString(); QString dataID = stationID + "-" + compoentID + "-" + pointID; QVariant colorData = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::DecorationRole); RealTimeDataType dataType = (RealTimeDataType)cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt(); Bars bars; bars.name = itemText; bars.dataID = dataID; bars.dataType = dataType; bars.color = colorData.value(); CustomBars* qBars = new CustomBars(keyAxis, valueAxis); qBars->setTextVisible(true); qBars->setName(bars.name); qBars->setPen(bars.color); //边框颜色 qBars->setBrush(bars.color); //填充颜色 bars.qBars = qBars; if(groupByType) { groupedBars[dataType].insert(dataID); //每一个类型创建一个QCPBarsGroup对象 QCPBarsGroup* barsGroup = nullptr; if(!m_barsGroups.contains(dataType)) { barsGroup = new QCPBarsGroup(m_pCustomPlot); m_barsGroups.insert(dataType, barsGroup); } } else { ticks << ++tick; tickLabels << itemText; bars.keys << tick; } m_bars.insert(dataID, bars); //实时模拟数据 DataManager::instance()->registerDataSource(dataID, [](){ static double min = 0, max = 10.0; double randomFloat = min + QRandomGenerator::global()->generateDouble() * (max - min); return QVariant::fromValue(randomFloat); }); } if(groupByType) { for(auto it = groupedBars.begin(); it != groupedBars.end(); ++it) { ticks.push_back(++tick); switch(it.key()) { case power: tickLabels.push_back("功率"); break; case voltage: tickLabels.push_back("电压"); break; case current: tickLabels.push_back("电流"); break; case temperature: tickLabels.push_back("温度"); break; default: tickLabels.push_back("未定义"); break; } for(auto bars_it = it.value().begin(); bars_it != it.value().end(); ++bars_it) { QString dataID = *bars_it; if(m_bars.contains(dataID)) m_bars[dataID].keys.push_back(tick); } } } //Axis if(groupByType) keyAxis->setTickLabels(true); else keyAxis->setTickLabels(false); QSharedPointer textTicker(new QCPAxisTickerText); textTicker->addTicks(ticks, tickLabels); keyAxis->setTicker(textTicker); keyAxis->setRange(0, ticks.count() + 1); valueAxis->setTickLabels(true); QSharedPointer fixedTicker(new QCPAxisTickerFixed); valueAxis->setTicker(fixedTicker); valueAxis->setRange(0, 11); for(auto it = m_bars.begin(); it != m_bars.end(); ++it) { if(it.value().qBars.isNull()) continue; //随机模拟值 QVector values; //double randomVaule = 1 + QRandomGenerator::global()->generateDouble() * (8 - 1); values << 0; Bars bar = it.value(); bar.qBars->setData(bar.keys, values); if(groupByType && m_barsGroups.value(bar.dataType)) { bar.qBars->setWidthType(QCPBars::wtPlotCoords); //bar.qBars->setWidth(bar.qBars->width() / groupedBars.value(bar.dataType).count()); bar.qBars->setWidth(bar.qBars->width() * ticks.count() / m_bars.count()); bar.qBars->setBarsGroup(m_barsGroups.value(bar.dataType)); } } //Legend if(cfg.showLegend && m_bars.count() > 0) m_pCustomPlot->legend->setVisible(true); else m_pCustomPlot->legend->setVisible(false); //m_pCustomPlot->replot(); m_updateData = true; } void dpBarsChart::onSignal_dataUpdated(const QString& dataID, const QVariant& data, const QDateTime& timestamp) { auto it = m_bars.find(dataID); if(it != m_bars.end()) { static double marginFactor = 1.0; double dData = data.toDouble(); Bars bar = it.value(); //调整所在轴的范围 QCPRange range = bar.qBars->valueAxis()->range(); if(dData > range.upper) { double upper = dData + marginFactor; bar.qBars->valueAxis()->setRangeUpper(upper); } else if(dData < range.lower) { double lower = dData - marginFactor; bar.qBars->valueAxis()->setRangeLower(lower); } //更新值 QVector values; values << dData; bar.qBars->setData(bar.keys, values); } }