在qt上实现qq的客户端(附源码)

最近做了一个qq的项目,在qt上实现qq的客户端,在vs上实现qq的服务器,先让大家看看效果图吧

 登录模块,按下登录后会连接服务器

登录后的好友列表,会显示所有的在线好友

 

有新好友上线会自动更新好友列表

 

双方进行聊天,互相收到消息

 

群聊功能,一个人发送消息其他在线的人都会收到

#ifndef CHATWIDGET_H
#define CHATWIDGET_H

#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QDesktopWidget>
#include <QApplication>
#include <QPalette>
#include <QBrush>
#include <QPixmap>
#include <QDebug>
#include <QString>
#include <QString>
#include <QMessageBox>
#include <QTcpServer>
#include <QTcpSocket>
#include <QListWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTextEdit>
typedef struct QQHead
{
    //功能码 确定执行什么功能 登录 发消息
    int funcode;
    //操作码
    int percode;
    //目标ID
    int dstid;
    //源ID
    int srcid;
    //数据长度
    int len;
}QQHEAD_T;
typedef struct QQData
{
    //包头
    QQHEAD_T head;
    //包体
    char buff[1024];
}QQDATA_T;
typedef struct QQLogin
{
    //用户名
    char username[32];
    //密码
    char userpwd[32];
    //socketid
    int socket;
}QQLOGIN_T;
class ChatWidget : public QWidget
{
    Q_OBJECT
public:
    explicit ChatWidget(QWidget *parent ,QTcpSocket *tcpsocket,QString titel);
    void initui();
    QListWidget *listwidget;
private:
    int tag;//用于判断是群聊还是私聊
    QTextEdit *chatedit;
    QPushButton *sendbutton;
    QHBoxLayout *layout1;
    QVBoxLayout *mainlayout;
    QTcpSocket *tcpSocket;
signals:

public slots:
    void on_pushbutton_sendmsg_click();
};

#endif // CHATWIDGET_H
#include "ChatWidget.h"

ChatWidget::ChatWidget(QWidget *parent,QTcpSocket *tcpsocket,QString titel) : QWidget(parent)
{
    this->initui();
    this->setWindowTitle(titel);
    this->tcpSocket=tcpsocket;
    if(strcmp(titel.toStdString().c_str(),"all people")==0)
    {
        this->tag=1;
    }else {
        this->tag=0;
    }
    connect(this->sendbutton,SIGNAL(clicked()),this,SLOT(on_pushbutton_sendmsg_click()));
}

void ChatWidget::initui()
{

    //将窗口居中,设置标题
    QDesktopWidget *screen =  QApplication::desktop();
    int appwidth=800;
    int appheight=600;
    int center_x=(screen->width()-appwidth)/2;
    int center_y=(screen->height()-appheight)/2;
    this->setGeometry(center_x,center_y,appwidth,appheight);



    this->listwidget=new QListWidget(this);
    this->listwidget->setMinimumSize(QSize(800,200));

    this->chatedit=new QTextEdit(this);
    this->chatedit->setMaximumSize(QSize(800,150));

    this->sendbutton=new QPushButton(tr("发送"),this);
    this->layout1=new QHBoxLayout();
    this->layout1->addStretch(8);
    this->layout1->addWidget(this->sendbutton,2);
    this->mainlayout=new QVBoxLayout();
    this->mainlayout->addWidget(this->listwidget);
    this->mainlayout->addWidget(this->chatedit);
    this->mainlayout->addLayout(this->layout1);
    this->setLayout(this->mainlayout);
}

