利用QT写的局域网聊天工具(客户端)

一、客户端涉及到UI界面的跳转和回显

代码实现思路:

1.1、界面跳转通过信号槽实现,登录界面完成后,发送信号给主界面,同时主界面通过信号函数获取服务端信息,从而建立socket,实现网络通信;

1.2、数据库记录现有用户列表,并建立对应的UI索引,因为每次在主界面双击时,就要弹出新的UI以实现多对多聊天;

1.3、主界面控制socket的收发,socket收发后依据字符流控制消息流向哪个打开UI界面,实现多对多聊天消息分发及隔离;

1.4、运行后的效果如图:

           利用QT写的局域网聊天工具(客户端)_第1张图片                                 

                        图1.登录界面                                                               图2.主界面 

利用QT写的局域网聊天工具(客户端)_第2张图片

                                 图3.聊天界面

二、代码如下:

salite记录数据相关文件:

cpp文件:(其实和服务端的相同)

/*--------------------------------------------------------
* Author      : Firdin
* E-mail      : [email protected]
* File Name   : server_sqlite.c
* Created Time: 2017年10月12日 星期四 15时27分11秒
* Introduction:
* 
*-------------------------------------------------------*/

#include "server_sqlite.h"
#include
#include

bool server_sqlite::sqlite_init()
{
    if(QSqlDatabase::contains("qt_sql_default_connection"))
        my_db=QSqlDatabase::database("qt_sql_default_connection");
    else
        my_db=QSqlDatabase::addDatabase("QSQLITE");//创建sqlite数据库文件
    if(!my_db.isValid())
    {
        qDebug()<<"数据库创建失败"<

H文件

#ifndef server_sqlite_H
#define server_sqlite_H

#include 
#include 
#include 
#include 
#include 

class server_sqlite //无继承的类(独立数据库操作类)
{

private:
    QSqlDatabase my_db;//用户数据表单建立
    int count;//用户在线人数
    QString temp;//用于拼接字符用的临时变量
    QString output;//用于输出用户信息
public:
    explicit server_sqlite()
    {
        count=0;
        temp.clear();
    }
    bool sqlite_init();//初始化数据库用成员函数
    bool sqlite_insert(int id_s,QString name_t,QString  IP_t);//插入数据
    bool sqlite_delete(QString name_m);//删除一条数据
    bool sqlite_delete_all();//删除所有的数据
    QString* sqlite_search(QString name_s);//查找指定用户数据
    QString* sqlite_search_IP(QString name_s);//查找制定用户的IP地址
    bool sqlite_update(QString name_u,QString state_u);//修改指定用户的在线与否信息
    QString* sqlite_online_server();//输出在线用户信息,通过判断state是否是online
    QString* sqlite_offline_server();//输出历史用户(不在线但是有其信息)
    bool sqlite_delete_table();//删除表单(表单为临时配置文件,因此可以删除)
    int sqlite_search_id(QString name_src);//依据名字查询ID号,ID号在转发数据时需要用于查找QList中的socket对象,以达到准确转发消息
     ~server_sqlite()
    {
        my_db.close();
    }
};
#endif

登录UI的代码实现:

cpp代码实现:

#include "my_login.h"
#include "ui_my_login.h"
#include

My_Login::My_Login(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::My_Login)
{
    ui->setupUi(this);
    this->setFixedSize(318,264);//设置窗体大小固定
    this->setWindowTitle("登陆到服务器");
    Img=QImage(":/bk_login");
    //点击响应
    connect(ui->pushButton_login,SIGNAL(clicked(bool)),this,SLOT(slot_send()));
}

My_Login::~My_Login()
{
    delete ui;
}

void My_Login::slot_send()//发送信息到主窗体(信号槽)
{
    if(ui->lineEdit_username->text().isEmpty() || ui->lineEdit_IPAddr->text().isEmpty() || ui->lineEdit_IP_Port->text().isEmpty())
    {
        QMessageBox::warning(this,"警告","请输入完整登陆信息后再登陆!",QMessageBox::Ok,QMessageBox::Cancel);
    }
    else
    {
        QString send_info;
        send_info+=ui->lineEdit_username->text()+":"+ui->lineEdit_IPAddr->text()+":"+ui->lineEdit_IP_Port->text();
        emit send_data(send_info);
    }
}
void My_Login::paintEvent(QPaintEvent *event)//绘制背景
{
    QPainter pt(this);  //定义一个在当前窗口画画的画家
    QImage drawing = Img.scaled(this->width(),this->height());
    pt.drawImage(0,0,drawing,0,0,this->width(),this->height());
    update();
}

H文件:

#ifndef MY_LOGIN_H
#define MY_LOGIN_H

#include 

#include 
#include 
#include 
#include 

#include
#include

#include

#include
#include

namespace Ui {
class My_Login;
}

class My_Login : public QDialog
{
    Q_OBJECT

public:
    explicit My_Login(QWidget *parent = 0);
    void paintEvent(QPaintEvent *event);
    ~My_Login();

private:
    Ui::My_Login *ui;
    QImage Img;

signals:
    void send_data(QString);
private slots:
    void slot_send();
};

#endif // MY_LOGIN_H

聊天界面的实现:

cpp文件的实现:

#include "my_chart.h"
#include "ui_my_chart.h"
#include
#include
#include

#include 
#include 
My_Chart::My_Chart(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::My_Chart)
{
    ui->setupUi(this);
    this->setFixedSize(653,441);
    ui->textEdit_show_message->setReadOnly(true);
    //点击响应
    connect(ui->pushButton_send,SIGNAL(clicked(bool)),this,SLOT(slot_send_message()));
}

My_Chart::~My_Chart()
{
    delete ui;
}
void My_Chart::setIP_min(QString res)//显示本机IP地址和聊天对象的IP地址
{
    QStringList analysis=res.split(";");
    ui->label_show_mine->setText(analysis.at(0));//显示本机IP地址
    ui->label_show_other_side->setText(analysis.at(1));//显示对方的IP地址
}

void My_Chart::show_message(QString src)//接收主窗体的字符串并显示到聊天界面上去
{
    QStringList analysis=src.split(":");//依据符号对原始字符串进行分割
    ui->textEdit_show_message->append(analysis.at(0)+":\n"+analysis.at(1));//将对方的消息内容显示在窗体上
}

void My_Chart::set_names_client(QString src)//传送用户姓名和接收方姓名
{
    QStringList analysis=src.split(":");
    name_local=analysis.at(0);
    username=analysis.at(1);//设置用户名
}

void My_Chart::slot_send_message()//发送消息
{
    QString mess="message:";//消息拼接
    QString temp;//取出聊天内容
    temp.clear();
    QTextStream out(&temp);//从textEdit中读取内容
    out << ui->textEdit_input_message->toPlainText();//保存成为html格式//保存到文件中
    //qDebug()<<"对话框中的内容"<textEdit_input_message->clear();//清除输入框中的字符
        QByteArray message;
        QDataStream out(&message,QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_5_7);
        out<write(message);
        qDebug()<<"消息已发出!";
        ui->textEdit_show_message->append(name_local + ":\n" + temp);
    }
}

void My_Chart::set_Socket_local(QTcpSocket *Socket_src)
{
    Socket_login=Socket_src;
}
void My_Chart::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawPixmap(0,0,width(), height(),QPixmap(":/10.jpg"));
}

