Qt:QChart绘图介绍(主要包含类:QChart,QTableWidget,QGridLayout)
首先点击【打开】摁键,从excel中读入相关数据
之后点击【计算】摁键,将数据进行处理,并将部分输出到TableWidget中,部分绘制到QChart中
目录
QChart相关内容(刷新,图例,绘制双曲线,自定义坐标系):
前界面UI设计,TableWidget及QChart初始化:
效果展示:
初始界面展示:
点击打开摁键:
点击计算:
点击DeltaTheta图例:
点击Err图例:
TableWidget绘制及数据输出:
参考内容:
Qt:读取已有数据的Excel文档,并将数据显示在通过QTableWidget绘制的表格中,之后将显示的数据保存成excel格式进行输出(包括表头等内容):https://blog.csdn.net/qq_41605114/article/details/86597744
.h中:
private:
..........
QTableWidget * TableFor;
..........
cpp中:
//构造函数中的内容:
TableFor = new QTableWidget(this);
//接口中的内容:
TableFor->setColumnCount(ColNumber);//列数,设置表格的行数
TableFor->setRowCount(Number_Fourier);//行数 设置表格的列数
// TableFor->move(10,40); 设置相对于(0,0)点的位置
TableFor->setWindowTitle("傅里叶级数显示:");//设置TableWidget的名称
TableFor->setFixedSize(280, 350);//设置表格的大小
QStringList header;//设置表头
header<<"Error"<<"2";//添加内容
TableFor->setHorizontalHeaderLabels(header);//设置表头(横)
QStringList header2;//设置表头
header2<<"1"<<"2"<<"3"<<"4"<<"5"<<"6"<<"7"<<"8"<<"9"<<"10"<<"11"<<"12"<<"13"<<"14"<<"15";//添加内容
TableFor->setVerticalHeaderLabels(header2);//设置表头(竖)
//设置行,列的宽度和高度
for(int i = 0; i < 15; i++)
TableFor->setRowHeight(i, 22);
TableFor->setColumnWidth(0,120);
TableFor->setColumnWidth(1,120);
补充内容:
右键
TableWidget右键
分两部分:1右键界面设置 2信号和槽3槽函数的编写
1:右键弹出窗口的设置
void Widget::menu_for_table()
{
qDebug()<<"右键设置";
table_widget_menu = new QMenu(table);
actdelete = new QAction("删除", this);
connect(actdelete,&QAction::triggered,this,&Widget::on_deletedata_clicked);//删除
table_widget_menu->addAction(actdelete);
actclear = new QAction("清空", this);
connect(actclear,&QAction::triggered,this,&Widget::on_clear_clicked);//清空
table_widget_menu->addAction(actclear);
}
在设置右键的时候,即可写入相关的信号和槽函数,以上只有删除和清空两项要求
2:信号和槽
connect(table,&QTableWidget::customContextMenuRequested,this,&Widget::showmenu);
在TableWidget上右键,会触发的signal:
[signal] void QWidget::customContextMenuRequested(const QPoint &pos)
信号会将鼠标相对于部件的原点(0,0)的坐标值传输给槽函数。正如信号函数中所描述的,会有参数const QPoint &pos。
注意需要TableWidget进行设置
table->setContextMenuPolicy(Qt::CustomContextMenu);
3:槽函数的编写(注意,这次是含有参数的)
void Widget::showmenu(const QPoint pt)
{
qDebug()<<"showmenu";
QPoint point = pt; //得到窗口坐标
QTableWidgetItem *item =table->itemAt(point);//会根据坐标值判断,目前选中的是哪儿一行
qDebug()<<item;
if(item != NULL)
{
// qDebug() << "row" << item->row(); //当前行
table_widget_menu->clear(); //清除原有菜单
table_widget_menu->addAction(actclear);
table_widget_menu->addAction(actdelete);
//菜单出现的位置为当前鼠标的位置
table_widget_menu->exec(QCursor::pos());
}
}
关于QTableWidget的详细用法,以下两篇文章写的很好
QTableWidget详细用法:https://blog.csdn.net/cwj066/article/details/83344705
QT QTableWidget 用法总结:https://blog.csdn.net/polokang/article/details/6696982
QChart相关内容(刷新,图例,绘制双曲线,自定义坐标系):
QTCharts入门 使用QChartView做折线图:https://blog.csdn.net/baizy77/article/details/84107786
QT中图表类QChart系列之(3)-各种缩放/平移:https://blog.csdn.net/qq_31073871/article/details/82990961
QT中图表类QChart系列之(4)-折线图:时间轴,网格,显示坐标值,动态滚动等:https://blog.csdn.net/qq_31073871/article/details/83019943
QT中图表类QChart系列之(5)-疑难问题:坐标轴和数据不对应、密集的散点图无法显示等:
https://blog.csdn.net/qq_31073871/article/details/83020712
QT中图表类QChart系列之(6)-在一个chart中显示两条曲线:https://blog.csdn.net/qq_31073871/article/details/83032884
QT中图表类QChart系列之(7)-小结,chart中显示曲线的标准步骤:https://blog.csdn.net/qq_31073871/article/details/83277795
QtCharts 图表各种问题填坑中。。。:https://blog.csdn.net/weixin_41712355/article/details/82217607
Qt QChart,利用QChart绘制动态曲线:https://blog.csdn.net/HiccupHiccup/article/details/74996618
QChart显示的点多了之后会卡顿的问题,解决方案:https://blog.csdn.net/qq_31073871/article/details/86352020
Qt QChart 图形可视化:https://blog.csdn.net/sinat_14854721/article/details/76563098
QT中图表类QChart 系列之(2):读取/设置X轴的显示区间:https://blog.csdn.net/qq_31073871/article/details/82990808
QtCharts小知识:如何把曲线显示到控件上:https://blog.csdn.net/ecourse/article/details/77636393
QChart创建完整创建过程:
第一部分:数据预处理
将相关数据压入list中,数据类型为QPoint类型
第二部分:添加数据
保存需要绘制曲线的Y值:
serial->append(list_2);//在serial中添加数据
QlineSeries可以设置曲线的名称,数据跟随的坐标系:
serial->attachAxis(axisY);
serial->setName("Line 2");
第三部分:核心部分,可以把这个部分看成是图表所有相关内容,属性的设置部分
QChart负责的部分很对,图例的设置,XY坐标,具体的数值,都需要添加到QCahrt对应的对象中
chart->addSeries(serial);//将数据加载到QChart中
第四部分:简单理解成画布,将已经完成的图表进行展示
注意:初始化的时候展示一次即可,后续的刷新部分,只需要对QCahrt中的相关内容进行设置即可
注意事项:
- 刷新:添加数据前,使用chart->removeAllSeries();
- 添加双曲线:重要操作,赋予serial 新的空间,serial = new QLineSeries(this);之后添加(append或replace)数据,再将其给QCahrt,chart->addSeries(serial);
- 双曲线坐标值: 如果绘制的连个曲线是在同一个坐标系下,那么每次在chart添加完数据后(addSerial),都需要进行一次坐标系的添加setAxisX/Y
程序如下:
//Part1 在界面初始化的时候,就已经将QChart初始化了
void Widget::UiForEC()
{
......
//此部分为QChart初始化
//将一系列数据存入serial.
//添加第一条线
QList<QPointF>list;//将数据压入链表中
QLineSeries *serial;//QChart的具体数据内容
serial = new QLineSeries(this);//必须要new, 才能实现更新
list<<QPointF(0,0)<<QPointF(Number_Size,0);//将数据压入链表中
serial->setName("Line 1");//名称
serial->append(list);//在serial中添加数据
chart->addSeries(serial);//将数据加载到QChart中
//添加第二条线
//绘制 两条线的方式
QList<QPointF>list_2;
list_2<<QPointF(0,0)<<QPointF(Number_Size,Number_Size);
serial = new QLineSeries(this);//需要赋予serial新的地址才有效,这也是在同一张绘制两条曲线的关键
serial->append(list_2);//在serial中添加数据
serial->setName("Line 2");
chart->addSeries(serial);//将数据加载到QChart中
//进行信号与槽的连接
connectMarkers();
chart->createDefaultAxes();//根据数据集,自动创建坐标轴,坐标轴的区间恰好完全容纳已有的数据集
chart->setTitle("SAW");//chart名称
chart->setAnimationOptions(QChart::SeriesAnimations);//以动画的形式显示
chart->legend()->setVisible(true);//图例显示
chart->legend()->setAlignment(Qt::AlignBottom);//(图例的位置)
//最后需要将chart交给QChartView
QChartView *view=new QChartView(chart);//将chart进行显示
view->setRenderHint(QPainter::Antialiasing);//消除锯齿
view->setFixedSize(600,600);//chart大小
........
}
..........
//之后需要根据需求,对QChart进行重新绘制或者刷新
void Widget::PutItOnScreen(QList<double> * PIOS,int size,QList<double> * ERROR1,QList<double> * ERROR2)
{
//tableWidget
qDebug()<<"进入显示:";
for(int i = 0;i<size;i++)
{
double test = PIOS->at(i);
QString item = QString::number(test,10,12);
TableFor->setItem(i,0,new QTableWidgetItem(item));
}
//求一下最大最小值,这个部分是为了确定QChart的上下限
double MAX_E = ERROR1->at(0),MAX_D = ERROR2->at(0),MIN_E = ERROR1->at(0),MIN_D = ERROR2->at(0);
for(int i = 1;i<Number_Size;i++)
{
//err
if(MAX_E<ERROR1->at(i))//最大值
{
MAX_E = ERROR1->at(i);
}
if(MIN_E>ERROR1->at(i))//最小值
{
MIN_E = ERROR1->at(i);
}
//deltaTheta
if(MAX_D<ERROR2->at(i))//最大值
{
MAX_D = ERROR2->at(i);
}
if(MIN_D>ERROR2->at(i))//最小值
{
MIN_D = ERROR2->at(i);
}
}
qDebug()<<"MAX_E"<<MAX_E<<"MIN_E"<<MIN_E<<"MAX_D"<<MAX_D<<"MIN_D"<<MIN_D;
//确定区间范围
double Y_MAX = MAX_E,Y_MIN = MIN_E ;
if(Y_MAX<MAX_D)
{
Y_MAX = MAX_D;
}
if(Y_MIN>MIN_D)
{
Y_MIN = MIN_D;
}
qDebug()<<"最小"<<Y_MIN<<"最大"<<Y_MAX;
//求一下最大最小值
//Chart
QList<QPointF> listForChartLINE1;
QList<QPointF> listForChartLINE2;
for(int i = 0;i<Number_Size;i++)
{
listForChartLINE1.append(QPointF(i,ERROR1->at(i)));
listForChartLINE2.append(QPointF(i,ERROR2->at(i)));
qDebug()<<ERROR2->at(i);
}
QLineSeries *serial;
//removeAllSeries是关键操作,只有这样,才能将之前的曲线完全剔除
chart->removeAllSeries();//清除即可,重要操作,QChart刷新的必要操作
//添加第一条线
serial = new QLineSeries(this);//必须要new, 才能实现更新
serial->append(listForChartLINE1);//在serial中添加数据
serial->setName("Err");
// chart->createDefaultAxes();
chart->addSeries(serial);//将数据加载到QChart中
//规定坐标系,注意,每次添加一条曲线,都需要进行坐标系的确定
QValueAxis *axisX = new QValueAxis();//轴变量、数据系列变量,都不能声明为局部临时变量
QValueAxis *axisY = new QValueAxis();//创建X/Y轴
axisX->setRange(0, Number_Size);
// axisY->setRange(MIN_D, MAX_D);//设置X/Y显示的区间Y_MINY_MAX
axisY->setRange(Y_MIN, Y_MAX);//设置X/Y显示的区间
chart->setAxisX(axisX);
chart->setAxisY(axisY);//设置chart的坐标轴
serial->attachAxis(axisY);
//添加第二条线
serial = new QLineSeries(this);
serial->append(listForChartLINE2);//在serial中添加数据
serial->setName("DeltaTheta");
// chart->createDefaultAxes();
chart->addSeries(serial);//将数据加载到QChart中
axisX = new QValueAxis();//轴变量、数据系列变量,都不能声明为局部临时变量
axisY = new QValueAxis();//创建X/Y轴
axisX->setRange(0, Number_Size);
// axisY->setRange(MIN_D, MAX_D);//设置X/Y显示的区间Y_MINY_MAX
axisY->setRange(Y_MIN, Y_MAX);//设置X/Y显示的区间
chart->setAxisX(axisX);
chart->setAxisY(axisY);//设置chart的坐标轴
serial->attachAxis(axisY);
// serial
//连接数据集与坐标轴。特别注意:如果不连接,那么坐标轴和数据集的尺度就不相同,显示
//需要再次添加信号和槽
connectMarkers();
qDebug()<<"完成绘制";
}
QGridLayout:
Qt学习之路14--布局管理器(QGridLayout):https://blog.csdn.net/tqs_1220/article/details/81842878
Qt之格栅布局(QGridLayout):https://blog.csdn.net/swartz_lubel/article/details/54932517
布局技巧,首先看看你的UI有几个部分
如本程序,有两个部分,左侧及右侧
第一个部分,其中摁键必然是在第0行,三个摁键分别为底0,1,2三列,TableWidget必然是第1行,第0列
第二部分,QCahrt显然是第0行,第3列(第0行前面已经有3列了)
本程序用到的部分:
//添加控件,将其显示到页面中来
QGridLayout *mainLayout = new QGridLayout(this);
//控件名称,行号,列号,所占行数,所占列数,设置居中或其他排版方式
mainLayout->addWidget(Save,0,0,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(Open,0,1,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(Cal,0,2,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(TableFor,1,0,8,3);
mainLayout->addWidget(view,0,3,9,1);
// mainLayout->setColumnStretch(1, 1);//拉伸因子
// mainLayout->setColumnStretch(0, 0);//拉伸因子
// 设置水平间距
mainLayout->setHorizontalSpacing(10);
// 设置垂直间距
mainLayout->setVerticalSpacing(10);
mainLayout->setContentsMargins(10, 10, 10, 10);
mainLayout->setRowStretch(1,1);
setLayout(mainLayout);
整个程序段展示:
头文件:
#include <QWidget>
//矩阵
#include<QList>
#include<QDebug>
#include<math.h>
#include<QSettings>
#include<QMessageBox>
#include<QFileDialog>
#include <QAxObject>
#include <iostream>
#include <QDateTime>
#include<QPushButton>
#include<QTableWidget>
//绘图
#include<QChart>//QChart
#include<QLineSeries>
#include<QChartView>
#include <QGridLayout>
#include<QVXYModelMapper>
#include<QLegendMarker>
#include <QValueAxis>
#define Number_Fourier 15
#define ColNumber 2
namespace Ui {
class Widget;
}
using namespace std;
using namespace Eigen;
using namespace QtCharts;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
// Ui::Widget *ui;
QList<double> Measure_Angle;//将存放从excel的第一列
QList<double> Angle_ERROR;//将存放从excel的第二列
QList<double> ReslutAngleERROR;//相关内容的结果将会保存在这个链表中
// QList<double> Reslut_ERROR;
QTableWidget * TableFor;
int Number_Size;
QChart *chart;
void UiForEC();
void Calculation();//具体的计算
void ReadTheAngle();//读取数据
void SaveReslut();//保存数据
void PutItOnScreen(QList<double> * PIOS,int size,QList<double> * ERROR1,QList<double> * ERROR2);
void connectMarkers();
void handleMarkerClicked();
};
#endif // WIDGET_H
从excel中读取数据,并进行数据处理,得出相应的结果,将其显示在前界面的TableWidget中:
构造函数及析构函数:
#include "widget.h"
#include "ui_widget.h"
using namespace QtCharts;//QChart
Widget::Widget(QWidget *parent) :
QWidget(parent)
// ui(new Ui::Widget)
{
TableFor = new QTableWidget(this);
chart=new QChart;
Number_Size = 24;
UiForEC();
}
Widget::~Widget()
{
// delete ui;
}
前界面UI设计,TableWidget及QChart初始化:
void Widget::UiForEC()
{
this->setFixedSize(800,450);
QPushButton * Save = new QPushButton("保存",this);
QPushButton * Open = new QPushButton("打开",this);
QPushButton * Cal = new QPushButton("计算",this);
connect(Save,&QPushButton::clicked,this,&Widget::SaveReslut);
connect(Open,&QPushButton::clicked,this,&Widget::ReadTheAngle);
connect(Cal,&QPushButton::clicked,this,&Widget::Calculation);
// Save->setGeometry(10,10,40,25);
// Open->setGeometry(80,10,40,25);
// Cal->setGeometry(150,10,40,25);
QFont FontForPush;
FontForPush.setBold(false);
FontForPush.setFamily("Microsoft YaHei");
FontForPush.setPointSize(10);
Save->setFont(FontForPush);
Open->setFont(FontForPush);
Cal->setFont(FontForPush);
TableFor->setColumnCount(ColNumber);//列数
TableFor->setRowCount(Number_Fourier);//行数
// TableFor->move(10,40);
TableFor->setWindowTitle("傅里叶级数显示:");
TableFor->setFixedSize(280, 350);
QStringList header;
header<<"Error"<<"2";
TableFor->setHorizontalHeaderLabels(header);//设置表头(横)
QStringList header2;
header2<<"1"<<"2"<<"3"<<"4"<<"5"<<"6"<<"7"<<"8"<<"9"<<"10"<<"11"<<"12"<<"13"<<"14"<<"15";
TableFor->setVerticalHeaderLabels(header2);//设置表头(竖)
for(int i = 0; i < 15; i++)
TableFor->setRowHeight(i, 22);
TableFor->setColumnWidth(0,120);
TableFor->setColumnWidth(1,120);
//将一系列数据存入道serial.
//添加第一条线
QList<QPointF>list;
QLineSeries *serial;
serial = new QLineSeries(this);//必须要new, 才能实现更新
list<<QPointF(0,0)<<QPointF(Number_Size,0);//x,y
serial->setName("Line 1");
serial->append(list);//在serial中添加数据
chart->addSeries(serial);//将数据加载到QChart中
//添加第二条线
//绘制 两条线的方式
QList<QPointF>list_2;
list_2<<QPointF(0,0)<<QPointF(Number_Size,Number_Size);
serial = new QLineSeries(this);
serial->append(list_2);//在serial中添加数据
serial->setName("Line 2");
chart->addSeries(serial);//将数据加载到QChart中
//添加第二条线
//进行信号与槽的连接
connectMarkers();
chart->createDefaultAxes();//根据数据集,自动创建坐标轴,坐标轴的区间恰好完全容纳已有的数据集
chart->setTitle("SAW");//chart名称
chart->setAnimationOptions(QChart::SeriesAnimations);//以动画的形式显示
chart->legend()->setVisible(true);//图例显示
chart->legend()->setAlignment(Qt::AlignBottom);//(图例的位置)
QChartView *view=new QChartView(chart);//将chart进行显示
view->setRenderHint(QPainter::Antialiasing);//消除锯齿
view->setFixedSize(600,600);//chart大小
//添加控件,将其显示到页面中来
QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->addWidget(Save,0,0,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(Open,0,1,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(Cal,0,2,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(TableFor,1,0,8,3);
mainLayout->addWidget(view,0,3,9,1);
// mainLayout->setColumnStretch(1, 1);//拉伸因子
// mainLayout->setColumnStretch(0, 0);//拉伸因子
// 设置水平间距
mainLayout->setHorizontalSpacing(10);
// 设置垂直间距
mainLayout->setVerticalSpacing(10);
mainLayout->setContentsMargins(10, 10, 10, 10);
mainLayout->setRowStretch(1,1);
setLayout(mainLayout);
}
QChart显示:
void Widget::PutItOnScreen(QList<double> * PIOS,int size,QList<double> * ERROR1,QList<double> * ERROR2)
{
//tableWidget
qDebug()<<"进入显示:";
for(int i = 0;i<size;i++)
{
double test = PIOS->at(i);
QString item = QString::number(test,10,12);
TableFor->setItem(i,0,new QTableWidgetItem(item));
}
//求一下最大最小值,这个部分是为了确定QChart的上下限
double MAX_E = ERROR1->at(0),MAX_D = ERROR2->at(0),MIN_E = ERROR1->at(0),MIN_D = ERROR2->at(0);
for(int i = 1;i<Number_Size;i++)
{
//err
if(MAX_E<ERROR1->at(i))//最大值
{
MAX_E = ERROR1->at(i);
}
if(MIN_E>ERROR1->at(i))//最小值
{
MIN_E = ERROR1->at(i);
}
//deltaTheta
if(MAX_D<ERROR2->at(i))//最大值
{
MAX_D = ERROR2->at(i);
}
if(MIN_D>ERROR2->at(i))//最小值
{
MIN_D = ERROR2->at(i);
}
}
qDebug()<<"MAX_E"<<MAX_E<<"MIN_E"<<MIN_E<<"MAX_D"<<MAX_D<<"MIN_D"<<MIN_D;
//确定区间范围
double Y_MAX = MAX_E,Y_MIN = MIN_E ;
if(Y_MAX<MAX_D)
{
Y_MAX = MAX_D;
}
if(Y_MIN>MIN_D)
{
Y_MIN = MIN_D;
}
qDebug()<<"最小"<<Y_MIN<<"最大"<<Y_MAX;
//求一下最大最小值
//Chart
QList<QPointF> listForChartLINE1;
QList<QPointF> listForChartLINE2;
for(int i = 0;i<Number_Size;i++)
{
listForChartLINE1.append(QPointF(i,ERROR1->at(i)));
listForChartLINE2.append(QPointF(i,ERROR2->at(i)));
qDebug()<<ERROR2->at(i);
}
QLineSeries *serial;
chart->removeAllSeries();//清除即可,重要操作,QChart刷新的必要操作
//添加第一条线
serial = new QLineSeries(this);//必须要new, 才能实现更新
serial->append(listForChartLINE1);//在serial中添加数据
serial->setName("Err");
// chart->createDefaultAxes();
chart->addSeries(serial);//将数据加载到QChart中
//规定坐标系
QValueAxis *axisX = new QValueAxis();//轴变量、数据系列变量,都不能声明为局部临时变量
QValueAxis *axisY = new QValueAxis();//创建X/Y轴
axisX->setRange(0, Number_Size);
// axisY->setRange(MIN_D, MAX_D);//设置X/Y显示的区间Y_MINY_MAX
axisY->setRange(Y_MIN, Y_MAX);//设置X/Y显示的区间
chart->setAxisX(axisX);
chart->setAxisY(axisY);//设置chart的坐标轴
serial->attachAxis(axisY);
//添加第二条线
serial = new QLineSeries(this);
serial->append(listForChartLINE2);//在serial中添加数据
serial->setName("DeltaTheta");
// chart->createDefaultAxes();
chart->addSeries(serial);//将数据加载到QChart中
axisX = new QValueAxis();//轴变量、数据系列变量,都不能声明为局部临时变量
axisY = new QValueAxis();//创建X/Y轴
axisX->setRange(0, Number_Size);
// axisY->setRange(MIN_D, MAX_D);//设置X/Y显示的区间Y_MINY_MAX
axisY->setRange(Y_MIN, Y_MAX);//设置X/Y显示的区间
chart->setAxisX(axisX);
chart->setAxisY(axisY);//设置chart的坐标轴
serial->attachAxis(axisY);
// serial
//连接数据集与坐标轴。特别注意:如果不连接,那么坐标轴和数据集的尺度就不相同,显示
//需要再次添加信号和槽
connectMarkers();
qDebug()<<"完成绘制";
}
点击图例,对应曲线消失,图例透明度更改:
void Widget::connectMarkers()
{
const auto markers = chart->legend()->markers();//将图例的相关内容返回
for (QLegendMarker *marker : markers)
{
// Disconnect possible existing connection to avoid multiple connections
disconnect(marker, &QLegendMarker::clicked,
this, &Widget::handleMarkerClicked);
connect(marker, &QLegendMarker::clicked, this, &Widget::handleMarkerClicked);
}
}
void Widget::handleMarkerClicked()
{
qDebug()<<"进入隐藏模式";
QLegendMarker* marker = qobject_cast<QLegendMarker*> (sender());
Q_ASSERT(marker);
//这就是Q_ASSERT的神奇之处!它是一个宏,接受布尔值,当其中的布尔值为真时,便什么也不做,当其中的布尔值为假时,便断下。
switch (marker->type())
{
case QLegendMarker::LegendMarkerTypeXY://相当于只要是图例,都会相应
{
// 将图例对应的曲线进行隐藏
marker->series()->setVisible(!marker->series()->isVisible());
marker->setVisible(true);//图例的可见性要为真
double alpha = 1.0;
if (!marker->series()->isVisible())//图例可见时执行,调整其透明度
alpha = 0.5;
//以下的内容,均是要图例变的黯淡而已
QColor color;
QBrush brush = marker->labelBrush();//目前的颜色
color = brush.color();
color.setAlphaF(alpha);//调整其透明度
brush.setColor(color);
marker->setLabelBrush(brush);
brush = marker->brush();
color = brush.color();
color.setAlphaF(alpha);//调整其透明度
brush.setColor(color);
marker->setBrush(brush);
QPen pen = marker->pen();
color = pen.color();
color.setAlphaF(alpha);//调整其透明度
pen.setColor(color);
marker->setPen(pen);
break;
}
default:
{
qDebug() << "Unknown marker type";
break;
}
}
}
读取数据部分:
void Widget::ReadTheAngle()
{
//一列压入Measure_Angle
// Measure_Angle
//一列压入Angle_ERROR
// Angle_ERROR
Measure_Angle.clear();//可能会出现多次打开的情况,务必清除
QSettings savesetting("./Setting.ini", QSettings::IniFormat);//为了能记住上次打开的路径,这个句子是关键
QString openpath = savesetting.value("LastFilePath").toString();
QString path = QFileDialog::getOpenFileName(this,"open",openpath,"execl(*.xlsx *.xls)");
qDebug()<<path;//C:/Users/Administrator/Desktop/point/1pos1.xls
if(path.isEmpty()==false)
{
//文件对象
QFile file(path);
//打开文件,默认为utf8变量,
bool flag = file.open(QIODevice::ReadOnly);
if(flag == true)//打开成功
{
qDebug()<<"打开成功";
QAxObject *excel = new QAxObject(this);//建立excel操作对象
excel->setControl("Excel.Application");//连接Excel控件
excel->setProperty("Visible", false);//不显示窗体看效果
excel->setProperty("DisplayAlerts", false);//不显示警告看效果
/*********获取COM文件的一种方式************/
QAxObject *workbooks = excel->querySubObject("WorkBooks");
//获取工作簿(excel文件)集合
workbooks->dynamicCall("Open(const QString&)", path);//path至关重要,获取excel文件的路径
//打开一个excel文件
QAxObject *workbook = excel->querySubObject("ActiveWorkBook");
QAxObject *worksheet = workbook->querySubObject("WorkSheets(int)",1);//访问excel中的工作表中第一个单元格
QAxObject *usedRange = worksheet->querySubObject("UsedRange");//sheet的范围
/*********获取COM文件的一种方式************/
//获取打开excel的起始行数和列数和总共的行数和列数
int intRowStart = usedRange->property("Row").toInt();//起始行数
qDebug()<<"起始行:"<<intRowStart;
int intColStart = usedRange->property("Column").toInt(); //起始列数
qDebug()<<"起始列:"<<intColStart;
QAxObject *rows, *columns;
rows = usedRange->querySubObject("Rows");//
columns = usedRange->querySubObject("Columns");//
int intRow = rows->property("Count").toInt();//
qDebug()<<"总行数:"<<intRow;
// int intCol = columns->property("Count").toInt();//
// int stri=0;
for (int i = intRowStart; i < intRowStart + intRow; i++)//行,把表头除去,所以要加1
{
QAxObject *cellStructPara = new QAxObject(this);
cellStructPara = excel->querySubObject("Cells(Int, Int)", i, intColStart );
QVariant cellValue = cellStructPara->dynamicCall("value");
Measure_Angle.append( cellValue.toDouble() );
cellStructPara = excel->querySubObject("Cells(Int, Int)", i, intColStart+1 );
cellValue = cellStructPara->dynamicCall("value");
Angle_ERROR.append( cellValue.toDouble() );
}
workbook->dynamicCall( "Close(Boolean)", false );
excel->dynamicCall( "Quit(void)" );
delete excel;
}
file.close();
}
Number_Size = Measure_Angle.size();
}
数据处理部分:(这个因人而异,此处省略)
void Widget::Calculation()
{
qDebug()<<"进入计算";
.......
qDebug()<<"完成计算";
}
将结果保存到excel中:
保存在ReslutAngleERROR这个链表里
void Widget::SaveReslut()
{
ReslutAngleERROR.clear();//可能会出现多次保存的情况,务必清除
QDateTime current_date_time =QDateTime::currentDateTime();
QString current_date =current_date_time.toString("yyyy_MM_dd_hh_mm_ss_ddd");
// path = QString("%1%2%3%4").arg(dataforexcel_name).arg("LM_result_").arg(current_date).arg(".xls");//最后是获取当前的时间作为命名的根据
QString path = QFileDialog::getSaveFileName(this,"Save",current_date,"execl(*.xlsx *.xls)");
qDebug()<<"path"<<path;
if (path!="")
{
QAxObject *excel ;
excel = new QAxObject;//建立excel操作对象
if (excel->setControl("Excel.Application")) //连接Excel控件
{
qDebug()<<"进入保存程序";
excel->dynamicCall("SetVisible (bool Visible)","false");//不显示窗体
excel->setProperty("DisplayAlerts", false);
//不显示任何警告信息。如果为true那么在关闭是会出现类似“文件已修改,是否保存”的提示
QAxObject *workbooks = excel->querySubObject("WorkBooks");//获取工作簿集合
workbooks->dynamicCall("Add");//新建一个工作簿
QAxObject *workbook = excel->querySubObject("ActiveWorkBook");//获取当前工作簿
QAxObject *worksheet = workbook->querySubObject("Worksheets(int)", 1);
//YDH
for (int dataj=0;dataj<Number_Fourier;dataj++)
{
worksheet->querySubObject("Cells(int,int)", 1, dataj+1)->dynamicCall("SetValue(const QString&)",ReslutAngleERROR.at(dataj));
}
workbook->dynamicCall("SaveAs(const QString&)",QDir::toNativeSeparators(path));
workbook->dynamicCall("Close()");//关闭工作簿
excel->dynamicCall("Quit()");//关闭excel
delete excel;
QMessageBox::warning(this,tr("save"),tr("导出成功"),QMessageBox::Yes);
}
else
{
QMessageBox::warning(this,"错误","未能创建 Excel 对象,请安装 Microsoft Excel。",QMessageBox::Apply);
}
}
}
完成CPP内容:
#include "widget.h"
#include "ui_widget.h"
//20190923测角误差的修正
//
using namespace std;
using namespace Eigen;
using namespace QtCharts;//QChart
Widget::Widget(QWidget *parent) :
QWidget(parent)
// ui(new Ui::Widget)
{
TableFor = new QTableWidget(this);
// serial=new QLineSeries(this);
chart=new QChart;
Number_Size = 24;
UiForEC();
}
Widget::~Widget()
{
// delete ui;
}
void Widget::UiForEC()
{
this->setFixedSize(800,450);
QPushButton * Save = new QPushButton("保存",this);
QPushButton * Open = new QPushButton("打开",this);
QPushButton * Cal = new QPushButton("计算",this);
connect(Save,&QPushButton::clicked,this,&Widget::SaveReslut);
connect(Open,&QPushButton::clicked,this,&Widget::ReadTheAngle);
connect(Cal,&QPushButton::clicked,this,&Widget::Calculation);
// Save->setGeometry(10,10,40,25);
// Open->setGeometry(80,10,40,25);
// Cal->setGeometry(150,10,40,25);
QFont FontForPush;
FontForPush.setBold(false);
FontForPush.setFamily("Microsoft YaHei");
FontForPush.setPointSize(10);
Save->setFont(FontForPush);
Open->setFont(FontForPush);
Cal->setFont(FontForPush);
TableFor->setColumnCount(ColNumber);//列数
TableFor->setRowCount(Number_Fourier);//行数
// TableFor->move(10,40);
TableFor->setWindowTitle("傅里叶级数显示:");
TableFor->setFixedSize(280, 350);
QStringList header;
header<<"Error"<<"2";
TableFor->setHorizontalHeaderLabels(header);//设置表头(横)
QStringList header2;
header2<<"1"<<"2"<<"3"<<"4"<<"5"<<"6"<<"7"<<"8"<<"9"<<"10"<<"11"<<"12"<<"13"<<"14"<<"15";
TableFor->setVerticalHeaderLabels(header2);//设置表头(竖)
for(int i = 0; i < 15; i++)
TableFor->setRowHeight(i, 22);
TableFor->setColumnWidth(0,120);
TableFor->setColumnWidth(1,120);
//将一系列数据存入道serial.
//添加第一条线
QList<QPointF>list;
QLineSeries *serial;
serial = new QLineSeries(this);//必须要new, 才能实现更新
list<<QPointF(0,0)<<QPointF(Number_Size,0);//x,y
serial->setName("Line 1");
serial->append(list);//在serial中添加数据
chart->addSeries(serial);//将数据加载到QChart中
// 去除添加第二根线的部分,即可显示第一根线
//添加第二条线
//绘制 两条线的方式
QList<QPointF>list_2;
list_2<<QPointF(0,0)<<QPointF(Number_Size,Number_Size);
serial = new QLineSeries(this);
serial->append(list_2);//在serial中添加数据
serial->setName("Line 2");
chart->addSeries(serial);//将数据加载到QChart中
//添加第二条线
//Series有系列的意思
//设置默认坐标,
connectMarkers();
chart->createDefaultAxes();//根据数据集,自动创建坐标轴,坐标轴的区间恰好完全容纳已有的数据集
chart->setTitle("SAW");
chart->setAnimationOptions(QChart::SeriesAnimations);//以动画的形式显示
chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignBottom);//(图例的位置)
QChartView *view=new QChartView(chart);//准备将chart进行显示
//这个应该不用说的,消除锯齿
view->setRenderHint(QPainter::Antialiasing);
view->setFixedSize(600,600);
//添加控件,将其显示到页面中来
QGridLayout *mainLayout = new QGridLayout(this);
// Save->setGeometry(10,10,40,25);
// Open->setGeometry(80,10,40,25);
// Cal->setGeometry(150,10,40,25);
mainLayout->addWidget(Save,0,0,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(Open,0,1,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(Cal,0,2,1,1,Qt::AlignLeft | Qt::AlignVCenter);
mainLayout->addWidget(TableFor,1,0,8,3);
mainLayout->addWidget(view,0,3,9,1);
//如此规划方式,
// mainLayout->setColumnStretch(1, 1);//拉伸因子
// mainLayout->setColumnStretch(0, 0);//拉伸因子
// 设置水平间距
mainLayout->setHorizontalSpacing(10);
// 设置垂直间距
mainLayout->setVerticalSpacing(10);
mainLayout->setContentsMargins(10, 10, 10, 10);
mainLayout->setRowStretch(1,1);
// mainLayout
setLayout(mainLayout);
}
void Widget::Calculation()
{
qDebug()<<"进入计算";
qDebug()<<"完成计算";
}
void Widget::PutItOnScreen(QList<double> * PIOS,int size,QList<double> * ERROR1,QList<double> * ERROR2)
{
//tableWidget
qDebug()<<"进入显示:";
qDebug()<<"尺寸:"<<size;
for(int i = 0;i<size;i++)
{
// QTableWidgetItem *item = PIOS->at(i);
// TableFor->setItem(i,0,new QTableWidgetItem(PIOS->at(i)));
double test = PIOS->at(i);
QString item = QString::number(test,10,12);
TableFor->setItem(i,0,new QTableWidgetItem(item));
// qDebug()<<PIOS->at(i);
}
//求一下最大最小值
// QList<double> RangeForXY;
double MAX_E = ERROR1->at(0),MAX_D = ERROR2->at(0),MIN_E = ERROR1->at(0),MIN_D = ERROR2->at(0);
for(int i = 1;i<Number_Size;i++)
{
//err
if(MAX_E<ERROR1->at(i))//最大值
{
MAX_E = ERROR1->at(i);
}
if(MIN_E>ERROR1->at(i))//最小值
{
MIN_E = ERROR1->at(i);
}
//deltaTheta
if(MAX_D<ERROR2->at(i))//最大值
{
MAX_D = ERROR2->at(i);
}
if(MIN_D>ERROR2->at(i))//最小值
{
MIN_D = ERROR2->at(i);
}
}
qDebug()<<"MAX_E"<<MAX_E<<"MIN_E"<<MIN_E<<"MAX_D"<<MAX_D<<"MIN_D"<<MIN_D;
double Y_MAX = MAX_E,Y_MIN = MIN_E ;
if(Y_MAX<MAX_D)
{
Y_MAX = MAX_D;
}
if(Y_MIN>MIN_D)
{
Y_MIN = MIN_D;
}
qDebug()<<"最小"<<Y_MIN<<"最大"<<Y_MAX;
//求一下最大最小值
//Chart
QList<QPointF> listForChartLINE1;
QList<QPointF> listForChartLINE2;
for(int i = 0;i<Number_Size;i++)
{
listForChartLINE1.append(QPointF(i,ERROR1->at(i)));
listForChartLINE2.append(QPointF(i,ERROR2->at(i)));
qDebug()<<ERROR2->at(i);
}
QLineSeries *serial;
chart->removeAllSeries();//清除即可, 重要操作,QChart刷新的必要操作
//添加第一条线
serial = new QLineSeries(this);//必须要new, 才能实现更新
serial->append(listForChartLINE1);//在serial中添加数据
serial->setName("Err");
// chart->createDefaultAxes();
chart->addSeries(serial);//将数据加载到QChart中
QValueAxis *axisX = new QValueAxis();//轴变量、数据系列变量,都不能声明为局部临时变量
QValueAxis *axisY = new QValueAxis();//创建X/Y轴
axisX->setRange(0, Number_Size);
// axisY->setRange(MIN_D, MAX_D);//设置X/Y显示的区间Y_MINY_MAX
axisY->setRange(Y_MIN, Y_MAX);//设置X/Y显示的区间
chart->setAxisX(axisX);
chart->setAxisY(axisY);//设置chart的坐标轴
serial->attachAxis(axisY);
//添加第二条线
serial = new QLineSeries(this);
serial->append(listForChartLINE2);//在serial中添加数据
serial->setName("DeltaTheta");
// chart->createDefaultAxes();
chart->addSeries(serial);//将数据加载到QChart中
axisX = new QValueAxis();//轴变量、数据系列变量,都不能声明为局部临时变量
axisY = new QValueAxis();//创建X/Y轴
axisX->setRange(0, Number_Size);
// axisY->setRange(MIN_D, MAX_D);//设置X/Y显示的区间Y_MINY_MAX
axisY->setRange(Y_MIN, Y_MAX);//设置X/Y显示的区间
chart->setAxisX(axisX);
chart->setAxisY(axisY);//设置chart的坐标轴
serial->attachAxis(axisY);
// serial
//连接数据集与坐标轴。特别注意:如果不连接,那么坐标轴和数据集的尺度就不相同,显示
//添加第二条线
connectMarkers();
qDebug()<<"完成绘制";
}
void Widget::connectMarkers()
{
const auto markers = chart->legend()->markers();//将图例的相关内容返回
for (QLegendMarker *marker : markers)
{
// Disconnect possible existing connection to avoid multiple connections
disconnect(marker, &QLegendMarker::clicked,
this, &Widget::handleMarkerClicked);
connect(marker, &QLegendMarker::clicked, this, &Widget::handleMarkerClicked);
}
}
void Widget::handleMarkerClicked()
{
qDebug()<<"进入隐藏模式";
QLegendMarker* marker = qobject_cast<QLegendMarker*> (sender());
Q_ASSERT(marker);
//这就是Q_ASSERT的神奇之处!它是一个宏,接受布尔值,当其中的布尔值为真时,便什么也不做,当其中的布尔值为假时,便断下。
switch (marker->type())
{
case QLegendMarker::LegendMarkerTypeXY://相当于只要是图例,都会相应
{
// 将图例对应的曲线进行隐藏
marker->series()->setVisible(!marker->series()->isVisible());
marker->setVisible(true);//图例的可见性要为真
double alpha = 1.0;
if (!marker->series()->isVisible())//图例可见时执行,调整其透明度
alpha = 0.5;
//以下的内容,均是要图例变的黯淡而已
QColor color;
QBrush brush = marker->labelBrush();//目前的颜色
color = brush.color();
color.setAlphaF(alpha);//调整其透明度
brush.setColor(color);
marker->setLabelBrush(brush);
brush = marker->brush();
color = brush.color();
color.setAlphaF(alpha);//调整其透明度
brush.setColor(color);
marker->setBrush(brush);
QPen pen = marker->pen();
color = pen.color();
color.setAlphaF(alpha);//调整其透明度
pen.setColor(color);
marker->setPen(pen);
break;
}
default:
{
qDebug() << "Unknown marker type";
break;
}
}
}
void Widget::SaveReslut()
{
ReslutAngleERROR.clear();//可能会出现多次保存的情况,务必清除
QDateTime current_date_time =QDateTime::currentDateTime();
QString current_date =current_date_time.toString("yyyy_MM_dd_hh_mm_ss_ddd");
// path = QString("%1%2%3%4").arg(dataforexcel_name).arg("LM_result_").arg(current_date).arg(".xls");//最后是获取当前的时间作为命名的根据
QString path = QFileDialog::getSaveFileName(this,"Save",current_date,"execl(*.xlsx *.xls)");
qDebug()<<"path"<<path;
if (path!="")
{
QAxObject *excel ;
excel = new QAxObject;//建立excel操作对象
if (excel->setControl("Excel.Application")) //连接Excel控件
{
qDebug()<<"进入保存程序";
excel->dynamicCall("SetVisible (bool Visible)","false");//不显示窗体
excel->setProperty("DisplayAlerts", false);
//不显示任何警告信息。如果为true那么在关闭是会出现类似“文件已修改,是否保存”的提示
QAxObject *workbooks = excel->querySubObject("WorkBooks");//获取工作簿集合
workbooks->dynamicCall("Add");//新建一个工作簿
QAxObject *workbook = excel->querySubObject("ActiveWorkBook");//获取当前工作簿
QAxObject *worksheet = workbook->querySubObject("Worksheets(int)", 1);
//YDH
for (int dataj=0;dataj<Number_Fourier;dataj++)
{
worksheet->querySubObject("Cells(int,int)", 1, dataj+1)->dynamicCall("SetValue(const QString&)",ReslutAngleERROR.at(dataj));
}
workbook->dynamicCall("SaveAs(const QString&)",QDir::toNativeSeparators(path));
workbook->dynamicCall("Close()");//关闭工作簿
excel->dynamicCall("Quit()");//关闭excel
delete excel;
QMessageBox::warning(this,tr("save"),tr("导出成功"),QMessageBox::Yes);
}
else
{
QMessageBox::warning(this,"错误","未能创建 Excel 对象,请安装 Microsoft Excel。",QMessageBox::Apply);
}
}
}
void Widget::ReadTheAngle()
{
//一列压入Measure_Angle
// Measure_Angle
//一列压入Angle_ERROR
// Angle_ERROR
Measure_Angle.clear();//可能会出现多次打开的情况,务必清除
QSettings savesetting("./Setting.ini", QSettings::IniFormat);//为了能记住上次打开的路径,这个句子是关键
QString openpath = savesetting.value("LastFilePath").toString();
QString path = QFileDialog::getOpenFileName(this,"open",openpath,"execl(*.xlsx *.xls)");
qDebug()<<path;//C:/Users/Administrator/Desktop/point/1pos1.xls
if(path.isEmpty()==false)
{
//文件对象
QFile file(path);
//打开文件,默认为utf8变量,
bool flag = file.open(QIODevice::ReadOnly);
if(flag == true)//打开成功
{
qDebug()<<"打开成功";
QAxObject *excel = new QAxObject(this);//建立excel操作对象
excel->setControl("Excel.Application");//连接Excel控件
excel->setProperty("Visible", false);//不显示窗体看效果
excel->setProperty("DisplayAlerts", false);//不显示警告看效果
/*********获取COM文件的一种方式************/
QAxObject *workbooks = excel->querySubObject("WorkBooks");
//获取工作簿(excel文件)集合
workbooks->dynamicCall("Open(const QString&)", path);//path至关重要,获取excel文件的路径
//打开一个excel文件
QAxObject *workbook = excel->querySubObject("ActiveWorkBook");
QAxObject *worksheet = workbook->querySubObject("WorkSheets(int)",1);//访问excel中的工作表中第一个单元格
QAxObject *usedRange = worksheet->querySubObject("UsedRange");//sheet的范围
/*********获取COM文件的一种方式************/
//获取打开excel的起始行数和列数和总共的行数和列数
int intRowStart = usedRange->property("Row").toInt();//起始行数
qDebug()<<"起始行:"<<intRowStart;
int intColStart = usedRange->property("Column").toInt(); //起始列数
qDebug()<<"起始列:"<<intColStart;
QAxObject *rows, *columns;
rows = usedRange->querySubObject("Rows");//
columns = usedRange->querySubObject("Columns");//
int intRow = rows->property("Count").toInt();//
qDebug()<<"总行数:"<<intRow;
// int intCol = columns->property("Count").toInt();//
// int stri=0;
for (int i = intRowStart; i < intRowStart + intRow; i++)//行,把表头除去,所以要加1
{
QAxObject *cellStructPara = new QAxObject(this);
cellStructPara = excel->querySubObject("Cells(Int, Int)", i, intColStart );
QVariant cellValue = cellStructPara->dynamicCall("value");
Measure_Angle.append( cellValue.toDouble() );
cellStructPara = excel->querySubObject("Cells(Int, Int)", i, intColStart+1 );
cellValue = cellStructPara->dynamicCall("value");
Angle_ERROR.append( cellValue.toDouble() );
}
workbook->dynamicCall( "Close(Boolean)", false );
excel->dynamicCall( "Quit(void)" );
delete excel;
}
file.close();
}
Number_Size = Measure_Angle.size();
}
转载:https://blog.csdn.net/qq_41605114/article/details/101474226