您的位置:首页 > 编程语言 > Qt开发

Qt编写信息管理系统(2)

2016-04-10 10:56 471 查看

接着上一次的登陆界面,这次首先进行了主窗口的框架设计:



[0]首先在最顶层加入了一些按钮用来响应界面的切换.

[1]接着在下方加入了一个stacked widget,可以用来进行页面切换(响应上方的按钮)

[2]然后就是加入一些搜索,插入,编辑,删除等按钮功能了.

[3]最后是本地音乐,操作日志,休闲模块.

[3]接下来是代码:

(1)这是用一个Connection的类来存储并控制连接的信息,方便以后拓展功能.

#ifndef CONNECTION_H
#define CONNECTION_H
#include "QString"
#include "QtSql/QSqlDatabase"
#include "QSqlError"
#include "QDebug"
#include "QMessageBox"

class Connection
{
public:
Connection();
bool connect(const QString& dbName );
private:
QSqlDatabase* currentdatabase;
};

#endif // CONNECTION_H


#include "connection.h"

Connection::Connection()
{

}

bool Connection::connect(const QString &dbName)
{

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setDatabaseName(dbName);//数据库的名字,这里是Test(注意这里的数据库名字实际上是workbench里面的数据库连接名)
db.setHostName("127.0.0.1");//ip地址
db.setUserName("root");//用户的名字
db.setPassword("19931218");//密码
db.setPort(3306);
qDebug()<<"success";

if (!db.open())
{
QMessageBox::critical(0, QObject::tr("Database Error"), db.lastError().text());
return false;
}
return true;
}


(2)这是主界面的一个模块(信息查询模块)的代码:

#ifndef LOGINDIALOG_H
#define LOGINDIALOG_H

#include <QDialog>
#include "QString"
#include "QPoint"

namespace Ui {
class LoginDialog;
class Modify_Dialog;
}

class LoginDialog : public QDialog
{
Q_OBJECT

public:
explicit LoginDialog(QWidget *parent = 0);
~LoginDialog();
void do_send_name(){emit send_name(account,rank);}//留给外部接口,为了隐藏account
signals:
void send_name(const QString &name,const int rank );//信号函数,传递用户名
private slots:
void on_loginbutton_clicked();
void on_Exitbutton_clicked();
void on_loginbutton_2_clicked();

protected:
void mousePressEvent(QMouseEvent *event); //鼠标按下事件
void mouseMoveEvent(QMouseEvent *event);//鼠标移动事件
private:
bool test(QString,QString);
bool eventFilter(QObject* obj,QEvent* event);
void do_set_text(QObject* selected,QObject* unselected,QString s);
void save_password(QString new_password);
private:
Ui::LoginDialog *ui;
QString account;
QString password;
int rank;
QPoint windowPos;
QPoint mousePos;
QPoint dPos;
};
#endif // LOGINDIALOG_H


注意我这里有一个很大的设计缺陷:

应该将model/view抽象为一个单独的类,这样就可以实现数据和操作分离,我直接把和model/view有关的操作代码比如删除,查询这些方法都放在主界面里面,这样导致我在一个方法里面要不停的小心区分是对哪个表进行操作,每个表的性质都不一样,这样对于代码复用是很麻烦的.

但是我还是在一定程度上进行数据和操作的分离.

主要是将数据库表的情况都用几个私有变量存储起来,并且通过几个方法来修改它们,这样我们在连接不同的表的时候只需要修改这几个私有变量就可以用同一段代码显示查询的结果.