H文件实现:

#ifndef MY_CHART_H
#define MY_CHART_H

#include 

#include 
#include 
#include 
#include 

#include 
#include 

#include
#include

namespace Ui {
class My_Chart;
}

class My_Chart : public QDialog
{
    Q_OBJECT

public:
    explicit My_Chart(QWidget *parent = 0);
    void setIP_min(QString res);//显示本地IP地址(测试用)
    void show_message(QString src);//接收主窗体的字符串并显示到聊天界面上去
    void set_names_client(QString src);//传送聊天双方的名字
    void set_Socket_local(QTcpSocket *Socket_src);//将Socket传送过来,在聊天窗口实现发送消息,减轻主窗体的网络负担
    void paintEvent(QPaintEvent *event);
    ~My_Chart();

    /*
signals:
    void send_message(QString);
    */
private slots:
    void slot_send_message();//发送消息到一个指定的用户(指定用户为打开的聊天界面是和谁在聊天)


private:
    Ui::My_Chart *ui;
    QString username;//聊天对像的名字(用于发送信息)
    QString name_local;//本家姓名(发起聊天的我的用户名)
    QTcpSocket *Socket_login;//接受主窗体的网络文件描述符
};

#endif // MY_CHART_H

主界面的代码实现:

cpp文件实现:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include

