


#ifndef QT_SERVER_H
#define QT_SERVER_H
#include
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Qt_Server; }
QT_END_NAMESPACE
class Qt_Server : public QWidget
{
Q_OBJECT
public:
Qt_Server(QWidget *parent = nullptr);
~Qt_Server();
private slots:
void on_startBtn_clicked();
public slots:
// 自定义的 处理连接的槽函数声明
void newConnection_slot();
// 自定义的 处理接收数据的槽函数声明
void readyRead_slot();
private:
Ui::Qt_Server *ui;
QTcpServer *server;
QList<QTcpSocket *> socketList;
};
#endif // QT_SERVER_H
#include "qt_server.h"
#include "ui_qt_server.h"
Qt_Server::Qt_Server(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Qt_Server)
{
ui->setupUi(this);
// 给服务器指针创建空间
server = new QTcpServer(this);
// socketList = new QList<>();
}
Qt_Server::~Qt_Server()
{
delete ui;
}
// 点击启动服务器按钮对应的槽函数实现
void Qt_Server::on_startBtn_clicked()
{
if(ui->startBtn->text() == "启动服务器"){
// 获取UI界面上输入的端口号
quint16 port = ui->portEdit->text().toUInt();
// 使服务器进入监听状态,返回值是bool类型
if(server->listen(QHostAddress::Any,port)){
QMessageBox::information(this,"提示","服务器启动成功");
}else{
QMessageBox::critical(this,"错误","服务器启动失败");
}
// 此时服务器已经进入监听状态,如果有客户端发来链接请求,
// 则服务器会自动发射一个newConnection信号,需要将该信号连接到自定义的槽函数中处理连接的套接字
connect(server, &QTcpServer::newConnection, this, &Qt_Server::newConnection_slot);
ui->startBtn->setText("已启动服务器");
ui->startBtn->setStyleSheet("background-color:green");
}else{
server->close();
disconnect(server, &QTcpServer::newConnection, this, &Qt_Server::newConnection_slot);
ui->startBtn->setStyleSheet("background-color:white");
ui->startBtn->setText("启动服务器");
}
}
// 自定义的 处理连接的槽函数声明
void Qt_Server::newConnection_slot()
{
qDebug() << "有新客户的连接";
// 获取最新连接的客户端套接字,并放入容器中,此时客户端与服务器已经建立起连接
QTcpSocket *s = server->nextPendingConnection();
socketList.push_back(s);
// 如果有客户端发送数据,那么此客户端就会自动发射readyRead信号
// 需要将该信号与自定义的处理接收数据的槽函数连接
connect(s, &QTcpSocket::readyRead, this, &Qt_Server::readyRead_slot);
}
// 自定义的 处理接收数据的槽函数实现
void Qt_Server::readyRead_slot()
{
// 移除无效的客户端
// 遍历所有的客户端
for(int i=0; i<socketList.count(); i++){
// 判断每个客户端的状态,返回值是枚举类型
// socketList.at(i)->state();
if(0 == socketList.at(i)->state()){
// 移除当前客户端,通过下标删除
socketList.removeAt(i);
}
}
// 遍历容器,找到有需要读取数据的客户端
for(int i=0; i<socketList.count(); i++){
// 如果当前客户端的 有效字节数 不为0,代表当前客户端有需要读取的数据
if(0 != socketList.at(i)->bytesAvailable()){
// 读取客户端中的数据
QByteArray msg = socketList.at(i)->readAll();
// 将读取的数据放到UI界面上
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
// 将数据发送给所有客户端
for (int j=0; j<socketList.count(); j++) {
socketList.at(i)->write(msg);
}
}
}
}
#include "qt_server.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Qt_Server w;
w.show();
return a.exec();
}

