目录
技术路线
效果展示
程序主体
sqoperator.h
mylogin.h
myenroll.h
chatinterface.h
tips.h
myapp.h
*******************
sqoperator.cpp
mylogin.cpp
myenroll.cpp
chatinterface.cpp
tips.cpp
myapp.cpp
main.cpp
widget.h
widget.cpp
main.cpp
QT程序设计、sqlite数据库调用、TCP/IP客户端与服务端的搭建
通过次程序代码,可以学习如何使用纯代码设计界面(非UI),了解如何通过QT调用sqlite数据库,以及如何使用TCP/IP协议简单地搭建客户端与服务端。 此项目中的界面主要做的有两个,一个登录界面,一个聊天消息收发界面,登录界面有登录和注册,通过创建数据库,调用数据库中的数据进行判断,程序实现对数据库中的资源进行增删改查。在界面跳转方面,通过QT独有的信号和槽机制,进行设计,此项目主要在登录界面和消息交互界面设计了界面的跳转。至于客户端和服务端的搭建,是本项目主要需要实现的地方,通过ip地址和端口号,进行,各个客户端之间的通信,数据先通过客户端发往服务端,再由服务端发往客户端,可以实现多个客户端的并发通信,只需要将服务端开启即可。
这是对数据库的封装,其中有部分封装本项目没用到
#ifndef SQLITEOPERATOR_H
#define SQLITEOPERATOR_H
#include
#include
#include
#include
#include
typedef struct
{
QString usrname;
QString usrpass;
}info;
//结构体用于存放用户名和密码
class SqOperator : public QWidget
{
Q_OBJECT
public:
explicit SqOperator(QWidget *parent = nullptr);
// 打开数据库
bool openDb(void);
// 创建数据表
void createTable(void);
// 判断数据表是否存在
bool isTableExist(QString& tableName);
// 查询全部数据
void queryTable(QList &list);
// 插入数据
bool singleInsertData(info &singleData); // 插入单条数据
void moreInsertData(QList &moreData); // 插入多条数据
// 修改数据
void modifyData(QString usrname,QString usrpass);
// 删除数据
void deleteData(QString usrname);
//删除数据表
void deleteTable(QString& tableName);
// 关闭数据库
void closeDb(void);
private:
QSqlDatabase database;// 用于建立和数据库的连接
};
#endif // SQLITEOPERATOR_H
#ifndef MYLOGIN_H
#define MYLOGIN_H
#include
#include
#include
#include
#include
#include
#include
class mylogin : public QDialog
{
Q_OBJECT
public:
mylogin(QWidget *parent = nullptr);
~mylogin();
void init_ui();
QLabel *lb1;
QLabel *lb2;
QLabel *lb3;
QPushButton *bnt_login;
QPushButton *bnt_register;
QLineEdit *usr_name_le;
QLineEdit *usr_pass_le;
QHBoxLayout *hb1;
QHBoxLayout *hb2;
QHBoxLayout *hb3;
QVBoxLayout *vb1;
signals:
void sig_login(QString usrname, QString usrpass); //自定义的登录信号,发给myapp
void sig_enroll(); //自定义的注册信号,发给myapp
public slots:
void do_login(); //为关联按键和信号发射所设的槽函数
void do_enroll();
};
#endif // MYLOGIN_H
#ifndef MYENROLL_H
#define MYENROLL_H
#include
#include
#include
#include
#include
#include
#include
class myenroll : public QWidget
{
Q_OBJECT
public:
explicit myenroll(QWidget *parent = nullptr);
void init_ui();
QLineEdit * name;
QLineEdit * pass;
QLabel * lb1;
QLabel * lb2;
QPushButton * bnt1;
QHBoxLayout * hb1;
QHBoxLayout * hb2;
QHBoxLayout * hb3;
QVBoxLayout * vb1;
signals:
void sig_enroll_info(QString usrname, QString usrpass); //自定义的注册信号,发送给myapp
public slots:
void send_msg(); //为注册信号所设置的槽函数
};
#endif // MYENROLL_H
#ifndef CHATINTERFACE_H
#define CHATINTERFACE_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "mylogin.h"
class chatInterface : public QWidget
{
Q_OBJECT
public:
explicit chatInterface(QWidget *parent = nullptr);
void init();
QLabel * lb1;
QLineEdit * le1;
QTextEdit * te1;
QPushButton * bnt1;
QHBoxLayout * hb1;
QVBoxLayout * vb1;
mylogin * login;
QTcpSocket * mysock;
signals:
public slots:
void connect_success_msg();
void recv_msg_slots();
void send_msg_slots();
};
#endif // CHATINTERFACE_H
#ifndef TIPS_H
#define TIPS_H
#include
#include
class tips : public QWidget
{
Q_OBJECT
public:
explicit tips(QWidget *parent = nullptr);
void loginfail();
void insertok();
signals:
public slots:
};
#endif // TIPS_H
#ifndef MYAPP_H
#define MYAPP_H
#include
#include
#include
#include "mylogin.h"
#include "myenroll.h"
#include "tips.h"
#include "chatinterface.h"
#include "sqoperator.h"
class myapp : public QObject
{
Q_OBJECT
public:
explicit myapp(QObject *parent = nullptr);
SqOperator *mydb; //数据库类
mylogin * login;
myenroll * enroll;
tips * tip;//提示信息类
chatInterface *face;//主界面信息类
signals:
public slots:
bool judge(QString usrname, QString usrpass);
void show_enroll_face();
void insertdb(QString usrname,QString usrpass);
};
#endif // MYAPP_H
#include "sqoperator.h"
SqOperator::SqOperator(QWidget *parent) : QWidget(parent)
{
if (QSqlDatabase::contains("qt_sql_default_connection"))
{
database = QSqlDatabase::database("qt_sql_default_connection");
}
else
{
// 建立和SQlite数据库的连接
database = QSqlDatabase::addDatabase("QSQLITE");
// 设置数据库文件的名字
database.setDatabaseName("chatapp.db");
}
}
// 打开数据库
bool SqOperator::openDb()
{
if (!database.open())
{
qDebug() << "Error: Failed to connect database." << database.lastError();
return false;
}
else
{
qDebug() <<"open database success";
}
return true;
}
// 创建数据表
void SqOperator::createTable()
{
// 用于执行sql语句的对象
QSqlQuery sqlQuery;
// 构建创建数据库的sql语句字符串
QString createSql = QString("CREATE TABLE if not exists idinfo(usrname TEXT PRIMARY KEY ,usrpass TEXT NOT NULL)");
sqlQuery.prepare(createSql);
// 执行sql语句
if(!sqlQuery.exec())
{
qDebug() << "Error: Fail to create table. " << sqlQuery.lastError();
}
else
{
qDebug() << "Table created!";
}
}
// 判断数据库中某个数据表是否存在
bool SqOperator::isTableExist(QString& tableName)
{
QSqlDatabase database = QSqlDatabase::database();
if(database.tables().contains(tableName))
{
return true;
}
return false;
}
// 查询全部数据,这里需要改造一下,我们传入一个空容器,然后,把数据弄出去
void SqOperator::queryTable(QList &list)
{
QSqlQuery sqlQuery;
sqlQuery.exec("SELECT * FROM idinfo");
if(!sqlQuery.exec())
{
qDebug() << "Error: Fail to query table. " << sqlQuery.lastError();
}
else
{
while(sqlQuery.next())
{
QString usrname = sqlQuery.value(0).toString();
list.append(usrname);
QString usrpass = sqlQuery.value(1).toString();
list.append(usrpass);
//qDebug()<& moredb)
{
// 进行多个数据的插入时,可以利用绑定进行批处理
QSqlQuery sqlQuery;
sqlQuery.prepare("INSERT INTO idinfo VALUES(?,?,?)");
QVariantList nameList,passList;
for(int i=0; i< moredb.size(); i++)
{
nameList << moredb.at(i).usrname;
passList << moredb.at(i).usrpass;
}
sqlQuery.addBindValue(nameList);
sqlQuery.addBindValue(passList);
if (!sqlQuery.execBatch()) // 进行批处理,如果出错就输出错误
{
qDebug() << sqlQuery.lastError();
}
}
// 修改数据
void SqOperator::modifyData(QString usrname,QString usrpass)
{
QSqlQuery sqlQuery;
sqlQuery.prepare("UPDATE student SET usrname=?,usrpass=?");
sqlQuery.addBindValue(usrname);
sqlQuery.addBindValue(usrpass);
if(!sqlQuery.exec())
{
qDebug() << sqlQuery.lastError();
}
else
{
qDebug() << "updated data success!";
}
}
// 删除数据
void SqOperator::deleteData(QString usrname)
{
QSqlQuery sqlQuery;
sqlQuery.exec(QString("DELETE FROM student WHERE id = %1").arg(usrname));
if(!sqlQuery.exec())
{
qDebug()<
#include "mylogin.h"
mylogin::mylogin(QWidget *parent)
: QDialog(parent)
{
this->init_ui();
connect(this->bnt_login, &QPushButton::clicked, this, &mylogin::do_login);
connect(this->bnt_register, &QPushButton::clicked , this ,&mylogin::do_enroll);
}
mylogin::~mylogin()
{
}
void mylogin::init_ui()
{
this->setFixedSize(QSize(600,350));
this->setWindowTitle(tr("大飞秋"));
this->setWindowIcon(QIcon(":/src/1.png"));
this->lb1 = new QLabel();
this->lb2 = new QLabel();
this->lb3 = new QLabel();
this->lb1->setFixedSize(QSize(560,200));
QPixmap pic;
pic.load(":/src/2.png");
//this->lb1->setPixmap(pic.scaled(this->lb1->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
this->lb1->setPixmap(QPixmap(":/src/2.png"));
this->lb2->setText(tr("用户名:"));
this->lb3->setText(tr("密 码:"));
this->usr_name_le = new QLineEdit(); //这两个参数后面传入信号中去,然后emit发射出去
this->usr_pass_le = new QLineEdit();
this->usr_pass_le->setEchoMode(QLineEdit::Password);
this->bnt_login = new QPushButton(tr("登 陆"));
this->bnt_register = new QPushButton(tr("注 册"));
this->hb1 = new QHBoxLayout();
this->hb2 = new QHBoxLayout();
this->hb3 = new QHBoxLayout();
this->hb1->addWidget(this->lb2);
this->hb1->addWidget(this->usr_name_le);
this->hb2->addWidget(this->lb3);
this->hb2->addWidget(this->usr_pass_le);
this->hb3->addWidget(this->bnt_login);
this->hb3->addWidget(this->bnt_register);
this->vb1 = new QVBoxLayout();
this->vb1->addWidget(this->lb1);
this->vb1->addLayout(this->hb1);
this->vb1->addLayout(this->hb2);
this->vb1->addLayout(this->hb3);
this->setLayout(this->vb1);
}
void mylogin::do_login()
{
emit sig_login(usr_name_le->text(), usr_pass_le->text());
//需要把这里输入的账号密码信息发送到myapp那去,用到的函数是emit
//需要自定义一个信号,sig_login
//这个槽函数能够发出信号
}
void mylogin::do_enroll()
{
emit sig_enroll();
}
#include "myenroll.h"
myenroll::myenroll(QWidget *parent) : QWidget(parent)
{
init_ui();
connect(this->bnt1,&QPushButton::clicked,this,&myenroll::send_msg);
}
void myenroll::init_ui()
{
this->setFixedSize(QSize(600,350));
this->setWindowTitle(tr("信息注册"));
this->setWindowIcon(QIcon(":/src/1.png"));
name = new QLineEdit; //用于写入名字
pass = new QLineEdit; //用于写入密码
lb1 = new QLabel;
lb2 = new QLabel;
bnt1 = new QPushButton;
hb1 = new QHBoxLayout;
hb2 = new QHBoxLayout;
hb3 = new QHBoxLayout;
vb1 = new QVBoxLayout;
this->lb1->setText(tr("请输入账号:"));
this->lb2->setText(tr("请输入密码:"));
this->bnt1->setText(tr("确认"));
this->hb1->addWidget(lb1);
this->hb1->addWidget(name);
this->hb2->addWidget(lb2);
this->hb2->addWidget(pass);
this->hb3->addWidget(bnt1);
this->vb1->addLayout(hb1);
this->vb1->addLayout(hb2);
this->vb1->addLayout(hb3);
this->setLayout(vb1);
}
void myenroll::send_msg()
{
emit sig_enroll_info(name->text(),pass->text());
}
#include "chatinterface.h"
chatInterface::chatInterface(QWidget *parent) : QWidget(parent)
{
this->init();
}
void chatInterface::init()
{
this->setFixedSize(QSize(600,900));
this->setWindowTitle(tr("大飞秋"));
this->setWindowIcon(QIcon(":/src/1.png"));
lb1 = new QLabel;
le1 = new QLineEdit;
te1 = new QTextEdit;
bnt1 = new QPushButton;
hb1 = new QHBoxLayout;
vb1 = new QVBoxLayout;
this->lb1->setFixedSize(QSize(565,80));
QPixmap pic;
pic.load(":/src/3.jpg");
this->lb1->setPixmap(pic.scaled(this->lb1->size()));
this->te1->setFixedSize(QSize(560,700));
this->te1->setStyleSheet(QString("background-color:") + "white");
this->le1->setFixedSize(QSize(450,50));
this->bnt1->setText(tr("发送"));
this->bnt1->setFixedSize(QSize(100,50));
this->hb1->addWidget(le1);
this->hb1->addWidget(bnt1);
this->vb1->addWidget(lb1);
this->vb1->addWidget(te1);
this->vb1->addLayout(hb1);
this->setLayout(vb1);
this->mysock = new QTcpSocket();
this->mysock->connectToHost("192.168.4.32",8888); //需查看自己的本机ip写入
connect(this->mysock, &QTcpSocket::connected, this, &chatInterface::connect_success_msg);
connect(this->mysock, &QTcpSocket::readyRead, this, &chatInterface::recv_msg_slots);
connect(this->bnt1, &QPushButton::clicked, this, &chatInterface::send_msg_slots);
}
void chatInterface::connect_success_msg()
{
qDebug() << "链接服务器成功";
}
void chatInterface::recv_msg_slots()
{
QByteArray con = this->mysock->readAll();
QString *str = new QString(con);
this->te1->append(*str);
}
void chatInterface::send_msg_slots()
{
this->te1->append(this->le1->text());
this->mysock->write( (this->le1->text()).toUtf8());
}
#include "tips.h"
tips::tips(QWidget *parent) : QWidget(parent)
{
}
void tips::loginfail()
{
QMessageBox msg;
msg.warning(this,tr("登录提示"),tr("账号或密码错误,请重新登录!"));
}
void tips::insertok()
{
QMessageBox msg;
msg.warning(this,tr("信息注册"),tr("用户注册成功!"));
}
#include "myapp.h"
myapp::myapp(QObject *parent) : QObject(parent)
{
//创建并打开SQLite数据库
this->mydb = new SqOperator;
mydb->openDb();
//创建数据表
mydb->createTable();
//这里分别新建的是登录和注册两个对象
this->login = new mylogin;
this->login->show();
this->enroll = new myenroll;
this->face = new chatInterface;
this->tip = new tips;
connect(login,&mylogin::sig_login,this,&myapp::judge);
connect(login,&mylogin::sig_enroll,this,&myapp::show_enroll_face);
connect(enroll,&myenroll::sig_enroll_info,this,&myapp::insertdb);
}
bool myapp::judge(QString usrname, QString usrpass)
{
qDebug()< list;
mydb->queryTable(list);
int i = 0;
//当存在两个账号的时候,这里循环里面的if必定会进去,错误和正确都会提示,应该在正确之后直接结束判断,而错误提示则应该放在循环结束
for(i = 0 ; i < list.size() ; i=i+2)
{
if(usrname == list[i] || usrpass == list[i+1])
{
this->face->show();
return true;
}
}
this->tip->loginfail();
return false;
}
void myapp::show_enroll_face()
{
this->enroll->show();
}
void myapp::insertdb(QString usrname,QString usrpass)
{
qDebug()<singleInsertData(info1))
{
this->tip->insertok();
}
}
#include "myapp.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
myapp w;
return a.exec();
}
程序至此,只是写了客户端的部分,下面是服务端
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
#include
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
public:
QTcpServer *myser;
QList myclis;//是一个QTcpSocket *类型的容器,可实现多个客户端socket的存放
QTextEdit *myte;
QHBoxLayout *hb1;
private slots:
void accept_client();
void do_work();
};
#endif // WIDGET_H
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->myte = new QTextEdit();
this->hb1 = new QHBoxLayout();
this->hb1->addWidget(this->myte);
this->setLayout(this->hb1);
this->myser = new QTcpServer();
this->myser->listen(QHostAddress::AnyIPv4,8888); //IP协议和端口号
this->myclis.clear();
connect(this->myser,&QTcpServer::newConnection,this,&Widget::accept_client);
}
Widget::~Widget()
{
}
void Widget::accept_client()
{
QTcpSocket * mysck = this->myser->nextPendingConnection();
this->myclis.append(mysck); //接收客户端的连接请求
connect(mysck,&QTcpSocket::readyRead,this,&Widget::do_work);//接收到信号后准备读,所以,我们需要一个读的槽函数去接收这个准备好的信号
}
void Widget::do_work()//实现
{
QTcpSocket *sck = (QTcpSocket *)sender();
QByteArray con = sck->readAll();
//遍历
for(int i = 0;i < this->myclis.size();i++)
{
if(this->myclis[i] == sck)
{
continue;
}
this->myclis[i]->write(con);
}
}
#include "widget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}