void ChatWidget::on_pushbutton_sendmsg_click()
{
    QString str=this->chatedit->toPlainText();

    QWidget *widget=new QWidget(this->listwidget);
    QHBoxLayout *hboxlayout=new QHBoxLayout(widget);
    QLabel *label=new QLabel(widget);
    label->setAlignment(Qt::AlignHCenter);
    QLabel *label1 =new QLabel(widget);
    label1->setAlignment(Qt::AlignHCenter);
    label1->setPixmap(QPixmap("./image/1.png").scaled(30,50,Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
    label->setText(str);
    hboxlayout->addStretch(6);
    hboxlayout->addWidget(label,3);
    hboxlayout->addWidget(label1,1);
    widget->setLayout(hboxlayout);
    QListWidgetItem *item=new QListWidgetItem(this->listwidget);
    this->listwidget->addItem(item);
    item->setSizeHint(QSize(500,50));
    this->listwidget->setItemWidget(item,widget);

    if(this->tag==0)
    {
        QQDATA_T data={ 0 };
        memset(&data,0,sizeof(QQDATA_T));
        printf("222222222222\n");
        data.head.funcode=2;
        data.head.percode=2;
        memcpy(data.buff,str.toStdString().c_str(),1024);
        this->tcpSocket->write((char *)&data,sizeof(QQDATA_T));

    }else if(this->tag==1){
        QQDATA_T data1={0};
        memset(&data1,0,sizeof(QQDATA_T));
        printf("111111111111\n");
        data1.head.funcode=3;
        data1.head.percode=3;
        memcpy(data1.buff,str.toStdString().c_str(),1024);
        this->tcpSocket->write((char *)&data1,sizeof(QQDATA_T));
    }

    this->chatedit->clear();

}


#ifndef DRAW_H
#define DRAW_H

#include <QToolBox>
#include <QToolButton>
#include <QWidget>
#include <QGroupBox>  //一个有标题的组合框
#include <QVBoxLayout>  //这个是垂直布局的头文件
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QDesktopWidget>
#include <QApplication>
#include <QPalette>
#include <QBrush>
#include <QPixmap>
#include <QDebug>
#include <QString>
#include <QMessageBox>
#include<QTcpServer>
#include<QTcpSocket>
#include <QPaintEvent>
#include <QStringList>
#include <QDebug>
#include <string.h>
#include "ChatWidget.h"
#include "Mytoolbtn.h"
class Draw:public QToolBox
{
    Q_OBJECT

public:
    Draw(QWidget *parent,QTcpSocket *tcpserver);
    void initui();
    void paintEvent(QPaintEvent *event);
private:
    Mytoolbtn *toolBtn1_1;
    QGroupBox *groupBox1;
    QGroupBox *groupBox2;
    Mytoolbtn *toolBtn1_2;
    QVBoxLayout *layout1;
    QVBoxLayout *layout2;
    QTcpSocket *tcpSocket;
    QStringList list;
    QStringList list1;
    QStringList list2;
    ChatWidget *chat;
signals:
public slots:
    void on_server_read();
    void click_button();
};

#endif // DRAW_H
#include "Draw.h"

Draw::Draw(QWidget *parent,QTcpSocket *tcpserver)
{
    this->initui();
    this->tcpSocket=tcpserver;
    connect(this->tcpSocket,SIGNAL(readyRead()),this,SLOT(on_server_read()));
}
void Draw::initui()
{
    QDesktopWidget *screen =  QApplication::desktop();
    int appwidth=400;
    int appheight=800;
    int center_x=(screen->width()-appwidth)*3/4;
    int center_y=(screen->height()-appheight)/2;
    this->setGeometry(center_x,center_y,appwidth,appheight);


    this->setWindowTitle(tr("QQ"));


    this->groupBox1 = new QGroupBox;
    this->layout1 = new QVBoxLayout(groupBox1);
    this->layout1->setMargin(10);   //设置布局中各窗体的显示间距
    this->layout1->setAlignment(Qt::AlignHCenter);    //布局中各个窗体显示的位置,这里应该是中间
    this->addItem((QWidget*)groupBox1, tr("my good friend"));   //好友

    this->groupBox2 = new QGroupBox;
    this->layout2 = new QVBoxLayout(groupBox2);
    this->layout2->setMargin(10);   //设置布局中各窗体的显示间距
    this->layout2->setAlignment(Qt::AlignHCenter);    //布局中各个窗体显示的位置,这里应该是中间
    this->addItem((QWidget*)groupBox2, tr("group"));   //群
    this->toolBtn1_2= new Mytoolbtn;   //创建一个toolbutton对象工具盒类
    this->toolBtn1_2->setText("all people");   //群
    this->toolBtn1_2->setIcon(QPixmap("./image/1.png"));    //引入照片1
    this->toolBtn1_2->setIconSize(QPixmap("./image/1.png").size());   //规定照片的大小
    this->toolBtn1_2->setAutoRaise(true);   //设置自动浮起是否有效为enable。
    this->toolBtn1_2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); //按钮的文字显示在旁边
    this->layout2->addWidget(toolBtn1_2);
    connect(this->toolBtn1_2,SIGNAL(doubleclicked()),this,SLOT(click_button()));
}

void Draw::paintEvent(QPaintEvent *event)
{
    for(int i=0;i<list1.size();i++)
    {
        if(!this->list2.contains(list1[i]))
        {
            this->toolBtn1_1= new Mytoolbtn;   //创建一个toolbutton对象工具盒类
            this->toolBtn1_1->setText(tr(this->list1[i].toStdString().c_str()));   //张三
            this->toolBtn1_1->setIcon(QPixmap("./image/1.png"));    //引入照片1
            this->toolBtn1_1->setIconSize(QPixmap("./image/1.png").size());   //规定照片的大小
            this->toolBtn1_1->setAutoRaise(true);   //设置自动浮起是否有效为enable。
            this->toolBtn1_1->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); //按钮的文字显示在旁边
            this->layout1->addWidget(toolBtn1_1);
            this->list2.append(list1[i]);
            connect(this->toolBtn1_1,SIGNAL(doubleclicked()),this,SLOT(click_button()));
        }
    }
}