#ifndef QT_CLIENT_H
#define QT_CLIENT_H
#include
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Qt_Client; }
QT_END_NAMESPACE
class Qt_Client : public QWidget
{
Q_OBJECT
public:
Qt_Client(QWidget *parent = nullptr);
~Qt_Client();
public slots:
void connected_slot();
void readyRead_slot();
private slots:
void on_connectBtn_clicked();
void on_msgBtn_clicked();
void on_disconnectBtn_clicked();
private:
Ui::Qt_Client *ui;
// 定一个客户端对象
QTcpSocket *socket;
// 定义一个用户名变量
QString uname;
};
#endif // QT_CLIENT_H
#include "qt_client.h"
#include "ui_qt_client.h"
Qt_Client::Qt_Client(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Qt_Client)
{
ui->setupUi(this);
// 给客户端对象创建空间
socket = new QTcpSocket(this);
// 初始化UI界面的组件状态
ui->msgEdit->setEnabled(false);
ui->msgBtn->setEnabled(false);
ui->disconnectBtn->setEnabled(false);
}
Qt_Client::~Qt_Client()
{
delete ui;
}
void Qt_Client::connected_slot()
{
// 告诉服务器我进来了
QString msg = uname + " 来了,快接驾";
// 将这个消息发送给服务器
socket->write(msg.toLocal8Bit());
// 此时说明服务器与客户端已经建立连接
// 现在将UI界面的组件状态修改一下
ui->msgEdit->setEnabled(true);
ui->msgBtn->setEnabled(true);
ui->disconnectBtn->setEnabled(true);
ui->unameEdit->setEnabled(false);
ui->ipEdit->setEnabled(false);
ui->portEdit->setEnabled(false);
ui->connectBtn->setEnabled(false);
// 如果服务器发来数据,客户端会自动发射readyRead信号
// 因此需要将readyRead信号连接到自定义的槽函数
// 因为只需要连接一次,所以也是该在构造函数中写连接函数
connect(socket, &QTcpSocket::readyRead, this, &Qt_Client::readyRead_slot);
}
void Qt_Client::readyRead_slot()
{
// 走到了这一步,说明服务器给客户端发送了消息,现在需要进行读取
QByteArray msg = socket->readAll();
// 将这个数据放到UI界面的消息显示框中
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}
// 连接服务器按钮 对应的槽函数
void Qt_Client::on_connectBtn_clicked()
{
// 获取UI界面的IP和PORT,还有uname
QString ip = ui->ipEdit->text();
quint16 port = ui->portEdit->text().toUInt();
uname = ui->unameEdit->text();
// 使客户端连接服务器
socket->connectToHost(ip, port);
// 判断客户端是否成功连接服务器,成功则客户端会自动发射connected信号
// 将该信号连接到自定义的槽函数中
// 因为只需要连接一次,所以连接函数应该写在构造函数中
connect(socket, &QTcpSocket::connected, this, &Qt_Client::connected_slot);
}
void Qt_Client::on_msgBtn_clicked()
{
// 获取UI界面上输入的内容
QString msg = uname + " : " + ui->msgEdit->toPlainText();
// 将消息发送给服务器
socket->write(msg.toLocal8Bit());
}
void Qt_Client::on_disconnectBtn_clicked()
{
QString msg = uname + " 走咯,我还会再回来的";
// 将消息发送给服务器
socket->write(msg.toLocal8Bit());
// 断开链接
socket->close();
disconnect(socket, &QTcpSocket::readyRead, this, &Qt_Client::readyRead_slot);
disconnect(socket, &QTcpSocket::connected, this, &Qt_Client::connected_slot);
// 更改UI界面的组件状态
ui->msgEdit->setEnabled(false);
ui->msgBtn->setEnabled(false);
ui->disconnectBtn->setEnabled(false);
ui->unameEdit->setEnabled(true);
ui->ipEdit->setEnabled(true);
ui->portEdit->setEnabled(true);
ui->connectBtn->setEnabled(true);
}
#include "qt_client.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Qt_Client w;
w.show();
return a.exec();
}
1. 添加数据库:[static] QSqlDatabase QSqlDatabase::addDatabase(QSqlDriver *driver, const QString &connectionName = QLatin1String(defaultConnection))
QSQLITE SQLite version 3 or above
2. 设置数据库名称:void QSqlDatabase::setDatabaseName(const QString &name)
3. 包含数据库:bool QSqlDatabase::contains(const QString &connectionName = QLatin1String(defaultConnection))
4. 打开数据库:bool QSqlDriver::open(const QString &db)
5. 关闭数据库:void QSqlDatabase::close()
6. 错误信息:QSqlError QSqlDatabase::lastError()
7. sql语句执行:构造一个QSqlQuery类对象,调用其成员函数exec,执行sql语句:bool QSqlQuery::exec(const QString &query)
8. bool QSqlQuery::next():遍历查询结果的函数

