当前位置:网站首页>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;
}
}
边栏推荐
- 使用BiSeNet实现自己的数据集
- IELTS review progress and method use [daily revision]
- How to realize the high temperature alarm of the machine room in the moving ring monitoring system
- PVTV2--Pyramid Vision TransformerV2学习笔记
- [Yu Yue education] higher vocational English reference materials of Nanjing Polytechnic University
- POJ - 3616 Milking Time(DP+LIS)
- Data type - integer (C language)
- SSM 整合
- Opencv learning note 5 - gradient calculation / edge detection
- Splunk查询csv lookup table数据动态查询
猜你喜欢
Low success rate of unit test report
2-3查找樹
Arm GIC (IV) GIC V3 register class analysis notes.
Golang 编译约束/条件编译 ( // +build <tags> )
Open3d ISS key points
Opencv learning note 4 - expansion / corrosion / open operation / close operation
Fluentd is easy to use. Combined with the rainbow plug-in market, log collection is faster
[Yu Yue education] basic reference materials of electrical and electronic technology of Nanjing Institute of information technology
Practice of implementing cloud native Devops based on rainbow library app
The truth of robot education in hands-on practice
随机推荐
GOLand idea intellij 无法输入汉字
POJ - 3616 Milking Time(DP+LIS)
Using helm to install rainbow in various kubernetes
Using nocalhost to develop microservice application on rainbow
SSM 整合
Basic data types and string types are converted to each other
A method for quickly viewing pod logs under frequent tests (grep awk xargs kuberctl)
Le système mes est un choix nécessaire pour la production de l'entreprise
How to integrate app linking services in harmonyos applications
redis故障处理 “Can‘t save in background: fork: Cannot allocate memory“
Input and output of floating point data (C language)
一种适用于应用频繁测试下快速查看Pod的日志的方法(grep awk xargs kuberctl)
接口作为参数(接口回调)
POJ - 3616 Milking Time(DP+LIS)
Rainbow version 5.6 was released, adding a variety of installation methods and optimizing the topology operation experience
Arm GIC (IV) GIC V3 register class analysis notes.
Tips for using jeditabletable
MES系統,是企業生產的必要選擇
MES系统,是企业生产的必要选择
Iptables' state module (FTP service exercise)