其次将搜索条件的设置尽可能通用话,并且考虑了外键的情况.对于不同的标进行搜索,我们也只需要传入不同的参数就可以了.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "myedit.h"
#include "QtSql/QSqlDatabase"
#include "QSqlRecord"
#include "QSqlRelationalDelegate"
#include "QAbstractItemView"
#include"QHeaderView"
#include "QModelIndexList"
#include "gmae_2048.h"
#include "QDesktopServices"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->stackedWidget->setCurrentIndex(2);//初始界面2
ui->stackedWidget->setCurrentIndex(0);//初始化界面0
set_tableattribute({"id","name","age","project","salary","email"});//设置开始处理student表的列名
set_ForienAbout({3,"projects","project_id","project_name"});//设置student外键情况
// ui->stackedWidget->setStyleSheet("background-color: rgb(114, 255, 255);");  //设置背景颜色
if(!c.connect("test"))
{
qDebug()<<"connect failed";
return;
}
/*************处理第一个model**************/
model = new QSqlRelationalTableModel(this);//初始化该查询模块
do_setmodel(model);
/********处理第二个model*****/
project_model = new QSqlRelationalTableModel(this);//初始化项目查询模块
do_setmodel(project_model);
/***********加入音乐**********************/
music_controller = new Mymusic(ui->listWidget,this);
/************初始化日志控制模块**********************************/
logcontroller = new log_controller(this,tr("./resource_file/log.txt"),ui->Log_Edit);
QObject::connect(ui->clear_button,&QPushButton::clicked,[&](){logcontroller->clear(1);});//暂时清空
QObject::connect(ui->tmp_clear_button,&QPushButton::clicked,[&](){logcontroller->clear(0);});//清空文件

QObject::connect(model,QSqlTableModel::beforeUpdate,[&](int row,QSqlRecord record)
{row= row;get_update_record(1,record);});//添加编辑的数据
QObject::connect(project_model,QSqlTableModel::beforeUpdate,[&](int row,QSqlRecord record)
{row = row;get_update_record(1,record);});//添加编辑的数据
/***********处理编辑邮箱*************************/
QObject::connect(model,QSqlTableModel::beforeUpdate,[&](int row,QSqlRecord record)
{
row = row;
QRegExp rx("^([\\dA-Za-z]{5,20})@(163|qq|gmail|icloud).com$");
if(!rx.exactMatch((record.value(5).toString())))
QMessageBox::critical(this,"Error","Wrong Email");
});

}
MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::recieve_name(QString name,int _rank)
{
account = name;
this->rank = _rank;

this->setWindowTitle(QString("%1-Manage Sysytem").arg(account));
/********************将模块数据传递给view*******************************/
initialize_pages(ui->tableView,0);
initialize_pages(ui->projectview,1);
/******************设置权限*******************/
if(rank<10)//权限不足,不能启动修改功能
{
ui->insert_splitter->setVisible(false);
ui->pro_splitter->setVisible(false);
ui->clear_button->setEnabled(false);
}
else
{
ui->tableView->setEditTriggers(QTableView::DoubleClicked);//可以编辑
ui->projectview->setEditTriggers(QTableView::DoubleClicked);//可以编辑
ui->Insert->setEnabled(true);
ui->Insert_project->setEnabled(true);
}
}
void MainWindow::initialize_pages(QTableView* view,int index)
{

auto _model = (index==0) ? model:project_model;//判断应该是哪个model
view->setModel(_model);
view->setSelectionMode(QAbstractItemView::ExtendedSelection);//设置每次选中的个数(单个,多个)
view->setSelectionBehavior(QAbstractItemView::SelectItems);//设置选中的形式(行,列,单个)
view->verticalHeader()->setVisible(false);//隐藏表头
view->resizeColumnsToContents();//列的宽度自适应内容
view->setEditTriggers(QTableView::NoEditTriggers);
view->setItemDelegate(new QSqlRelationalDelegate( view));
QHeaderView *header =  view ->horizontalHeader();
header->setStretchLastSection(true);//最后一行占据整个窗口
/******************添加右键菜单***********************/
auto delete_menu = new QAction(tr("Delete"),view);//创建删除右键菜单
view-> addAction(delete_menu);
view->setContextMenuPolicy(Qt::ActionsContextMenu);
/****************添加相应的动作********************/
connect(delete_menu,&QAction::triggered,[=](){Delete(view);});//添加的action的槽函数
/******************************************************/
ui->insert_ageedit->setValidator(new QIntValidator(0,100,this));
if(index == 1)//第二个表
{
/****************对第二个表添加打开动作******************************/
auto open_menu = new QAction(tr("Open"),view);//创建打开右键菜单
view-> addAction(open_menu);
view->setContextMenuPolicy(Qt::ActionsContextMenu);
connect(open_menu,&QAction::triggered,[=](){Open(view);});
/*****************************************************************************/
}
}

