此处主要是贴了曲线类,可以自行进行修改。里面具有部分变量得从外部传参数。
下面是.h文件:
#pragma once
#include <QtCharts>
#include <QWidget>
#include <QColor>
#include <QButtonGroup>
#include "typedefine.h"
class CustomChartView : public QChartView
{
Q_OBJECT
public:
explicit CustomChartView(QWidget* parent = nullptr,
const QString& title = "曲线图",
const QColor& lineColor = Qt::blue);
// 清空数据
void clearData();
// 设置坐标轴范围
void setAxisRange(double xMin, double xMax, double yMin, double yMax);
// 设置曲线颜色
void setLineColor(const QColor& color);
// 设置图表标题
void setChartTitle(const QString& title);
// 添加新曲线(返回新创建的QLineSeries指针)
QLineSeries* addSeries(DataSeries& series);
// 根据名称移除曲线
void removeSeries(const QString& seriesName);
// 新增右键菜单事件
void contextMenuEvent(QContextMenuEvent* event) override;
// 获取图表图片
QPixmap getChartPixmap(int width = 0, int height = 0) const;
// 创建高分辨率图表
QChart* createHighResChart() const;
// 导出图表为图片
bool exportToImage(const QString& filePath, int width = 0, int height = 0);
// 从数据库中读取指定区间段的数据并存到m_mapDBData中,供生成指定时间段的图片使用
bool LoadDataInRange(double nStart, double nEnd);
// 设置当前表的图例名称
void SetLengedName(const QString& strLenged);
public slots:
// 显示导出对话框
void SlotShowExportDialog();
void SlotResetBestChart();
void SlotResetBest();
void SlotChangeAsixRange();
signals:
void selected(CustomChartView* selectedView); // 新增选中信号
void exportFinished(bool success, const QString& message); // 新增导出完成信号
protected:
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override; // 新增
void mouseMoveEvent(QMouseEvent* event) override; // 新增
void paintEvent(QPaintEvent* event) override;
private:
QChart* m_chart; // 图表对象
QValueAxis *m_axisX; // X轴
QValueAxis *m_axisY; // Y轴
QValueAxis *m_axisY_Right;
QColor m_borderColor = Qt::gray; // 默认边框颜色
QList<QLineSeries*> m_seriesList; // 管理所有曲线
QMap<QString, QLineSeries*> m_variableSeries; // 管理变量曲线
bool m_selected = false;
mutable QMutex m_dataMutex; // 用于保护数据访问
QMap<QString, QQueue<double>> m_mapDBData; // 存储从数据库中读取的所有数据
QString m_strLenged;
QLabel *m_pCustomLegend;
// 坐标轴范围
double m_nXAsixRange;
double m_nYAsixMinRange;
double m_nYAsixMaxRange;
bool m_bFlagRangeChange;
private:
static CustomChartView* m_currentSelected; // 静态成员跟踪当前选中项
};
下面是.cpp文件:
#include "customchartview.h"
#include "utils.h"
#include "xyrangeselect.h"
#include <QColor>
#include <QMessageBox>
CustomChartView* CustomChartView::m_currentSelected = nullptr;
CustomChartView::CustomChartView(QWidget* parent, const QString& title, const QColor& lineColor)
: QChartView(parent)
, m_bFlagRangeChange(false)
{
// 初始化图表
m_chart = new QChart();
m_chart->setBackgroundBrush(QBrush(Qt::white));
m_chart->legend()->setVisible(false); // 隐藏图例
// 初始化坐标轴
m_axisX = new QValueAxis();
m_axisY = new QValueAxis();
m_axisY_Right = new QValueAxis();
m_axisX->setTitleText(QStringLiteral("时间"));
m_axisY->setTitleText(QStringLiteral("参数值"));
m_axisY_Right->setTitleText(QStringLiteral("误差值"));
// 设置坐标轴可见性
m_axisX->setVisible(true);
m_axisY->setVisible(true);
m_axisY_Right->setVisible(true);
// 设置默认显示范围(重要!)
m_axisX->setRange(-1, 1); // 初始显示-1到1的范围
m_axisY->setRange(-1, 1);
m_axisY_Right->setRange(-1, 1);
// 设置网格线为黑色虚线
m_axisX->setGridLinePen(QPen(Qt::black, 1, Qt::DashLine));
m_axisY->setGridLinePen(QPen(Qt::black, 1, Qt::DashLine));
// 设置坐标轴轴线颜色
m_axisX->setLinePen(QPen(Qt::black, 2)); // 黑色,2像素宽
m_axisY->setLinePen(QPen(Qt::black, 2));
//// 设置刻度线颜色
//m_axisX->setTickPen(QPen(Qt::black, 1)); // 黑色,1像素宽
//m_axisY->setTickPen(QPen(Qt::black, 1));
// 设置刻度标签颜色
m_axisX->setLabelsColor(Qt::black);
m_axisY->setLabelsColor(Qt::black);
// 添加坐标轴到图表
m_chart->addAxis(m_axisX, Qt::AlignBottom);
m_chart->addAxis(m_axisY, Qt::AlignLeft);
m_chart->addAxis(m_axisY_Right, Qt::AlignRight);
// 设置图表视图
this->setChart(m_chart);
this->setRenderHint(QPainter::Antialiasing);
this->setRubberBand(QChartView::RectangleRubberBand); // 支持框选缩放
// 设置图例可见
m_chart->legend()->setVisible(true);
//m_pCustomLegend = new QLabel("", this);
//m_pCustomLegend->setStyleSheet("background: lightgray; border: 1px solid gray;");
//m_pCustomLegend->setAlignment(Qt::AlignCenter);
m_chart->setMargins(QMargins(0, 0, 0, 0)); // 左、上、右、下边距全为0
m_chart->setBackgroundRoundness(0); // 消除圆角导致的空隙
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
}
// 清空数据
void CustomChartView::clearData()
{
m_axisX->setRange(0, 1);
m_axisY->setRange(0, 1);
}
// 设置坐标轴范围
void CustomChartView::setAxisRange(double xMin, double xMax, double yMin, double yMax)
{
m_axisX->setRange(xMin, xMax);
m_axisY->setRange(yMin, yMax);
}
// 设置曲线颜色
void CustomChartView::setLineColor(const QColor& color)
{
}
// 设置图表标题
void CustomChartView::setChartTitle(const QString& title)
{
m_chart->setTitle(title);
}
QLineSeries* CustomChartView::addSeries(DataSeries& series)
{
static QList<QColor> colors =
{
Qt::red, // 红色
Qt::green, // 绿色
Qt::blue, // 蓝色
};
QLineSeries* newSeries = new QLineSeries;
if(series.tag == DataTag::eWuCha)
{
series.color = Qt::red;
newSeries->setName(QStringLiteral("误差"));
}
else if(series.tag == DataTag::eFangZhen)
{
series.color = Qt::green;
newSeries->setName(QStringLiteral("仿真"));
}
else if(series.tag == DataTag::eShiWu)
{
series.color = Qt::blue;
newSeries->setName(QStringLiteral("实物"));
}
//series.color = colors.at(m_seriesList.size() % colors.size());
// 创建新曲线
newSeries->replace(series.data);
newSeries->setColor(series.color);
// 添加到图表
m_chart->addSeries(newSeries);
newSeries->attachAxis(m_axisX);
newSeries->attachAxis(m_axisY);
m_seriesList.append(newSeries);
return newSeries;
}
void CustomChartView::removeSeries(const QString& seriesName)
{
for(auto it = m_seriesList.begin(); it != m_seriesList.end(); ++it)
{
if((*it)->name() == seriesName)
{
m_chart->removeSeries(*it);
delete *it;
m_seriesList.erase(it);
break;
}
m_chart->removeSeries(*it);
delete *it;
m_seriesList.erase(it);
break;
}
}
void CustomChartView::contextMenuEvent(QContextMenuEvent* event)
{
QMenu menu(this);
// 导出菜单项
QAction* exportAction = menu.addAction(QIcon(":/icons/export.png"), QStringLiteral("导出图表"));
connect(exportAction, &QAction::triggered, this, &CustomChartView::SlotShowExportDialog);
menu.addSeparator();
QAction* zoomResetAction = menu.addAction(QStringLiteral("重置缩放"));
connect(zoomResetAction, &QAction::triggered, [this]()
{
m_chart->zoomReset();
});
QAction* resetBestAction = menu.addAction(QStringLiteral("缩放到最佳"));
connect(resetBestAction, &QAction::triggered, this, &CustomChartView::SlotResetBestChart);
menu.addSeparator();
QAction* xyAsixRangeAction = menu.addAction(QStringLiteral("横纵范围"));
connect(xyAsixRangeAction, &QAction::triggered, this, &CustomChartView::SlotChangeAsixRange);
// 显示菜单
menu.exec(event->globalPos());
}
QPixmap CustomChartView::getChartPixmap(int width /*= 0*/, int height /*= 0*/) const
{
// 确定输出尺寸
QSize outputSize;
if(width > 0 && height > 0)
{
outputSize = QSize(width, height);
}
else
{
// 使用屏幕分辨率作为默认尺寸
QScreen *screen = QApplication::primaryScreen();
if(screen)
{
outputSize = screen->size() * 0.8; // 屏幕尺寸的80%
}
else
{
outputSize = QSize(1920, 1080); // 默认尺寸
}
}
// 创建空位图
QPixmap pixmap(outputSize);
if(pixmap.isNull())
{
qWarning() << "无法创建位图,尺寸:" << outputSize;
return QPixmap();
}
// 填充透明背景
pixmap.fill(Qt::transparent);
// 创建绘图器
QPainter painter(&pixmap);
if(!painter.isActive())
{
qWarning() << "无法在位图上创建绘图器";
return QPixmap();
}
// 设置高质量渲染
painter.setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing |
QPainter::SmoothPixmapTransform);
// 创建临时图表对象(不添加到视图)
QScopedPointer<QChart> tempChart(createHighResChart());
if(!tempChart)
{
qWarning() << "无法创建临时图表";
return QPixmap();
}
// 创建临时场景
QGraphicsScene tempScene;
tempScene.addItem(tempChart.data());
tempChart->setParent(&tempScene); // 转移所有权
// 设置图表大小
tempChart->resize(outputSize);
// 渲染场景到位图
tempScene.render(&painter, QRectF(), tempScene.sceneRect());
// 释放资源(避免双重删除)
tempScene.removeItem(tempChart.take()); // 从场景移除但不删除
return pixmap;
}
QT_CHARTS_NAMESPACE::QChart* CustomChartView::createHighResChart() const
{
// 创建新图表对象
QChart* highResChart = new QChart();
// 复制当前图表属性(线程安全方式)
highResChart->setTitle(m_chart->title());
highResChart->setBackgroundBrush(m_chart->backgroundBrush());
highResChart->setMargins(m_chart->margins());
highResChart->setBackgroundRoundness(m_chart->backgroundRoundness());
highResChart->setTheme(m_chart->theme());
// 复制坐标轴
QValueAxis* newAxisX = new QValueAxis();
newAxisX->setRange(m_axisX->min(), m_axisX->max());
newAxisX->setTitleText(m_axisX->titleText());
newAxisX->setGridLineColor(m_axisX->gridLineColor());
newAxisX->setLabelsColor(m_axisX->labelsColor());
QValueAxis* newAxisY = new QValueAxis();
newAxisY->setRange(m_axisY->min(), m_axisY->max());
newAxisY->setTitleText(m_axisY->titleText());
newAxisY->setGridLineColor(m_axisY->gridLineColor());
newAxisY->setLabelsColor(m_axisY->labelsColor());
highResChart->addAxis(newAxisX, Qt::AlignBottom);
highResChart->addAxis(newAxisY, Qt::AlignLeft);
// 复制所有曲线(使用互斥锁保护原始数据)
QMutexLocker locker(&m_dataMutex);
for(QLineSeries* series : m_seriesList)
{
QLineSeries* newSeries = new QLineSeries();
newSeries->setName(series->name());
// 复制点数据(避免直接访问原始系列)-----后续此处数据可从数据库中取
QVector<QPointF> points = series->pointsVector();
newSeries->replace(points);
newSeries->setColor(series->color());
newSeries->setPen(series->pen());
highResChart->addSeries(newSeries);
newSeries->attachAxis(newAxisX);
newSeries->attachAxis(newAxisY);
}
return highResChart;
}
bool CustomChartView::exportToImage(const QString& filePath, int width /*= 0*/, int height /*= 0*/)
{
QPixmap pixmap = getChartPixmap(width, height);
if(pixmap.isNull())
{
emit exportFinished(false, QStringLiteral("无法创建图表图片"));
return false;
}
// 根据文件扩展名确定格式
QString format = "PNG";
if(filePath.endsWith(".jpg", Qt::CaseInsensitive) ||
filePath.endsWith(".jpeg", Qt::CaseInsensitive))
{
format = "JPG";
}
else if(filePath.endsWith(".bmp", Qt::CaseInsensitive))
{
format = "BMP";
}
// 保存图片
bool success = pixmap.save(filePath, format.toUtf8().constData(), 95);
if(success)
{
emit exportFinished(true, QString("图表已成功导出到: %1").arg(filePath));
}
else
{
emit exportFinished(false, QString("导出失败: %1").arg(filePath));
}
return success;
}
bool CustomChartView::LoadDataInRange(double nStart, double nEnd)
{
m_mapDBData.clear();
int nStartRow = nStart / 0.2; // 数据库起始行
int nEndRow = nEnd / 0.2; // 数据库结束行
return true;
}
void CustomChartView::SetLengedName(const QString& strLenged)
{
m_strLenged = strLenged;
}
void CustomChartView::SlotShowExportDialog()
{
// 创建文件对话框
QString fileName = QFileDialog::getSaveFileName(
this,
"导出图表",
QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/chart.png",
"图片文件 (*.png *.jpg *.jpeg *.bmp)"
);
if(fileName.isEmpty())
{
return; // 用户取消
}
// 分辨率选择对话框(添加时间段功能)
QDialog dialog(this);
dialog.setWindowTitle(QStringLiteral("选择分辨率")); // 修改标题
QVBoxLayout mainLayout(&dialog); // 改用垂直布局作为主布局
//// ===== 新增部分:时间范围选择 =====
//QGroupBox timeGroup(QStringLiteral("选择时间段"));
//QFormLayout timeLayout(&timeGroup);
//QLineEdit startTimeEdit;
//QLineEdit endTimeEdit;
//timeLayout.addRow(QStringLiteral("开始时间:"), &startTimeEdit);
//timeLayout.addRow(QStringLiteral("结束时间:"), &endTimeEdit);
//// ===== 时间范围选择结束 =====
QGroupBox resGroup(QStringLiteral("选择分辨率"));
QFormLayout resLayout(&resGroup);
QSpinBox widthSpin;
widthSpin.setRange(400, 10000);
widthSpin.setValue(1920);
widthSpin.setSuffix(" px");
QSpinBox heightSpin;
heightSpin.setRange(300, 10000);
heightSpin.setValue(1080);
heightSpin.setSuffix(" px");
QCheckBox keepRatioCheck(QStringLiteral("保持宽高比"));
keepRatioCheck.setChecked(true);
// 当前视图宽高比
double currentAspect = static_cast<double>(width()) / height();
// 连接宽高比保持
QObject::connect(&widthSpin, QOverload<int>::of(&QSpinBox::valueChanged),
[&](int value)
{
if(keepRatioCheck.isChecked())
{
heightSpin.blockSignals(true);
heightSpin.setValue(static_cast<int>(value / currentAspect));
heightSpin.blockSignals(false);
}
});
QObject::connect(&heightSpin, QOverload<int>::of(&QSpinBox::valueChanged),
[&](int value)
{
if(keepRatioCheck.isChecked())
{
widthSpin.blockSignals(true);
widthSpin.setValue(static_cast<int>(value * currentAspect));
widthSpin.blockSignals(false);
}
});
resLayout.addRow(QStringLiteral("宽度:"), &widthSpin);
resLayout.addRow(QStringLiteral("高度:"), &heightSpin);
resLayout.addRow(&keepRatioCheck);
// ===== 添加到主布局 =====
//mainLayout.addWidget(&timeGroup);
mainLayout.addWidget(&resGroup);
// ===== 底部按钮区域 =====
QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
mainLayout.addWidget(&buttons);
QObject::connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
if(dialog.exec() != QDialog::Accepted)
{
return;
}
//// ===== 获取用户输入的时间值 =====
//QString strStartTime = startTimeEdit.text().trimmed();
//QString strEndTime = endTimeEdit.text().trimmed();
//bool bFlatStart = Utils::instance()->isInputNumber(strStartTime);
//bool bFlatEnd = Utils::instance()->isInputNumber(strEndTime);
//if(!bFlatStart || !bFlatEnd)
//{
// QMessageBox::critical(nullptr, QStringLiteral("提示"), QStringLiteral("请输入正确数字!"));
// return;
//}
//else if(strStartTime.toDouble() > strEndTime.toDouble())
//{
// QMessageBox::critical(nullptr, QStringLiteral("提示"), QStringLiteral("请输入正确范围!"));
// return;
//}
//bool bResFlag = LoadDataInRange(strStartTime.toDouble(), strEndTime.toDouble());
//if(!bResFlag)
//{
// QMessageBox::critical(nullptr, QStringLiteral("提示"), QStringLiteral("数据库读取失败!"));
// return;
//}
int selectedWidth = widthSpin.value();
int selectedHeight = heightSpin.value();
// 导出图片
exportToImage(fileName, widthSpin.value(), heightSpin.value());
}
void CustomChartView::SlotResetBestChart()
{
m_bFlagRangeChange = false;
SlotResetBest();
}
void CustomChartView::SlotResetBest()
{
if(!m_bFlagRangeChange)
{
const auto seriesList = m_chart->series();
if(seriesList.isEmpty())
{
return;
}
qreal minX = std::numeric_limits<qreal>::max();
qreal maxX = std::numeric_limits<qreal>::lowest();
qreal minY = minX;
qreal maxY = maxX;
for(QAbstractSeries* series : seriesList)
{
if(auto xySeries = qobject_cast<QXYSeries*>(series))
{
for(const QPointF& point : xySeries->points())
{
minX = qMin(minX, point.x());
maxX = qMax(maxX, point.x());
minY = qMin(minY, point.y());
maxY = qMax(maxY, point.y());
}
}
}
//minX = maxX - m_nXAsixRange;
//minY = maxY - m_nYAsixRange;
const qreal margin = 0.05;
const qreal xRange = maxX - minX;
const qreal yRange = maxY - minY;
// X轴正常处理
minX -= xRange * margin;
maxX += xRange * margin;
// Y轴特殊处理恒定值
if(qFuzzyIsNull(yRange))
{
const qreal baseY = minY;
const qreal offset = (qFuzzyIsNull(baseY) ? 1.0 : qAbs(baseY * 0.1));
minY = baseY - offset;
maxY = baseY + offset;
// 防止相等导致坐标轴崩溃
if(qFuzzyCompare(minY, maxY))
{
maxY += 0.001;
}
}
else
{
minY -= yRange * margin;
maxY += yRange * margin;
}
m_chart->axisX()->setRange(minX, maxX);
m_chart->axisY()->setRange(minY, maxY);
// 设置误差值坐标轴的范围
// 使用 std::find_if 查找目标序列
auto it = std::find_if(seriesList.begin(), seriesList.end(),
[](QAbstractSeries * series)
{
// 检查序列名称是否匹配 "误差"
return series->name() == QStringLiteral("误差");
}
);
if(it != seriesList.end())
{
QAbstractSeries* errorSeries = *it;
if(auto lineSeries = qobject_cast<QLineSeries*>(errorSeries))
{
// 获取序列所有数据点
const auto points = lineSeries->pointsVector();
// 处理空序列情况
if(points.isEmpty())
{
qWarning() << QStringLiteral("'误差'曲线数据为空");
return;
}
// 获取Y值范围
const double tolerance = 1e-6; // 浮点精度容差
// 修改点:使用pair接收minmax_element结果(兼容C++11/14)
auto result = std::minmax_element(
points.begin(), points.end(),
[](const QPointF & a, const QPointF & b)
{
return a.y() < b.y();
});
// 修改点:显式定义迭代器
auto minIt = result.first; // 指向最小值的迭代器
auto maxIt = result.second; // 指向最大值的迭代器
double minY = minIt->y();
double maxY = maxIt->y();
// 处理极值相等的情况
if(qFuzzyCompare(minY + 1, maxY + 1)) // 避免浮点精度问题
{
qDebug() << QStringLiteral("警告:最大值与最小值相等 (%1)").arg(minY);
// 自动扩展显示范围
const double margin = qAbs(minY) * 0.1;
minY -= (margin < tolerance ? 1.0 : margin);
maxY += (margin < tolerance ? 1.0 : margin);
}
//// 输出结果
//qDebug() << QStringLiteral("'误差'曲线Y轴范围: [%1, %2]")
// .arg(minY).arg(maxY);
// 设置坐标轴范围
m_axisY_Right->setRange(minY, maxY);
}
}
else
{
qWarning() << QStringLiteral("未找到名为'误差'的曲线");
}
}
else
{
const auto seriesList = m_chart->series();
if(seriesList.isEmpty())
{
return;
}
qreal minX = std::numeric_limits<qreal>::max();
qreal maxX = std::numeric_limits<qreal>::lowest();
qreal minY = minX;
qreal maxY = maxX;
for(QAbstractSeries* series : seriesList)
{
if(auto xySeries = qobject_cast<QXYSeries*>(series))
{
for(const QPointF& point : xySeries->points())
{
minX = qMin(minX, point.x());
maxX = qMax(maxX, point.x());
minY = qMin(minY, point.y());
maxY = qMax(maxY, point.y());
}
}
}
minX = maxX - m_nXAsixRange;
//minY = maxY - m_nYAsixRange;
const qreal margin = 0.05;
const qreal xRange = maxX - minX;
const qreal yRange = maxY - minY;
// X轴正常处理
minX -= xRange * margin;
maxX += xRange * margin;
// Y轴特殊处理恒定值
if(qFuzzyIsNull(yRange))
{
const qreal baseY = minY;
const qreal offset = (qFuzzyIsNull(baseY) ? 1.0 : qAbs(baseY * 0.1));
minY = baseY - offset;
maxY = baseY + offset;
// 防止相等导致坐标轴崩溃
if(qFuzzyCompare(minY, maxY))
{
maxY += 0.001;
}
}
else
{
minY -= yRange * margin;
maxY += yRange * margin;
}
m_chart->axisX()->setRange(minX, maxX);
m_chart->axisY()->setRange(m_nYAsixMinRange, m_nYAsixMaxRange);
}
}
void CustomChartView::SlotChangeAsixRange()
{
XYRangeSelect dlg;
if(dlg.exec() == QDialog::Accepted)
{
m_nXAsixRange = dlg.GetXAsixRange();
m_nYAsixMinRange = dlg.GetYAsixMinRange();
m_nYAsixMaxRange = dlg.GetYAsixMaxRange();
m_bFlagRangeChange = true;
}
//QDialog dialog(this);
//dialog.setWindowTitle(QStringLiteral("横纵轴范围")); // 匹配图片标题
//// 创建垂直布局作为主布局
//QVBoxLayout mainLayout(&dialog);
//mainLayout.setContentsMargins(15, 15, 15, 15); // 添加适当边距
//// 创建时间范围选择分组框 - 匹配图片中的样式
//QGroupBox AsixGroup(QStringLiteral("选择时间范围"));
//AsixGroup.setStyleSheet(
// "QGroupBox {"
// " border: 1px solid #DDD;"
// " border-radius: 5px;"
// " margin-top: 1.5em;"
// " background: white;"
// " font-weight: bold;"
// "}"
// "QGroupBox::title {"
// " subcontrol-origin: margin;"
// " left: 10px;"
// " padding: 0 3px;"
// "}"
//);
//// 使用表单布局作为分组框的内部布局
//QFormLayout *AsixLayout = new QFormLayout(&AsixGroup);
//AsixLayout->setSpacing(10); // 行间距
//AsixLayout->setContentsMargins(15, 20, 15, 15); // 内部边距
//// 创建输入框和单位标签
//QLineEdit XAsixEdit;
//XAsixEdit.setStyleSheet("background: white; padding: 4px;");
//// 水平布局容器:输入框 + 单位标签
//QHBoxLayout *hLayoutX = new QHBoxLayout;
//hLayoutX->addWidget(&XAsixEdit);
//// 添加单位标签(匹配图片中的空白位置)
//QLabel *unitLabelX = new QLabel(" S", &AsixGroup);
//unitLabelX->setStyleSheet("QLabel { color: #666; }");
//hLayoutX->addWidget(unitLabelX);
//hLayoutX->setContentsMargins(0, 0, 0, 0); // 取消内边距
//QLineEdit YAsixEdit;
//YAsixEdit.setStyleSheet("background: white; padding: 4px;");
//// 垂直轴单位布局
//QHBoxLayout *hLayoutY = new QHBoxLayout;
//hLayoutY->addWidget(&YAsixEdit);
//QLabel *unitLabelY = new QLabel("", &AsixGroup);
//unitLabelY->setStyleSheet("QLabel { color: #666; }");
//hLayoutY->addWidget(unitLabelY);
//hLayoutY->setContentsMargins(0, 0, 0, 0);
//// 添加带单位的行到表单布局
//AsixLayout->addRow(QStringLiteral("横轴范围:"), hLayoutX); // 匹配图片标签文本
//AsixLayout->addRow(QStringLiteral("纵轴范围:"), hLayoutY); // 匹配图片标签文本
//// 添加分组框到主布局
//mainLayout.addWidget(&AsixGroup);
//// 添加标准按钮
//QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
// Qt::Horizontal, &dialog);
//buttonBox.setStyleSheet("QPushButton { padding: 5px 15px; min-width: 80px; }");
//mainLayout.addWidget(&buttonBox);
//// 连接按钮信号
//QObject::connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
//QObject::connect(&buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
//// 显示对话框
//if(dialog.exec() != QDialog::Accepted)
//{
// return;
//}
//m_nXAsixRange = XAsixEdit.text().toInt();
//m_nYAsixRange = YAsixEdit.text().toInt();
}
void CustomChartView::mousePressEvent(QMouseEvent* event)
{
if(event->button() == Qt::LeftButton)
{
// 取消前一个选中项的高亮
if(m_currentSelected && m_currentSelected != this)
{
m_currentSelected->m_selected = false;
m_currentSelected->update();
}
// 设置当前项为选中状态
m_selected = true;
m_currentSelected = this;
update();
emit selected(this);
}
QChartView::mousePressEvent(event);
}
void CustomChartView::mouseReleaseEvent(QMouseEvent* event)
{
if(event->button() == Qt::LeftButton)
{
// 只传递左键释放事件
QChartView::mouseReleaseEvent(event);
}
else
{
// 拦截非左键释放事件
event->accept();
}
}
void CustomChartView::mouseMoveEvent(QMouseEvent* event)
{
if(event->buttons() & Qt::LeftButton)
{
// 只传递左键拖动事件
QChartView::mouseMoveEvent(event);
}
else
{
// 拦截非左键移动事件
event->accept();
}
}
void CustomChartView::paintEvent(QPaintEvent* event)
{
QChartView::paintEvent(event);
QPainter painter(viewport());
// 绘制默认边框
painter.setPen(QPen(QColor(200, 200, 200), 2));
painter.drawRect(rect());
// 选中高亮
if(m_selected)
{
painter.setPen(QPen(QColor(255, 165, 0), 4));
painter.drawRect(rect().adjusted(2, 2, -2, -2));
}
}