小言_互联网的博客

Qt:QChart绘图介绍(主要包含类:QChart,QTableWidget,QGridLayout)

634人阅读  评论(0)

Qt:QChart绘图介绍(主要包含类:QChart,QTableWidget,QGridLayout)

首先点击【打开】摁键,从excel中读入相关数据

之后点击【计算】摁键,将数据进行处理,并将部分输出到TableWidget中,部分绘制到QChart中


目录

效果展示:

TableWidget绘制及数据输出:

QChart相关内容(刷新,图例,绘制双曲线,自定义坐标系):

QGridLayout:

整个程序段展示:

头文件:

构造函数及析构函数:

前界面UI设计,TableWidget及QChart初始化:

QChart显示:

 点击图例,对应曲线消失,图例透明度更改:

读取数据部分:

数据处理部分:(这个因人而异,此处省略)

将结果保存到excel中:


效果展示:

初始界面展示:

点击打开摁键:

点击计算: 

 

点击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中的相关内容进行设置即可

注意事项:

  1. 刷新:添加数据前,使用chart->removeAllSeries();
  2. 添加双曲线:重要操作,赋予serial 新的空间,serial = new QLineSeries(this);之后添加(append或replace)数据,再将其给QCahrt,chart->addSeries(serial);
  3. 双曲线坐标值: 如果绘制的连个曲线是在同一个坐标系下,那么每次在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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场