01-1. 为"主窗口"添加滚动条
效果图:
mainwindow.cpp
#include "mainwindow.h"
#include "logindlg.h"
#include <QMessageBox>
#include <QIcon> //窗口图标用到此类
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
//设置窗口标题
this->setWindowTitle("CDMA无线基站管理系统");
//设置窗口图标
//QIcon icon("./images/main.png");
//setWindowIcon(icon);
setWindowIcon(QIcon("./images/main.png"));//设置窗口图标
//设置多文档界面中央控件
//QMdiArea控件只能在QMainWindow当中使用,是用来实现多文档界面的必备控件
//多文档界面控件,也是一种窗口的中央控件,在这个中央控件中可以添加多个控件
mdiArea = new QMdiArea;
setCentralWidget(mdiArea);
//中央控件背景设置
mdiArea->setBackground(Qt::NoBrush);
//mdiArea->setStyleSheet("background-color: blue");//设置背景颜色
//mdiArea->setStyleSheet("border-image: url(./images/1.jpg)");//单张图片拉伸铺满
mdiArea->setStyleSheet("background-image: url(./images/1.jpg)");//图片重复铺满
//添加滚动条, 当子窗口的边框,超过父窗口的显示范围时,父窗口自动添加滚动条
mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);//横向滚动条
mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);//纵向滚动条
createAction();//创建菜单项
createMenus(); //创建菜单
}
01-2. 为'执行脚本'的菜单项, 关联'数据表格'窗口
效果图:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QCloseEvent>
#include <QMdiArea> //多文档界面中央控件支持
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//重载
void closeEvent(QCloseEvent *event);
private:
void createMenus(); //创建菜单的函数
void createAction();//创建菜单项的函数
void showsub();//为"执行脚本"的菜单项, 添加显示子窗口的函数
void showview();//显示'数据表'窗口
//多文档界面中央控件支持
QMdiArea *mdiArea;
///菜单
QMenu *adminMenu; //"管理"菜单
QMenu *dataMenu; //"数据"菜单
QMenu *windowMenu;//"窗口"菜单
QMenu *helpMenu; //"帮助"菜单
///"管理"菜单的菜单项
QAction *loginAction; //"登录"菜单项
QAction *logoutAction;//"注销"菜单项
QAction *exitAction; //"退出"菜单项
///"数据"菜单的菜单项
QAction *scriptAction;//"执行脚本"菜单项
///"窗口"菜单的菜单项
QAction *cascadeAction;//"层叠窗口"菜单项
QAction *tileAction;//"并列窗口"菜单项
///"帮助"菜单的菜单项
QAction *helpAction;//"帮助"菜单项
QAction *aboutAction;//"关于"菜单项
//槽函数
private slots:
void on_login(); //"登录"菜单项的响应槽函数
void on_logout();//"注销"菜单项的响应槽函数
void on_exit(); //"退出"菜单项的响应槽函数
void on_script();//"执行脚本"菜单项的槽函数
void cascadeSubWindows();//"层叠窗口"菜单项的响应槽函数
void titleSubWindows();//"并列窗口"菜单项的响应槽函数
void on_help();//"帮助"菜单项的响应槽函数
void on_about();//"关于"菜单项的响应槽函数
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "logindlg.h"
#include <QMessageBox>
#include <QMdiSubWindow>
#include <QIcon> //窗口图标用到此类
#include <QStandardItemModel> //在内存中建立数据表
#include <QTableView>//显示数据表
/**
* "执行脚本"菜单项的响应槽函数
*/
void MainWindow::on_script()
{
//QMessageBox::information(this, "", "hello world");
// showsub();//调用"显示子窗口"的函数
showview();//显示数据表格窗口
}
/**
* @ 显示数据表
*/
void MainWindow::showview()
{
///创建存储数据的model, 在内存中建立5行3列的数据表
QStandardItemModel *model = new QStandardItemModel(5, 3);
//设置数据表的列名
//参数1:表示从第几列开始设置 //参数2:Horizontal表示水平(横向)设置
//参数3:表示要设置的列名
model->setHeaderData(0, Qt::Horizontal, "姓名");
model->setHeaderData(1, Qt::Horizontal, "性别");
model->setHeaderData(2, Qt::Horizontal, "年龄");
//设置数据表的每一个单元格的内容
model->setData(model->index(0, 0, QModelIndex()), "张三");
model->setData(model->index(0, 1, QModelIndex()), "男");
model->setData(model->index(0, 2, QModelIndex()), "20");
model->setData(model->index(1, 0, QModelIndex()), "李四");
model->setData(model->index(1, 1, QModelIndex()), "男");
model->setData(model->index(1, 2, QModelIndex()), "30");
///创建视图
QTableView *view1 = new QTableView;
//设置视图, 当关闭主窗口时, 自动释放"view1"子窗口的资源,也会自动删除model的资源
view1->setAttribute(Qt::WA_DeleteOnClose);
//将"视图"添加到多文档中央控件, 也主是将"视图"作为子窗口, 内嵌到主窗口之内
mdiArea->addSubWindow(view1);
view1->setWindowTitle("bbb");//设置子窗口标题
view1->setStyleSheet("background-image: url(3.jpg)");//图片重复铺满
//将存储数据的model保存到view1视图
view1->setModel(model);
view1->show();//显示视图
//activeSubWindow()方法永远返回当前活动的子窗口, 再用 resize()改变当前活动主窗口的大小
mdiArea->activeSubWindow()->resize(width()-100, height()-100);
}
01-3. 创建执行SQL的对话框
效果图:
添加类文件:
1. 右键"项目" ---添加新文件
---C++ ---C++ Class
类名: ScriptDlg
基类: 选择"自定义"
手动输入"QDialog"
scriptdlg.h
#ifndef SCRIPTDLG_H
#define SCRIPTDLG_H
#include <QDialog>
#include <QLabel>
#include <QTextEdit>
#include <QPushButton>
#include <QGridLayout> //网格布局
#include <QHBoxLayout> //水平布局
class ScriptDlg : public QDialog
{
//启动Qt元对象系统的一些特性(比如支持信号和槽等)
Q_OBJECT
public:
// 构造函数, explicit 修饰构造函数, 用于禁止隐式转换
// 参数定义了对话框对象的父窗口部件,默认NULL意味着自定义的对话框没有父窗口部件
explicit ScriptDlg(QWidget *parent = nullptr);
private:
QLabel *label0;
QTextEdit *textEditSQL;//多行文本框
QPushButton *okBtn;//执行按钮
QPushButton *cancelBtn;//取消按钮
//信号
signals:
//槽函数
public slots:
};
#endif // SCRIPTDLG_H
scriptdlg.cpp
#include "scriptdlg.h"
ScriptDlg::ScriptDlg(QWidget *parent) : QDialog(parent)
{
label0 = new QLabel;
label0->setText("请输入SQL");
//创建多选文本框
textEditSQL = new QTextEdit;//多选文本框
//创建按钮
okBtn = new QPushButton;
okBtn->setText("执行");
cancelBtn = new QPushButton;
cancelBtn->setText("取消");
//创建网格布局
QGridLayout *layout1 = new QGridLayout(this);
layout1->addWidget(label0, 0, 0);
layout1->addWidget(textEditSQL, 0, 1);//将'多行文本框'添加到布局
//创建水平布局, 因为要放入网格布局,所以不需要this
QHBoxLayout *layout2 = new QHBoxLayout;
//将"按钮"控件添加到水平布局
layout2->addWidget(okBtn);
layout2->addWidget(cancelBtn);
//将水平布局添加网格布局
layout1->addLayout(layout2, 1, 1);
}
mainwindow.cpp
#include "mainwindow.h"
#include "logindlg.h"
#include "scriptdlg.h"
#include <QMessageBox>
#include <QMdiSubWindow>
#include <QIcon> //窗口图标用到此类
#include <QStandardItemModel> //在内存中建立数据表
#include <QTableView>//显示数据表
/**
* "执行脚本"菜单项的响应槽函数
*/
void MainWindow::on_script()
{
//QMessageBox::information(this, "", "hello world");
// showsub();//调用"显示子窗口"的函数
// showview();//显示数据表格窗口
ScriptDlg dlg; //创建scriptDlg类的实例
dlg.exec(); //显示模式对话框
}
02. 远程登录 mysql
效果图:
cdma.pro 项目配制文件
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# 在windows下引用第三方库的方法
LIBS += -LD:/Program1/mysql-5.7.31/lib -llibmysql
# 在linux下引用第三方库的方法
#LIBS += -lmysqlclient
添加类文件:
1. 右键"项目" ---添加新文件
---C++ ---C++ Class
类名: MyMysql
mymysql.h
#ifndef MYMYSQL_H
#define MYMYSQL_H
//包含SOCKET数据类型, 必须放在包含mysql.h之前
#include <windows.h>
#include "D:/Program1/mysql-5.7.31/include/mysql.h"
class MyMysql
{
public:
MyMysql();
//声明连接函数(远程IP地址, 用户名, 密码, 数据库名)
int sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName);
private:
MYSQL *connection;
MYSQL mysql;
};
#endif // MYMYSQL_H
mymysql.cpp
#include "mymysql.h"
#include <QMessageBox>
MyMysql::MyMysql()
{
//mysql 初始化
mysql_init(&mysql);
connection = nullptr;
}
/**
* @ 连接到 mysql
* @param Hostname 为mysql服务器主机地址
* @param User 为mysql数据库的用户名
* @param Password 为mysql数据库的密码
* @param DBName 为要连接的数据库名称
* @return
*/
int MyMysql::sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName)
{
connection = mysql_real_connect(&mysql, Hostname, User, Password, DBName, 0, nullptr, 0);
if(connection == nullptr)
{
//如果连接失败, 弹出一个消息提示框
QMessageBox::information(nullptr, "", mysql_error(&mysql));
return -1;
}else
{
return 0;
}
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "mymysql.h"
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QCloseEvent>
#include <QMdiArea> //多文档界面中央控件支持
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//重载
void closeEvent(QCloseEvent *event);
private:
MyMysql db;//连接mysql的实例
void createMenus(); //创建菜单的函数
void createAction();//创建菜单项的函数
void showsub();//为"执行脚本"的菜单项, 添加显示子窗口的函数
void showview();//显示'数据表'窗口
mainwindow.cpp
#include "mainwindow.h"
#include "logindlg.h"
#include "scriptdlg.h"
#include <QMessageBox>
#include <QMdiSubWindow>
#include <QIcon> //窗口图标用到此类
#include <QStandardItemModel> //在内存中建立数据表
#include <QTableView>//显示数据表
/**
* "登录"菜单项的响应槽函数
*/
void MainWindow::on_login()
{
// QMessageBox::information(this, "", "hello world");
LoginDlg dlg;//实例化登录对话框
//dlg.show();//产生一个非模式对话框
dlg.exec();//调用exec产生一个模式对话框(不能操作其它的对话框)
//如何在这里获取用户名,密码,IP等用户输入的信息呢?
//QMessageBox::information(this, "用户名", dlg.userid);
//如果标志位为true, 表示用户点击了登录按钮
if(dlg.islogin)
{
MyMysql db;
//连接数据库
int res = db.sql_connect(
dlg.hostip.toStdString().data(), //数据库服务器IP地址
dlg.userid.toStdString().data(), //用户名
dlg.passwd.toStdString().data(), //密码
dlg.dbname.toStdString().data()); //数据库名称
if(res == -1)
{
QMessageBox::information(this, "", "登录失败!");
}else
{
QMessageBox::information(this, "", "登录成功!");
}
}
}
测试:
1. 项目引用本地的"libmysql.dll"库为64位版本, 编译项目时要使用64位编译器
// LIBS += -LD:/Program1/mysql-5.7.31/lib -llibmysql
"D:\Program1\mysql-5.7.31\lib\libmysql.dll"
2. 运行项目 --管理 --登录, 填写相关参数
3. 点击"登录"按钮, 提示登录成功表示程序正常
04. 返回登录mysql的错误信息
效果图:
mymysql.h
#ifndef MYMYSQL_H
#define MYMYSQL_H
//windows 下使用mysql.h的方式
//<windows.h>必须放在包含mysql.h之前
#include <windows.h>
#include "D:/Program1/mysql-5.7.31/include/mysql.h"
//linux 下使用mysql.h的方式
//#include </usr/local/mysql-5.7.38/include/mysql.h>
class MyMysql
{
public:
MyMysql();
//声明连接函数(远程IP地址, 用户名, 密码, 数据库名)
int sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName);
const char *geterror(); //返回错误信息
private:
MYSQL *connection;
MYSQL mysql;
char buf[1024];//用来保存错误信息
};
#endif // MYMYSQL_H
mymysql.cpp
#include "mymysql.h"
#include <QMessageBox>
MyMysql::MyMysql()
{
//mysql 初始化
mysql_init(&mysql);
connection = nullptr;
memset(buf, 0, sizeof(buf));//清空buf
}
/**
* @ 连接到 mysql
* @param Hostname 为mysql服务器主机地址
* @param User 为mysql数据库的用户名
* @param Password 为mysql数据库的密码
* @param DBName 为要连接的数据库名称
* @return
*/
int MyMysql::sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName)
{
connection = mysql_real_connect(&mysql, Hostname, User, Password, DBName, 0, nullptr, 0);
if(connection == nullptr)
{
memset(buf, 0, sizeof(buf)); //清空 buf
strcpy(buf, mysql_error(&mysql));//将错误提示信息保存到buf中
return -1;
}else
{
return 0;
}
}
/**
* @ 返回保存在buf中的错误信息
*/
const char* MyMysql::geterror()
{
return buf;
}
mainwindow.cpp
/**
* "登录"菜单项的响应槽函数
*/
void MainWindow::on_login()
{
// QMessageBox::information(this, "", "hello world");
LoginDlg dlg;//实例化登录对话框
//dlg.show();//产生一个非模式对话框
dlg.exec();//调用exec产生一个模式对话框(不能操作其它的对话框)
//如何在这里获取用户名,密码,IP等用户输入的信息呢?
//QMessageBox::information(this, "用户名", dlg.userid);
//如果标志位为true, 表示用户点击了登录按钮
if(dlg.islogin)
{
//连接数据库
int res = db.sql_connect(
dlg.hostip.toStdString().data(), //数据库服务器IP地址
dlg.userid.toStdString().data(), //用户名
dlg.passwd.toStdString().data(), //密码
dlg.dbname.toStdString().data()); //数据库名称
//连接失败
if(res == -1)
{
// QMessageBox::information(this, "失败", "登录失败!");
//弹出错误提示信息:
QMessageBox::information(this, "失败", db.geterror());
}else
{
QMessageBox::information(this, "成功", "登录成功!");
}
}
}
05-1. 在注销的槽函数中断开mysql连接
mymysql.h
#ifndef MYMYSQL_H
#define MYMYSQL_H
//windows 下使用mysql.h的方式
//<windows.h>必须放在包含mysql.h之前
#include <windows.h>
#include "D:/Program1/mysql-5.7.31/include/mysql.h"
//linux 下使用mysql.h的方式
//#include </usr/local/mysql-5.7.38/include/mysql.h>
class MyMysql
{
public:
MyMysql();
//声明连接函数(远程IP地址, 用户名, 密码, 数据库名)
int sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName);
const char *geterror(); //返回错误信息
void sql_disconnect();//断开mysql连接
private:
MYSQL *connection;
MYSQL mysql;
char buf[1024];//用来保存错误信息
};
#endif // MYMYSQL_H
mymysql.cpp
#include "mymysql.h"
#include <QMessageBox>
MyMysql::MyMysql()
{
//mysql 初始化
mysql_init(&mysql);
connection = nullptr;
memset(buf, 0, sizeof(buf));//清空buf
}
/**
* @ 连接到 mysql
* @param Hostname 为mysql服务器主机地址
* @param User 为mysql数据库的用户名
* @param Password 为mysql数据库的密码
* @param DBName 为要连接的数据库名称
* @return
*/
int MyMysql::sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName)
{
connection = mysql_real_connect(&mysql, Hostname, User, Password, DBName, 0, nullptr, 0);
if(connection == nullptr)
{
memset(buf, 0, sizeof(buf)); //清空 buf
strcpy(buf, mysql_error(&mysql));//将错误提示信息保存到buf中
return -1;
}else
{
return 0;
}
}
/**
* @ 返回保存在buf中的错误信息
*/
const char* MyMysql::geterror()
{
return buf;
}
/**
* @ 断开mysql连接
*/
void MyMysql::sql_disconnect()
{
if(connection)
{
mysql_close(connection);
connection = NULL;
}
}
mainwindow.cpp
/**
* "注销"菜单项的响应槽函数
*/
void MainWindow::on_logout()
{
QMessageBox::StandardButton button;
button = QMessageBox::question(this, "提示", "是否注销",
QMessageBox::Yes | QMessageBox::No);
if(button == QMessageBox::Yes)
{
db.sql_disconnect();//断开mysql连接
scriptAction->setEnabled(false);//设置"执行脚本"菜单项为"不可用状态"
}
}
05-2. 执行"增删改"SQL语句
mymysql.h
#ifndef MYMYSQL_H
#define MYMYSQL_H
//windows 下使用mysql.h的方式
//<windows.h>必须放在包含mysql.h之前
#include <windows.h>
#include "D:/Program1/mysql-5.7.31/include/mysql.h"
//linux 下使用mysql.h的方式
//#include </usr/local/mysql-5.7.38/include/mysql.h>
#include <QStandardItemModel>
class MyMysql
{
public:
MyMysql();
//声明连接函数(远程IP地址, 用户名, 密码, 数据库名)
int sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName);
const char *geterror(); //返回错误信息
void sql_disconnect();//断开mysql连接
//执行"增删改"的SQL语句
int sql_exec(const char *SQL);
//执行查询的SQL语句
int sql_open(const char *SQL, QStandardItemModel **p);
private:
MYSQL *connection;
MYSQL mysql;
char buf[1024];//用来保存错误信息
};
#endif // MYMYSQL_H
mymysql.cpp
#include "mymysql.h"
#include <QMessageBox>
MyMysql::MyMysql()
{
//mysql 初始化
mysql_init(&mysql);
connection = nullptr;
memset(buf, 0, sizeof(buf));//清空buf
}
/**
* @ 连接到 mysql
* @param Hostname 为mysql服务器主机地址
* @param User 为mysql数据库的用户名
* @param Password 为mysql数据库的密码
* @param DBName 为要连接的数据库名称
* @return
*/
int MyMysql::sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName)
{
connection = mysql_real_connect(&mysql, Hostname, User, Password, DBName, 0, nullptr, 0);
if(connection == nullptr)
{
memset(buf, 0, sizeof(buf)); //清空 buf
strcpy(buf, mysql_error(&mysql));//将错误提示信息保存到buf中
return -1;
}else
{
//连接mysql成功, 设置数据库的字符集
mysql_query(connection, "set names utf8");
return 0;
}
}
/**
* @ 返回保存在buf中的错误信息
*/
const char* MyMysql::geterror()
{
return buf;
}
/**
* @ 断开mysql连接
*/
void MyMysql::sql_disconnect()
{
if(connection)
{
mysql_close(connection);
connection = nullptr;
}
}
/**
* @ 执行查询的SQL语句
*/
int MyMysql::sql_exec(const char *SQL)
{
if (mysql_query(connection, SQL) != 0)
{
memset(buf, 0, sizeof(buf));
strcpy(buf, mysql_error(&mysql));
return -1;
}
return 0;
}
mainwindow.cpp
/**
* "执行脚本"菜单项的响应槽函数
*/
void MainWindow::on_script()
{
//QMessageBox::information(this, "", "hello world");
// showsub();//调用"显示子窗口"的函数
// showview();//显示数据表格窗口
ScriptDlg dlg; //创建scriptDlg类的实例
// dlg.exec(); //显示模式对话框
// db.sql_exec() 执行SQL的"增删改"语句
if(db.sql_exec("delete from table1 where name='张三'") == -1)
{
QMessageBox::information(this, "sql_exec()失败!", db.geterror());
}else
{
QMessageBox::information(this, "执行成功", "执行成功!");
}
}
05-3. 执行"脚本对话框"中, 用户输入的SQL语句
效果图:
update table1 set age=88 where name='李四';
scriptdlg.h
#ifndef SCRIPTDLG_H
#define SCRIPTDLG_H
#include <QDialog>
#include <QLabel>
#include <QTextEdit>
#include <QPushButton>
#include <QGridLayout> //网格布局
#include <QHBoxLayout> //水平布局
class ScriptDlg : public QDialog
{
//启动Qt元对象系统的一些特性(比如支持信号和槽等)
Q_OBJECT
public:
// 构造函数, explicit 修饰构造函数, 用于禁止隐式转换
// 参数定义了对话框对象的父窗口部件,默认NULL意味着自定义的对话框没有父窗口部件
explicit ScriptDlg(QWidget *parent = nullptr);
QString SQL; //保存用户输入的SQL语句
bool islogin; //用户是否登录mysql的标志
private:
QLabel *label0;
QTextEdit *textEditSQL; //多行文本框
QPushButton *okBtn; //"执行"按钮
QPushButton *cancelBtn; //"取消"按钮
//信号
signals:
//槽函数
public slots:
void okBtnOnclick(); //"执行"按钮的槽函数
void cancelBtnOnclick(); //"取消"按钮的槽函数
};
#endif // SCRIPTDLG_H
scriptdlg.cpp
#include "scriptdlg.h"
ScriptDlg::ScriptDlg(QWidget *parent) : QDialog(parent)
{
label0 = new QLabel;
label0->setText("请输入SQL");
//创建多选文本框
textEditSQL = new QTextEdit;//多选文本框
//创建按钮
okBtn = new QPushButton;
okBtn->setText("执行");
cancelBtn = new QPushButton;
cancelBtn->setText("取消");
//创建网格布局
QGridLayout *layout1 = new QGridLayout(this);
layout1->addWidget(label0, 0, 0);
layout1->addWidget(textEditSQL, 0, 1);//将'多行文本框'添加到布局
//创建水平布局, 因为要放入网格布局,所以不需要this
QHBoxLayout *layout2 = new QHBoxLayout;
//将"按钮"控件添加到水平布局
layout2->addWidget(okBtn);
layout2->addWidget(cancelBtn);
//将水平布局添加网格布局
layout1->addLayout(layout2, 1, 1);
//为按钮关联槽函数
connect(okBtn, SIGNAL(clicked()), this, SLOT(okBtnOnclick()));
connect(cancelBtn, SIGNAL(clicked()), this, SLOT(cancelBtnOnclick()));
}
/**
* @ "执行"按钮的槽函数
*/
void ScriptDlg::okBtnOnclick()
{
//保存用户输入的SQL语句
SQL = textEditSQL->toPlainText();
islogin = true;//设置用户登录状态
close();//关闭脚本窗口
}
/**
* @ "取消"按钮的槽函数
*/
void ScriptDlg::cancelBtnOnclick()
{
close();//关闭脚本窗口
}
mainwindow.cpp
/**
* "执行脚本"菜单项的响应槽函数
*/
void MainWindow::on_script()
{
//QMessageBox::information(this, "", "hello world");
// showsub();//"显示子窗口"的函数
// showview();//显示数据表格窗口
ScriptDlg dlg; //创建scriptDlg类的实例
dlg.exec(); //显示模式对话框
// db.sql_exec() 执行SQL的"增删改"语句
if(db.sql_exec(dlg.SQL.toStdString().data()) == -1)
{
QMessageBox::information(this, "sql_exec()失败!", db.geterror());
}else
{
QMessageBox::information(this, "执行成功", "执行成功!");
}
}
06-1. 程序优化
mainwindow.cpp
1. 在"未登录"状态下, 将"执行脚本"菜单项设置为"不可用"状态
/**
* 创建菜单项
*/
void MainWindow::createAction()
{
///"数据"菜单的菜单项
//创建"执行脚本"菜单项
scriptAction = new QAction(tr("执行脚本"), this);
scriptAction->setShortcut(tr("Ctrl+t"));//快捷键
scriptAction->setEnabled(false);//将"执行脚本"菜单项设置为"不可用"状态
//为"执行脚本"菜单项关联槽函数
connect(scriptAction, SIGNAL(triggered()), this, SLOT(on_script()));
}
2. 登录成功, 将"执行脚本"菜单项设置为"可用状态"
/**
* "登录"菜单项的响应槽函数
*/
void MainWindow::on_login()
{
//连接失败
if(res == -1)
{
// QMessageBox::information(this, "失败", "登录失败!");
//弹出错误提示信息:
QMessageBox::information(this, "失败", db.geterror());
}else
{
QMessageBox::information(this, "成功", "登录成功!");
scriptAction->setEnabled(true); //登录成功, 将"执行脚本"菜单项设置为可用状态
}
}
3. 用户注销后, 将"执行脚本"菜单项设置为"不可用状态"
/**
* "注销"菜单项的响应槽函数
*/
void MainWindow::on_logout()
{
QMessageBox::StandardButton button;
button = QMessageBox::question(this, "提示", "是否注销",
QMessageBox::Yes | QMessageBox::No);
if(button == QMessageBox::Yes)
{
db.sql_disconnect();//断开mysql连接
scriptAction->setEnabled(false);//设置"执行脚本"菜单项为"不可用状态"
}
}
在"执行脚本"对话框中, 增加是否点击了"执行按钮"的状态标志
scriptdlg.h
class ScriptDlg : public QDialog
{
//启动Qt元对象系统的一些特性(比如支持信号和槽等)
Q_OBJECT
public:
// 构造函数, explicit 修饰构造函数, 用于禁止隐式转换
// 参数定义了对话框对象的父窗口部件,默认NULL意味着自定义的对话框没有父窗口部件
explicit ScriptDlg(QWidget *parent = nullptr);
QString SQL; //保存用户输入的SQL语句
bool islogin; //用户是否登录mysql的状态
scriptdlg.cpp
1. 在构造函数中, 初始化"状态"为false
ScriptDlg::ScriptDlg(QWidget *parent) : QDialog(parent)
{
islogin = false;//初始化状态为false
}
2. 用户点击"执行"按钮后, 设置"状态"为true
void ScriptDlg::okBtnOnclick()
{
//保存用户输入的SQL语句
SQL = textEditSQL->toPlainText();
islogin = true;//表示用户点击了执行按钮
close();//关闭脚本窗口
}
mainwindow.cpp
/**
* "执行脚本"菜单项的响应槽函数
*/
void MainWindow::on_script()
{
//QMessageBox::information(this, "", "hello world");
// showsub();//调用"显示子窗口"的函数
// showview();//显示数据表格窗口
ScriptDlg dlg; //创建scriptDlg类的实例
dlg.exec(); //显示模式对话框
//如果用户点击了"执行"按钮, 才执行SQL语句
if(dlg.islogin)
{
// db.sql_exec() 执行SQL的"增删改"语句
if(db.sql_exec(dlg.SQL.toStdString().data()) == -1)
{
QMessageBox::information(this, "sql_exec()失败!", db.geterror());
}else
{
QMessageBox::information(this, "执行成功", "执行成功!");
}
}
}
06-2. 执行"查询"的SQL语句
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//重载
void closeEvent(QCloseEvent *event);
private:
MyMysql db;//连接mysql的实例
void createMenus(); //创建菜单的函数
void createAction();//创建菜单项的函数
void showsub();//为"执行脚本"的菜单项, 添加显示子窗口的函数
void showview();//显示'数据表'窗口
void script_msg(const char *SQL);//执行SQL的函数
mainwindow.cpp
/**
* "执行脚本"菜单项的响应槽函数
*/
void MainWindow::on_script()
{
//QMessageBox::information(this, "", "hello world");
// showsub();//调用"显示子窗口"的函数
// showview();//显示数据表格窗口
ScriptDlg dlg; //创建scriptDlg类的实例
dlg.exec(); //显示模式对话框
if(dlg.islogin) //如果用户点击了"执行"按钮
{
//调用执行SQL的函数
script_msg(dlg.SQL.toStdString().data());
}
}
/**
* @ 调用执行SQL的函数
*/
void MainWindow::script_msg(const char *SQL)
{
int res = 0;
//判断SQL语句是否以"select"开头
if ((strncmp(SQL, "SELECT", 6) == 0) || (strncmp(SQL, "select", 6) == 0))
{
QStandardItemModel *modul = nullptr;
//如果是SELECT,那么执行sql_open这个函数
res = db.sql_open(SQL, &modul);
QTableView *view1 = new QTableView;
//view在close的时候自动会delete,这个时候如果view有modul的话,这个modul会被view自动释放。
view1->setAttribute(Qt::WA_DeleteOnClose);
//将"view1"子窗口添加到多文档中央控件, 实现多文档界面, 其实就是子窗口被"内嵌"在主窗口内的效果
mdiArea->addSubWindow(view1);
view1->setStyleSheet("border-image: url(./images/3.jpg);");//设置widget背景图片
//将modul保存到view1,如果没有modul,那么view不会显示任何数据.
view1->setModel(modul);
view1->show(); //显示子窗口
//"多文档中央控件"设置窗口尺寸
mdiArea->activeSubWindow()->resize(width() - 100, height() - 100);
}else
{
//如果用户执行的不是select语句, 那么执行sql_exec函数
res = db.sql_exec(SQL);
}
//判断执行结果
if (res == -1)
{
QMessageBox::information(this, "执行失败", db.geterror());
}else
{
QMessageBox::information(this, "提示", "执行成功");
}
}
mymysql.h
#ifndef MYMYSQL_H
#define MYMYSQL_H
//windows 下使用mysql.h的方式
//<windows.h>必须放在包含mysql.h之前
#include <windows.h>
#include "D:/Program1/mysql-5.7.31/include/mysql.h"
//linux 下使用mysql.h的方式
//#include </usr/local/mysql-5.7.38/include/mysql.h>
#include <QStandardItemModel>
class MyMysql
{
public:
MyMysql();
//声明连接函数(远程IP地址, 用户名, 密码, 数据库名)
int sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName);
const char *geterror(); //返回错误信息
void sql_disconnect();//断开mysql连接
//执行"增删改"的SQL语句
int sql_exec(const char *SQL);
//执行查询的SQL语句
int sql_open(const char *SQL, QStandardItemModel **p);
private:
MYSQL *connection;
MYSQL mysql;
char buf[1024];//用来保存错误信息
};
#endif // MYMYSQL_H
mymysql.cpp
#include "mymysql.h"
#include <QMessageBox>
MyMysql::MyMysql()
{
//mysql 初始化
mysql_init(&mysql);
connection = nullptr;
memset(buf, 0, sizeof(buf));//清空buf
}
/**
* @ 连接到 mysql
* @param Hostname 为mysql服务器主机地址
* @param User 为mysql数据库的用户名
* @param Password 为mysql数据库的密码
* @param DBName 为要连接的数据库名称
* @return
*/
int MyMysql::sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName)
{
connection = mysql_real_connect(&mysql, Hostname, User, Password, DBName, 0, nullptr, 0);
if(connection == nullptr)
{
memset(buf, 0, sizeof(buf)); //清空 buf
strcpy(buf, mysql_error(&mysql));//将错误提示信息保存到buf中
return -1;
}else
{
//连接mysql成功, 设置数据库的字符集
mysql_query(connection, "set names utf8");
return 0;
}
}
/**
* @ 返回保存在buf中的错误信息
*/
const char* MyMysql::geterror()
{
return buf;
}
/**
* @ 断开mysql连接
*/
void MyMysql::sql_disconnect()
{
if(connection)
{
mysql_close(connection);
connection = nullptr;
}
}
/**
* @ 执行"增删改"的SQL语句
*/
int MyMysql::sql_exec(const char *SQL)
{
if (mysql_query(connection, SQL) != 0)
{
memset(buf, 0, sizeof(buf));
strcpy(buf, mysql_error(&mysql));
return -1;
}
return 0;
}
/**
* @ 执行查询的SQL语句
*/
int MyMysql::sql_open(const char *SQL, QStandardItemModel **p)
{
// 如果执行失败
if (mysql_query(connection, SQL) != 0)
{
memset(buf, 0, sizeof(buf));
strcpy(buf, mysql_error(&mysql));
return -1;
}
// 执行成功
// 获取查询的结果集
MYSQL_RES *result = mysql_store_result(connection);
if (result == nullptr)//没有查询到结果
{
memset(buf, 0, sizeof(buf));
strcpy(buf, mysql_error(&mysql));
return -1;
}
//获取结果集的行数, static_cast<int>() 将longlong转int类型
int rowcount = static_cast<int>(mysql_affected_rows(connection));
//获取结果集的列数
int fieldcount = static_cast<int>(mysql_field_count(connection));
//根据SQL语句返回的行列总数,动态的建一个model.
*p = new QStandardItemModel(rowcount, fieldcount);
MYSQL_FIELD *field;
int i = 0;
int j = 0;
//遍历列, 设置model的数据头
for(i = 0;i<fieldcount;i++)
{
//获取每一列
field = mysql_fetch_field(result);
//QMessageBox::information(nullptr, "", field->name);//显示表字段名称
//设置model数据表的字段名称
(*p)->setHeaderData(i, Qt::Horizontal, field->name);
}
//二维遍历, 设置model的数据体
for(i = 0;i<rowcount;i++)
{
//获取每一行
MYSQL_ROW row = mysql_fetch_row(result);
//遍历列
for(j = 0;j<fieldcount;j++)
{
//显示每一行每一列的数据
//QMessageBox::information(nullptr, "", row[j]);
//保存数据到model的数据体
(*p)->setData((*p)->index(i, j, QModelIndex()), row[j]);
}
}
//释放通过mysql_store_result函数分配的内存空间
mysql_free_result(result);
return 0;
}
测试:
1. 打开VM虚拟机, 启动"数据库"服务器
2. 运行程序, 连接mysql数据库
菜单栏 --管理 --登录
3. 登录成功后, 执行SQL查询语句
菜单栏 --数据 --执行脚本
select * from table1;