Qt版聊天软件
来源:互联网 发布:php 没有soapclient 编辑:程序博客网 时间:2024/04/29 18:24
18.1 核心功能界面演示
drawer.h
#ifndef DRAWER_H
#define DRAWER_H
#include "widget.h"
#include <QToolBox>
#include <QToolButton>
class Drawer : public QToolBox
{
Q_OBJECT
public:
Drawer(QWidget *parent=0,Qt::WindowFlags f=0);
private:
QToolButton *toolBtn1;
QToolButton *toolBtn2;
QToolButton *toolBtn3;
QToolButton *toolBtn4;
QToolButton *toolBtn5;
QToolButton *toolBtn6;
QToolButton *toolBtn7;
QToolButton *toolBtn8;
QToolButton *toolBtn9;
private slots:
void showChatWidget1();
void showChatWidget2();
void showChatWidget3();
void showChatWidget4();
void showChatWidget5();
void showChatWidget6();
void showChatWidget7();
void showChatWidget8();
void showChatWidget9();
private:
Widget *chatWidget1;
Widget *chatWidget2;
Widget *chatWidget3;
Widget *chatWidget4;
Widget *chatWidget5;
Widget *chatWidget6;
Widget *chatWidget7;
Widget *chatWidget8;
Widget *chatWidget9;
};
#endif // DRAWER_H
drawer.cpp
#include "drawer.h"
#include <QGroupBox>
#include <QVBoxLayout>
class QString rsrcPath = ":/images";
Drawer::Drawer(QWidget *parent, Qt::WindowFlags f)
:QToolBox(parent,f)
{
setWindowTitle (tr("Myself QQ 2015"));
setWindowIcon (QPixmap(rsrcPath + "/qq.png"));
toolBtn1 = new QToolButton;
toolBtn1->setText (tr(" 苦涩沙漠"));
toolBtn1->setIcon (QPixmap(rsrcPath + "/Cherry.png"));
toolBtn1->setIconSize (QPixmap(rsrcPath + "/Cherry.png").size () * 0.58);
toolBtn1->setAutoRaise (true); //当鼠标离开时,按钮自动恢复成弹起状态
toolBtn1->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn1, SIGNAL(clicked(bool)), this, SLOT(showChatWidget1()));
toolBtn2 = new QToolButton;
toolBtn2->setText (tr(" 飘逝的云"));
toolBtn2->setIcon (QPixmap(rsrcPath + "/dr.png"));
toolBtn2->setIconSize (QPixmap(rsrcPath + "/dr.png").size () * 0.58);
toolBtn2->setAutoRaise (true); //当鼠标离开时,按钮自动恢复成弹起状态
toolBtn2->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn2, SIGNAL(clicked(bool)), this, SLOT(showChatWidget2()));
toolBtn3 = new QToolButton;
toolBtn3->setText (tr(" 会飞的狼"));
toolBtn3->setIcon (QPixmap(rsrcPath + "/jj.png"));
toolBtn3->setIconSize (QPixmap(rsrcPath + "/dr.png").size () * 0.58);
toolBtn3->setAutoRaise (true);
toolBtn3->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn3, SIGNAL(clicked(bool)), this, SLOT(showChatWidget3()));
toolBtn4 = new QToolButton;
toolBtn4->setText (tr(" 金色的鱼"));
toolBtn4->setIcon (QPixmap(rsrcPath + "/lswh.png"));
toolBtn4->setIconSize (QPixmap(rsrcPath + "/lswh.png").size () * 0.58);
toolBtn4->setAutoRaise (true);
toolBtn4->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn4, SIGNAL(clicked(bool)), this, SLOT(showChatWidget4()));
toolBtn5 = new QToolButton;
toolBtn5->setText (tr(" 一夜情柔"));
toolBtn5->setIcon (QPixmap(rsrcPath + "/qmnn.png"));
toolBtn5->setIconSize (QPixmap(rsrcPath + "/qmnn.png").size () * 0.58);
toolBtn5->setAutoRaise (true);
toolBtn5->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn5, SIGNAL(clicked(bool)), this, SLOT(showChatWidget5()));
toolBtn6 = new QToolButton;
toolBtn6->setText (tr(" 天马行空"));
toolBtn6->setIcon (QPixmap(rsrcPath + "/spqy.png"));
toolBtn6->setIconSize (QPixmap(rsrcPath + "/spqy.png").size () * 0.58);
toolBtn6->setAutoRaise (true);
toolBtn6->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn6, SIGNAL(clicked(bool)), this, SLOT(showChatWidget6()));
toolBtn7 = new QToolButton;
toolBtn7->setText (tr(" 飞奔时代"));
toolBtn7->setIcon (QPixmap(rsrcPath + "/wy.png"));
toolBtn7->setIconSize (QPixmap(rsrcPath + "/wy.png").size () * 0.58);
toolBtn7->setAutoRaise (true);
toolBtn7->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn7, SIGNAL(clicked(bool)), this, SLOT(showChatWidget7()));
toolBtn8 = new QToolButton;
toolBtn8->setText (tr(" 一世情缘"));
toolBtn8->setIcon (QPixmap(rsrcPath + "/qq.png"));
toolBtn8->setIconSize (QPixmap(rsrcPath + "/qq.png").size () * 0.58);
toolBtn8->setAutoRaise (true);
toolBtn8->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn8, SIGNAL(clicked(bool)), this, SLOT(showChatWidget8()));
toolBtn9 = new QToolButton;
toolBtn9->setText (tr(" 钟爱一生"));
toolBtn9->setIcon (QPixmap(rsrcPath + "/ymrl.png"));
toolBtn9->setIconSize (QPixmap(rsrcPath + "/ymrl.png").size () * 0.58);
toolBtn9->setAutoRaise (true);
toolBtn9->setToolButtonStyle (Qt::ToolButtonTextBesideIcon);
connect(toolBtn9, SIGNAL(clicked(bool)), this, SLOT(showChatWidget9()));
//创建一个QGroupBox类类实例,在文本例中对应抽屉“群成员”
QGroupBox *groupBox = new QGroupBox;
QVBoxLayout *layout = new QVBoxLayout(groupBox);
layout->setMargin (6); //设置边框距
layout->setSpacing (2);
layout->setAlignment (Qt::AlignLeft | Qt::AlignTop);
layout->addWidget (toolBtn1);
layout->addWidget (toolBtn2);
layout->addWidget (toolBtn3);
layout->addWidget (toolBtn4);
layout->addWidget (toolBtn5);
layout->addWidget (toolBtn6);
layout->addWidget (toolBtn7);
layout->addWidget (toolBtn8);
layout->addWidget (toolBtn9);
this->addItem ((QWidget*)groupBox, tr("群成员"));
}
void Drawer::showChatWidget1 ()
{
//以按钮toolBtn1的文本为用户名创建一个Widget类的实例,对应于一个聊天窗口
chatWidget1 = new Widget(0, toolBtn1->text ());
//设置聊天的标题文字
chatWidget1->setWindowTitle (toolBtn1->text ());
//设置聊天窗口图标
chatWidget1->setWindowIcon (toolBtn1->icon ());
chatWidget1->show ();
}
void Drawer::showChatWidget2 ()
{
chatWidget2 = new Widget(0, toolBtn2->text ());
chatWidget2->setWindowTitle (toolBtn2->text ());
chatWidget2->setWindowIcon (toolBtn2->icon ());
chatWidget2->show ();
}
void Drawer::showChatWidget3 ()
{
chatWidget3 = new Widget(0, toolBtn3->text ());
chatWidget3->setWindowTitle (toolBtn3->text ());
chatWidget3->setWindowIcon (toolBtn3->icon ());
chatWidget3->show ();
}
void Drawer::showChatWidget4 ()
{
chatWidget4 = new Widget(0, toolBtn4->text ());
chatWidget4->setWindowTitle (toolBtn4->text ());
chatWidget4->setWindowIcon (toolBtn4->icon ());
chatWidget4->show ();
}
void Drawer::showChatWidget5 ()
{
chatWidget5 = new Widget(0, toolBtn5->text ());
chatWidget5->setWindowTitle (toolBtn5->text ());
chatWidget5->setWindowIcon (toolBtn5->icon ());
chatWidget5->show ();
}
void Drawer::showChatWidget6 ()
{
chatWidget6 = new Widget(0, toolBtn6->text ());
chatWidget6->setWindowTitle (toolBtn6->text ());
chatWidget6->setWindowIcon (toolBtn6->icon ());
chatWidget6->show ();
}
void Drawer::showChatWidget7 ()
{
chatWidget7 = new Widget(0, toolBtn7->text ());
chatWidget7->setWindowTitle (toolBtn7->text ());
chatWidget7->setWindowIcon (toolBtn7->icon ());
chatWidget7->show ();
}
void Drawer::showChatWidget8 ()
{
chatWidget8 = new Widget(0, toolBtn8->text ());
chatWidget8->setWindowTitle (toolBtn8->text ());
chatWidget8->setWindowIcon (toolBtn8->icon ());
chatWidget8->show ();
}
void Drawer::showChatWidget9 ()
{
chatWidget9 = new Widget(0, toolBtn9->text ());
chatWidget9->setWindowTitle (toolBtn9->text ());
chatWidget9->setWindowIcon (toolBtn9->icon ());
chatWidget9->show ();
}
client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <QDialog>
#include <QHostAddress>
#include <QFile>
#include <QTime>
class QTcpSocket;
namespace Ui {
class Client;
}
class Client : public QDialog
{
Q_OBJECT
public:
explicit Client(QWidget *parent = 0);
~Client();
void setHostAddr(QHostAddress addr); //获取发送端IP地址
void setFileName(QString name); //获取文件保存路径
protected:
void closeEvent(QCloseEvent *);
private:
Ui::Client *ui;
QTcpSocket *tClnt; //客户端套接字类
quint16 blockSize;
QHostAddress hostAddr;
qint16 tPort;
qint64 totalBytes; //总共需接收的字节数
qint64 bytesReceived; //已接收字节数
qint64 fileNameSize;
QString fileName;
QFile *locFile; //待接收的文件
QByteArray inBlock; //缓存一次接收的数据
QTime time;
private slots:
void newConn(); //连接到服务器
void readMsg(); //读取文件数据
void displayErr(QAbstractSocket::SocketError); //显示错误信息
void on_cCancleBtn_clicked();
void on_cCloseBtn_clicked();
};
#endif // CLIENT_H
client.cpp
#include "client.h"
#include "ui_client.h"
#include <QTcpSocket>
#include <QDebug>
#include <QMessageBox>
Client::Client(QWidget *parent) :
QDialog(parent),
ui(new Ui::Client)
{
ui->setupUi(this);
setFixedSize (400, 190);
totalBytes = 0;
bytesReceived = 0;
fileNameSize = 0;
tClnt = new QTcpSocket(this);
tPort = 5555;
/**/
connect (tClnt, SIGNAL(readyRead()), this, SLOT(readMsg()));
/*接收文件的中途,一旦发生错误,则采用displayErr()槽函数输出错误信息*/
connect (tClnt, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayErr(QAbstractSocket::SocketError)));
}
Client::~Client()
{
delete ui;
}
/*
* 获取文件保存路径
*/
void Client::setFileName (QString name)
{
locFile = new QFile(name);
}
/*
* 获取发送端IP地址
*/
void Client::setHostAddr (QHostAddress addr)
{
hostAddr = addr;
newConn ();
}
/*
* 用来设置与服务器的连接
*/
void Client::newConn ()
{
blockSize = 0;
//中止当前的连接和重置套接字
tClnt->abort ();
tClnt->connectToHost (hostAddr, tPort);
time.start ();
}
void Client::readMsg ()
{
QDataStream in(tClnt);
in.setVersion(QDataStream::Qt_4_7);
float useTime = time.elapsed();
if (bytesReceived <= sizeof(qint64)*2) {
if ((tClnt->bytesAvailable() >= sizeof(qint64)*2) && (fileNameSize == 0))
{
in>>totalBytes>>fileNameSize;
bytesReceived += sizeof(qint64)*2;
}
if((tClnt->bytesAvailable() >= fileNameSize) && (fileNameSize != 0)){
in>>fileName;
bytesReceived +=fileNameSize;
if(!locFile->open(QFile::WriteOnly)){
QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2.").arg(fileName).arg(locFile->errorString()));
return;
}
} else {
return;
}
}
if (bytesReceived < totalBytes) {
bytesReceived += tClnt->bytesAvailable();
inBlock = tClnt->readAll();
locFile->write(inBlock);
inBlock.resize(0);
}
ui->progressBar->setMaximum(totalBytes);
ui->progressBar->setValue(bytesReceived);
double speed = bytesReceived / useTime;
ui->cStatusLbl->setText(tr("已接收 %1MB (%2MB/s) \n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
.arg(bytesReceived / (1024*1024))
.arg(speed*1000/(1024*1024),0,'f',2)
.arg(totalBytes / (1024 * 1024))
.arg(useTime/1000,0,'f',0)
.arg(totalBytes/speed/1000 - useTime/1000,0,'f',0));
if(bytesReceived == totalBytes)
{
locFile->close();
tClnt->close();
ui->cStatusLbl->setText(tr("接收文件 %1 完毕").arg(fileName));
}
}
/*
* 接收文件的中途,一旦发生错误,则采用displayErr()槽函数输出错误信息
*/
void Client::displayErr (QAbstractSocket::SocketError sockErr)
{
switch(sockErr)
{
case QAbstractSocket::RemoteHostClosedError : break;
default : qDebug() << tClnt->errorString();
}
}
void Client::on_cCancleBtn_clicked()
{
//中止当前的连接和重置套接字
tClnt->abort ();
if(locFile->isOpen ())
{
locFile->close ();
}
}
void Client::on_cCloseBtn_clicked()
{
//中止当前的连接和重置套接字
tClnt->abort ();
if(locFile->isOpen ())
{
locFile->close ();
}
close ();
}
void Client::closeEvent (QCloseEvent *)
{
on_cCloseBtn_clicked ();
}
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QDialog>
#include <QTime>
class QFile;
class QTcpServer;
class QTcpSocket;
namespace Ui {
class Server;
}
class Server : public QDialog
{
Q_OBJECT
public:
explicit Server(QWidget *parent = 0);
~Server();
void initSrv(); //初始化服务器
void refused(); //关闭服务器
protected:
void closeEvent(QCloseEvent *);
private:
Ui::Server *ui;
qint16 tPort;
QTcpServer *tSrv;
QString fileName;
QString theFileName;
QFile *locFile; //待发送的文件
qint64 totalBytes; //总共需要发送的字节
qint64 bytesWritten; //已经发送字节数
qint64 bytesTobeWrite; //待发送的字节数
qint64 payloadSize; //被初始化为一个常量
QByteArray outBlock; //缓存一次发送的数据
QTcpSocket *clntConn; //客户端连接的套接字
QTime time;
private slots:
void sndMsg(); //发送数据
void updClntProgress(qint64 numBytes); //更新进度条
void on_sSendBtn_clicked();
void on_sOpenBtn_clicked();
void on_sCloseBtn_clicked();
signals:
void sndFileName(QString fileName);
};
#endif // SERVER_H
server.cpp
#include "server.h"
#include "ui_server.h"
#include <QFile>
#include <QTcpServer>
#include <QTcpSocket>
#include <QMessageBox>
#include <QFileDialog>
#include <QDebug>
Server::Server(QWidget *parent) :
QDialog(parent),
ui(new Ui::Server)
{
ui->setupUi (this);
setFixedSize (400, 207);
tPort = 5555;
tSrv = new QTcpServer(this);
connect(tSrv, SIGNAL(newConnection()), this, SLOT(sndMsg()));
initSrv ();
}
Server::~Server()
{
delete ui;
}
/*
* 初始化服务器
*/
void Server::initSrv ()
{
payloadSize = 64 * 1024;
totalBytes = 0;
bytesWritten = 0;
bytesTobeWrite = 0;
ui->sStatusLbl->setText (tr("请选择要传送的文件"));
//重新设置进度条
ui->progressBar->reset ();
ui->sOpenBtn->setEnabled (true);
ui->sSendBtn->setEnabled (false);
//关闭服务器
tSrv->close ();
}
/*
* 发送数据
*/
void Server::sndMsg ()
{
ui->sSendBtn->setEnabled (false);
clntConn = tSrv->nextPendingConnection (); //获取下一个等待连接
connect(clntConn, SIGNAL(bytesWritten(qint64)), this, SLOT(updClntProgress(qint64)));
ui->sStatusLbl->setText (tr("开始传送文件%1 !").arg (theFileName));
locFile = new QFile(fileName);
//首先以只读方式打开选中的文件
if(!locFile->open((QFile::ReadOnly)))
{
QMessageBox::warning(this, tr("应用程序"), tr("无法读取文件 %1:\n%2").arg(fileName).arg(locFile->errorString()));
return;
}
/*通过QFile类的size()函数获取待发送文件的大小,并将该值暂存于totalBytes变量中*/
totalBytes = locFile->size ();
/*将发送缓冲区outBlock封装在一个QDataStream类型的变量中,这样做可以很方便地通过重载的"<<"操作符填写文件头指针*/
QDataStream sendout(&outBlock, QIODevice::WriteOnly);
sendout.setVersion (QDataStream::Qt_4_7);
//time是QTime对象,用来统计传输所用的时间
time.start ();
/*通过QString类的right()函数去掉文件的路径部分,仅将文件部分保存在curFile变量中,最后位置-1,减去‘/’的长度*/
QString curFile = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
/*构造一个临时的文件头,将该值追加到totalBytes字段,从而完成实际需要发送字节数的记录*/
sendout << qint64(0) << qint64(0) << curFile;
totalBytes += outBlock.size();
/*将读写操作指向从头开始*/
sendout.device ()->seek (0);
/*填写实际的总长度和文件长度*/
sendout << totalBytes << qint64((outBlock.size () - sizeof(qint64) * 2));
/*将文件头发出,同时修改发送字节数bytesTobeWrite*/
bytesTobeWrite = totalBytes - clntConn->write (outBlock);
/*清空发送缓存区以备下次使用*/
outBlock.resize (0);
}
/*
* 更新进度条
*/
void Server::updClntProgress (qint64 numBytes)
{
/*用于在传输大文件时使界面不会冻结*/
qApp->processEvents ();
bytesWritten += (int)numBytes;
/*如果已发送的字节数大于0*/
if(bytesWritten > 0)
{
/*将待发送的字节数读到发送缓冲区outBlock中*/
outBlock = locFile->read (qMin(bytesTobeWrite, payloadSize));
/*更新待发送的字节数*/
bytesTobeWrite -= (int)clntConn->write (outBlock);
/*将发送缓冲区清空*/
outBlock.resize (0);
}
else
{
//关闭文件
locFile->close ();
}
ui->progressBar->setMaximum (totalBytes);
ui->progressBar->setValue (bytesWritten);
/*time.elapsed ()函数来获取耗费的时间,这个是从time.start()开始计时的。通过获取的时间*/
float useTime = time.elapsed ();
double speed = bytesWritten / useTime;
ui->sStatusLbl->setText(tr("已发送 %1MB (%2MB/s) \n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
.arg(bytesWritten / (1024*1024))
.arg(speed*1000 / (1024*1024), 0, 'f', 2)
.arg(totalBytes / (1024 * 1024))
.arg(useTime/1000, 0, 'f', 0)
.arg(totalBytes/speed/1000 - useTime/1000, 0, 'f', 0));
if(bytesWritten == totalBytes)
{
locFile->close ();
tSrv->close ();
ui->sStatusLbl->setText (tr("传送文件 %1 成功").arg (theFileName));
}
}
/*
* 打开文件函数
*/
void Server::on_sOpenBtn_clicked()
{
fileName = QFileDialog::getOpenFileName (this);
if(!fileName.isEmpty ())
{
/*仅将文件部分保存在theFileName变量中*/
theFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
ui->sStatusLbl->setText(tr("要传送的文件为:%1 ").arg(theFileName));
ui->sSendBtn->setEnabled(true);
ui->sOpenBtn->setEnabled(false);
}
}
/*
* 发送文件槽函数
*/
void Server::on_sSendBtn_clicked()
{
/*开始监听*/
if(!tSrv->listen(QHostAddress::Any,tPort))//开始监听
{
qDebug() << tSrv->errorString();
close();
return;
}
ui->sStatusLbl->setText(tr("等待对方接收... ..."));
emit sndFileName(theFileName);
}
/*
* 关闭监听槽函数
*/
void Server::on_sCloseBtn_clicked()
{
/*关闭服务器*/
if(tSrv->isListening ())
{
tSrv->close ();;
if(locFile->isOpen ())
{
locFile->close ();
}
clntConn->abort ();
}
/*关闭对话框*/
close ();
}
void Server::closeEvent (QCloseEvent *)
{
on_sCloseBtn_clicked ();
}
/*
* 如果接收端拒绝接收该文件,则关闭服务器
*/
void Server::refused ()
{
tSrv->close ();
ui->sStatusLbl->setText (tr("对方拒绝接收!"));
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QKeyEvent>
#include <QTextCharFormat>
class QUdpSocket;
class Server;
namespace Ui {
class Widget;
}
enum MsgType{Msg, UsrEnter, UsrLeft, FileName, Refuse}; //消息类型
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent,QString usrname);
~Widget();
protected:
void usrEnter(QString usename, QString ipaddr); //处理新用户加入
void usrLeft(QString usrname, QString time); //处理用户离开
void sndMsg(MsgType type, QString srvaddr=""); //获取UDP消息
QString getIP(); //获取IP地址
QString getUsr(); //获取用户名
QString getMsg(); //获取聊天消息
//用于在收到文件名UDP消息时判断是否接受该文件
void hasPendingFile(QString usrname, QString srvaddr,QString clntaddr, QString filename);
bool saveFile(const QString& filename);
void closeEvent(QCloseEvent *);
private:
Ui::Widget *ui;
QUdpSocket *udpSocket;
qint16 port;
QString uName;
QString fileName;
Server *srv;
QColor color;
private slots:
void processPendingDatagrams(); //接收UDP消息
void on_sendBtn_clicked();
void getFileName(QString); //获取服务器类sndFileName()信号发送过来的文件名
void on_exitBtn_clicked();
void on_sendTBtn_clicked();
void on_fontCbx_activated(const QString &arg1);
void on_sizeCbx_activated(const QString &arg1);
void on_boldTBtn_clicked(bool checked);
void on_italicTBtn_clicked(bool checked);
void on_underlineTBtn_clicked(bool checked);
void curFmtChanged(const QTextCharFormat &fmt);
void on_colorTBtn_clicked();
void on_saveTBtn_clicked();
void on_clearTBtn_clicked();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QUdpSocket>
#include <QMessageBox>
#include <QScrollBar>
#include <QDateTime>
#include <QNetworkInterface>
#include "server.h"
#include "client.h"
#include <QFileDialog>
#include <QColorDialog>
Widget::Widget(QWidget *parent,QString usrname) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
uName = usrname;
udpSocket = new QUdpSocket(this);
//设置UDP的端口号参数,服务器定向此端口发送广播信息
port = 23232;
//绑定指定的端口上
udpSocket->bind (port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
//connect()槽函数,随时接收来自其他用户的UDP广播消息
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
//发送UDP广播消息则是通过调用sndMSg函数来实现的,该函数专门用于发送各类UDP数据
sndMsg (UsrEnter);
srv = new Server(this);
connect(srv, SIGNAL(sndFileName(QString)), this, SLOT(getFileName(QString)));
connect(ui->msgTxtEdit, SIGNAL(currentCharFormatChanged(QTextCharFormat)),this, SLOT(curFmtChanged(const QTextCharFormat)));
}
Widget::~Widget()
{
delete ui;
}
/*
* 广播UDP消息
*/
void Widget::sndMsg (MsgType type, QString srvaddr)
{
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
QString address = getIP ();
out << type << getUsr (); //向要发送的数据中写入信息类型type、用户名
switch(type)
{
case Msg : //处理聊天信息
if(ui->msgTxtEdit->toPlainText () == "")
{
QMessageBox::warning (0, tr("警告"), tr("发送内容不能为空"), QMessageBox::Ok);
return;
}
out << address << getMsg ();
ui->msgBrowser->verticalScrollBar ()->setValue (ui->msgBrowser->verticalScrollBar ()->maximum ());
break;
case UsrEnter: //对于新用户加入UsrEnter,只是简单地向数据中写入IP地址
out << address;
break;
case UsrLeft :
break;
case FileName:
{
int row = ui->usrTblWidget->currentRow();
QString clntaddr = ui->usrTblWidget->item(row, 1)->text();
out << address << clntaddr << fileName;
break;
}
case Refuse:
out << srvaddr;
break;
}
//完成对消息的处理后,最后使用writeDatagram()函数进行UDP广播
udpSocket->writeDatagram (data, data.length (), QHostAddress::Broadcast, port);
}
/*
* 接收UDP消息
*/
void Widget::processPendingDatagrams ()
{
//hasPendingDatagrams()判断是否有可提供读取的数据
while(udpSocket->hasPendingDatagrams ())
{
QByteArray datagram;
//如果有可读取的数据则通过pendingDatagramSize()获取当前可供读取的UDP报文大小,并据此大小分配接收缓冲区datagram,
//最后使用QUdpSocket类的成员函数readDatagram读取相应数据
datagram.resize (udpSocket->pendingDatagramSize ());
udpSocket->readDatagram (datagram.data (), datagram.size ());
QDataStream in(&datagram, QIODevice::ReadOnly);
int msgType;
in >> msgType;//首先获取信息的类型
QString usrName,ipAddr,msg;
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
switch(msgType)
{
case Msg: //处理接收消息
//如果是普通的聊天消息Msg,那么就获取其中的用户名,IP地址和内容信息等数据,然后用户名和聊天内容显示
//在界面左上角的信息浏览器msgBrowser中,在显示信息的同时显示系统当前日期时间
in >> usrName >> ipAddr >> msg;
ui->msgBrowser->setTextColor(Qt::blue);
ui->msgBrowser->setCurrentFont(QFont("Times New Roman",12));
ui->msgBrowser->append("[ " +usrName+" ] "+ time);
ui->msgBrowser->append(msg);
break;
case UsrEnter: //如果是新用户加入UsrEnter,那么就获取其中的用户名和IP地址信息,然后使用usrEnter()函数进行新用户登录的处理
in >> usrName >> ipAddr;
usrEnter (usrName, ipAddr);
break;
case UsrLeft: //如果是用户退出UsrLeft,那么获取其中的用户名,然后使用usrLeft()函数进行用户离开的处理
in >>usrName;
usrLeft(usrName,time);
break;
case FileName:
{
in >> usrName >> ipAddr;
QString clntAddr, fileName;
in >> clntAddr >> fileName;
hasPendingFile(usrName, ipAddr, clntAddr, fileName);
break;
}
case Refuse:
{
in >> usrName;
QString srvAddr;
in >> srvAddr;
QString ipAddr = getIP();
if(ipAddr == srvAddr)
{
srv->refused();
}
break;
}
}
}
}
/*
* 处理新用户加入
*/
void Widget::usrEnter (QString usrname, QString ipaddr)
{
bool isEmpty = ui->usrTblWidget->findItems(usrname, Qt::MatchExactly).isEmpty();
if (isEmpty) {
QTableWidgetItem *usr = new QTableWidgetItem(usrname);
QTableWidgetItem *ip = new QTableWidgetItem(ipaddr);
ui->usrTblWidget->insertRow(0);
ui->usrTblWidget->setItem(0,0,usr);
ui->usrTblWidget->setItem(0,1,ip);
ui->msgBrowser->setTextColor(Qt::gray);
ui->msgBrowser->setCurrentFont(QFont("Times New Roman",10));
ui->msgBrowser->append(tr("%1 在线!").arg(usrname));
ui->usrNumLbl->setText(tr("在线人数:%1").arg(ui->usrTblWidget->rowCount()));
sndMsg(UsrEnter);
}
}
/*
* 处理用户离开
*/
void Widget::usrLeft (QString usrname, QString time)
{
int rowNum = ui->usrTblWidget->findItems(usrname, Qt::MatchExactly).first()->row();
ui->usrTblWidget->removeRow(rowNum);
ui->msgBrowser->setTextColor(Qt::gray);
ui->msgBrowser->setCurrentFont(QFont("Times New Roman", 10));
ui->msgBrowser->append(tr("%1 于 %2 离开!").arg(usrname).arg(time));
ui->usrNumLbl->setText(tr("在线人数:%1").arg(ui->usrTblWidget->rowCount()));
}
/*
* 获得IP地址
*/
QString Widget::getIP ()
{
//QNetworkInterface类提供了一个主机IP地址和网络接口的列表
QList<QHostAddress> list = QNetworkInterface::allAddresses ();
foreach(QHostAddress addr, list)
{
//判断IP的协议
if(addr.protocol () == QAbstractSocket::IPv4Protocol)
{
return addr.toString ();
}
}
return 0;
}
/*
* 获取用户名
*/
QString Widget::getUsr ()
{
return uName;
}
/*
* 获取聊天信息
*/
QString Widget::getMsg ()
{
QString msg = ui->msgTxtEdit->toHtml ();
ui->msgTxtEdit->clear ();
ui->msgTxtEdit->setFocus ();
return msg;
}
/*
* 发送消息按钮
*/
void Widget::on_sendBtn_clicked()
{
sndMsg (Msg);
}
/*
* 退出聊天窗口按钮
*/
void Widget::on_exitBtn_clicked()
{
close();
}
/*
* 获取服务器类sndFileName()信号发送过来的文件名
*/
void Widget::getFileName (QString name)
{
fileName = name;
sndMsg (FileName);
}
/*
* 传输文件
*/
void Widget::on_sendTBtn_clicked()
{
if(ui->usrTblWidget->selectedItems().isEmpty())
{
QMessageBox::warning(0, tr("选择用户"),tr("请先选择目标用户!"), QMessageBox::Ok);
return;
}
srv->show();
srv->initSrv();
}
/*
* 来判断是否要接收该文件,当发送过来拒绝信息时,需要判断改程序是否是发送端,如果是,则执行服务器的refused()函数
*/
void Widget::hasPendingFile (QString usrname, QString srvaddr, QString clntaddr, QString filename)
{
QString ipAddr = getIP();
if(ipAddr == clntaddr)
{
int btn = QMessageBox::information(this,tr("接受文件"),tr("来自%1(%2)的文件:%3,是否接收?").arg(usrname).arg(srvaddr).arg(filename),QMessageBox::Yes,QMessageBox::No);
if (btn == QMessageBox::Yes)
{
QString name = QFileDialog::getSaveFileName(0,tr("保存文件"),filename);
if(!name.isEmpty())
{
Client *clnt = new Client(this);
clnt->setFileName(name);
clnt->setHostAddr(QHostAddress(srvaddr));
clnt->show();
}
}
else {
sndMsg(Refuse, srvaddr);
}
}
}
void Widget::closeEvent(QCloseEvent *e)
{
sndMsg(UsrLeft);
QWidget::closeEvent(e);
}
void Widget::on_fontCbx_activated(const QString &arg1)
{
ui->msgTxtEdit->setCurrentFont (arg1);
ui->msgTxtEdit->setFocus ();
}
void Widget::on_sizeCbx_activated(const QString &arg1)
{
ui->msgTxtEdit->setFontPointSize (arg1.toDouble ());
ui->msgTxtEdit->setFocus ();
}
void Widget::on_boldTBtn_clicked(bool checked)
{
if(checked)
{
ui->msgTxtEdit->setFontWeight (QFont::Bold);
}
else
{
ui->msgTxtEdit->setFontWeight (QFont::Normal);
}
ui->msgTxtEdit->setFocus ();
}
void Widget::on_italicTBtn_clicked(bool checked)
{
ui->msgTxtEdit->setFontItalic (checked);
ui->msgTxtEdit->setFocus ();
}
void Widget::on_underlineTBtn_clicked(bool checked)
{
ui->msgTxtEdit->setFontUnderline (checked);
ui->msgTxtEdit->setFocus ();
}
void Widget::on_colorTBtn_clicked()
{
color = QColorDialog::getColor (color, this);
if(color.isValid ())
{
ui->msgTxtEdit->setTextColor (color);
ui->msgTxtEdit->setFocus ();
}
}
bool Widget::saveFile (const QString &filename)
{
QFile file(filename);
if(!file.open (QFile::WriteOnly | QFile::Text))
{
QMessageBox::warning (this, tr("保存文件"), tr("无法保存文件 %1:\n%2").arg (filename).arg (file.errorString ()));
return false;
}
QTextStream out(&file);
out << ui->msgBrowser->toPlainText ();
return true;
}
void Widget::on_saveTBtn_clicked()
{
if(ui->msgTxtEdit->document ()->isEmpty ())
{
QMessageBox::warning (0, tr("警告"), tr("聊天记录为空,无法保存!"), QMessageBox::Ok);
}
else
{
QString name = QFileDialog::getSaveFileName (this, tr("保存聊天记录"), tr("聊天记录"), tr("文本(*.txt);;所有文件(*.*)"));
if(!name.isEmpty ())
{
saveFile(name);
}
}
}
void Widget::on_clearTBtn_clicked()
{
ui->msgBrowser->clear ();
}
void Widget::curFmtChanged (const QTextCharFormat &fmt)
{
ui->fontCbx->setCurrentFont(fmt.font());
if (fmt.fontPointSize() < 8) {
ui->sizeCbx->setCurrentIndex(4);
} else {
ui->sizeCbx->setCurrentIndex(ui->sizeCbx->findText(QString::number(fmt.fontPointSize())));
}
ui->boldTBtn->setChecked(fmt.font().bold());
ui->italicTBtn->setChecked(fmt.font().italic());
ui->underlineTBtn->setChecked(fmt.font().underline());
color = fmt.foreground().color();
}
0 0
- Qt版聊天软件
- Qt局域网聊天软件
- Qt局域网聊天软件
- Qt UDP聊天软件
- Qt 聊天软件 源码下载
- 基于Qt的局域网聊天软件
- 基于Linux和Qt的聊天软件
- QT 即时聊天软件(一)
- QT开发的即时通讯聊天软件
- python版 聊天软件
- Qt学习之路_6(Qt局域网聊天软件)
- Qt学习之路_6(Qt局域网聊天软件)
- Qt学习之路_6(Qt局域网聊天软件)
- Qt学习之路_6(Qt局域网聊天软件)
- Qt学习之路_6(Qt局域网聊天软件)
- 基于Qt的UDP传输文字聊天小软件实现
- 聊天软件
- TT聊天软件v1.0版
- java开发自定义表单功能类:FormUtil
- Activity管理工具类AppManager
- 朝花夕拾——Java的synthetic修饰词
- next_permutation(全排列算法)
- 虚函数 假多态 C++
- Qt版聊天软件
- iOS开发之JsonKit
- 04 计算平台数
- 眼保健操
- 备份
- Android:菜单随记
- 红黑树的应用
- 4-1 简单输出整数
- Waitkey函数的用法