最近做了一个qq的项目,在qt上实现qq的客户端,在vs上实现qq的服务器,先让大家看看效果图吧
登录模块,按下登录后会连接服务器
登录后的好友列表,会显示所有的在线好友
有新好友上线会自动更新好友列表
双方进行聊天,互相收到消息
群聊功能,一个人发送消息其他在线的人都会收到
#ifndef CHATWIDGET_H
#define CHATWIDGET_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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
#include
#include
#include //一个有标题的组合框
#include //这个是垂直布局的头文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;ilist2.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;iupdate();
}
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(sender());
qDebug()<text()<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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#include
#include
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();
}
}
有不懂的可以在评论区问我哦,也欢迎各位大神指教,毕竟还是个新手