#include

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    user_count=2;
    current_user=0;
    this->setFixedSize(252,532);//设置窗体大小固定,数值源自UI设计图形界面
    this->setWindowTitle("FeiQ低配版");//设置窗体的名称
    get_IP_Address();//获取本机IP地址并显示

//初始化数据库
    my_client.sqlite_init();//初始化数据库,为聊天用户建立一个在线用户表单

//控件动作响应
    connect(Login_u,SIGNAL(send_data(QString)),this,SLOT(slot_recv(QString)));//登陆窗体动作响应

    connect(ui->listWidget_onlineuser_list,SIGNAL(itemDoubleClicked(QListWidgetItem*)),this,SLOT(slot_select_user(QListWidgetItem*)));//双击用户列表动作响应

    Login_u->show();//显示登陆界面
}

MainWindow::~MainWindow()//析构函数
{
    qDebug()<<"退出聊天程序";
    QString mess="exit:"+username_local+":"+IP_Addr;
    QByteArray message;
    QDataStream out(&message,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_7);
    out<write(message);
    qDebug()<<"消息已发出!";
    delete ui;
}

void MainWindow::slot_recv(QString res)//核对登陆信息并控制窗体切换
{
    QStringList analysis=res.split(":");
    Img=QImage(":/bk_Main.png");
    Server_IP=analysis.at(1);
    QString Port_server=analysis.at(2);

    Socket_login=new QTcpSocket(this);
    Socket_login->abort();
    //qDebug()<<"服务器IP地址:"<connectToHost(Server_IP,Port_server.toInt());//连接到服务器,connectToHost函数为虚函数,无返回值
    connect(Socket_login,SIGNAL(readyRead()),this,SLOT(slot_recv_Message()));//数据读取响应连接到读取函数

    if(!Socket_login->waitForConnected(10000))
    {
        QMessageBox::warning(Login_u,"网络连接错误","未连接到网络,请稍后重试!",QMessageBox::Ok,QMessageBox::Cancel);
    }
    else
    {

        this->show();
        //设置用户头像(label控件)
        Login_u->close();//关闭登陆界面
        ui->label_show_username->setText(analysis.at(0));
        username_local=analysis.at(0);

        QString string="user:"+username_local+":"+IP_Addr;//拼接消息为格式:user:uesrname:IPAddr
        QByteArray message;
        QDataStream out(&message,QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_5_7);
        out<write(message);


    }
}

void MainWindow::slot_select_user(QListWidgetItem *src)//双击用户名弹出聊天界面
{
    QString temp=src->text();//获取当前双击用户的名字
    QString *IP_temp=my_client.sqlite_search_IP(temp);
    int ID=my_client.sqlite_search_id(temp);//在数据库中查找对应的ID号
    if(-1 != ID)
    {
        Chart_u[ID].setWindowTitle("和"+temp+"聊天中");//依据ID号建立一个子窗口
        Chart_u[ID].setIP_min(IP_Addr+";"+*IP_temp);//显示聊天界面上的IP地址
        Chart_u[ID].set_names_client(username_local+":"+temp);//传送聊天双方的名字到聊天窗口
        Chart_u[ID].show();//显示子窗体
        Chart_u[ID].set_Socket_local(Socket_login);//传送文件描述符,以便窗体发送消息
    }
    else
    {
        qDebug()<<"ID号查询失败,请检查数据库文件!!";
    }
}

void MainWindow::get_IP_Address()//获取本机IP地址并解析IPV4地址(源自网络)
{
    QHostInfo info = QHostInfo::fromName(QHostInfo::localHostName());//首先获取本机名称,其次依据本机名称获的本机IP地址
    info.addresses();//QHostInfo的address函数获取本机ip地址
    //存在多条ip地址ipv4和ipv6:
    foreach(QHostAddress address,info.addresses())//该语句为从集合中每个成员中进行筛选:for each member进行遍历
    {
            if(address.protocol()==QAbstractSocket::IPv4Protocol)//只取ipv4协议的地址
            {
                ui->label_showIPAddr->setText(address.toString());
                IP_Addr=address.toString();
            }
    }
    //qDebug()<<"IPv4地址:"<width(),this->height());
    pt.drawImage(0,0,drawing,0,0,this->width(),this->height());
    update();
}

