712 lines
17 KiB
C++
712 lines
17 KiB
C++
#include "Chart.h"
|
|
|
|
int Chart::ChannelIndex = 0;
|
|
|
|
Chart::Chart(QChart *chart, QWidget *parent)
|
|
{
|
|
|
|
QFile file(":/qss/Scope.qss");
|
|
file.open(QFile::ReadOnly);
|
|
QTextStream filetext(&file);
|
|
QString stylesheet = filetext.readAll();
|
|
this->setStyleSheet(stylesheet);
|
|
file.close();
|
|
|
|
chart->legend()->setAlignment(Qt::AlignRight);
|
|
chart->legend()->setMarkerShape(QLegend::MarkerShapeDefault);
|
|
chart->setTheme(QChart::ChartThemeQt);
|
|
chart->setBackgroundBrush(Qt::white);
|
|
//chart->setPlotArea(this->geometry());
|
|
chart->setAnimationOptions(QChart::SeriesAnimations);
|
|
|
|
|
|
QFont font;
|
|
font.setFamily("微软雅黑");
|
|
font.setPointSize(9);
|
|
|
|
QValueAxis *axisX = new QValueAxis();
|
|
axisX->setLabelsFont(font);
|
|
axisX->setRange(0, 60);
|
|
axisX->setTickCount(11);
|
|
axisX->setLabelFormat("%.0f");
|
|
chart->addAxis(axisX, Qt::AlignBottom);
|
|
|
|
|
|
QValueAxis *axisY = new QValueAxis();
|
|
axisY->setLabelsFont(font);
|
|
axisY->setRange(-3, 3);
|
|
axisY->setTickCount(7);
|
|
axisY->setLabelFormat("%.2f");
|
|
chart->addAxis(axisY, Qt::AlignLeft);
|
|
|
|
setParent(parent);
|
|
setChart(chart);
|
|
|
|
setScroll(true);
|
|
|
|
chart->setPos(0,0);
|
|
chart->resize(parent->size());
|
|
|
|
|
|
//默认不使用,因为使用显卡加速图形会闪
|
|
setUseOpenGL(true);
|
|
|
|
chart->layout()->setContentsMargins(2, 2, 2, 2);
|
|
//chart->setContentsMargins(0, 0, 0, 0); //设置外边界全部为0
|
|
chart->setMargins(QMargins(0, 0, 0, 0));//设置内边界全部为0
|
|
chart->setBackgroundRoundness(0); //设置背景区域无圆角
|
|
|
|
if(!updateTimer)
|
|
{
|
|
updateTimer = new QTimer(this);
|
|
connect(updateTimer,SIGNAL(timeout()),
|
|
this,SLOT(timeout()));
|
|
updateTimer->start(200);//5hz刷新
|
|
}
|
|
|
|
}
|
|
|
|
Chart::Chart(QWidget *parent)
|
|
{
|
|
setParent(parent);
|
|
chart()->legend()->setAlignment(Qt::AlignRight);
|
|
chart()->legend()->setMarkerShape(QLegend::MarkerShapeDefault);
|
|
chart()->setTheme(QChart::ChartThemeQt);
|
|
chart()->setBackgroundBrush(Qt::white);
|
|
//chart()->setPlotArea(this->geometry());
|
|
chart()->setAnimationOptions(QChart::SeriesAnimations);
|
|
|
|
QFont font;
|
|
font.setFamily("微软雅黑");
|
|
font.setPointSize(9);
|
|
|
|
QValueAxis *axisX = new QValueAxis();
|
|
axisX->setLabelsFont(font);
|
|
axisX->setRange(0, 60);
|
|
axisX->setTickCount(11);
|
|
axisX->setLabelFormat("%.0f");
|
|
chart()->addAxis(axisX, Qt::AlignBottom);
|
|
|
|
|
|
QValueAxis *axisY = new QValueAxis();
|
|
axisY->setLabelsFont(font);
|
|
axisY->setRange(-1, 1);
|
|
axisY->setTickCount(7);
|
|
axisY->setLabelFormat("%.2f");
|
|
chart()->addAxis(axisY, Qt::AlignLeft);
|
|
|
|
chart()->setPos(0,0);
|
|
chart()->resize(parent->size());
|
|
|
|
setScroll(true);
|
|
|
|
//默认不使用,因为使用显卡加速图形会闪
|
|
setUseOpenGL(true);
|
|
|
|
chart()->layout()->setContentsMargins(2, 2, 2, 2);
|
|
//chart()->setContentsMargins(0, 0, 0, 0); //设置外边界全部为0
|
|
chart()->setMargins(QMargins(0, 0, 0, 0));//设置内边界全部为0
|
|
chart()->setBackgroundRoundness(0); //设置背景区域无圆角
|
|
|
|
if(!updateTimer)
|
|
{
|
|
updateTimer = new QTimer(this);
|
|
connect(updateTimer,SIGNAL(timeout()),
|
|
this,SLOT(timeout()));
|
|
updateTimer->start(200);//5hz刷新
|
|
}
|
|
|
|
}
|
|
|
|
|
|
Chart::~Chart()
|
|
{
|
|
if(updateTimer)
|
|
{
|
|
if(updateTimer->isActive())
|
|
{
|
|
updateTimer->stop();
|
|
}
|
|
delete updateTimer;
|
|
}
|
|
}
|
|
|
|
void Chart::enterEvent(QEvent *event)
|
|
{
|
|
//setCursor(Qt::SizeVerCursor);
|
|
QChartView::leaveEvent(event);
|
|
}
|
|
|
|
void Chart::leaveEvent(QEvent *event)
|
|
{
|
|
isPress = false;
|
|
setCursor(Qt::ArrowCursor);
|
|
QChartView::leaveEvent(event);
|
|
}
|
|
|
|
void Chart::hideEvent(QHideEvent *event)
|
|
{
|
|
qDebug() << event;
|
|
|
|
|
|
}
|
|
|
|
void Chart::showEvent(QShowEvent *event)
|
|
{
|
|
qDebug() << event;
|
|
}
|
|
|
|
|
|
|
|
void Chart::mouseMoveEvent(QMouseEvent *event)
|
|
{
|
|
if(isoperation)
|
|
{
|
|
const QPoint curPos = event->pos();
|
|
if (isPress)
|
|
{
|
|
QPoint offset = curPos - lastPoint;
|
|
lastPoint = curPos;
|
|
chart()->scroll(-offset.x(), offset.y());
|
|
}
|
|
}
|
|
//QChartView::mouseMoveEvent(e);
|
|
}
|
|
|
|
void Chart::mouseReleaseEvent(QMouseEvent *event)
|
|
{
|
|
if(isoperation)
|
|
{
|
|
isPress = false;
|
|
setCursor(Qt::ArrowCursor);
|
|
}
|
|
//QChartView::mouseReleaseEvent(e);
|
|
}
|
|
|
|
void Chart::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
|
|
|
|
if(isoperation)
|
|
{
|
|
if (event->button() == Qt::RightButton)
|
|
{
|
|
lastPoint = event->pos();
|
|
isPress = true;
|
|
setCursor(Qt::ClosedHandCursor);
|
|
}
|
|
}
|
|
//QChartView::mousePressEvent(e);
|
|
|
|
if(Select())
|
|
{
|
|
setSelect(false);
|
|
}
|
|
else
|
|
{
|
|
setSelect(true);
|
|
}
|
|
|
|
emit select(Select());//被选中
|
|
|
|
}
|
|
|
|
void Chart::mouseDoubleClickEvent(QMouseEvent *event)
|
|
{
|
|
qDebug() << "Chart double clicked" << event;
|
|
//双击生成一个标
|
|
|
|
|
|
//QChartView::mouseDoubleClickEvent(e);
|
|
}
|
|
|
|
void Chart::wheelEvent(QWheelEvent *event)
|
|
{
|
|
if(isoperation)
|
|
{
|
|
//以鼠标坐标为中心进行缩放
|
|
QPointF curVal = chart()->mapToValue(QPointF(event->pos()));
|
|
//缩放比例
|
|
const double factor = 1.5;
|
|
switch(event->modifiers())
|
|
{
|
|
case Qt::ControlModifier://垂直缩放
|
|
{
|
|
QValueAxis *axis = dynamic_cast<QValueAxis*>(chart()->axisY());
|
|
const double Min = axis->min();
|
|
const double Max = axis->max();
|
|
const double Central = curVal.y();
|
|
|
|
double bottomOffset;
|
|
double topOffset;
|
|
if (event->delta() > 0)
|
|
{//放大
|
|
bottomOffset = 1.0 / factor * (Central - Min);
|
|
topOffset = 1.0 / factor * (Max - Central);
|
|
}
|
|
else
|
|
{//缩小
|
|
bottomOffset = 1.0 * factor * (Central - Min);
|
|
topOffset = 1.0 * factor * (Max - Central);
|
|
}
|
|
chart()->axisY()->setRange(Central - bottomOffset, Central + topOffset);
|
|
|
|
}break;
|
|
case Qt::ShiftModifier://水平缩放
|
|
{
|
|
//setCursor(Qt::SizeVerCursor);
|
|
QValueAxis *axis = dynamic_cast<QValueAxis*>(chart()->axisX());
|
|
const double Min = axis->min();
|
|
const double Max = axis->max();
|
|
const double Central = curVal.x();
|
|
|
|
double bottomOffset;
|
|
double topOffset;
|
|
if (event->delta() > 0)
|
|
{//放大
|
|
bottomOffset = 1.0 / factor * (Central - Min);
|
|
topOffset = 1.0 / factor * (Max - Central);
|
|
}
|
|
else
|
|
{//缩小
|
|
bottomOffset = 1.0 * factor * (Central - Min);
|
|
topOffset = 1.0 * factor * (Max - Central);
|
|
}
|
|
chart()->axisX()->setRange(Central - bottomOffset, Central + topOffset);
|
|
}break;
|
|
default://水平移动
|
|
{
|
|
QValueAxis *axis = dynamic_cast<QValueAxis*>(chart()->axisX());
|
|
qreal dwidth = chart()->plotArea().width()/(axis->tickCount()*2);
|
|
if(event->delta() > 0)
|
|
{
|
|
chart()->scroll(-dwidth,0);
|
|
}
|
|
else if(event->delta() < 0)
|
|
{
|
|
chart()->scroll(dwidth,0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//QChartView::wheelEvent(e);
|
|
}
|
|
|
|
void Chart::resizeEvent(QResizeEvent *event)
|
|
{
|
|
chart()->setPos(0,0);
|
|
chart()->setGeometry(this->geometry());
|
|
//chart()->setPlotArea(this->geometry());
|
|
}
|
|
|
|
|
|
|
|
void Chart::timeout(void)//10Hz
|
|
{
|
|
timeseries += updateTimer->interval() * 0.001f;
|
|
chartUpdate();
|
|
}
|
|
|
|
|
|
|
|
|
|
void Chart::chartUpdate(void)
|
|
{
|
|
//读取新数据,如果没有,那就保持
|
|
|
|
|
|
//当到达最大时(0.95),开始滚动
|
|
if(isScroll() == true)
|
|
{
|
|
QValueAxis *axis = dynamic_cast<QValueAxis*>(chart()->axisX());
|
|
const double Min = axis->min();
|
|
const double Max = axis->max();
|
|
if(timeseries > (Min + (Max - Min) * 0.95))
|
|
{
|
|
float err = (timeseries - (Min + (Max - Min) * 0.95));
|
|
|
|
chart()->axisX()->setRange(Min + err,Max + err);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if(isoperation == false)
|
|
{
|
|
QValueAxis *axis = dynamic_cast<QValueAxis*>(chart()->axisX());
|
|
const double Min = axis->min();
|
|
const double Max = axis->max();
|
|
MaxCount = 0.86 * (Max - Min)/(updateTimer->interval() * 0.001);
|
|
|
|
|
|
|
|
//自适应纵轴
|
|
QList<float> yMax;
|
|
QList<float> yMin;
|
|
|
|
QList<QAbstractSeries *> slist = chart()->series();
|
|
for(QAbstractSeries *serie:slist)
|
|
{
|
|
QLineSeries *s = qobject_cast<QLineSeries *>(serie);
|
|
if(s)
|
|
{
|
|
QVector<QPointF> pv = s->pointsVector();
|
|
|
|
//qDebug() << s->name() << pv;
|
|
|
|
float max = pv.at(0).y();
|
|
float min = pv.at(0).y();
|
|
|
|
foreach (QPointF p, pv) {
|
|
|
|
if(max < p.y())
|
|
{
|
|
max = p.y();
|
|
}
|
|
|
|
if(min > p.y())
|
|
{
|
|
min = p.y();
|
|
}
|
|
}
|
|
|
|
yMax.append(max);
|
|
yMin.append(min);
|
|
}
|
|
}
|
|
|
|
if((yMax.size() > 0)&&(yMin.size() > 0))
|
|
{
|
|
|
|
float maxValue = yMax.at(0);
|
|
foreach (float max, yMax) {
|
|
if(maxValue < max)
|
|
{
|
|
maxValue = max;
|
|
}
|
|
}
|
|
|
|
float minValue = yMin.at(0);
|
|
foreach (float min, yMin) {
|
|
if(minValue > min)
|
|
{
|
|
minValue = min;
|
|
}
|
|
}
|
|
|
|
|
|
float scale = 0.5;
|
|
if(maxValue != minValue)
|
|
{
|
|
scale = qAbs((maxValue - minValue) * 0.5 * 0.2);
|
|
|
|
if(scale == 0)
|
|
{
|
|
scale = 0.5;
|
|
}
|
|
}
|
|
|
|
float top = maxValue + scale;
|
|
float bottom = minValue - scale;
|
|
|
|
if(top == bottom)
|
|
{
|
|
top += 1;
|
|
bottom -= 1;
|
|
}
|
|
chart()->axisY()->setRange(bottom,top);
|
|
|
|
|
|
//chart()->axisY()->setRange((int)(minValue - qAbs(minValue - 1) * 0.5 - 1) ,(int)(maxValue + qAbs(maxValue + 1) * 0.5 + 1));
|
|
|
|
|
|
update();
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
void Chart::setUseOpenGL(const bool &value)
|
|
{
|
|
isOpenGL= value;
|
|
}
|
|
|
|
bool Chart::addSeries(QString name = tr("new"))
|
|
{
|
|
//查找有没有这个名字的序列
|
|
bool isContain = false;
|
|
QList<QAbstractSeries *> slist = chart()->series();
|
|
for(QAbstractSeries *serie:slist)
|
|
{
|
|
if(serie->name() == name)
|
|
{
|
|
isContain = true;
|
|
}
|
|
}
|
|
|
|
if(isContain == false)
|
|
{
|
|
QLineSeries *s = new QLineSeries();
|
|
s->setColor(ColorMap::Color[ChannelIndex]);
|
|
s->setName(name);
|
|
s->setPointLabelsClipping(true);
|
|
s->pen().setStyle(Qt::SolidLine);
|
|
s->pen().setColor(ColorMap::Color[ChannelIndex]);
|
|
//s->append(timeseries,0);
|
|
s->setUseOpenGL(isOpenGL);
|
|
chart()->addSeries(s);
|
|
chart()->setAxisX(chart()->axisX(),s);
|
|
chart()->setAxisY(chart()->axisY(),s);
|
|
|
|
ChannelIndex ++;
|
|
if(ChannelIndex >= ColorMap::size())
|
|
{
|
|
ChannelIndex = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qInfo() << "this chart has contain a serie name by :" << name;
|
|
}
|
|
return isContain;
|
|
}
|
|
|
|
bool Chart::addSeries(QString name = tr("new"), int index = 0)
|
|
{
|
|
|
|
//查找有没有这个名字的序列
|
|
bool isContain = false;
|
|
QList<QAbstractSeries *> slist = chart()->series();
|
|
for(QAbstractSeries *serie:slist)
|
|
{
|
|
if(serie->name() == name)
|
|
{
|
|
isContain = true;
|
|
}
|
|
}
|
|
|
|
if(isContain == false)
|
|
{
|
|
QLineSeries *s = new QLineSeries();
|
|
s->setColor(ColorMap::Color[ChannelIndex]);
|
|
s->setName(name);
|
|
s->setPointLabelsClipping(true);
|
|
s->pen().setStyle(Qt::SolidLine);
|
|
s->pen().setColor(ColorMap::Color[ChannelIndex]);
|
|
//s->append(timeseries,0);
|
|
s->setUseOpenGL(isOpenGL);
|
|
chart()->addSeries(s);
|
|
chart()->setAxisX(chart()->axisX(),s);
|
|
chart()->setAxisY(chart()->axisY(),s);
|
|
|
|
qDebug() << ChannelIndex << s->color().name() << ColorMap::Color[ChannelIndex].name();
|
|
|
|
connect(s,&QLineSeries::clicked,
|
|
this,&Chart::lineClicked);
|
|
|
|
ChannelIndex ++;
|
|
if(ChannelIndex >= ColorMap::size())
|
|
{
|
|
ChannelIndex = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qInfo() << "this chart has contain a serie name by :" << name;
|
|
}
|
|
return isContain;
|
|
}
|
|
|
|
bool Chart::addSeries(QString name = tr("new"),QColor color = QColor("#FFFFFF"),Qt::PenStyle pen = Qt::PenStyle(Qt::SolidLine))
|
|
{
|
|
//查找有没有这个名字的序列
|
|
bool isContain = false;
|
|
QList<QAbstractSeries *> slist = chart()->series();
|
|
for(QAbstractSeries *serie:slist)
|
|
{
|
|
if(serie->name() == name)
|
|
{
|
|
isContain = true;
|
|
}
|
|
}
|
|
|
|
if(isContain == false)
|
|
{
|
|
QLineSeries *s = new QLineSeries();
|
|
s->setColor(color);
|
|
s->setName(name);
|
|
s->setPointLabelsClipping(true);
|
|
|
|
s->pen().setStyle(pen);
|
|
s->pen().setColor(ColorMap::Color[ChannelIndex]);
|
|
//s->append(timeseries,0);
|
|
s->setUseOpenGL(isOpenGL);
|
|
chart()->addSeries(s);
|
|
chart()->setAxisX(chart()->axisX(),s);
|
|
chart()->setAxisY(chart()->axisY(),s);
|
|
|
|
ChannelIndex ++;
|
|
if(ChannelIndex >= ColorMap::size())
|
|
{
|
|
ChannelIndex = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qInfo() << "this chart has contain a serie name by :" << name;
|
|
}
|
|
|
|
return isContain;
|
|
}
|
|
|
|
|
|
|
|
void Chart::setSerieData(QString name,QVariant data)
|
|
{
|
|
//timeseries++;
|
|
//qDebug() << timeseries << timeseries;
|
|
//出新了比以前更大或者更小的值,那么就设置一下量程
|
|
{
|
|
QValueAxis *axis = dynamic_cast<QValueAxis*>(chart()->axisY());
|
|
if(data.toDouble() > axis->max())
|
|
{
|
|
//设置最大值
|
|
const double Min = axis->min();
|
|
double FreeArea = (data.toDouble() - Min) * 0.1;
|
|
chart()->axisY()->setRange(Min, data.toDouble() + FreeArea);
|
|
}
|
|
else if(data.toDouble() < axis->min())
|
|
{
|
|
//设置最小值
|
|
const double Max = axis->max();
|
|
double FreeArea = (Max - data.toDouble()) * 0.1;
|
|
chart()->axisY()->setRange(data.toDouble() - FreeArea, Max);
|
|
}
|
|
}
|
|
|
|
//查找有没有这个名字的序列
|
|
bool isContain = false;
|
|
QList<QAbstractSeries *> slist = chart()->series();
|
|
for(QAbstractSeries *serie:slist)
|
|
{
|
|
QLineSeries *s = qobject_cast<QLineSeries *>(serie);
|
|
|
|
if(s->name() == name)
|
|
{
|
|
|
|
s->append(timeseries,data.toDouble());
|
|
|
|
if(isOperation() == false)
|
|
{
|
|
|
|
if(s->pointsVector().size() > MaxCount)
|
|
{
|
|
QList<QPointF> pv = s->points();
|
|
pv.removeFirst();
|
|
|
|
s->clear();
|
|
s->replace(pv);
|
|
//qDebug() << "remove()" << s->points().size() ;
|
|
}
|
|
}
|
|
|
|
isContain = true;
|
|
}
|
|
}
|
|
|
|
if(isContain == false)
|
|
{
|
|
|
|
addSeries(name,ChannelIndex);
|
|
|
|
QList<QAbstractSeries *> slist = chart()->series();
|
|
for(QAbstractSeries *serie:slist)
|
|
{
|
|
QLineSeries *s = qobject_cast<QLineSeries *>(serie);
|
|
if(s->name() == name)
|
|
{
|
|
s->append(timeseries,data.toDouble());
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
chartUpdate();
|
|
}
|
|
|
|
void Chart::removeSerie(QString name)
|
|
{
|
|
//找到,删除
|
|
QList<QAbstractSeries *> slist = chart()->series();
|
|
for(QAbstractSeries *serie:slist)
|
|
{
|
|
QLineSeries *s = qobject_cast<QLineSeries *>(serie);
|
|
if(s)
|
|
{
|
|
QString str = s->name();
|
|
|
|
if(str.contains('['))
|
|
{
|
|
str = str.left(str.indexOf('['));
|
|
}
|
|
|
|
if(str == name)
|
|
{
|
|
chart()->removeSeries(s);
|
|
s->clear();
|
|
s->deleteLater();
|
|
delete s;
|
|
}
|
|
}
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
void Chart::removeAllSerie(void)
|
|
{
|
|
//找到,删除
|
|
QList<QAbstractSeries *> slist = chart()->series();
|
|
for(QAbstractSeries *serie:slist)
|
|
{
|
|
QLineSeries *s = qobject_cast<QLineSeries *>(serie);
|
|
if(s)
|
|
{
|
|
chart()->removeSeries(s);
|
|
s->clear();
|
|
s->deleteLater();
|
|
delete s;
|
|
|
|
}
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
void Chart::lineClicked(const QPointF &point)
|
|
{
|
|
qDebug() << "clicked";
|
|
QObject *obj = sender();
|
|
QLineSeries *s = qobject_cast<QLineSeries *>(obj);
|
|
if(s)
|
|
{
|
|
s->pen().setWidth(10);
|
|
}
|
|
}
|
|
|
|
void Chart::lineHover(const QPointF &point, bool state)
|
|
{
|
|
QObject *obj = sender();
|
|
QLineSeries *s = qobject_cast<QLineSeries *>(obj);
|
|
if(s)
|
|
{
|
|
s->pen().setWidth(10);
|
|
qDebug() << "hover";
|
|
}
|
|
}
|
|
|