当前位置:网站首页>Qt Charts使用(重写QChartView,实现一些自定义功能)
Qt Charts使用(重写QChartView,实现一些自定义功能)
2022-07-07 05:48:00 【xiaozhu丶】
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;
}
}
边栏推荐
- Practice of combining rook CEPH and rainbow, a cloud native storage solution
- Deit learning notes
- Give full play to the wide practicality of maker education space
- Analyzing the influence of robot science and technology development concept on Social Research
- The single value view in Splunk uses to replace numeric values with text
- How to integrate app linking services in harmonyos applications
- Golan idea IntelliJ cannot input Chinese characters
- Teach you how to select PCB board by hand (II)
- Data type - integer (C language)
- GFS distributed file system
猜你喜欢
登山小分队(dfs)
Explore creativity in steam art design
All about PDF crack, a complete solution to meet all your PDF needs
Rsync remote synchronization
Splunk查询csv lookup table数据动态查询
调用华为游戏多媒体服务的创建引擎接口返回错误码1002,错误信息:the params is error
DeiT学习笔记
使用SwinUnet训练自己的数据集
Using helm to install rainbow in various kubernetes
[untitled]
随机推荐
Opencv learning note 3 - image smoothing / denoising
Are you holding back on the publicity of the salary system for it posts such as testing, development, operation and maintenance?
Download and install orcale database11.2.0.4
One click deployment of highly available emqx clusters in rainbow
登山小分队(dfs)
The single value view in Splunk uses to replace numeric values with text
The truth of robot education in hands-on practice
Virtual address space
AVL balanced binary search tree
Famine cloud service management script
National SMS center number inquiry
Tronapi-波场接口-源码无加密-可二开--附接口文档-基于ThinkPHP5封装-作者详细指导-2022年7月6日-新手快速上手-可无缝升级tp6版本
2-3查找树
PVTV2--Pyramid Vision TransformerV2学习笔记
Novice entry SCM must understand those things
MES系统,是企业生产的必要选择
Thirteen forms of lambda in kotlin
调用华为游戏多媒体服务的创建引擎接口返回错误码1002,错误信息:the params is error
Grpc, oauth2, OpenSSL, two-way authentication, one-way authentication and other column directories
Golan idea IntelliJ cannot input Chinese characters