读取已有数据的Excel文档,并将数据显示在通过QTableWidget绘制的表格中,之后将显示的数据保存成excel格式进行输出(包括表头等内容)
//于Mainwindow中,on_read_clicked属于Pushbotton摁键的槽函数
void MainWindow::on_read_clicked()
{
execel_read();//调用读取类方法,execel_read的具体内容见下文
}
选择【设置好内容的Excel文档】进行读取
结束后会显示读取完成。
上图为模板1.xlsx中的内容
//于Mainwindow中,on_pushButton_clicked属于Pushbotton摁键的槽函数
void MainWindow::on_pushButton_clicked()
{
dom->datasend(exceldata);//在MainWindow中调用dialog的类方法datasend()
//dom是属于dialog类的对象,需要在MainWindow中包含dialog头文件,之后定义指针对象dom,并分配空间
//具体操作如下***处
QMessageBox::warning(this,tr("生成波表情况:"),tr("报表已经生成!"),QMessageBox::Yes);
}
*********************************
//MainWindow中包含dialog的头文件
#include"dialog.h"
//MainWindow.h中声明属于dialog类的对象
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
............
private slots:
............
private:
............
Dialog *dom;//命名还是个大问题,保留dialog,不能在前后加数字
};
//MainWindow.cpp中分配dom指针对象空间
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
.............
dom = new Dialog(this);
.............
}
*********************************
点击后会显示报表已经生成。
void MainWindow::on_sheet_clicked()
//显示部分,关于TableWidget已经于生成报表部分绘制完成,如有需要,生成报表和查看报表可以统一为一个部分
{
dom->exec();//保持窗口
}
将会显示生成报表的结果。
将生成的报表保存成Excel文档
保存会出现提示窗口,选择是否要打开。选择是
void MainWindow::on_pushButton_2_clicked()
{
saveas();
}
以上情况不具有普世应用的意义,如何应用需要根据工程中的具体内容而定,因为程序内部未对从excel中读取到的数据进行处理,所以输出的报表中,数据和读取时选择的【模板1.xlsx】数据一样。
在实际工程中,会出现对大量excel数据进行读取(录入),并进行数据处理,之后输出显示成表格(如查看报表功能),必要的话,有可能需要将显示表格中的内容进行保存。
本文的内容主要是省去了数据处理的部分,概括性的对上述复杂问题进行一个精炼。
读取excel
void MainWindow::execel_read()
{
QString path = QFileDialog::getOpenFileName(this,"open",
"../","execl(*.xlsx)");
//指定父对象(this),“open”具体操作,打开,“../”默认,之后可以添加要打开文件的格式
if(path.isEmpty()==false)
{
//文件对象
QFile file(path);
//打开文件,默认为utf8变量,
bool flag = file.open(QIODevice::ReadOnly);
if(flag == true)//打开成功
{
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();//起始行数
int intColStart = usedRange->property("Column").toInt(); //起始列数
QAxObject *rows, *columns;
rows = usedRange->querySubObject("Rows");//行
columns = usedRange->querySubObject("Columns");//列
int intRow = rows->property("Count").toInt();//行数
int intCol = columns->property("Count").toInt();//列数
//起始行列号
qDebug()<querySubObject("Cells(Int, Int)", i, j );
QVariant cellValue = cell->dynamicCall("value");
text[coerow][coecol]=cellValue.toByteArray();//QVariant转换为QByteArray
exceldata[coerow][coecol]=QString(text[coerow][coecol]);//QByteArray转换为QString
}
}
workbook->dynamicCall( "Close(Boolean)", false );
excel->dynamicCall( "Quit(void)" );
delete excel;
QMessageBox::warning(this,tr("读取情况"),tr("读取完成!"),QMessageBox::Yes);
}
file.close();
}
}
QTableWidget绘制表格
void Dialog::putoutsend()
{
table->setRowCount(6); //设置行数
table->setColumnCount(4); //设置列数
table->move(20,20);
//QTableWidget *tableWidget = new QTableWidget(10,5); //这个可以代替上两行
table->setWindowTitle("QTableWidget & Item");
table->resize(550, 400);
setFixedSize(580,500);//固定窗口的大小
//设置表格的表头
QStringList header;
header<<"1"<<"2"<<"3"<<"4";
table->setHorizontalHeaderLabels(header);//设置表头(横)
QStringList header2;
header2<<"abc"<<"jmc"<<"Month"<<"Description"<<"Month"<<"Description";
table->setVerticalHeaderLabels(header2);//设置表头(竖)
//设置行列的宽和高
/*for(int i = 0;i<10;++i)
{
Table_one->setRowHeight(i,40);
}
for(int i = 0;i<4;++i)
{
Table_one->setColumnWidth(i,65);
}*/
//设置表格内容(横坐标,纵坐标,QTableWidgetItem("输入文本"))
//如果有要输入的需要,就是把处理过后的数据输出到报表中,即可使用这个功能
//显示阶段
for(int i=0;i<6;i++)
{
for(int j=0;j<4;j++)
{
table->setItem(i,j,new QTableWidgetItem(exsheet[i][j]));//注意,exsheet为QString类型的数组,只有QString类型才能显示,如果是double等数值类型,请使用QString::number转换类型
qDebug()<setEditTriggers(QAbstractItemView::NoEditTriggers);//只读模式
//表列随着表格变化而自适应变化
table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
//表行随着表格变化而自适应变化
table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
//将widget设置为窗口的中心控件
//setCentralWidget(widget);
//将读到的内容存在tableDate中
arow=table->rowCount(),acol=table->columnCount();
//QString tabeDate[table->rowCount()][table->columnCount()];//读取行数和列数
for(int i=0; iitem(i, j)->text();//将数据读入一个全局变量中,方便之后进行保存操作
}
}
table->show();
}
行列高宽的设置
自定义:
for(int i = 0;i<10;++i)
{
Table_one->setRowHeight(i,40);
}
for(int i = 0;i<4;++i)
{
Table_one->setColumnWidth(i,65);
}
其他类型:
Table_one->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
Table_one->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
其中的参数:ResizeMode mode的具体内容如下:
从上到下分别为:手动调整,固定大小,根据内容分配(两种模式)。
读取QTableWidget绘制的表格中的内容
void Dialog::savedata()
{
QString filepath = QFileDialog::getSaveFileName(table, "保存",
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
"Excel 文件(*.xls *.xlsx)");
//返回应写入文件类型的目录,返回包含用户文档文件的目录
if (filepath!="")
{
QAxObject *excel = new QAxObject(this);//建立excel操作对象
if (excel->setControl("Excel.Application")) //连接Excel控件
{
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);
//访问excel中的工作表中第一个单元格
//保存到execl,总的来说就是操作单元格,赋值的赋值,改格式大的改格式,遵循一点,修改颜色,行高,字体这些属性,务必是要设定一个修改范围再动手
int i,j,colcount=table->columnCount(),rowcount=table->rowCount();//表格的列数
QAxObject *cell,*col;
//标题行
cell=worksheet->querySubObject("Cells(int,int)", 1, 1);//操作单元格
cell->dynamicCall("SetValue(const QString&)", "title");//设置标题内容,SetValue(const QString&),后面就是打印的文本内容
cell->querySubObject("Font")->setProperty("Size", 18);
//前半句是获取单元格字体,后半句是设置字体大小
//cell->setProperty("Name", QStringLiteral("华文彩云"));//设置单元格字体
// cell->setProperty("Italic", true); //设置单元格字体斜体
//cell->setProperty("Underline", 2); //设置单元格下划线
//获取这个范围内的单元格,直接调整行高
worksheet->querySubObject("Range(const QString&)", "1:1")->setProperty("RowHeight", 60);
//合并标题行
QString cellTitle;
cellTitle.append("A1:");//初始原点
cellTitle.append(QChar(colcount + 'A'));//终止列(一般都要总列数减去1,Qchar)
cellTitle.append(QString::number(1));//终止行()Qstring
//下述第一条,可以理解为对sellTitle这个范围的单元格进行操作
QAxObject *range = worksheet->querySubObject("Range(const QString&)", cellTitle);
range->setProperty("WrapText", true);//自动换行
range->setProperty("MergeCells", true);//合并单元格
//排版:居中
//左对齐(xlLeft):-4131 居中(xlCenter):-4108 右对齐(xlRight):-4152
range->setProperty("HorizontalAlignment", -4108);//xlCenter
range->setProperty("VerticalAlignment", -4108);//xlCenter
//行的表头
for(i=0;iquerySubObject("Cells(int,int)", 2, i+2);//确定操作单元格,将数据保存到哪儿,行的表头,所以要从第二列开始
columnName=table->horizontalHeaderItem(i)->text();//获取此处的文本内容,i是列号,就是第几列中的文本内容
cell->dynamicCall("SetValue(const QString&)", columnName);//打印到excel
//前半句是获取单元格字体,后半句是字体加粗
cell->querySubObject("Font")->setProperty("Bold", true);
cell->querySubObject("Interior")->setProperty("Color",QColor(191, 191, 191));
cell->setProperty("HorizontalAlignment", -4108);//xlCenter
cell->setProperty("VerticalAlignment", -4108);//xlCenter
}
//列的表头
for(i=0;iquerySubObject("Cells(int,int)", i+3, 1);//确定操作单元格,将数据保存到哪儿列的表头,需要从第三行开始,所以+3
rowName=table->verticalHeaderItem(i)->text();
//horizontalHeaderItem(i)->text();//获取此处的文本内容,i是列号,就是第几列中的文本内容
cell->dynamicCall("SetValue(const QString&)",rowName);//打印到excel
//前半句是获取单元格字体,后半句是字体加粗
cell->querySubObject("Font")->setProperty("Bold", true);
cell->querySubObject("Interior")->setProperty("Color",QColor(191, 191, 191));
cell->setProperty("HorizontalAlignment", -4108);//xlCenter
cell->setProperty("VerticalAlignment", -4108);//xlCenter
}
//数据区
for(i=0;irowCount();i++)
{
for (j=0;jitem(i,j)->text();
worksheet->querySubObject("Cells(int,int)", i+3, j+2)->dynamicCall("SetValue(const QString&)",
rowdata[j]);
}
}
//画框线
QString lrange;
lrange.append("A2:");//起始行列位置(原点),修改后,开始的位置会变化,A2的从A2那一行开始,A3就是第三行
lrange.append(colcount + 'A');//终止列,-1,就是正常状态,改变colcount后面的
lrange.append(QString::number(table->rowCount() +2));//终止行
//这个起始的位置,相当于原点,最终给一个行列的终止位置就行
range = worksheet->querySubObject("Range(const QString&)", lrange);
//querySubObject("Borders")是对边框的设置,必须有
range->querySubObject("Borders")->setProperty("LineStyle", QString::number(1));
range->querySubObject("Borders")->setProperty("Color", QColor(0, 0, 0));//颜色的设置
//调整数据区行高
QString rowsName;
rowsName.append("A2:");
rowsName.append(colcount + 'A');
//上面两句也可以变成
//rowsName.append("2:");//起始列
rowsName.append(QString::number(table->rowCount() + 2));//终止行
range = worksheet->querySubObject("Range(const QString&)", rowsName);
range->setProperty("RowHeight", 20);//设置行高
range->setProperty("ColumnWidth", 60); //设置单元格列宽
workbook->dynamicCall("SaveAs(const QString&)",QDir::toNativeSeparators(filepath));
//保存至filepath
//并将'/'分隔符转换为适合底层操作系统的分隔符。
//在Windows上,toNativeSeparators(“c:/ winnt / system32”)返回“c:\ winnt \ system32”。
//将filepath的路径
workbook->dynamicCall("Close()");//关闭工作簿
excel->dynamicCall("Quit()");//关闭excel
delete excel;
excel=NULL;
if (QMessageBox::question(NULL,"完成","文件已经导出,是否现在打开?",QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes)
{
//QDesktopServices类提供了访问常见桌面服务的方法。
//QDesktopServices::openUrl(const QUrl &url)
//打开指定url中的文件
//QDir目录结构及其内容的访问。
QDesktopServices::openUrl(QUrl("file:///" + QDir::toNativeSeparators(filepath)));
}
}
else
{
QMessageBox::warning(NULL,"错误","未能创建 Excel 对象,请安装 Microsoft Excel。",QMessageBox::Apply);
}
}
整体程序布局(仅供参考)
整个头文件及源文件分布如下
mainwindow.h包含以下头文件
#include
#include //excel必须包含此头文件
#include
#include //文件操作必要
#include//绘制表格需要
#include"dialog.h"//dialog源文件的头文件
#include
dialog.h包含以下头文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
上述的读取Excel代码位于mainwindow.cpp中
其他功能的代码位于dialog.cpp中
所以在选择查看报表的时候,会另外弹出一个QDialog类型的窗口显示内容,也可将以上功能都放置于同一个cpp中。
补充:
如果现在TableWidget中删除某行,执行以下操作
int rowIndex = table->currentRow();
if(rowIndex == -1)
{
QMessageBox::warning(this,"Warning!","请选择一行再删除!",QMessageBox::Yes);
}
else if(rowIndex != -1)
{
table->removeRow(rowIndex);
}
解释:需要写入保护程序,当TableWidget没有行被选中的时候,返回值是-1,所以当有返回值不是-1,也就是我们选中某一行的时候,再进行删除操作,否则在调用过程中,可能会有如下错误。
行数: -1
ASSERT failure in QList
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
Error -
RtlWerpReportException failed with status code :-1073741823. Will try to launch the process directly