void MainWindow::slot_recv_Message()//接受数据响应函数
{
    QDataStream in(Socket_login);//定义数据流
    in.setVersion(QDataStream::Qt_5_7);//规定QT网络版本
    QString recv_Message;
    in >> recv_Message;
    if(recv_Message.isEmpty())
    {
         QMessageBox::warning(this,"警告","网络错误,请检查网络连接!",QMessageBox::Ok,QMessageBox::Cancel);//如果,没有接收到信息,则网络出错,没有数据
    }
    else
        network_server(recv_Message);//接受到信息,则进入字符分解程序
}

void  MainWindow::network_server(QString src)//网络服务函数
{
    QMap map;//以QMap形式将字符串与整型一一对应
    map.insert("user",0);//接受到用户列表信息
    map.insert("message",1);//接收到消息
    map.insert("file",2);//接收到除音乐、图片、视频外的文件

//由于多媒体文件可以预览,因此将其与其他文件分开,同时压缩文件也应该与其他的分开,以下功能以后再实现
    map.insert("video",3);//接收到视频文件
    map.insert("picture",4);//接收到图片文件
    map.insert("music",5);//接收到音乐文件
    map.insert("ZIP",6);//接收到压缩包文件
    map.insert("DIR",7);//接收到带有目录的文件

    map.insert("",888);//无数据时的错误码

    QStringList info = src.split(":");//收到的字符串以“:”为分割标志对其进行分解,并存入字符数组(列表)中,以便后期使用
//user:kk;mm;:192.168.132.108;192.168.1.140;      传输用户列表
//message:username:Hello There!  传输消息
//file:username:filename  传输文件
    //qDebug() << "类型:" << info[0]<< "  对方姓名" << info[1]<< "  内容:" << info[2];

    switch(map[info.at(0)])
    {
    case 0:
        refresh_userinfo(info.at(1)+":"+info.at(2));//刷新用户列表信息(依据服务器发送信息刷新,无需本地定时)
        break;
//接收到服务器转发的消息,消息类型:message:username:Hello There!!
    case 1:
        qDebug()<<"接收到服务器的消息:"<=1&&IP_dis.length()>=1)
        {
            QString name_client;//临时变量存放用户名
            QIcon user_list_logo(":/user_list.png");
             ui->listWidget_onlineuser_list->clear();//清除之前的用户列表
            for(int i=0;ilistWidget_onlineuser_list->addItem(temp_list);//加入列表显示
                }
            }
        }
    }
    //qDebug()<<"在线用户信息刷新完成!!";
}

void  MainWindow::splite_message(QString src)//将从服务器接受的消息依据接收用户名分发到各自的窗口上
{

    qDebug()<<"分发消息服务函数:"<

H文件的实现:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
//主窗体用户列表使用
#include

#include"my_chart.h"//添加聊天窗体类
#include"my_login.h"//添加登陆窗体类
//添加网络类
#include 
#include 
#include 
#include 
//创建套接字使用
#include
#include
//解析字符串使用
#include
//绘制背景图片以及头像使用
#include
#include
#include

#include
#include

#include"server_sqlite.h"//自定义sqlite控制类

namespace Ui {
class MainWindow;
}

class MainWindow : public QWidget
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    void get_IP_Address();
    void paintEvent(QPaintEvent *event);
    void network_server(QString src);//用于分析字符串并作出相应的响应
    void refresh_userinfo(QString src);//该函数用于刷新在线用户信息
    void splite_message(QString src);//将从服务器接受的消息依据接收用户名分发到各自的窗口上(由于可以同时和多人聊天,故该部分很必要)
    ~MainWindow();
private slots:
    void slot_recv(QString res);
    void slot_select_user(QListWidgetItem *src);
    void slot_recv_Message();
private:
    Ui::MainWindow *ui;
    server_sqlite my_client;//定义一个数据库对象
    int user_count,current_user;//用于记录用户数量和当前打开窗口数
    QTcpSocket *Socket_login;//用于登陆和聊天的文件描述符
    My_Login *Login_u=new My_Login;//登录界面对象,仅显示一个
    My_Chart Chart_u[10];//聊天界面子窗口(最多打开10个)
    QString IP_Addr;//本机IP地址
    QString Server_IP;//服务器IP地址
    QImage Img;//背景图片
    QPicture *pix;//图像图片
    QString username_local;
};

#endif // MAINWINDOW_H

main.c实现

#include "mainwindow.h"
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    //w.show();

    return a.exec();
}

UI界面过多,参考图片吧!

你可能感兴趣的:(Linux学习&开发)