接着上一次的登陆界面,这次首先进行了主窗口的框架设计:
[0]首先在最顶层加入了一些按钮用来响应界面的切换.
[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);
db.setHostName("127.0.0.1");
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);}
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);
ui->stackedWidget->setCurrentIndex(0);
set_tableattribute({"id","name","age","project","salary","email"});
set_ForienAbout({3,"projects","project_id","project_name"});
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;
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);});
/******************************************************/
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()
{
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);
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->setTable(tablename);
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);
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就会查不到任何东西….具体我还没有太清楚,弄清楚了再细说)
************************************************************
主要说明搜索功能:可以自定义搜索,比如((<xxx)&(>xxx))|(=xxx)
这样的条件搜索.因为MySQL有条件语句的组合,所以我们只需要将编辑框的文字转化为可执行的sql语句,比较麻烦的是注意所有搜索的值都要加单引号,我们需要将搜索值和表达符号区分开.