#ifndef DATABASE_H
#define DATABASE_H
#include
#include // 数据库管理类
#include // 数据库操作类
#include // 数据库记录类
#include // 数据库错误类
#include // 消息对话框类
#include
QT_BEGIN_NAMESPACE
namespace Ui { class DataBase; }
QT_END_NAMESPACE
class DataBase : public QWidget
{
Q_OBJECT
public:
DataBase(QWidget *parent = nullptr);
~DataBase();
private slots:
void on_addBtn_clicked();
void on_showAllEdit_clicked();
void on_showEdit_clicked();
void on_deleteBtn_clicked();
void on_deleteAllBtn_clicked();
private:
Ui::DataBase *ui;
// 实例化一个数据库对象
QSqlDatabase db;
};
#endif // DATABASE_H
#include "database.h"
#include "ui_database.h"
DataBase::DataBase(QWidget *parent)
: QWidget(parent)
, ui(new Ui::DataBase)
{
ui->setupUi(this);
// 判断数据库是否存在
if(!db.contains())
{
// 不存在,则创建数据库
db = QSqlDatabase::addDatabase("QSQLITE"); // 表示数据库驱动为sqlite3
// 给刚创建的数据库起名
db.setDatabaseName("stuInfo.db");
// 提示用户:数据库创建成功
QMessageBox::information(this,"提示","数据库创建成功");
}
// 打开数据库
if(!db.open()){
QMessageBox::critical(this,"错误","数据库无法打开");
return;
}
// 创建数据库表
QSqlQuery table;
// Sql语句
QString sql = "create table if not exists stu_info_table("
"id integer primary key autoincrement,"
"numb integer,"
"name varchar(20),"
"sex varchar(4),"
"score integer);";
if(table.exec(sql)){
QMessageBox::information(this,"提示","数据库学生表创建成功");
}else{
QMessageBox::critical(this,"错误","数据库学生表创建失败");
}
}
DataBase::~DataBase()
{
delete ui;
}
// 添加
void DataBase::on_addBtn_clicked()
{
// 获取UI界面上的信息
int num = ui->numEdit->text().toUInt();
QString name = ui->nameEdit->text();
QString sex = ui->sexEdit->text();
int score = ui->scoreEdit->text().toUInt();
// 保证用户输入完整信息
if(num == 0 || name.isEmpty() || sex.isEmpty() || score == 0){
QMessageBox::warning(this,"警告","请完善信息");
return;
}
// 将信息存放到数据库学生表中
QSqlQuery query;
// SQL语句
QString sql = QString("insert into stu_info_table (numb, name, sex, score) "
"values(%1,'%2','%3',%4)")
.arg(num).arg(name).arg(sex).arg(score);
// 执行SQL语句
if(query.exec(sql)){
QMessageBox::information(this,"提示","数据添加成功");
}else{
QMessageBox::critical(this,"错误","数据添加失败");
}
DataBase::on_showAllEdit_clicked();
}
// 查看所有
void DataBase::on_showAllEdit_clicked()
{
ui->tableWidget->clear();
// 将信息存放到数据库学生表中
QSqlQuery query;
// SQL语句
QString sql = QString("select * from stu_info_table");
// 执行SQL语句
if(query.exec(sql)){
// 将数据库的内容放到UI界面上
int i = 0; // 记录行号
// 用next()遍历
while (query.next()) {
for(int j=0; j<query.record().count(); j++){
ui->tableWidget->setItem(i,j,new QTableWidgetItem(query.value(j+1).toString()));
}
i++;
}
}
}
// 查询某个学生
void DataBase::on_showEdit_clicked()
{
QString name = ui->nameEdit_2->text();
if(name.isEmpty()){
QMessageBox::information(this, "提示", "请输入要查询的学生姓名");
return;
}
ui->tableWidget->clear();
QSqlQuery query;
QString sql = QString("select * from stu_info_table where name='%1';").arg(name);
if(query.exec(sql)){
int i=0;
while (query.next()) {
// qDebug() << i;
for(int j=0; j<query.record().count(); j++){
ui->tableWidget->setItem(i, j, new QTableWidgetItem(query.value(j+1).toString()));
}
i++;
}
}else{
QMessageBox::warning(this, "警告", "查询错误");
return;
}
}
void DataBase::on_deleteBtn_clicked()
{
QString name = ui->nameEdit_2->text();
if(name.isEmpty()){
QMessageBox::information(this, "提示", "请输入要删除的学生姓名");
return ;
}
QString sql = QString("delete from stu_info_table where name='%1';").arg(name);
QSqlQuery query;
if(query.exec(sql)){
QMessageBox::information(this, "提示", "删除成功");
DataBase::on_showAllEdit_clicked();
}else{
QMessageBox::warning(this, "警告", "删除失败");
DataBase::on_showAllEdit_clicked();
}
return ;
}
void DataBase::on_deleteAllBtn_clicked()
{
QString sql = QString("delete from stu_info_table");
QSqlQuery query;
if(query.exec(sql)){
QMessageBox::information(this, "提示", "删除成功");
DataBase::on_showAllEdit_clicked();
}else{
QMessageBox::warning(this, "警告", "删除失败");
DataBase::on_showAllEdit_clicked();
}
ui->tableWidget->clear();
return ;
}
#include "database.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
DataBase w;
w.show();
return a.exec();
}