因工作需要,要实现一个小型的数据管理系统。本着想捡起来QT技能的想法,学习下QT下管理系统设计。
首先肯定是设计界面按照想要的方式进行展示,使用sqlite对数据进行管理,数据excel格式的导入导出,界面的搜索功能,条件选择功能,单条数据的编辑更改功能,账户管理功能。
根据不同模块进行分类设计
数据仓库类
对于数据源的管理设计DBFactory类对数据库操作进行封装,提供数据库连接,创建表,select等操作
数据模型类
模型本身不存储数据,仅提供接口供视图使用,QT提供的QsqlTableModel已经够用
单条数据的编辑可用QDataWidgetMaper类进行数据映射。
数据视图类
提供视图用来展示数据,和搜索功能
数据I/O类
提供excel文件的导入导出功能
登录管理类
提供登录功能及账户管理功能
定义了创建数据库连接和创建表的函数。
#ifndef DBFACTORY_H
#define DBFACTORY_H
#include <QtSql>
#include <QSqlDatabase>
class DBFactory
{
public:
DBFactory();
QSqlError createConnection();
QSqlError createUserTable(const QSqlDatabase &DataBase);
QSqlError createTable(const QSqlDatabase &DataBase);
void addUser(QSqlQuery &q, const QString &name, const QString &password,const QString &phoneNumber,const QString &role);
void addProvince(QSqlQuery &q, const QString &province, const QString &area);
QSqlDatabase DataBase() const;
void setDataBase(const QSqlDatabase &DataBase);
QStringList getContentFromDataBase(const QString &tableName, const int column);
private:
QSqlDatabase m_DataBase;
};
#endif // DBFACTORY_H
具体实现可以参考QT帮助文档关于SQL的页面。
提供一个对话框供用户输入用户名和密码。
在main函数中,首先构造登录对话框,在登录对话框构造函数中,建立数据库连接,并初始化用户表,如有,则直接跳过。
LoginDialog::LoginDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::LoginDialog)
{
//建立数据库连接
m_pDBFactory = new DBFactory();
QSqlError err = m_pDBFactory->createConnection();
if(err.type() != QSqlError::NoError)
{
QMessageBox::critical(this,tr("错误"),tr("数据库连接错误,请稍后重试!")+ err.text(),QMessageBox::Ok);
// return;
}
m_pDBFactory->createUserTable(m_pDBFactory->DataBase());
ui->setupUi(this);
}
用户输入完成后点击界面登录按钮触发相应槽函数,在对应槽函数中,检索数据库用户表,匹配密码是否正确。如正确则发出accept信号,主函数接受到后,关闭登录界面,打开主显示界面。
if(checkUserPassword(ui->UserNameEdit->text(),ui->PassWordEdit->text()))
{QDialog::accept();}
bool LoginDialog::checkUserPassword(QString name,QString passward)
{
QSqlQuery checkquery;
QString str = QString("select * from user where UName = '%1' and UPassward = '%2'").arg(name).arg(passward);
checkquery.exec(str);
//返回最后一条符合记录的位置,
checkquery.last();
int record = checkquery.at() + 1;
if(record == 0)
{
return false;
}
loginRole = checkquery.value(3).toString();
qDebug()<<loginRole;
return true;
}
在checkuserPassword函数中检索数据库,并根据不同的用户名分配不同的权限,传递给主界面构造函数用于限制部分功能。
主界面用于管理视图和模型,提供一个构造函数,和相应的菜单及其槽函数。在构造函数中进行相应视图的创建。并根据传入角色分配不同的菜单。
MainWindow::MainWindow(const QString &role, QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//创建数据表格,导入数据
m_pDBFactory = new DBFactory();
m_pDBFactory->createCustomerTable(m_pDBFactory->DataBase());
//先构建视图
m_pViewManager = new ViewManager();
setCentralWidget(m_pViewManager->pTabWidget());
//获取视图对应的模型
m_pModel=m_pViewManager->pCustomerManager()->getCustomerModel();
CreateMenu(role);
}
为方便拓展,先建立一个视图管理类添加一个tabwidget控件,再结合不同模型建立对应视图类,将视图作为tab页添加到视图管理类的tab控件中。
使用QTableView控件作为视图进行数据展示。使用该控件提供的函数进行一些基本的增删改查函数编写。
默认该视图是可编辑的,故提供了一个函数用来导入模型并设置标签。并在视图构造函数中调用并将模型设置给视图。
bool CustomerManager::setModel()
{
//关联数据模型
customerModel = new QSqlTableModel(ui->tableView);
customerModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
customerModel->setTable("Customers");
//添加表头
customerModel->setHeaderData(0,Qt::Horizontal, tr("ID"));
customerModel->setHeaderData(1,Qt::Horizontal, tr("客户地址"));
// Populate the model:
if(!customerModel->select())
{
return false;
}
return true;
}
setModel();
ui->tableView->setModel(customerModel);
//列宽随窗口大小改变而改变,每列平均分配,充满整个表,但是此时列宽不能拖动进行改变
ui->tableView->resizeColumnsToContents();
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
上边的步骤完成后,就可以将数据库中的数据显示在界面上了。接下来就是实现增删改查的功能。
单行新增
通过按钮槽函数,打开新的对话框表单,填写后将表单获取的数据组合成需要的SQL语句并提交,在槽函数中更新视图。
void CustomerManager::on_addButton_clicked()
{
AddCustomerDialog *dialog = new AddCustomerDialog(customerModel,this);
int accepted = dialog->exec();
if (accepted == 1)
{
int lastRow = customerModel->rowCount() - 1;
ui->tableView->selectRow(lastRow);
ui->tableView->scrollToBottom();
}
}
单行删除
删除选中记录,因视图设置为单行选中,所以仅实现单行删除功能。
void CustomerManager::delCustomer()
{
QModelIndexList selection = ui->tableView->selectionModel()->selectedRows(0);
if(!selection.empty())
{
QModelIndex idIndex = selection.at(0);
QMessageBox::StandardButton button;
button = QMessageBox::question(this,tr("删除确认"),QString(tr("确认删除此条客户信息吗?")),QMessageBox::Yes|QMessageBox::No);
if(button == QMessageBox::Yes){
removeCustomerFromDatabase(idIndex);
}else{
QMessageBox::information(this, tr("删除客户"),tr("请选择要删除的客户信息。"));
}
}
}
void CustomerManager::removeCustomerFromDatabase(QModelIndex index)
{
customerModel->removeRow(index.row());
customerModel->submit();
}
条件搜索
条件选择搜索功能实现,依据下拉框选项组合where条件选择语句,设置customermodel的过滤器filter。
如
void CustomerManager::on_AreaSelectBox_currentIndexChanged(const QString &arg1)
{
//更新省区选择项
QSqlQueryModel *provinceselectModel = new QSqlQueryModel(this);
QString provinceSelectstr = QString("select DISTINCT province from Provinces where area = '%1'").arg(arg1);
provinceselectModel->setQuery(provinceSelectstr);
ui->ProvinceSelectBox->setModel(provinceselectModel);
if(arg1 != "请选择归属大区"){
//构建过滤器即where条件语句
QString filter;
filter.append(QString("CArea = '%1'").arg(arg1));
if(ui->ProvinceSelectBox->currentText()!= "请选择归属省份")
{
filter.append(QString(" and "));
filter.append(QString("CProvince = '%1'").arg(ui->ProvinceSelectBox->currentText()));
}
if(ui->ProduceTypeBox->currentText()!="请选择企业性质")
{
filter.append(QString(" and "));
filter.append(QString("CProduceType = '%1'").arg(ui->ProduceTypeBox->currentText()));
}
if(ui->CustomerTypeBox->currentText()!="请选择客户类型")
{
filter.append(QString(" and "));
filter.append(QString("CCustomerType = '%1'").arg(ui->CustomerTypeBox->currentText()));
}
qDebug()<<filter;
customerModel->setFilter(filter);
ui->ProvinceSelectBox->setEnabled(true);
}else
{
//重置所有下拉框并显示所有数据
ui->ProvinceSelectBox->setCurrentIndex(0);
ui->ProvinceSelectBox->setEnabled(false);
ui->ProduceTypeBox->setCurrentIndex(0);
ui->CustomerTypeBox->setCurrentIndex(0);
customerModel->setFilter(QString(""));
customerModel->select();
}
}
文字搜索
文字搜索功能实现,依据输入文本对视图数据项进行检索
void CustomerManager::on_SearchButton_clicked()
{
QString searchText = ui->SearchEdit->text();
if(searchText=="")
{
for(int i=0;i<ui->tableView->model()->rowCount();i++)
ui->tableView->setRowHidden(i,false);
}
else
{
//获取文本框内容
searchText.remove(QRegExp("\\s"));
for(int i=0;i<ui->tableView->model()->rowCount();i++)
{
ui->tableView->setRowHidden(i,true);
QString r="";
//提取客户信息
QAbstractItemModel *model=ui->tableView->model();
QModelIndex index;
for(int j=0;j<ui->tableView->model()->columnCount();j++)
{
index=model->index(i,j);
r+=model->data(index).toString();
}
r.remove(QRegExp("\\s"));
if(r.contains(searchText,Qt::CaseSensitive))
ui->tableView->setRowHidden(i,false);
}
}
}
后期还需实现图片显示,数据量大时分页显示,可通过子类化QSQLTableModel来实现。