#include "CustomQwtPlot.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CustomQwtPlot::CustomQwtPlot(QWidget *parent) : QwtPlot(parent) { } CustomQwtPlot::~CustomQwtPlot() { qDebug() << "~CustomQwtPlot"; } void CustomQwtPlot::SetEventFilterFunc(std::function event_filter_func) { this->_event_filter_func = event_filter_func; } void CustomQwtPlot::SetXaxisDragScale(bool enable) { QwtScaleWidget *x_scale = axisWidget(QwtPlot::xBottom); x_scale->setMouseTracking(enable); x_scale->installEventFilter(enable ? this : nullptr); } void CustomQwtPlot::ResetPlot() { this->setAxisScale(QwtPlot::xBottom, _init_x_min, _init_x_max); this->setAxisScale(QwtPlot::yLeft, _init_y_min, _init_y_max); this->replot(); } QwtPlotCurve *CustomQwtPlot::GetCurve(const QString &curve_name) { return _curves.value(curve_name, nullptr); } QList CustomQwtPlot::GetCurveList() const { return _curves.values(); } void CustomQwtPlot::AddCurve(QwtPlotCurve *curve) { if (curve) { curve->setPen(QPen(getDistinctColorForManyCurves(_curves.count()), 1)); curve->setZ(0); curve->attach(this); _curves[curve->title().text()] = curve; } } QwtPlotMarker *CustomQwtPlot::GetMarker(const QString &marker_name, const QString &postion) { return _markers.value(marker_name).value(postion); } QList CustomQwtPlot::GetMarkerList() const { QList markers; for (auto tmp_markers : this->_markers) { markers.append(tmp_markers.values()); } return markers; } void CustomQwtPlot::AddMarker(QwtPlotMarker *marker, const QString &marker_name, const QString &postion) { if (marker) { QwtPlotCurve* curve = GetCurve(marker_name); if (curve) { QPen pen = curve->pen(); pen.setWidth(2); marker->setLinePen(pen); marker->setZ(20); marker->attach(this); _markers[marker_name][postion] = marker; } } } void CustomQwtPlot::RemoveMarker(const QString &marker_name, const QString &postion) { QwtPlotMarker* marker = GetMarker(marker_name, postion); if (marker) { marker->detach(); delete marker; } _markers[marker_name].remove(postion); } void CustomQwtPlot::CleanMarkers() { QList markers = GetMarkerList(); for (auto marker : markers) { if (marker) { marker->detach(); delete marker; } } this->_markers.clear(); } QwtPlotZoneItem* CustomQwtPlot::GetZoneItem(const QString& zone_item_name) { return _zone_items.value(zone_item_name); } QList CustomQwtPlot::GetZoneItemList() const { return this->_zone_items.values(); } void CustomQwtPlot::AddZoneItem(QwtPlotZoneItem *zone_item, const QString &zone_item_name) { if (zone_item) { zone_item->setPen(Qt::transparent); // 无边框 zone_item->setBrush(QColor(0, 120, 215, 95)); // 半透明蓝色(RGBA:A=80 透明度) zone_item->setZ(10); zone_item->attach(this); _zone_items[zone_item_name] = zone_item; } } void CustomQwtPlot::RemoveZoneItem(const QString& zone_item_name) { QwtPlotZoneItem* zone_item = GetZoneItem(zone_item_name); if (zone_item) { zone_item->detach(); delete zone_item; } _zone_items.remove(zone_item_name); } void CustomQwtPlot::CleanZoneItems() { QList zone_items = GetZoneItemList(); for (auto zone_item : zone_items) { if (zone_item) { zone_item->detach(); delete zone_item; } } this->_zone_items.clear(); } bool CustomQwtPlot::eventFilter(QObject *obj, QEvent *event) { if (this->_event_filter_func) { bool filted = this->_event_filter_func(obj, event); if (filted) { return filted; } } if (dynamic_cast(obj) != this->axisWidget(QwtPlot::xBottom)) return false; QMouseEvent *me = static_cast(event); QwtScaleMap map = this->canvasMap(QwtPlot::xBottom); // ===================== 1. 鼠标拖动 X 轴 ===================== if (event->type() == QEvent::MouseButtonPress) { this->_is_dragging = true; this->_last_pos = me->pos(); return true; } else if (event->type() == QEvent::MouseMove && this->_is_dragging) { // 计算坐标偏移 double old_x = map.invTransform(_last_pos.x()); double new_x = map.invTransform(me->pos().x()); double dx = old_x - new_x; // 移动 X 轴 double x_min = axisScaleDiv(QwtPlot::xBottom).lowerBound() + dx; double x_max = axisScaleDiv(QwtPlot::xBottom).upperBound() + dx; this->setAxisScale(QwtPlot::xBottom, x_min, x_max); this->replot(); this->_last_pos = me->pos(); return true; } else if (event->type() == QEvent::MouseButtonRelease) { this->_is_dragging = false; return true; } // ===================== 2. 滚轮缩放 X 轴 ===================== if (event->type() == QEvent::Wheel) { QWheelEvent *we = static_cast(event); double scale = we->angleDelta().y() > 0 ? 0.8 : 1.25; // 放大/缩小 // 以鼠标所在位置为中心缩放 double mouse_x = map.invTransform(we->pos().x()); double x1 = this->axisScaleDiv(QwtPlot::xBottom).lowerBound(); double x2 = this->axisScaleDiv(QwtPlot::xBottom).upperBound(); double new1 = mouse_x - (mouse_x - x1) * scale; double new2 = mouse_x + (x2 - mouse_x) * scale; this->setAxisScale(QwtPlot::xBottom, new1, new2); this->replot(); return true; } return QwtPlot::eventFilter(obj, event); } void CustomQwtPlot::showEvent(QShowEvent *event) { Q_UNUSED(event); this->updateAxes(); double x_min = this->axisScaleDiv(QwtPlot::xBottom).lowerBound(); double x_max = this->axisScaleDiv(QwtPlot::xBottom).upperBound(); double y_min = this->axisScaleDiv(QwtPlot::yLeft).lowerBound(); double y_max = this->axisScaleDiv(QwtPlot::yLeft).upperBound(); this->_init_x_min = x_min; this->_init_x_max = x_max; this->_init_y_min = y_min; this->_init_y_max = y_max; } CustomQwtPlotXaxisPanner::CustomQwtPlotXaxisPanner(QWidget *canvas) : QwtPlotPanner(canvas) { } CustomQwtPlotXaxisPanner::~CustomQwtPlotXaxisPanner() { qDebug() << "~CustomQwtPlotXaxisPanner"; } void CustomQwtPlotXaxisPanner::moveCanvas(int dx, int dy) { QwtPlotPanner::moveCanvas(dx, 0); } CustomQwtPlotXaxisMagnifier::CustomQwtPlotXaxisMagnifier(QWidget *canvas) : QwtPlotMagnifier(canvas) { } CustomQwtPlotXaxisMagnifier::~CustomQwtPlotXaxisMagnifier() { qDebug() << "~CustomQwtPlotXaxisMagnifier"; } void CustomQwtPlotXaxisMagnifier::rescale(double factor) { factor = qBound(0.1, factor, 10.0); QwtScaleMap x_map = plot()->canvasMap(QwtPlot::xBottom); double center = x_map.invTransform(plot()->canvas()->width() / 2); plot()->setAxisScale( QwtPlot::xBottom, center - (center - x_map.s1()) * factor, center + (x_map.s2() - center) * factor ); plot()->replot(); } CustomQwtPlotXaxisSelector::CustomQwtPlotXaxisSelector(QWidget *canvas) : QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft, QwtPicker::NoRubberBand, QwtPicker::AlwaysOn, canvas) , _min_x(0.0) , _max_x(0.0) { this->setStateMachine(new QwtPickerDragRectMachine()); this->setRubberBandPen(QPen(Qt::NoPen)); _overlay = new QwtPlotShapeItem; _overlay->setRenderHint(QwtPlotItem::RenderAntialiased); _overlay->setPen(QPen(Qt::red, 2)); _overlay->setBrush(QBrush(QColor(0, 120, 210, 50))); _overlay->setZ(100); _overlay->attach(plot()); _overlay->setVisible(false); } CustomQwtPlotXaxisSelector::~CustomQwtPlotXaxisSelector() { qDebug() << "~CustomQwtPlotXaxisSelector"; } double CustomQwtPlotXaxisSelector::selectedMinX() const { return _min_x; } double CustomQwtPlotXaxisSelector::selectedMaxX() const { return _max_x; } void CustomQwtPlotXaxisSelector::clearSelection() { _min_x = 0.0; _max_x = 0.0; if (_overlay) _overlay->setVisible(false); } void CustomQwtPlotXaxisSelector::move(const QPoint & pos) { QPolygon points = pickedPoints(); if (points.size() < 2) { clearSelection(); return QwtPlotPicker::move(pos); } QPointF p1 = invTransform(points.first()); QPointF p2 = invTransform(points.last()); // 计算X范围 _min_x = qMin(p1.x(), p2.x()); _max_x = qMax(p1.x(), p2.x()); // Y轴铺满 double y_min = plot()->axisScaleDiv(QwtPlot::yLeft).lowerBound(); double y_max = plot()->axisScaleDiv(QwtPlot::yLeft).upperBound(); QRectF area(_min_x, y_min, _max_x - _min_x, y_max - y_min); _overlay->setRect(area); _overlay->setVisible(true); plot()->replot(); QwtPlotPicker::move(pos); } bool CustomQwtPlotXaxisSelector::end(bool ok) { if (!ok) { clearSelection(); return QwtPlotPicker::end(ok); } if (_overlay->isVisible()) { _overlay->setVisible(false); plot()->replot(); } if ( (_max_x - _min_x) > 3 ) { emit selectionFinished(_min_x, _max_x); } return QwtPlotPicker::end(ok); } QColor getDistinctColorForManyCurves(int curve_index) { // 1. 定义基础色相(覆盖不同主色系,0-360度) const QList base_hues = { 0, // 红色 30, // 橙色 60, // 黄色 90, // 黄绿色 120, // 绿色 150, // 青绿色 180, // 青色 210, // 天蓝色 240, // 蓝色 270, // 紫色 300, // 洋红色 330 // 玫红色 }; // 2. 定义不同的饱和度/明度组合(避免颜色太暗/太灰) const QList> sv_combinations = { {85, 90}, // 高饱和、高明度 {70, 85}, // 中高饱和、中高明度 {85, 75}, // 高饱和、中明度 {60, 80}, // 中饱和、中高明度 {75, 70}, // 中高饱和、中明度 {90, 80} // 极高饱和、中高明度 }; // 3. 计算当前曲线对应的色相和饱和度/明度 int hue_index = curve_index % base_hues.size(); // 循环使用基础色相 int sv_index = (curve_index / base_hues.size()) % sv_combinations.size(); // 循环使用饱和度/明度组合 // 4. 获取HSV参数(色相0-360,饱和度0-255,明度0-255) int hue = base_hues[hue_index]; int saturation = sv_combinations[sv_index].first * 255 / 100; // 转换为0-255范围 int value = sv_combinations[sv_index].second * 255 / 100; // 转换为0-255范围 // 5. 生成并返回颜色(HSV转RGB) QColor color; color.setHsv(hue, saturation, value); // 额外优化:避免极浅/极暗的颜色(保证曲线可见) if (value < 50 * 255 / 100) { value = 50 * 255 / 100; color.setHsv(hue, saturation, value); } return color; }