void MainWindow::set_tableattribute(std::initializer_list<QString> args)//设置表的列名
{
attribute.clear();//清除这个表
attribute = QStringList(args);//将表的属性设置为传入的参数
}
void MainWindow::set_ForienAbout(std::initializer_list<QVariant> args)
{
AboutForeign.clear();//清除外键相关的信息
AboutForeign = QVariantList(args);
}

void MainWindow::on_AnyButton_clicked()//处理最顶层的按钮事件,响应page变化
{

QPushButton* btn =static_cast<QPushButton*>(sender()); //获取点击的按钮
if(btn->objectName()=="Query_button")//发送信号的是查询按钮
ui->stackedWidget->setCurrentIndex(0);
else if(btn->objectName()=="Game_button")
{
ui->stackedWidget->setCurrentIndex(1);//切换页面
auto game = new Game_1024_Window();
game->show();
}
else if(btn->objectName()=="Project_button")//发送信号的是项目信息按钮
ui->stackedWidget->setCurrentIndex(2);
else if(btn->objectName()=="log_button")
ui->stackedWidget->setCurrentIndex(3);
else
qDebug()<<"something wrong on the PageChanged";
}
QString MainWindow::set_student_filter(QStringList query_name,QStringList query_value)
{

QString filter ("");
auto name_beg = query_name.begin();
for(auto beg = query_value.begin(),end = query_value.end()
;beg!=end;++beg,++name_beg)
{
*beg = beg->simplified();//去掉所有空格
if(*beg=="")//搜索条件为空
continue;
QRegExp token("[^><&~()=//|]");
QString ans = "";
for(int i = 0;i<beg->length();++i)
{
auto it = beg->at(i);
if(it == '('||it==')')
ans.append(it);
else if (it == '>'||it=='<'||it=='!'||it=='=')
{
if(it == '=')//=
ans +=*name_beg + beg->mid(i,1);
else if(beg->at(i+1)=='=')//>= <= !=
ans += *name_beg + beg->mid(i++,2);//注意i++,跳过=,>= <=
else
{
ans += *name_beg + beg->mid(i,1);//> <

}
}
else if(it=='&'||it=='|'||it=='~')
ans.append(it);
else //查询的值
{
qDebug()<<"查询 开始"<<i;
int j = i;
while(j<beg->length()&&token.exactMatch((beg->mid(j,1)))){++j;}
if(j-1!=beg->length())
{
ans += ("'" + beg->mid(i,j-i)+  "'");
qDebug()<<"查询"<< ("'" + beg->mid(i,j-i)+  "'");
}
i = j-1;
qDebug()<<"查询 结束"<<i;
}
}
qDebug()<<"ans:"<<ans;
ans.replace("~"," not ");
ans.replace("&"," and ");
ans.replace("|"," OR ");
qDebug()<<"replaced ans"<<ans;
filter += QString(" %1 and ").arg(ans);
}

filter = filter.mid(0,filter.length()-4);
qDebug()<<"Filter"<<filter;
return filter;
}
void MainWindow::setmodel(QSqlRelationalTableModel* _model, const QString& tablename, bool HaveForeignKey, const QString& Filter)//重新设置model的属性
{

_model->setTable(tablename);//关联student表
int i = 0;
for(auto beg = attribute.begin(),end = attribute.end();beg!=end;++beg)
{
QString this_attribute = *beg;//获取第一个属性
_model->setHeaderData(i,Qt::Horizontal,this_attribute);
qDebug()<<this_attribute;
i+=1;
}
if(HaveForeignKey)//如果有外键
{
if(AboutForeign.length()!=4)
{
qDebug()<<AboutForeign;
qDebug()<<"The args for ForeignKey must be 4!";
}
int index = AboutForeign.at(0).toInt();
QString another_tablename = AboutForeign.at(1).toString();//外键关联的表名
QString Foreign_attribute =  AboutForeign.at(2).toString();//外键关联的列
QString  Foreign_displayattribute = AboutForeign.at(3).toString();//想要显示的列
qDebug()<<index<<another_tablename<<Foreign_attribute<<Foreign_displayattribute;
_model->setRelation(index, QSqlRelation(another_tablename,
Foreign_attribute, Foreign_displayattribute));//设置关系
}
_model->setSort(0, Qt::AscendingOrder);
if(Filter!="")
_model->setFilter(Filter);
_model->select();
}