void Draw::on_server_read()
{
    QQDATA_T data={ 0 };
    this->tcpSocket->read((char *)&data,sizeof(QQDATA_T));
    switch(data.head.funcode)
    {
    case 1:
    {
        QString str=QString(QLatin1String(data.buff));
        this->list1=str.split("#");
        this->list1.removeOne("");//清除掉空字符
        for(int i=0;i<list1.size();i++)
        {
            if(!list.contains(list1[i]))
            {
                list.append(list1[i]);//不在列表里面的话就进行添加
            }
        }
        this->update();
    }
        break;
    case 2:
    {
        QString str=QString(QLatin1String(data.buff));
        QWidget *widget=new QWidget(this->chat->listwidget);
        QHBoxLayout *hboxlayout=new QHBoxLayout(widget);
        QLabel *label=new QLabel(widget);
        QLabel *label1 =new QLabel(widget);
        label1->setPixmap(QPixmap("./image/1.png").scaled(30,50,Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
        label->setText(str);
        hboxlayout->addWidget(label1,1);
        hboxlayout->addWidget(label,3);
        hboxlayout->addStretch(6);
        widget->setLayout(hboxlayout);
        QListWidgetItem *item=new QListWidgetItem(this->chat->listwidget);
        item->setSizeHint(QSize(500,50));
        this->chat->listwidget->addItem(item);
        this->chat->listwidget->setItemWidget(item,widget);
    }
    break;
    default:
        break;
    }
}


void Draw::click_button()
{
    QToolButton *editor = qobject_cast<QToolButton *>(sender());
    qDebug()<<editor->text()<<endl;
    if(strcmp(editor->text().toStdString().c_str(),"all people")==0)
    {
        this->chat=new ChatWidget(0,this->tcpSocket,editor->text());
        this->chat->show();
    }else {
        QQDATA_T data={ 0 };
        data.head.funcode=6;
        data.head.percode=6;
        memcpy(data.buff,editor->text().toStdString().c_str(),1024);
        this->tcpSocket->write((char *)&data,sizeof(data));
        this->chat=new ChatWidget(0,this->tcpSocket,editor->text());
        this->chat->show();
    }

}


#ifndef LOGINWIDGET_H
#define LOGINWIDGET_H

#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QDesktopWidget>
#include <QApplication>
#include <QPalette>
#include <QBrush>
#include <QPixmap>
#include <QDebug>
#include <QString>
#include <QString>
#include <QMessageBox>
#include<QTcpServer>
#include<QTcpSocket>
#include "Draw.h"
class LoginWidget : public QWidget
{
    Q_OBJECT

public:
    LoginWidget(QWidget *parent = 0);
    ~LoginWidget();
    void initui();
    QString changecode();
private:

    QPixmap pix;
    QLabel *namelabel;
    QLineEdit *nameedit;
    QLabel *passlabel;
    QLineEdit *passedit;
    QLineEdit *codeedit;
    QPushButton *codebutton;
    QPushButton *okbutton;
    QPushButton *cancelbutton;
    QPushButton *passicon;
    QIcon showicon;
    QIcon hideicon;
    QPushButton *registerbutton;
    QPalette palette;
    bool passtag;
    QTcpSocket *tcpSocket;
    Draw *drawwidget;
signals:

public slots:
    void on_pushbutton_change_click();
    void on_pushbutton_showpassword_click();
    void on_pushbutton_login_click();
};

#endif // LOGINWIDGET_H
#include "LoginWidget.h"

LoginWidget::LoginWidget(QWidget *parent)
    : QWidget(parent)
{
    this->initui();
    this->passtag=true;
    this->tcpSocket=new QTcpSocket(this);
    connect(this->codebutton,SIGNAL(clicked()),this,SLOT(on_pushbutton_change_click()));
    connect(this->passicon,SIGNAL(clicked()),this,SLOT(on_pushbutton_showpassword_click()));
    connect(this->okbutton,SIGNAL(clicked()),this,SLOT(on_pushbutton_login_click()));
}

LoginWidget::~LoginWidget()
{

}

void LoginWidget::initui()
{
    //读取图片
     this->pix.load("./image/1000.jpg");
     //将窗口居中,设置标题
     QDesktopWidget *screen =  QApplication::desktop();
     int appwidth=400;
     int appheight=400;
     int center_x=(screen->width()-appwidth)/2;
     int center_y=(screen->height()-appheight)/2;
     this->setGeometry(center_x,center_y,appwidth,appheight);
     this->setWindowTitle(tr("登录"));

     //账号
     this->namelabel = new QLabel(tr("账号:"),this,0);
     this->namelabel->setGeometry(100,100,60,30);
     this->nameedit =new QLineEdit(this);
     this->nameedit->setGeometry(160,100,150,30);
     this->nameedit->setMaxLength(12);

     //密码
     this->passlabel = new QLabel(tr("密码:"),this,0);
     this->passicon=new QPushButton(this);
     this->showicon.addFile(tr("./image/4.png"));
     this->hideicon.addFile(tr("./image/3.png"));
     this->passicon->setIcon(this->hideicon);
     this->passicon->setGeometry(320,160,30,30);
     this->passlabel->setGeometry(100,160,60,30);
     this->passedit = new QLineEdit(this);
     this->passedit->setGeometry(160,160,150,30);
     this->passedit->setEchoMode(QLineEdit::Password);
     this->passedit->setMaxLength(8);

     //验证码
     this->codeedit = new QLineEdit(this);
     this->codeedit->setGeometry(100,220,100,30);
     this->codebutton = new QPushButton(this);
     this->codebutton->setGeometry(240,220,60,30);
     this->codebutton->setText(this->changecode());
     this->codeedit->setMaxLength(4);

     //登录和取消、注册按钮
     this->okbutton = new QPushButton(tr("登录"),this);
     this->okbutton->setGeometry(100,280,80,30);
     this->cancelbutton = new QPushButton(tr("取消"),this);
     this->cancelbutton->setGeometry(230,280,80,30);
     this->registerbutton = new QPushButton(tr("注册"),this);
     this->registerbutton->setGeometry(20,340,60,30);

     //设置登录界面的背景
     this->palette.setBrush(QPalette::Background,QBrush(this->pix));
     this->setPalette(this->palette);

}

QString LoginWidget::changecode()
{
    QString randstr;
    int num=0;
    while(num<999)
    {
        num=qrand()%10000;
    }
    randstr=QString::number(num);
    return randstr;
}

void LoginWidget::on_pushbutton_change_click()
{
    this->codebutton->setText(this->changecode());
}

void LoginWidget::on_pushbutton_showpassword_click()
{
    if(this->passtag==false)
    {
        this->passicon->setIcon(this->hideicon);
        this->passedit->setEchoMode(QLineEdit::Password);
        this->passtag=true;
    }else {
        this->passicon->setIcon(this->showicon);
        this->passedit->setEchoMode(QLineEdit::Normal);
        this->passtag=false;
    }
}

void LoginWidget::on_pushbutton_login_click()
{
    if(this->codeedit->text().compare(this->codebutton->text())!=0)
    {
         QMessageBox msgBox;
         msgBox.setWindowTitle("提示");
         msgBox.setText(tr("你输入的验证码有误!!!"));
         msgBox.exec();
         this->codebutton->setText(this->changecode());
    }else {
        QQDATA_T data={0};
        QQLOGIN_T login = { 0 };
        data.head.funcode=1;
        data.head.percode=1;
        memcpy(login.username,this->nameedit->text().toStdString().c_str(),32);
        memcpy(login.userpwd,this->passedit->text().toStdString().c_str(),32);
        this->tcpSocket->connectToHost(QHostAddress::LocalHost,8888);
        memcpy(data.buff, login.username, 32);
        memcpy(data.buff + 32, login.userpwd, 32);
        this->drawwidget=new Draw(0,this->tcpSocket);
        this->tcpSocket->write((char *)&data,sizeof (data));   //登录后将账号密码传到服务器去
        this->close();
        this->drawwidget->show();
    }
}


#ifndef MYTOOLBTN_H
#define MYTOOLBTN_H

#include <QToolButton>
#include <QMouseEvent>
#include <QWidget>
class Mytoolbtn:public QToolButton
{
    Q_OBJECT
public:
    Mytoolbtn(QWidget *parent = 0);
    void mouseDoubleClickEvent(QMouseEvent *ev); /*双击事件响应函数*/
private:
signals:
    void doubleclicked();
};

#endif // MYTOOLBTN_H
#include "Mytoolbtn.h"

Mytoolbtn::Mytoolbtn(QWidget *parent)
{

}

void Mytoolbtn::mouseDoubleClickEvent(QMouseEvent *ev)
{
    if(ev->button()==Qt::LeftButton)
    {
        emit doubleclicked();
    }
}

 有不懂的可以在评论区问我哦,也欢迎各位大神指教,毕竟还是个新手

  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
Qt是一个跨平台的GUI开发框架,通过Qt库可以很方便地实现各种功能。MQTT是一种轻量级的消息发布/订阅协议,用于在物联网设备之间传输消息。因此,我们可以通过Qt实现MQTT客户端来进行消息的发布和订阅。 首先,我们需要在Qt项目中添加MQTT库的支持。可以使用Qt自带的网络模块或者第三方的MQTT库,如QMQTT、Paho等。然后,在Qt的代码中引入相关的头文件,并创建一个MQTT客户端对象。 接下来,我们可以配置MQTT客户端的连接参数,包括服务器地址、端口号、用户名、密码等。可以通过调用MQTT客户端对象的setHostname、setPort、setUsername、setPassword等方法进行设置。 然后,我们需要连接到MQTT服务器。可以调用MQTT客户端对象的connect方法来连接到服务器。连接成功后,可以订阅特定的主题或者取消已有的订阅。可以调用MQTT客户端对象的subscribe和unsubscribe方法进行操作。 在连接成功后,我们可以发送消息到指定的主题。可以调用MQTT客户端对象的publish方法来发送消息,需要指定消息的主题和内容。同时,我们也可以接收来自服务器的消息。可以通过继承MQTT客户端的回调函数,在接收到消息时进行处理。 最后,在使用完MQTT客户端后,记得要正确地关闭连接,以释放资源。可以调用MQTT客户端对象的disconnect方法来关闭连接。 通过以上步骤,我们就可以使用Qt实现一个简单的MQTT客户端。通过该客户端,我们可以实现消息的发布和订阅功能,方便地在物联网设备之间进行通信。当然,具体的实现细节还需要根据具体的需求进行适配和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值