1、charts简单使用
QLineSeries* m_pSeries = new QLineSeries();
QFile file("C:\\Users\\Administrator\\Desktop\\2.txt");
file.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&file);
while (!in.atEnd())
{
QString line = in.readLine();
QStringList listLine = line.split("\t");
// 从文件读取数据
m_pSeries->append(listLine[0].toDouble(), listLine[1].toDouble());
}
file.close();
// QChartView *m_pChartView = new QChartView(this);
// 用重写QChartView做显示
mycharts* m_pChartView = new mycharts(this);
QChart* m_pChart = new QChart();
m_pChart->addSeries(m_pSeries);
m_pSeries->setUseOpenGL(true);
m_pChart->createDefaultAxes();
m_pChart->axes(Qt::Vertical).at(0)->setRange(-240, 240);
m_pChart->axisX()->setRange(-160,160);
m_pChart->legend()->hide();
m_pChartView->setChart(m_pChart);
m_pChartView->resize(QSize(600, 500));
m_pChartView->setRenderHints(QPainter::Antialiasing);
2、重写QChartView
注意:提升性能方案
m_pSeries->setUseOpenGL(true);
不使用openGL时,3000个点左右就卡死,在上绘制会更卡,性能提升有限,提升了10倍左右
mycharts.h
#ifndef MYCHARTS_H
#define MYCHARTS_H
#include <QWidget>
#include <QtCharts/QLineSeries>
#include <QtCharts/QValueAxis>
#include <QChart>
#include <QChartView>
QT_CHARTS_USE_NAMESPACE
#include "mainwindow.h"
class mycharts : public QChartView
{
Q_OBJECT
public:
explicit mycharts(QWidget *parent = nullptr);
public:
//鼠标在区域的哪个位置
enum AreaPosition : int
{
Outside = 0x00,
Inside = 0xFF, //任意值
AtLeft = 0x01,
AtRight = 0x02,
AtTop = 0x10,
AtBottom = 0x20,
AtTopLeft = 0x11, //AtLeft|AtTop
AtTopRight = 0x12, //AtRight|AtTop
AtBottomLeft = 0x21, //AtLeft|AtBottom
AtBottomRight = 0x22 //AtRight|AtBottom
};
//当前编辑类型
enum EditType : int
{
EditNone, //无操作
PressInside, //在选区范围内按下
PressOutside, //在选区范围外按下
DrawSelection, //绘制
MoveSelection, //拖动
EditSelection //拉伸编辑
};
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
private:
//计算鼠标相对区域的位置
AreaPosition calcPosition(const QPoint &pos);
AreaPosition calcPosition1(const QPoint &pos);
//当前鼠标对应选区的位置
void setCurPosition(AreaPosition position);
void setCurPosition1(AreaPosition position);
//根据鼠标当前位置更新鼠标样式
void updateCursor();
void updateCursor1();
private:
//当前选区
//QRect有四个成员变量,分别对应左上角和右下角点坐标
//x1-左上角坐标x
//x2-等于x1+width-1
//y1-左上角坐标y
//y2-等于y1+height-1
//即QRect(50,50,200,200)时,topLeft=(50,50)bottomRight=(249,249)
//fillRect会填充整个区域
//drawRect在画笔宽度奇数时,右下角会多1px,绘制时整体宽度先减去1px
QRect selection;
QRect select1;
//是否有选区
bool hasSelection{false};
//鼠标当前操作位置
AreaPosition curPosition{AreaPosition::Outside};
AreaPosition curPosition1{ AreaPosition::Outside };
//当前操作类型
EditType curEditType{EditType::EditNone};
EditType curEditType1{ EditType::EditNone };
//鼠标按下标志
bool pressFlag{false};
bool pressFlag1{ false };
//鼠标按下位置
QPoint pressPos;
//目前用于记录press时鼠标与选区左上角的坐标差值
QPoint tempPos;
QPoint tempPos1;
//鼠标当前位置
QPoint mousePos;
//最小宽度
static const int Min_Width{5};
int m_xl;
int m_yl;
int m_xr;
int m_yr;
MainWindow* m_pwindows;
signals:
public slots:
};
#endif // MYCHARTS_H
QChartView.cpp
#include "mycharts.h"
#include <qdebug.h>
mycharts::mycharts(QWidget *parent) : QChartView(parent)
{
m_pwindows = (MainWindow*)parent;
setMouseTracking(true);
selection = QRect(85, 37, 60, 415);
hasSelection = true;
select1 = QRect(400, 37,60,415);
}
void mycharts::paintEvent(QPaintEvent *event)
{
QChartView::paintEvent(event);
QPainter painter(viewport());
if (!hasSelection)
return;
painter.save();
if (pressFlag && curPosition != AreaPosition::Outside)
{ //点击样式,选用纯正的原谅绿主题
//painter.setPen(QColor(0, 255, 255));
painter.setPen(QColor(205,104,57,100));
painter.setBrush(QColor(46, 139, 87, 100));
}
else if (curPosition != AreaPosition::Outside)
{ //悬停样式
painter.setPen(QColor(0, 255, 255,100));
painter.setBrush(QColor(46, 139, 87, 100));
}
else
{ //未选中样式
painter.setPen(QColor(0, 150, 255,100));
painter.setBrush(QColor(46,139,87,100));
}
//-1是为了边界在rect范围内
painter.drawRect(selection.adjusted(0, 0, -1, -1));
if (pressFlag1 && curPosition1 != AreaPosition::Outside)
{ //点击样式,选用纯正的原谅绿主题
//painter.setPen(QColor(0, 255, 255));
painter.setPen(QColor(205, 104, 57,150));
painter.setBrush(QColor(205, 104, 57,100));
}
else if (curPosition1 != AreaPosition::Outside)
{ //悬停样式
painter.setPen(QColor(139,115,85,100));
//painter.setBrush(QColor(0, 160, 0));
painter.setBrush(QColor(205, 104, 57, 100));
}
else
{ //未选中样式
painter.setPen(QColor(255,231,186,100));
//painter.setBrush(QColor(0, 140, 0));
painter.setBrush(QColor(205, 104, 57, 100));
}
painter.drawRect(select1.adjusted(0, 0, -1, -1));
painter.restore();
}
void mycharts::mousePressEvent(QMouseEvent *event)
{
QChartView::mousePressEvent(event);
//event->accept();
mousePos = event->pos();
if (event->button() == Qt::LeftButton)
{
pressFlag1 = true;
//鼠标左键进行编辑操作
pressFlag = true;
pressPos = event->pos();
if (curPosition == AreaPosition::Inside)
{
curEditType = PressInside;
//鼠标相对选区左上角的位置
tempPos = mousePos - selection.topLeft();
//tempPos1 = mousePos - select1.topLeft();
}
else if (curPosition != AreaPosition::Outside)
{
curEditType = EditSelection;
}
else
{
curEditType = PressOutside;
}
if (curPosition1 == AreaPosition::Inside)
{
curEditType1 = PressInside;
tempPos1 = mousePos - select1.topLeft();
}
else if (curPosition1 != AreaPosition::Outside)
{
curEditType1 = EditSelection;
}
else
{
curEditType1 = PressOutside;
}
}
else
{
//非单独按左键时的操作
}
update();
}
void mycharts::mouseMoveEvent(QMouseEvent *event)
{
//qDebug() << this->chart()->mapToValue(event->pos());
//qDebug() << this->chart()->mapToValue(QPointF(QPoint(selection.left(),0))).x();
//qDebug() << this->chart()->mapToValue(QPointF(QPoint(selection.right(), 0)));
m_xl = this->chart()->mapToValue(QPointF(QPoint(selection.left(), 0))).x();
m_yl = this->chart()->mapToValue(QPointF(QPoint(selection.right(), 0))).x();
m_xr = this->chart()->mapToValue(QPointF(QPoint(select1.left(), 0))).x();
m_yr = this->chart()->mapToValue(QPointF(QPoint(select1.right(), 0))).x();
m_pwindows->setLine(m_xl, m_yl,m_xr,m_yr);
QChartView::mouseMoveEvent(event);
mousePos = event->pos();
if (curEditType == MoveSelection && curEditType1 == MoveSelection)
curEditType1 = PressOutside;
if (pressFlag)
{
if (curEditType == PressInside)
{
//在选区内点击且移动,则移动选区
if (QPoint(pressPos - mousePos).manhattanLength() > 3)
{
curEditType = MoveSelection;
}
}
QPoint mouse_p = mousePos;
//限制范围在可视区域
if (mouse_p.x() < 0)
{
//mouse_p.setX(0);
mouse_p.setX(0);
}
else if (mouse_p.x() > width() - 1)
{
mouse_p.setX(width() - 1);
}
if (mouse_p.y() < 0)
{
mouse_p.setY(0);
}
else if (mouse_p.y() > height() - 1)
{
mouse_p.setY(height() - 1);
}
if (curEditType == DrawSelection)
{
//根据按下时位置和当前位置确定一个选区
selection = QRect(pressPos, mouse_p);
}
else if (curEditType == MoveSelection)
{
//移动选区
selection.moveTopLeft(mousePos - tempPos);
//select1.moveTopLeft(mousePos - tempPos1);
//限制范围在可视区域
if (selection.left() < 73)
{
//selection.moveLeft(0);
selection.moveLeft(73);
}
else if (selection.right() > width() - 48)
{
selection.moveRight(width() - 48);
//selection.moveRight(450);
}
if (selection.top() < 37)
{
selection.moveTop(37);
}
else if (selection.bottom() > height() - 53)
{
//selection.moveBottom(height() - 1);
selection.moveBottom(height() - 53);
}
}
else if (curEditType == EditSelection)
{
//拉伸选区边界
int position = curPosition;
if (position & AtLeft)
{
if (mouse_p.x() < selection.right())
{
selection.setLeft(mouse_p.x());
}
else
{
selection.setLeft(selection.right() - 10);
}
}
else if (position & AtRight)
{
if (mouse_p.x() > selection.left())
{
selection.setRight(mouse_p.x());
}
else
{
selection.setRight(selection.left() + 10);
}
}
}
}
else
{
setCurPosition(calcPosition(mousePos));
}
if (pressFlag1)
{
if (curEditType1 == PressInside)
{
if (QPoint(pressPos - mousePos).manhattanLength() > 3)
{
curEditType1 = MoveSelection;
}
}
QPoint mouse_p = mousePos;
//限制范围在可视区域
if (mouse_p.x() < 0)
{
mouse_p.setX(0);
}
else if (mouse_p.x() > width() - 1)
{
mouse_p.setX(width() - 1);
}
if (mouse_p.y() < 0)
{
mouse_p.setY(0);
}
else if (mouse_p.y() > height() - 1)
{
mouse_p.setY(height() - 1);
}
if (curEditType1 == DrawSelection)
{
//根据按下时位置和当前位置确定一个选区
select1 = QRect(pressPos, mouse_p);
}
else if (curEditType1 == MoveSelection)
{
//移动选区
select1.moveTopLeft(mousePos - tempPos1);
//限制范围在可视区域
if (select1.left() < 73)
{
select1.moveLeft(73);
}
else if (select1.right() > width() - 48)
{
select1.moveRight(width() - 48);
}
if (select1.top() < 37)
{
select1.moveTop(37);
}
else if (select1.bottom() > height() - 53)
{
select1.moveBottom(height() - 53);
}
}
else if (curEditType1 == EditSelection)
{
//拉伸选区边界
int position = curPosition1;
if (position & AtLeft)
{
if (mouse_p.x() < select1.right())
{
select1.setLeft(mouse_p.x());
}
else
{
select1.setLeft(select1.right() - 10);
}
}
else if (position & AtRight)
{
if (mouse_p.x() > select1.left())
{
select1.setRight(mouse_p.x());
}
else
{
select1.setRight(select1.left() + 10);
}
}
}
}
else
{
setCurPosition1(calcPosition1(mousePos));
}
update();
}
void mycharts::mouseReleaseEvent(QMouseEvent *event)
{
QChartView::mouseReleaseEvent(event);
//event->accept();
mousePos = event->pos();
pressFlag = false;
pressFlag1 = false;
if (curEditType != EditNone)
{
//编辑结束后判断是否小于最小宽度,是则取消选区
if (curEditType == DrawSelection)
{
selection = selection.normalized();
if (selection.width() < Min_Width || selection.height() < Min_Width)
{
hasSelection = false;
}
}
else if (curEditType == MoveSelection)
{
}
else if (curEditType == EditSelection)
{
/* if (selection.width() < Min_Width || selection.height() < Min_Width)
{
hasSelection = false;
}*/
}
curEditType = EditNone;
}
setCurPosition(calcPosition(mousePos));
if (curEditType1 != EditNone)
{
if (curEditType1 == DrawSelection)
{
select1 = select1.normalized();
if (select1.width() < Min_Width || select1.height() < Min_Width)
{
hasSelection = false;
}
}
else if (curEditType1 == MoveSelection)
{
}
else if (curEditType1 == EditSelection)
{
/* if (selection.width() < Min_Width || selection.height() < Min_Width)
{
hasSelection = false;
}*/
}
curEditType1 = EditNone;
}
setCurPosition1(calcPosition1(mousePos));
update();
}
mycharts::AreaPosition mycharts::calcPosition(const QPoint &pos)
{
//一条线太窄,不好触发,增加判断范围又会出现边界太近时交叠在一起
//目前的策略是从右下开始判断,左上的优先级更低一点
static const int check_radius = 3;
int position = AreaPosition::Outside;
QRect check_rect = selection.adjusted(-check_radius, -check_radius, check_radius-1, check_radius-1);
//无选区,或者不在选区判定范围则返回outside
if (!hasSelection || !check_rect.contains(pos))
{
return (mycharts::AreaPosition)position;
}
//判断是否在某个边界上
if (std::abs(pos.x() - selection.right()) < check_radius)
{
position |= AreaPosition::AtRight;
}
else if (std::abs(pos.x() - selection.left()) < check_radius)
{
position |= AreaPosition::AtLeft;
}
if (std::abs(pos.y() - selection.bottom()) < check_radius)
{
position |= AreaPosition::AtBottom;
}
else if (std::abs(pos.y() - selection.top()) < check_radius)
{
position |= AreaPosition::AtTop;
}
//没在边界上就判断是否在内部
if (position == AreaPosition::Outside && selection.contains(pos))
{
position = AreaPosition::Inside;
}
return (mycharts::AreaPosition)position;
}
mycharts::AreaPosition mycharts::calcPosition1(const QPoint & pos)
{
//一条线太窄,不好触发,增加判断范围又会出现边界太近时交叠在一起
//目前的策略是从右下开始判断,左上的优先级更低一点
static const int check_radius = 3;
int position = AreaPosition::Outside;
QRect check_rect = select1.adjusted(-check_radius, -check_radius, check_radius - 1, check_radius - 1);
//无选区,或者不在选区判定范围则返回outside
if (!hasSelection || !check_rect.contains(pos))
{
return (mycharts::AreaPosition)position;
}
//判断是否在某个边界上
if (std::abs(pos.x() - select1.right()) < check_radius)
{
position |= AreaPosition::AtRight;
}
else if (std::abs(pos.x() - select1.left()) < check_radius)
{
position |= AreaPosition::AtLeft;
}
if (std::abs(pos.y() - select1.bottom()) < check_radius)
{
position |= AreaPosition::AtBottom;
}
else if (std::abs(pos.y() - select1.top()) < check_radius)
{
position |= AreaPosition::AtTop;
}
//没在边界上就判断是否在内部
if (position == AreaPosition::Outside && select1.contains(pos))
{
position = AreaPosition::Inside;
}
return (mycharts::AreaPosition)position;
}
void mycharts::setCurPosition(mycharts::AreaPosition position)
{
if (position != curPosition)
{
curPosition = position;
updateCursor();
}
}
void mycharts::setCurPosition1(AreaPosition position)
{
if (position != curPosition1)
{
curPosition1 = position;
updateCursor1();
}
}
void mycharts::updateCursor()
{
switch (curPosition)
{
case AtLeft:
case AtRight:
setCursor(Qt::SizeHorCursor);
break;
case AtTop:
case AtBottom:
setCursor(Qt::SizeVerCursor);
break;
case AtTopLeft:
case AtBottomRight:
setCursor(Qt::SizeFDiagCursor);
break;
case AtTopRight:
case AtBottomLeft:
setCursor(Qt::SizeBDiagCursor);
break;
default:
setCursor(Qt::ArrowCursor);
break;
}
}
void mycharts::updateCursor1()
{
switch (curPosition1)
{
case AtLeft:
case AtRight:
setCursor(Qt::SizeHorCursor);
break;
case AtTop:
case AtBottom:
setCursor(Qt::SizeVerCursor);
break;
case AtTopLeft:
case AtBottomRight:
setCursor(Qt::SizeFDiagCursor);
break;
case AtTopRight:
case AtBottomLeft:
setCursor(Qt::SizeBDiagCursor);
break;
default:
setCursor(Qt::ArrowCursor);
break;
}
}