目录

技术路线

效果展示

程序主体

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地址和端口号,进行,各个客户端之间的通信,数据先通过客户端发往服务端,再由服务端发往客户端,可以实现多个客户端的并发通信,只需要将服务端开启即可。

效果展示


程序主体

sqoperator.h

这是对数据库的封装,其中有部分封装本项目没用到

#ifndef SQLITEOPERATOR_H
#define SQLITEOPERATOR_H#include <QWidget>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>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<QString> &list);// 插入数据bool singleInsertData(info &singleData); // 插入单条数据void moreInsertData(QList<info> &moreData); // 插入多条数据// 修改数据void modifyData(QString usrname,QString usrpass);// 删除数据void deleteData(QString usrname);//删除数据表void deleteTable(QString& tableName);// 关闭数据库void closeDb(void);private:QSqlDatabase database;// 用于建立和数据库的连接};#endif // SQLITEOPERATOR_H

mylogin.h

#ifndef MYLOGIN_H
#define MYLOGIN_H#include <QDialog>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPixmap>class mylogin : public QDialog
{Q_OBJECTpublic: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); //自定义的登录信号,发给myappvoid sig_enroll();    //自定义的注册信号,发给myapppublic slots:void do_login();        //为关联按键和信号发射所设的槽函数void do_enroll();};
#endif // MYLOGIN_H

myenroll.h

#ifndef MYENROLL_H
#define MYENROLL_H#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPixmap>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); //自定义的注册信号,发送给myapppublic slots:void send_msg();    //为注册信号所设置的槽函数
};#endif // MYENROLL_H

chatinterface.h

#ifndef CHATINTERFACE_H
#define CHATINTERFACE_H#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPixmap>
#include <QTextEdit>
#include <QTcpSocket>
#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

tips.h

#ifndef TIPS_H
#define TIPS_H#include <QWidget>
#include <QMessageBox>class tips : public QWidget
{Q_OBJECT
public:explicit tips(QWidget *parent = nullptr);void loginfail();void insertok();signals:public slots:};#endif // TIPS_H

myapp.h

#ifndef MYAPP_H
#define MYAPP_H#include <QObject>
#include <QDebug>
#include <QString>
#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

*******************

sqoperator.cpp

#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<QString> &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()<<QString("id:%1    name:%2").arg(id).arg(name);}}
}// 插入单条数据
bool SqOperator::singleInsertData(info &singledb)
{QSqlQuery sqlQuery;sqlQuery.prepare("INSERT INTO idinfo VALUES(:usrname,:usrpass)");sqlQuery.bindValue(":usrname", singledb.usrname);sqlQuery.bindValue(":usrpass", singledb.usrpass);if(!sqlQuery.exec()){qDebug() << "Error: Fail to insert data. " << sqlQuery.lastError();return false;}else{qDebug() <<"insert success.";// do somethingreturn true;}
}// 插入多条数据
void SqOperator::moreInsertData(QList<info>& 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()<<sqlQuery.lastError();}else{qDebug()<<"deleted data success!";}
}//删除数据表
void SqOperator::deleteTable(QString& tableName)
{QSqlQuery sqlQuery;sqlQuery.exec(QString("DROP TABLE %1").arg(tableName));if(sqlQuery.exec()){qDebug() << sqlQuery.lastError();}else{qDebug() << "deleted table success";}
}void SqOperator::closeDb(void)
{database.close();
}

mylogin.cpp

#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();
}

myenroll.cpp

#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());
}

chatinterface.cpp

#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());
}

tips.cpp

#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("用户注册成功!"));
}

myapp.cpp

#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()<<usrname<<usrpass;//查询全部数据,并且放入list中QList<QString> 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()<<usrname<<usrpass;info info1;info1.usrname = usrname;info1.usrpass = usrpass;if(mydb->singleInsertData(info1)){this->tip->insertok();}
}

main.cpp

#include "myapp.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);myapp w;return a.exec();
}

程序至此,只是写了客户端的部分,下面是服务端

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTextEdit>
#include <QHBoxLayout>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = 0);~Widget();
public:QTcpServer *myser;QList <QTcpSocket *> myclis;//是一个QTcpSocket *类型的容器,可实现多个客户端socket的存放QTextEdit *myte;QHBoxLayout *hb1;private slots:void accept_client();void do_work();
};#endif // WIDGET_H

widget.cpp

#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);}}

main.cpp

#include "widget.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

