先奉上源码地址: QT-Information-Management-System
软件功能及开发环境:
1-1.实现对excel读取写入功能
1-2.完成从excel文件导入到数据库sqlite的功能
1-3.完成将sqlite数据显示在tableview的功能
1-4.实现对数据库数据查找的功能
1-5.实现截取控件保存为图片功能
1-6.实现自定义软件边框的功能
1-7.本软件是基于QT Creator 4.0.3在win10下开发
在设计中主要的功能为写入数据,重点是对开源的excel操作库的运用。关于excel的读写库请参考:qtxlsx
这里还是简单说一下库的加入方法:
2-1.首先到github下载源码以备使用:QtXlsxWriter
2-2.将源码解压到QT工程目录下,可以新建一个文件夹3rdparty存放库文件:
|-- project. pro
|-- …
|-- 3rdparty\
| |-- qtxlsx\
| |
2-3.在完成以上的准备工作之后,将刚刚新建的文件夹路径添加到工程文件中:
include (3rdparty/src/xlsx/qtxlsx.pri)
2-4.添加完成之后就可以通过在文件中添加头文件#include "xlsxdocument.h"
来对excel进行操作
图1为导出excel模板的软件界面:
2-5代码实现:
这里还做了一个按键下拉功能:
/***Function: export excel model*/
void MainWindow::btnExportExcelsetting(void){
connect(exportMenu,SIGNAL(triggered(QAction *)),this,SLOT(onExportMenuTriggered(QAction *)));
exportMenu->addAction(exportMenu_action_scholarship);
exportMenu->addAction(exportMenu_action_stipend);
exportMenu_action_scholarship->setText(QStringLiteral("Export Scholarship model"));
exportMenu_action_stipend->setText(QStringLiteral("Export Stipend model"));
exportMenu->setStyleSheet("font: 8pt ,'Microsoft YaHei'");
ui->btnExportExcel->setMenu(exportMenu);
}
以下是具体的excel写入操作函数
void MainWindow::onExportMenuTriggered(QAction *action){
QXlsx::Document xlsx;
xlsx.write("A1", QStringLiteral("StudentName"));
xlsx.write("B1", QStringLiteral("IDNumber"));
xlsx.write("C1", QStringLiteral("StudentID"));
xlsx.write("D1", QStringLiteral("College"));
xlsx.write("E1", QStringLiteral("Class"));
xlsx.write("H1", QStringLiteral("IssueDate"));
xlsx.write("I1", QStringLiteral("Issuer"));
QString modelFileName;
if (action == exportMenu_action_scholarship){
xlsx.write("F1", QStringLiteral("ScholarshipName"));
xlsx.write("G1", QStringLiteral("ScholarshipAmount"));
QString strModelFile = QStringLiteral("\\ScholarshipModel") + ".xlsx";
modelFileName = QFileDialog::getSaveFileName(this,QStringLiteral("ScholarshipModel"),strModelFile,"EXCEL (*.xlsx)");
}
else if (action == exportMenu_action_stipend){
xlsx.write("F1", QStringLiteral("StipendName"));
xlsx.write("G1", QStringLiteral("StipenAmount"));
QString strModelFile = QStringLiteral("\\StipendModel") + ".xlsx";
modelFileName = QFileDialog::getSaveFileName(this,QStringLiteral("StipendModel"),strModelFile,"EXCEL (*.xlsx)");
}
xlsx.setDocumentProperty("title", QStringLiteral("ExcelModel"));
xlsx.setDocumentProperty("creator", QStringLiteral("https://github.com/pyuxing"));
if (!modelFileName.isNull())
{
xlsx.saveAs(modelFileName);
}
}
由于在实际操作中发现,并没有能够直接将excel的数据导入sqlite的函数,所以软件使用以下策略:
*.xlsx – *.CSV-- *.db 也就先把excel文件存为CSV文件,再将CSV文件存为sqlite数据库文件。
以下为具体代码实现:
3-1 excel文件存储为CSV文件:
/***Function: transfer excel file to CSV*/
bool connection::tranExcelToCSV(QString InputExcel,QString OutputCSV){
//Using QAxObject in a background thread must be initialized first
CoInitializeEx(NULL, COINIT_MULTITHREADED);
QAxObject excel("Excel.Application");
excel.setProperty("Visible", false); //NO show
excel.setProperty("DisplayAlerts", false);//NO warning
QAxObject * workBooks = excel.querySubObject("WorkBooks");
workBooks->dynamicCall("Open(const QString&)", QString(InputExcel));
QAxObject *workbook = excel.querySubObject("ActiveWorkBook");
QAxObject * worksheet = workbook->querySubObject("Worksheets(int)", 1);
QAxObject *first_sheet = worksheet->querySubObject("Rows(int)", 1);//delete the first row
first_sheet->dynamicCall("delete");
worksheet->dynamicCall("SaveAs(const QString&,int)",QDir::toNativeSeparators(OutputCSV),6);
workbook->dynamicCall("Close (Boolean)", false); //close file
excel.dynamicCall("Quit(void)");//close excel
return true;
}
3-2 CSV文件导入sqlite数据库中
这里使用QTextStream
进行文件流的读入:
/***s: import data of CSV file to sqlite*/
bool connection::createConnection(QString inputFilepath,QString outputFilepath,QString tableName)
{
QFile file(inputFilepath);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
std::cerr << "Cannot open file for reading: "
<< qPrintable(file.errorString()) << std::endl;
return false;
}
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(outputFilepath);
if(!db.open())
{
QMessageBox::critical(0 , "Can not open database",
"Unable to establish a database connection.",QMessageBox::Cancel);
std::cerr<<"stop!";
return false;
}
QSqlQuery query;
query.exec("create table "+ tableName + "(stuName varchar(50),idNum varchar(50),"
"stuID varchar(50),stuCollege varchar(50),"
"stuClass varchar(50),projName varchar(50),"
"projAmount varchar(50),projDate varchar(50),"
"projIssuer varchar(50), primary key(projName,projDate,idNum))");
QStringList list;
list.clear();
QTextStream in(&file); //QTextStream reading data
while(!in.atEnd())
{
QString fileLine = in.readLine();//from 1st line to next
list = fileLine.split(",", QString::SkipEmptyParts);
qDebug()<<list.at(0)<<list.at(1);
query.prepare("INSERT INTO " + tableName + " (stuName,idNum,stuID,stuCollege,stuClass,projName,projAmount,projDate,projIssuer)"
" VALUES (:stuName,:idNum,:stuID,:stuCollege,:stuClass,:projName,:projAmount,:projDate,:projIssuer)");
query.bindValue(":stuName", list.at(0)); //bind data
query.bindValue(":idNum", list.at(1));
query.bindValue(":stuID", list.at(2));
query.bindValue(":stuCollege", list.at(3));
query.bindValue(":stuClass", list.at(4));
query.bindValue(":projName", list.at(5));
query.bindValue(":projAmount", list.at(6));
query.bindValue(":projDate", list.at(7));
query.bindValue(":projIssuer", list.at(8));
query.exec();
}
if(!db.commit()){
qDebug()<<"ERROR commit";
}
query.clear();
db.close();
return true;
}
这里主要用到QSqlTableModel
类,具体实现如下(这里以导入助学金信息为例,奖学金类似):
void MainWindow::on_btnScholarship_clicked()
{
connection con;
if(!con.createConnection(scholarshipPath,"scholarship.db",scholarshipTable))
{
qDebug() << "Can not create connection";
MyMessageBox::showMyMessageBox(this, QStringLiteral("Error Reminder"), QStringLiteral("Please make sure the scholarship data\n import is correct!"), MESSAGE_WARNNING, BUTTON_OK_AND_CANCEL, true);
}
QSqlTableModel *model;
model = new QSqlTableModel(this);
model->setTable(scholarshipTable);
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select(); //select the table
ui->tableviewScholarshipInfo->setModel(model);
setTableHead(model);
ui->tableviewScholarshipInfo->setEditTriggers(QAbstractItemView::NoEditTriggers);//Make it uneditable
ui->tableviewScholarshipInfo->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//Set the column width to automatically adjust according to the text
ui->tableviewScholarshipInfo->setSelectionBehavior(QAbstractItemView::SelectRows); //Set the selected behavior to select the entire row
ui->tableviewStipendInfo->setVisible(false);
}
这里主要用到QSqlQueryModel
类,具体实现如下:
/***Function:filter query data*/
bool MainWindow::searchData(QObject *ptrTableviewInfo,QString strHeadItem,QString strExactItem,QString strTableName){
QSqlQueryModel *model = new QSqlQueryModel(ptrTableviewInfo);
if((strHeadItem != "TABLE") && (strExactItem != "NO SEARCH")){
model->setQuery(QString("select * from " + strTableName + " where %1 = '%2'").arg(strHeadItem).arg(strExactItem));
}
else{//Did not enter the query content
MyMessageBox::showMyMessageBox(this, QStringLiteral("Query Reminder"), QStringLiteral("No data to be queried in the database!"), MESSAGE_WARNNING, BUTTON_OK_AND_CANCEL, true);
}
model->setHeaderData(0,Qt::Horizontal,"headstuName");
setTableHead(model);
QTableView *ptrTableview = qobject_cast<QTableView *>(ptrTableviewInfo);
ptrTableview->setModel(model);
if(!ptrTableview->verticalHeader()->count()){
MyMessageBox::showMyMessageBox(this, QStringLiteral("Query Reminder"), QStringLiteral("No data to be queried in the database!"), MESSAGE_WARNNING, BUTTON_OK_AND_CANCEL, true);
}
return true;
}
这里实现的功能是截取控件区域为图片,并将其另存为,代码实现如下:
/***Function: save cars as images*/
void MainWindow::on_btn_SaveScreenShot_clicked()
{
QString strDir = QCoreApplication::applicationDirPath() + QStringLiteral("\\StuInfoCard\\");
QDir dir(strDir);
if(!dir.exists()){
dir.mkdir(strDir);
}
QString strFile = strDir + fileStuName + QDateTime::currentDateTime().toString("_yyyyMMddHHmmss") + ".png";
ui->btn_confirmCloseInfoCard->setVisible(false);
ui->btn_SaveScreenShot->setVisible(false);
ui->line_btwSaveConfirm->setVisible(false);
QPixmap pix = QPixmap::grabWidget(ui->frameInfoDetail);
ui->btn_confirmCloseInfoCard->setVisible(true);
ui->btn_SaveScreenShot->setVisible(true);
ui->line_btwSaveConfirm->setVisible(true);
QString fileName = QFileDialog::getSaveFileName(this,QStringLiteral("SaveAsImages"),strFile,"PNG (*.png);;BMP (*.bmp);;JPEG (*.jpg *.jpeg)");
if(!fileName.isNull()){
pix.save(fileName);
}
}
在实现自定义边框的方法上主要参考了Jorgen-VikingGod的 Qt-Frameless-Window-DarkStyle(有具体的实现方法,这里不展开)
前文的软件截图都是在修改过边框下实现的,现在看一下没有自定义边框的时候什么样子的,如图6:
a)将源代码放到自己工程的目录下,并在工程文件下添加路径,比如 INCLUDEPATH +="framelesswindow"
b)在main函数包含头文件#include "framelesswindow.h"
,具体如下代码所示:
#include "mainwindow.h"
#include "DarkStyle.h"
#include "framelesswindow.h"
int main(int argc, char *argv[]){
QApplication a(argc, argv);
a.setStyle(new DarkStyle);
FramelessWindow framelessWindow;
MainWindow *mainWindow = new MainWindow;
framelessWindow.setContent(mainWindow);
framelessWindow.show();
return a.exec();
}
在功能的实现上将excel数据存入数据库花费了比较多的精力,最后也没实现excel直接存入数据库的方法,而是将其存为CSV文件,再将CSV转存入数据库。这里使用的数据库是QT自带的sqlite数据库,尝试过mysql,但涉及到要为电脑安装数据库,最后没有继续往下做。(ps:采用英文是因为原始版本里有一些真实数据,所以公开版本做此修改) 源码传送门
总之还有很多需要学习的地方,继续加油吧!
PS:公众号上线啦,技术干货分享,欢迎关注。