void MainWindow::on_SearchButton_clicked()//处理查找操作
{
QPushButton* btn =static_cast<QPushButton*>(sender()); //获取点击的按钮
if(btn->objectName()=="SearchButton")
{
/********获取搜索条件**/
QString project = ui->AdressEdit->text();
QString Id = ui->IdEdit->text();
QString Name = ui->NameEdit->text();
QString Age = ui->AgeEdit->text();
QString Email = ui->Email_Edit->text();
QString Salary = ui->Salary_Edit->text();
/******重新赋值查询模块**********/
do_setmodel(model,set_student_filter({"id","name","age","project_name","salary","Email"},
{Id,Name,Age,project,Salary,Email}));
}
else//处理项目模块
{
/********获取搜索条件**/
QString Id = ui->projectId_edit->text();
QString Name = ui->projectName_edit->text();
/******重新赋值查询模块**********/
do_setmodel(project_model,set_student_filter({"project_id","project_name"},{Id,Name}));
}
}

void MainWindow::on_comboBox_currentIndexChanged(int index)
{
qDebug()<<"start";

auto btn = static_cast<QPushButton*>(sender());
auto _model = btn->objectName()=="comboBox"?model:project_model;
_model->setSort(index, Qt::AscendingOrder);//按第一列排序
_model->select();
}

/****************信息修改模块的分界线***************************************************/
bool MainWindow::check_type(QList<bool> T )//检查参数是否合法
{
return std::all_of(T.begin(),T.end(),[](bool t){return t==true;});

}