QT程序设计多人聊天室(基于QT、sqlite3、TCP/IP)相关推荐

  1. node php聊天室,利用socket.io实现多人聊天室(基于Nodejs)

    利用socket.io实现多人聊天室(基于Nodejs) socket.io简介 在Html5中存在着这样的一个新特性,引入了websocket,关于websocket的内部实现原理可以看这篇文章,这 ...

  2. python多人聊天室 跨主机_python+tcp实现多人聊天室

    tcp介绍 引用百度百科的介绍 传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793 [1 ...

  3. Python多人聊天室-基于socket UDP协议

    简介 使用Python编写的基于socket UDP通信的多功能即时聊天室,包含Tkinter编写的图形化聊天界面,功能包括有账号注册和登录,登录成功后可以查看在线用户,并和聊天室内的其他在线用户聊天 ...

  4. php 多人聊天室,基于swoole实现多人聊天室,聊天室实现

    namespace app\common;require_once 'Predis.php';require_once 'Task.php';/** * socket面向对象的编译*/ classWs ...

  5. linux多人聊天室 qt,Qt编程详解--网络通信之基于TCP的多人聊天室

    一.了解TCP的通信过程 Qt中封装了TCP协议 QTcpServer类负责服务端: 1.创建QTcpServer对象 2.监听listen需要的参数是地址和端口号 3.当有新的客户端连接成功时会发射 ...

  6. 基于python面向对象多人聊天室

    基于python面向对象多人聊天室 1.项目环境 项目名称:多人聊天室 项目模式:C/S 开发环境:win10+python3.8+pycharm 所需知识:python GUI编程,多线程编程,网络 ...

  7. java多人聊天室的实验任务_Java基于中介者模式实现多人聊天室功能示例

    本文实例讲述了Java基于中介者模式实现多人聊天室功能.分享给大家供大家参考,具体如下: 一 模式定义 中介者模式,用一个中介对象来封装一系列对象之间的交互,使各个对象中不需要显示地引用其他对象实例, ...

  8. java 网络编程 聊天_Java——网络编程(实现基于命令行的多人聊天室)

    目录: 1.ISO和TCP/IP分层模型 2.IP协议 3.TCP/UDP协议 4.基于TCP的网络编程 5.基于UDP的网络编程 6.基于TCP的多线程的聊天室的实现 1.ISO和TCP/IP分层模 ...

  9. Java——网络编程(实现基于命令行的多人聊天室)

    2019独角兽企业重金招聘Python工程师标准>>> 目录: 1.ISO和TCP/IP分层模型 2.IP协议 3.TCP/UDP协议 4.基于TCP的网络编程 5.基于UDP的网络 ...

最新文章

  1. 使用face_recognition(二)目标人脸“实时”检测
  2. 云效云栖大会首发应用交付和项目协作新品,助力企业DevOps到BizDevOps
  3. IO编程__字节流__输入、输出__图片移动
  4. 自学python(一)
  5. 记事本状态栏不会自动_如何在记事本中同时启用状态栏和自动换行
  6. 15条常用的视频音频编辑脚本命令(mencoder/ffmpeg等)
  7. statement执行insert into语句_【图文并茂】源码解析MyBatis ShardingJdbc SQL语句执行流程详解...
  8. 百度SEO 统计平台推送工具 1.8
  9. 【今日CV 计算机视觉论文速览 第136期】Wed, 26 Jun 2019
  10. Digix联合创始人:在接下来的12个月中 比特币将被称为真正的价值存储
  11. 统计1到2021中6的个数
  12. word加了脚注,分节符(连续)后的内容,跳到下一页
  13. JS版汉字与拼音互转终极方案,附简单的JS拼音
  14. java rsa x509_Java使用RSA加密解密签名及校验
  15. 黑马程序员——网络编程的应用
  16. 怎么删除日历每日重复提醒事项
  17. 学习Python,怎能不懂点PEP呢?
  18. 本本蓝屏,自己解决了,很高兴
  19. 由一道简单的图片隐写题总结思路
  20. 学习编程与学习编程语言不同

热门文章

  1. 基于SSM网络蛋糕商城管理系统
  2. 在html中写js打开是乱码,javascript脚本中文乱码如何解决?
  3. 多目标车辆路径问题学习全过程(详细)
  4. c语言界面函数,C语言图形界面常用函数集锦
  5. 芯片测试随笔之一:采用Excel进行处理数据
  6. 记录一下使用nodejs爬取双色球历史开奖数据并写入文件过程,仅自己做着玩玩
  7. CRH和谐号动车组列车知识大全
  8. U盘文件系统FAT32、exFAT、NTFS之间有什么区别?
  9. 游戏充值订单金额修改思路与实践
  10. 360Lib中的坐标系