void MainWindow::insertdata(QSqlTableModel* _model,std::initializer_list<QVariant> insert_value)
{

int row = 0;
_model->insertRows(row, 1);//插入空的一行
QString information("*******Insert Operation******");
int i = 1;
for(auto beg = insert_value.begin(),end = insert_value.end();beg!=end;++beg)
{
information += ( " ' "+attribute.at(i) + "' ': ");
qDebug()<<"index :::"<<_model->index(row,i);
_model->setData(_model->index(row,i++), *beg);//给空的一行设置数据
information +=  beg->toString();
}
/*****************记录数据**********************************/
QString data;
/***************如果有外键,正确的处理外键对应的索引和显示的值之间的关系*************/

if(!AboutForeign.empty())
{
qDebug()<<AboutForeign;
QSqlQuery query;
int relational_index;
auto foreignkey = (insert_value.begin() + AboutForeign.at(0).toInt()-1)->toString();
auto rel_id = AboutForeign.at(2).toString();
auto rel_table = AboutForeign.at(1).toString();
auto rel_display = AboutForeign.at(3).toString();
query.exec("PRAGMA foreign_keys = ON");//添加外键
if(!query.exec(QString("select %1 from %2 where %3 = '%4' ").
arg(rel_id).arg(rel_table).arg(rel_display).arg(foreignkey)))
{
QMessageBox::critical(0, QObject::tr("Insert Error"), query.lastError().text());
return;
}

if(query.next())
{
relational_index = query.value(0).toInt();//获取索引

qDebug()<<"index"<<_model->index(row,AboutForeign.at(0).toInt());
_model->setData(_model->index(row,AboutForeign.at(0).toInt()),relational_index);
}
else
{
QMessageBox::critical(0, QObject::tr("Insert Error"), QString("The %1 don't exist").arg(foreignkey));
return;
}
}

if(!_model->submitAll())//插入失败
{
QMessageBox::critical(0, QObject::tr("Insert Error"), _model->lastError().text());
_model->revertAll();
return;
}
logcontroller->add(information);//向日志里面插入数据
QMessageBox::information(this,"Ok.","Insert a row successfully!");
}
/*********************************************插入一条员工信息***************************/
void MainWindow::on_Insert_clicked()
{
/************确认要插入**************************/
if(QMessageBox::Yes != QMessageBox::question(this,"Question","Do you want to add one record?",
QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes))
return;

QPushButton* btn =static_cast<QPushButton*>(sender()); //获取点击的按钮
if(btn->objectName()=="Insert")
{
/************获取要插入的信息*****************/
QRegExp rx("^([\\dA-Za-z]{5,20})@(163|qq|gmail|icloud).com$");
QString project = ui->Insert_adressedit->text();
QString Name = ui->Insert_nameedit->text();
QString Email = ui->insert_email_edit->text();
int Age = ui->insert_ageedit->text().toInt();
int Salary =  ui->insert_salary_edit->text().toInt();
bool ok = rx.exactMatch(Email);
/**************确认对话框*******************/
if(!check_type({ok}))//检测输入合法性
{
QMessageBox::critical(0, QObject::tr("Insert Error"), "the Email inputs is wrong");
return;
}
do_setmodel(model);//设置attribute的属性
insertdata(model,{Name,Age,project,Salary,Email});//插入数据
}
else
{

QString Name = ui->Insert_pro_nameedit->text();
do_setmodel(project_model);
insertdata(project_model,{Name});//插入数据
}
}
/*********************打开选中的信息****************************************************************/
void MainWindow::Open(QTableView *view)
{
QItemSelectionModel *select = view->selectionModel();
auto _model = (view==ui->tableView)?model:project_model;
auto Selected_List = select->selectedIndexes();
for(const auto &selected:Selected_List)//逐个删除选中的目标
{
auto path = _model->data(_model->index(selected.row(),3));
qDebug()<<path;
if(!QDesktopServices::openUrl(QUrl(path.toString(), QUrl::TolerantMode)))
{
qDebug()<<"open failed";
return;
}
}
}
/********************删除选中的信息******************************************************/
void MainWindow::Delete(QTableView* view)
{

if(rank<10)
{
QMessageBox::critical(0, QObject::tr("Warnig"),"Not Root Mode!");
return;
}
QItemSelectionModel *select = view->selectionModel();
auto _model = (view==ui->tableView)?model:project_model;
auto Selected_List = select->selectedIndexes();
for(const auto &selected:Selected_List)//逐个删除选中的目标
{
qDebug()<<selected<<"*****";
auto record = _model->record(selected.row());
get_update_record(0,record);
if(!_model->removeRows(selected.row(), 1))
QMessageBox::critical(0, QObject::tr("Insert Error"), _model->lastError().text());
}
_model->submitAll();//提交事件
}
/***********************日志处理编辑时的模块的数据*****************************************/
void MainWindow::get_update_record(int operation, QSqlRecord record)
{
QString Data("");
if(operation == 1)
Data = ("********Edit Operation: *********");

for(int i = 0;i!=record.count();++i)
{
Data += (record.fieldName(i) + " : ");
Data += (record.value(i).toString()+"*****");
}
logcontroller->add(Data);
}


需要注意的一个坑是:采用了setrelation函数相当于联结查询,要让两个关联的表不要有重复的名字(比如都叫id那么你去查询id就会查不到任何东西….具体我还没有太清楚,弄清楚了再细说)

[b]************************************************************[/b]

主要说明搜索功能:可以自定义搜索,比如
((<xxx)&(>xxx))|(=xxx)
这样的条件搜索.因为MySQL有条件语句的组合,所以我们只需要将编辑框的文字转化为可执行的sql语句,比较麻烦的是注意所有搜索的值都要加单引号,我们需要将搜索值和表达符号区分开.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: