实现较简单,主要就四个类:
widget 主窗口,群聊,发送文件,
Tcpclient 接收文件
Tcpserver 发送文件
Chat 建立私聊
Widget >> setupUi
Widget >> new TcpServer
Widget >> sendMessage(NewParticipant)
Widget >> new QUdpSocket
Widget >> tableWidget_doubleClicked >> new Chat
Widget >> bind(udpSocket) >> connet(udpSocket, processPending)
processPending >> NewParticipant >> add new(判断是否已有) >> sendMessage(NewParticipant )(回应)
processPending >> ParticipantLeft >> release partner
processPending >> new chat(name,ip) >> showChat
processPending >> Message >> ui->textBrowser->append(message)
processPending >> FileName >> hasPendingFile >> QMessageBox::information >> yes >>new TcpClient
QMessageBox::information >> refuse >> send
processPending >> Refuse >> tcpServer->close()
TcpServer >> setupUi
TcpServer >> Send_clicked >> emit sendFileName(theFileName) >> sendMessage
Tcpclient >> setupUi
Tcpclient >> connect(readyRead(),readMessage())
Tcpclient >> connect(SocketError(),SocketError())
Chat >> setupUi
Chat >> new QUdpSocket >> bind >> connect(readyRead(),PendingData()) //the same as Widget
Chat >> new TcpServer //the same as Widget
main.c
#include
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
w.show();
return a.exec();
}
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include "tcpclient.h"
#include "tcpserver.h"
#include "chat.h"
using namespace std::tr1;
namespace Ui {
class Widget;
}
//enum MessageType
//{
// Message,
// NewParticipant,
// ParticipantLeft,
// FileName,
// Refuse,
// xchat
//};
//枚举变量标志信息的类型,分别为消息,新用户加入,和用户退出
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
QString getUserName();
QString getMessage();
chat* privatechat;
chat* privatechat1;
protected:
void changeEvent(QEvent *e);
void sendMessage(MessageType type,QString serverAddress="");
void newParticipant(QString userName,QString localHostName,QString ipAddress);
void participantLeft(QString userName,QString localHostName,QString time);
void closeEvent(QCloseEvent *);
void hasPendingFile(QString userName,QString serverAddress,
QString clientAddress,QString fileName);
bool eventFilter(QObject *target, QEvent *event);//事件过滤器
private:
Ui::Widget *ui;
QUdpSocket *udpSocket;
qint32 port;
qint32 bb;
QString fileName;
TcpServer *server;
//chat *privatechat;
QString getIP();
QColor color;//颜色
bool saveFile(const QString& fileName);//保存聊天记录
void showxchat(QString name, QString ip);
private slots:
void on_tableWidget_doubleClicked(QModelIndex index);
void on_textUnderline_clicked(bool checked);
void on_clear_clicked();
void on_save_clicked();
void on_textcolor_clicked();
void on_textitalic_clicked(bool checked);
void on_textbold_clicked(bool checked);
void on_fontComboBox_currentFontChanged(QFont f);
void on_fontsizecomboBox_currentIndexChanged(QString );
void on_close_clicked();
void on_sendfile_clicked();
void on_send_clicked();
void processPendingDatagrams();
void sentFileName(QString);
void currentFormatChanged(const QTextCharFormat &format);
signals:
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
using namespace std::tr1;
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->resize(850,550);
ui->textEdit->setFocusPolicy(Qt::StrongFocus);
ui->textBrowser->setFocusPolicy(Qt::NoFocus);
ui->textEdit->setFocus();
ui->textEdit->installEventFilter(this);//设置完后自动调用其eventFilter函数
privatechat = NULL;
privatechat1 = NULL;
udpSocket = new QUdpSocket(this);
port = 45454;
bb = 0;
udpSocket->bind(port,QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));
sendMessage(NewParticipant);
server = new TcpServer(this);
connect(server,SIGNAL(sendFileName(QString)),this,SLOT(sentFileName(QString)));
connect(ui->textEdit,SIGNAL(currentCharFormatChanged(QTextCharFormat)),this,SLOT(currentFormatChanged(const QTextCharFormat)));
}
void Widget::currentFormatChanged(const QTextCharFormat &format)
{//当编辑器的字体格式改变时,我们让部件状态也随之改变
ui->fontComboBox->setCurrentFont(format.font());
if(format.fontPointSize()<9) //如果字体大小出错,因为我们最小的字体为9
{
ui->fontsizecomboBox->setCurrentIndex(3); //即显示12
}
else
{
ui->fontsizecomboBox->setCurrentIndex(ui->fontsizecomboBox->findText(QString::number(format.fontPointSize())));
}
ui->textbold->setChecked(format.font().bold());
ui->textitalic->setChecked(format.font().italic());
ui->textUnderline->setChecked(format.font().underline());
color = format.foreground().color();
}
void Widget::processPendingDatagrams() //接收数据UDP
{
while(udpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(),datagram.size());
QDataStream in(&datagram,QIODevice::ReadOnly);
int messageType;
in >> messageType;
QString userName,localHostName,ipAddress,message;
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
switch(messageType)
{
case Message:
{
in >>userName >>localHostName >>ipAddress >>message;
ui->textBrowser->setTextColor(Qt::blue);
ui->textBrowser->setCurrentFont(QFont("Times New Roman",12));
ui->textBrowser->append("[ " +localHostName+" ] "+ time);
ui->textBrowser->append(message);
break;
}
case NewParticipant:
{
in >>userName >>localHostName >>ipAddress;
newParticipant(userName,localHostName,ipAddress);
break;
}
case ParticipantLeft:
{
in >>userName >>localHostName;
participantLeft(userName,localHostName,time);
break;
}
case FileName:
{
in >>userName >>localHostName >> ipAddress;
QString clientAddress,fileName;
in >> clientAddress >> fileName;
hasPendingFile(userName,ipAddress,clientAddress,fileName);
break;
}
case Refuse:
{
in >> userName >> localHostName;
QString serverAddress;
in >> serverAddress;
QString ipAddress = getIP();
if(ipAddress == serverAddress)
{
server->refused();
}
break;
}
case Xchat:
{
in >>userName >>localHostName >>ipAddress;
showxchat(localHostName,ipAddress);//显示与主机名聊天中,不是用户名
break;
}
}
}
}
//处理新用户加入
void Widget::newParticipant(QString userName,QString localHostName,QString ipAddress)
{
bool bb = ui->tableWidget->findItems(localHostName,Qt::MatchExactly).isEmpty();
if(bb)
{
QTableWidgetItem *user = new QTableWidgetItem(userName);
QTableWidgetItem *host = new QTableWidgetItem(localHostName);
QTableWidgetItem *ip = new QTableWidgetItem(ipAddress);
ui->tableWidget->insertRow(0);
ui->tableWidget->setItem(0,0,user);
ui->tableWidget->setItem(0,1,host);
ui->tableWidget->setItem(0,2,ip);
ui->textBrowser->setTextColor(Qt::gray);
ui->textBrowser->setCurrentFont(QFont("Times New Roman",10));
ui->textBrowser->append(tr("%1 在线!").arg(localHostName));
ui->onlineUser->setText(tr("在线人数:%1").arg(ui->tableWidget->rowCount()));
sendMessage(NewParticipant);
}
}
//处理用户离开
void Widget::participantLeft(QString userName,QString localHostName,QString time)
{
int rowNum = ui->tableWidget->findItems(localHostName,Qt::MatchExactly).first()->row();
ui->tableWidget->removeRow(rowNum);
ui->textBrowser->setTextColor(Qt::gray);
ui->textBrowser->setCurrentFont(QFont("Times New Roman",10));
ui->textBrowser->append(tr("%1 于 %2 离开!").arg(localHostName).arg(time));
ui->onlineUser->setText(tr("在线人数:%1").arg(ui->tableWidget->rowCount()));
}
Widget::~Widget()
{
delete ui;
// delete privatechat;
// privatechat = NULL;
//udpSocket
//server
}
void Widget::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
QString Widget::getIP() //获取ip地址
{
QList list = QNetworkInterface::allAddresses();
foreach (QHostAddress address, list)
{
if(address.protocol() == QAbstractSocket::IPv4Protocol) //我们使用IPv4地址
return address.toString();
}
return 0;
}
void Widget::sendMessage(MessageType type, QString serverAddress) //发送信息
{
QByteArray data;
QDataStream out(&data,QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIP();
out << type << getUserName() << localHostName;
switch(type)
{
case ParticipantLeft:
{
break;
}
case NewParticipant:
{
out << address;
break;
}
case Message :
{
if(ui->textEdit->toPlainText() == "")
{
QMessageBox::warning(0,tr("警告"),tr("发送内容不能为空"),QMessageBox::Ok);
return;
}
out << address << getMessage();
ui->textBrowser->verticalScrollBar()->setValue(ui->textBrowser->verticalScrollBar()->maximum());
break;
}
case FileName:
{
int row = ui->tableWidget->currentRow();
QString clientAddress = ui->tableWidget->item(row,2)->text();
out << address << clientAddress << fileName;
break;
}
case Refuse:
{
out << serverAddress;
break;
}
}
udpSocket->writeDatagram(data,data.length(),QHostAddress::Broadcast, port);
}
QString Widget::getUserName() //获取用户名
{
QStringList envVariables;
envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*"
<< "HOSTNAME.*" << "DOMAINNAME.*";
QStringList environment = QProcess::systemEnvironment();
foreach (QString string, envVariables)
{
int index = environment.indexOf(QRegExp(string));
if (index != -1)
{
QStringList stringList = environment.at(index).split('=');
if (stringList.size() == 2)
{
return stringList.at(1);
break;
}
}
}
return false;
}
QString Widget::getMessage() //获得要发送的信息
{
QString msg = ui->textEdit->toHtml();
ui->textEdit->clear();
ui->textEdit->setFocus();
return msg;
}
void Widget::closeEvent(QCloseEvent *)
{
sendMessage(ParticipantLeft);
}
void Widget::sentFileName(QString fileName)
{
this->fileName = fileName;
sendMessage(FileName);
}
void Widget::hasPendingFile(QString userName,QString serverAddress, //接收文件
QString clientAddress,QString fileName)
{
QString ipAddress = getIP();
if(ipAddress == clientAddress)
{
int btn = QMessageBox::information(this,tr("接受文件"),
tr("来自%1(%2)的文件:%3,是否接收?")
.arg(userName).arg(serverAddress).arg(fileName),
QMessageBox::Yes,QMessageBox::No);
if(btn == QMessageBox::Yes)
{
QString name = QFileDialog::getSaveFileName(0,tr("保存文件"),fileName);
if(!name.isEmpty())
{
TcpClient *client = new TcpClient(this);
client->setFileName(name);
client->setHostAddress(QHostAddress(serverAddress));
client->show();
}
}
else{
sendMessage(Refuse,serverAddress);
}
}
}
void Widget::on_send_clicked()//发送
{
sendMessage(Message);
}
void Widget::on_sendfile_clicked()
{
if(ui->tableWidget->selectedItems().isEmpty())
{
QMessageBox::warning(0,tr("选择用户"),tr("请先从用户列表选择要传送的用户!"),QMessageBox::Ok);
return;
}
server->show();
server->initServer();
}
void Widget::on_close_clicked()//关闭
{
this->close();
}
bool Widget::eventFilter(QObject *target, QEvent *event)
{
if(target == ui->textEdit)
{
if(event->type() == QEvent::KeyPress)//回车键
{
QKeyEvent *k = static_cast(event);
if(k->key() == Qt::Key_Return)
{
on_send_clicked();
return true;
}
}
}
return QWidget::eventFilter(target,event);
}
void Widget::on_fontComboBox_currentFontChanged(QFont f)//字体设置
{
ui->textEdit->setCurrentFont(f);
ui->textEdit->setFocus();
}
//字体大小设置
void Widget::on_fontsizecomboBox_currentIndexChanged(QString size)
{
ui->textEdit->setFontPointSize(size.toDouble());
ui->textEdit->setFocus();
}
void Widget::on_textbold_clicked(bool checked)
{
if(checked)
ui->textEdit->setFontWeight(QFont::Bold);
else
ui->textEdit->setFontWeight(QFont::Normal);
ui->textEdit->setFocus();
}
void Widget::on_textitalic_clicked(bool checked)
{
ui->textEdit->setFontItalic(checked);
ui->textEdit->setFocus();
}
void Widget::on_textUnderline_clicked(bool checked)
{
ui->textEdit->setFontUnderline(checked);
ui->textEdit->setFocus();
}
void Widget::on_textcolor_clicked()
{
color = QColorDialog::getColor(color,this);
if(color.isValid())
{
ui->textEdit->setTextColor(color);
ui->textEdit->setFocus();
}
}
void Widget::on_save_clicked()//保存聊天记录
{
if(ui->textBrowser->document()->isEmpty())
QMessageBox::warning(0,tr("警告"),tr("聊天记录为空,无法保存!"),QMessageBox::Ok);
else
{
//获得文件名,注意getSaveFileName函数的格式即可
QString fileName = QFileDialog::getSaveFileName(this,tr("保存聊天记录"),tr("聊天记录"),tr("文本(*.txt);;All File(*.*)"));
if(!fileName.isEmpty())
saveFile(fileName);
}
}
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->textBrowser->toPlainText();
return true;
}
void Widget::on_clear_clicked()//清空聊天记录
{
ui->textBrowser->clear();
}
void Widget::on_tableWidget_doubleClicked(QModelIndex index)
{
if(ui->tableWidget->item(index.row(),0)->text() == getUserName() &&
ui->tableWidget->item(index.row(),2)->text() == getIP())
{
QMessageBox::warning(0,tr("警告"),tr("你不可以跟自己聊天!!!"),QMessageBox::Ok);
}
else
{
// else
if(!privatechat){
// chat *privatechatTemp;
privatechat = new chat(ui->tableWidget->item(index.row(),1)->text(), //接收主机名
ui->tableWidget->item(index.row(),2)->text()) ;//接收用户IP
}
// if( privatechat->is_opened )delete privatechat;//如果其曾经显示过则删除掉
QByteArray data;
QDataStream out(&data,QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIP();
out << Xchat << getUserName() << localHostName << address;
udpSocket->writeDatagram(data,data.length(),QHostAddress::QHostAddress(ui->tableWidget->item(index.row(),2)->text()), port);
// privatechat->xchat->writeDatagram(data,data.length(),QHostAddress::QHostAddress(ui->tableWidget->item(index.row(),2)->text()), 45456);
// if(!privatechat->is_opened)
privatechat->show();
privatechat->is_opened = true;
// (privatechat->a) = 0;
}
}
void Widget::showxchat(QString name, QString ip)
{
// if(!privatechat){
// chat *privatechatTemp;
if(!privatechat1)
privatechat1 = new chat(name,ip);
// privatechat = privatechatTemp;}
// chat privatechat(name,ip);//如果不用new函数,则程序运行时只是闪烁显示一下就没了,因为类的生命周期结束了
// privatechat->is_opened = false;
// privatechat->show();
//privatechat.textBrowser.show();
//privatechat->is_opened = true;
bb++;
//delete privatechat;
}
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include
#include
#include
#include
namespace Ui {
class TcpServer;
}
class TcpServer : public QDialog
{
Q_OBJECT
public:
explicit TcpServer(QWidget *parent = 0);
~TcpServer();
void refused();
void initServer();
protected:
void changeEvent(QEvent *e);
private:
Ui::TcpServer *ui;
qint16 tcpPort;
QTcpServer *tcpServer;
QString fileName;
QString theFileName;
QFile *localFile;
qint64 TotalBytes;
qint64 bytesWritten;
qint64 bytesToWrite;
qint64 loadSize;
QByteArray outBlock;//缓存一次发送的数据
QTcpSocket *clientConnection;
QTime time;//计时器
private slots:
void on_serverSendBtn_clicked();
void on_serverCloseBtn_clicked();
void on_serverOpenBtn_clicked();
void sendMessage();
void updateClientProgress(qint64 numBytes);
signals:
void sendFileName(QString fileName);
};
#endif // TCPSERVER_H
#include "tcpserver.h"
#include "ui_tcpserver.h"
#include
#include
#include
TcpServer::TcpServer(QWidget *parent):QDialog(parent),
ui(new Ui::TcpServer)
{
ui->setupUi(this);
this->setFixedSize(350,180);
tcpPort = 6666;
tcpServer = new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(sendMessage()));
initServer();
}
TcpServer::~TcpServer()
{
delete ui;
}
void TcpServer::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void TcpServer::sendMessage() //开始发送数据
{
ui->serverSendBtn->setEnabled(false);
clientConnection = tcpServer->nextPendingConnection();
connect(clientConnection,SIGNAL(bytesWritten(qint64)),SLOT(updateClientProgress(qint64)));
ui->serverStatusLabel->setText(tr("开始传送文件 %1 !").arg(theFileName));
localFile = new QFile(fileName);
if(!localFile->open((QFile::ReadOnly))){//以只读方式打开
QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2").arg(fileName).arg(localFile->errorString()));
return;
}
TotalBytes = localFile->size();
QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_4_6);
time.start(); //开始计时
QString currentFile = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
sendOut<seek(0);
sendOut<write(outBlock);
qDebug()< 0){
outBlock = localFile->read(qMin(bytesToWrite,loadSize));
bytesToWrite -= (int)clientConnection->write(outBlock);
outBlock.resize(0);
}
else{
localFile->close();
}
ui->progressBar->setMaximum(TotalBytes);
ui->progressBar->setValue(bytesWritten);
float useTime = time.elapsed();
double speed = bytesWritten / useTime;
ui->serverStatusLabel->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));//剩余时间
//num.sprintf("%.1f KB/s", (bytesWritten*1000) / (1024.0*time.elapsed()));
if(bytesWritten == TotalBytes)
ui->serverStatusLabel->setText(tr("传送文件 %1 成功").arg(theFileName));
}
void TcpServer::on_serverOpenBtn_clicked() //打开
{
fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
{
theFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
ui->serverStatusLabel->setText(tr("要传送的文件为:%1 ").arg(theFileName));
ui->serverSendBtn->setEnabled(true);
ui->serverOpenBtn->setEnabled(false);
}
}
void TcpServer::refused() //被对方拒绝
{
tcpServer->close();
ui->serverStatusLabel->setText(tr("对方拒绝接收!!!"));
}
void TcpServer::on_serverSendBtn_clicked() //发送
{
if(!tcpServer->listen(QHostAddress::Any,tcpPort))//开始监听
{
qDebug() << tcpServer->errorString();
close();
return;
}
ui->serverStatusLabel->setText(tr("等待对方接收... ..."));
emit sendFileName(theFileName);
}
void TcpServer::on_serverCloseBtn_clicked()//退出
{
if(tcpServer->isListening())
{
tcpServer->close();
clientConnection->abort();
}
this->close();
}
void TcpServer::initServer()//初始化
{
loadSize = 4*1024;
TotalBytes = 0;
bytesWritten = 0;
bytesToWrite = 0;
ui->serverStatusLabel->setText(tr("请选择要传送的文件"));
ui->progressBar->reset();
ui->serverOpenBtn->setEnabled(true);
ui->serverSendBtn->setEnabled(false);
tcpServer->close();
}
#ifndef TCPCLIENT_H
#define TCPCLIENT_H
#include
#include
#include
#include
#include
namespace Ui {
class TcpClient;
}
class TcpClient : public QDialog
{
Q_OBJECT
public:
explicit TcpClient(QWidget *parent = 0);
~TcpClient();
void setHostAddress(QHostAddress address);
void setFileName(QString fileName){localFile = new QFile(fileName);}
protected:
void changeEvent(QEvent *e);
private:
Ui::TcpClient *ui;
QTcpSocket *tcpClient;
quint16 blockSize;
QHostAddress hostAddress;
qint16 tcpPort;
qint64 TotalBytes;
qint64 bytesReceived;
qint64 bytesToReceive;
qint64 fileNameSize;
QString fileName;
QFile *localFile;
QByteArray inBlock;
QTime time;
private slots:
void on_tcpClientCancleBtn_clicked();
void on_tcpClientCloseBtn_clicked();
void newConnect();
void readMessage();
void displayError(QAbstractSocket::SocketError);
};
#endif // TCPCLIENT_H
#include "tcpclient.h"
#include "ui_tcpclient.h"
#include
#include
TcpClient::TcpClient(QWidget *parent) :
QDialog(parent),
ui(new Ui::TcpClient)
{
ui->setupUi(this);
this->setFixedSize(350,180);
TotalBytes = 0;
bytesReceived = 0;
fileNameSize = 0;
tcpClient = new QTcpSocket(this);
tcpPort = 6666;
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(readMessage()));
connect(tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,
SLOT(displayError(QAbstractSocket::SocketError)));
}
TcpClient::~TcpClient()
{
delete ui;
}
void TcpClient::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void TcpClient::setHostAddress(QHostAddress address) //设置服务器地址并连接服务器
{
hostAddress = address;
newConnect();
}
void TcpClient::newConnect()
{
blockSize = 0;
tcpClient->abort();
tcpClient->connectToHost(hostAddress,tcpPort);
time.start();
}
void TcpClient::readMessage()
{
QDataStream in(tcpClient);
in.setVersion(QDataStream::Qt_4_6);
float useTime = time.elapsed();
if(bytesReceived <= sizeof(qint64)*2){
if((tcpClient->bytesAvailable() >= sizeof(qint64)*2) && (fileNameSize == 0)){
in>>TotalBytes>>fileNameSize;
bytesReceived += sizeof(qint64)*2;
}
if((tcpClient->bytesAvailable() >= fileNameSize) && (fileNameSize != 0)){
in>>fileName;
bytesReceived +=fileNameSize;
if(!localFile->open(QFile::WriteOnly)){
QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2.").arg(fileName).arg(localFile->errorString()));
return;
}
}else{
return;
}
}
if(bytesReceived < TotalBytes){
bytesReceived += tcpClient->bytesAvailable();
inBlock = tcpClient->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
ui->progressBar->setMaximum(TotalBytes);
ui->progressBar->setValue(bytesReceived);
qDebug()<tcpClientStatusLabel->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)
{
tcpClient->close();
ui->tcpClientStatusLabel->setText(tr("接收文件 %1 完毕").arg(fileName));
localFile->close(); //接收完文件后,一定要关闭,不然可能出问题
}
}
void TcpClient::displayError(QAbstractSocket::SocketError socketError) //错误处理
{
switch(socketError)
{
case QAbstractSocket::RemoteHostClosedError : break;
default : qDebug() << tcpClient->errorString();
}
}
void TcpClient::on_tcpClientCloseBtn_clicked()//关闭
{
tcpClient->abort();
this->close();
}
void TcpClient::on_tcpClientCancleBtn_clicked()//取消
{
tcpClient->abort();
}
chat.h
#ifndef CHAT_H
#define CHAT_H
#include
#include
#include
#include "tcpclient.h"
#include "tcpserver.h"
namespace Ui {
class chat;
}
enum MessageType
{
Message,
NewParticipant,
ParticipantLeft,
FileName,
Refuse,
Xchat
};
class chat : public QDialog
{
Q_OBJECT
public:
~chat();
// chat();
chat(QString pasvusername, QString pasvuserip);
QString xpasvuserip;
QString xpasvusername;
QUdpSocket *xchat;
qint32 xport;
void sendMessage(MessageType type,QString serverAddress="");
quint16 a;
// static qint32 is_opened = 0;
bool is_opened;
public slots:
protected:
void hasPendingFile(QString userName,QString serverAddress, //接收文件
QString clientAddress,QString fileName);
void participantLeft(QString userName,QString localHostName,QString time);
bool eventFilter(QObject *target, QEvent *event); //事件过滤器
private:
Ui::chat *ui;
TcpServer *server;
QColor color;//颜色
bool saveFile(const QString& fileName);//保存聊天记录
QString getMessage();
QString getIP();
QString getUserName();
QString message;
QString fileName;
private slots:
void sentFileName(QString);
void on_sendfile_clicked();
void processPendingDatagrams();
void on_send_clicked();
void on_close_clicked();
void on_clear_clicked();
void on_save_clicked();
void on_textcolor_clicked();
void on_textUnderline_clicked(bool checked);
void on_textitalic_clicked(bool checked);
void on_textbold_clicked(bool checked);
void on_fontComboBox_currentFontChanged(QFont f);
void on_fontsizecomboBox_currentIndexChanged(QString );
void currentFormatChanged(const QTextCharFormat &format);
};
#endif // CHAT_H
#ifndef CHAT_H
#define CHAT_H
#include
#include
#include
#include "tcpclient.h"
#include "tcpserver.h"
namespace Ui {
class chat;
}
enum MessageType
{
Message,
NewParticipant,
ParticipantLeft,
FileName,
Refuse,
Xchat
};
class chat : public QDialog
{
Q_OBJECT
public:
~chat();
// chat();
chat(QString pasvusername, QString pasvuserip);
QString xpasvuserip;
QString xpasvusername;
QUdpSocket *xchat;
qint32 xport;
void sendMessage(MessageType type,QString serverAddress="");
quint16 a;
// static qint32 is_opened = 0;
bool is_opened;
public slots:
protected:
void hasPendingFile(QString userName,QString serverAddress, //接收文件
QString clientAddress,QString fileName);
void participantLeft(QString userName,QString localHostName,QString time);
bool eventFilter(QObject *target, QEvent *event); //事件过滤器
private:
Ui::chat *ui;
TcpServer *server;
QColor color;//颜色
bool saveFile(const QString& fileName);//保存聊天记录
QString getMessage();
QString getIP();
QString getUserName();
QString message;
QString fileName;
private slots:
void sentFileName(QString);
void on_sendfile_clicked();
void processPendingDatagrams();
void on_send_clicked();
void on_close_clicked();
void on_clear_clicked();
void on_save_clicked();
void on_textcolor_clicked();
void on_textUnderline_clicked(bool checked);
void on_textitalic_clicked(bool checked);
void on_textbold_clicked(bool checked);
void on_fontComboBox_currentFontChanged(QFont f);
void on_fontsizecomboBox_currentIndexChanged(QString );
void currentFormatChanged(const QTextCharFormat &format);
};
#endif // CHAT_H
chat.c
#include "chat.h"
#include "ui_chat.h"
//chat::chat():ui(new Ui::chat)
//{
// is_opened = false;
//}
chat::chat(QString pasvusername, QString pasvuserip) : ui(new Ui::chat)
{
ui->setupUi(this);
ui->textEdit->setFocusPolicy(Qt::StrongFocus);
ui->textBrowser->setFocusPolicy(Qt::NoFocus);
ui->textEdit->setFocus();
ui->textEdit->installEventFilter(this);
a = 0;
is_opened = false;
// this->is_opened = false;
xpasvusername = pasvusername;
xpasvuserip = pasvuserip;
ui->label->setText(tr("与%1聊天中 对方IP:%2").arg(xpasvusername).arg(pasvuserip));
//UDP部分
xchat = new QUdpSocket(this);
xport = 45456;
// xchat->bind(xport, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
xchat->bind( QHostAddress::QHostAddress(getIP()), xport );
connect(xchat, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
//TCP部分
server = new TcpServer(this);
connect(server,SIGNAL(sendFileName(QString)),this,SLOT(sentFileName(QString)));
connect(ui->textEdit,SIGNAL(currentCharFormatChanged(QTextCharFormat)),this,SLOT(currentFormatChanged(const QTextCharFormat)));
}
chat::~chat()
{
is_opened = false;
delete ui;
}
bool chat::eventFilter(QObject *target, QEvent *event)
{
if(target == ui->textEdit)
{
if(event->type() == QEvent::KeyPress)//按下键盘某键
{
QKeyEvent *k = static_cast(event);
if(k->key() == Qt::Key_Return)//回车键
{
on_send_clicked();
return true;
}
}
}
return QWidget::eventFilter(target,event);
}
//处理用户离开
void chat::participantLeft(QString userName,QString localHostName,QString time)
{
ui->textBrowser->setTextColor(Qt::gray);
ui->textBrowser->setCurrentFont(QFont("Times New Roman",10));
ui->textBrowser->append(tr("%1 于 %2 离开!").arg(userName).arg(time));
}
QString chat::getUserName() //获取用户名
{
QStringList envVariables;
envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*"
<< "HOSTNAME.*" << "DOMAINNAME.*";
QStringList environment = QProcess::systemEnvironment();
foreach (QString string, envVariables)
{
int index = environment.indexOf(QRegExp(string));
if (index != -1)
{
QStringList stringList = environment.at(index).split('=');
if (stringList.size() == 2)
{
return stringList.at(1);
break;
}
}
}
return false;
}
QString chat::getIP() //获取ip地址
{
QList list = QNetworkInterface::allAddresses();
foreach (QHostAddress address, list)
{
if(address.protocol() == QAbstractSocket::IPv4Protocol) //我们使用IPv4地址
return address.toString();
}
return 0;
}
void chat::hasPendingFile(QString userName,QString serverAddress, //接收文件
QString clientAddress,QString fileName)
{
QString ipAddress = getIP();
if(ipAddress == clientAddress)
{
int btn = QMessageBox::information(this,tr("接受文件"),
tr("来自%1(%2)的文件:%3,是否接收?")
.arg(userName).arg(serverAddress).arg(fileName),
QMessageBox::Yes,QMessageBox::No);
if(btn == QMessageBox::Yes)
{
QString name = QFileDialog::getSaveFileName(0,tr("保存文件"),fileName);
if(!name.isEmpty())
{
TcpClient *client = new TcpClient(this);
client->setFileName(name);
client->setHostAddress(QHostAddress(serverAddress));
client->show();
}
}
else{
sendMessage(Refuse,serverAddress);
}
}
}
void chat::processPendingDatagrams() //接收数据UDP
{
while(xchat->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(xchat->pendingDatagramSize());
xchat->readDatagram(datagram.data(),datagram.size());
QDataStream in(&datagram,QIODevice::ReadOnly);
int messageType;
in >> messageType;
QString userName,localHostName,ipAddress,messagestr;
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
switch(messageType)
{
case Xchat:
{
// ui.show();
break;
}
case Message:
{
//这2条语句都没有用。why??、
/*this->hide();
this->close();*/
in >>userName >>localHostName >>ipAddress >>messagestr;
ui->textBrowser->setTextColor(Qt::blue);
ui->textBrowser->setCurrentFont(QFont("Times New Roman",12));
ui->textBrowser->append("[ " +localHostName+" ] "+ time);//与主机名聊天中
ui->textBrowser->append(messagestr);
// ui->textBrowser->show();
//this->textBrowser->setTextColor(Qt::blue);
//this->textBrowser->setCurrentFont(QFont("Times New Roman",12));
//this->textBrowser->append("[ " +localHostName+" ] "+ time);//与主机名聊天中
//this->textBrowser->append(messagestr);
// a ++;
// if( is_opened == false )//加了这句,接收端B不显示端口了
{
this->show();////解决bug1.收到私聊消息后才显示
// ui->textBrowser->show();
// this->show();
// ui->textBrowser->show();
// ui.show();
// if( this->show() )
// this->hide();
// 0 == a;
is_opened = true;
}
break;
}
case FileName:
{
in >>userName >>localHostName >> ipAddress;
QString clientAddress,fileName;
in >> clientAddress >> fileName;
hasPendingFile(userName,ipAddress,clientAddress,fileName);
break;
}
case Refuse:
{
in >> userName >> localHostName;
QString serverAddress;
in >> serverAddress;
QString ipAddress = getIP();
if(ipAddress == serverAddress)
{
server->refused();
}
break;
}
case ParticipantLeft:
{
in >>userName >>localHostName;
participantLeft(userName,localHostName,time);
QMessageBox::information(0,tr("本次对话关闭"),tr("对方结束了对话"),QMessageBox::Ok);
a = 1;
ui->textBrowser->clear();
//is_opened = true;
// this->is_opened = false;
ui->~chat();
close();
// delete ui;
// ui = 0;
break;
}
}
}
}
void chat::sentFileName(QString fileName)
{
this->fileName = fileName;
sendMessage(FileName);
}
QString chat::getMessage() //获得要发送的信息
{
QString msg = ui->textEdit->toHtml();
qDebug()<textEdit->clear();
ui->textEdit->setFocus();
return msg;
}
//通过私聊套接字发送到对方的私聊专用端口上
void chat::sendMessage(MessageType type , QString serverAddress) //发送信息
{
QByteArray data;
QDataStream out(&data,QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIP();
out << type << getUserName() << localHostName;
switch(type)
{
case ParticipantLeft:
{
break;
}
case Message :
{
if(ui->textEdit->toPlainText() == "")
{
QMessageBox::warning(0,tr("警告"),tr("发送内容不能为空"),QMessageBox::Ok);
return;
}
message = getMessage();
out << address << message;
ui->textBrowser->verticalScrollBar()->setValue(ui->textBrowser->verticalScrollBar()->maximum());
break;
}
case FileName:
{
QString clientAddress = xpasvuserip;
out << address << clientAddress << fileName;
break;
}
case Refuse:
{
out << serverAddress;
break;
}
}
xchat->writeDatagram(data,data.length(),QHostAddress::QHostAddress(xpasvuserip), 45456);
}
void chat::currentFormatChanged(const QTextCharFormat &format)
{//当编辑器的字体格式改变时,我们让部件状态也随之改变
ui->fontComboBox->setCurrentFont(format.font());
if(format.fontPointSize()<9) //如果字体大小出错,因为我们最小的字体为9
{
ui->fontsizecomboBox->setCurrentIndex(3); //即显示12
}
else
{
ui->fontsizecomboBox->setCurrentIndex(ui->fontsizecomboBox->findText(QString::number(format.fontPointSize())));
}
ui->textbold->setChecked(format.font().bold());
ui->textitalic->setChecked(format.font().italic());
ui->textUnderline->setChecked(format.font().underline());
color = format.foreground().color();
}
void chat::on_fontComboBox_currentFontChanged(QFont f)//字体设置
{
ui->textEdit->setCurrentFont(f);
ui->textEdit->setFocus();
}
void chat::on_fontsizecomboBox_currentIndexChanged(QString size)
{
ui->textEdit->setFontPointSize(size.toDouble());
ui->textEdit->setFocus();
}
void chat::on_textbold_clicked(bool checked)
{
if(checked)
ui->textEdit->setFontWeight(QFont::Bold);
else
ui->textEdit->setFontWeight(QFont::Normal);
ui->textEdit->setFocus();
}
void chat::on_textitalic_clicked(bool checked)
{
ui->textEdit->setFontItalic(checked);
ui->textEdit->setFocus();
}
void chat::on_save_clicked()//保存聊天记录
{
if(ui->textBrowser->document()->isEmpty())
QMessageBox::warning(0,tr("警告"),tr("聊天记录为空,无法保存!"),QMessageBox::Ok);
else
{
//获得文件名
QString fileName = QFileDialog::getSaveFileName(this,tr("保存聊天记录"),tr("聊天记录"),tr("文本(*.txt);;All File(*.*)"));
if(!fileName.isEmpty())
saveFile(fileName);
}
}
void chat::on_clear_clicked()//清空聊天记录
{
ui->textBrowser->clear();
}
bool chat::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->textBrowser->toPlainText();
return true;
}
void chat::on_textUnderline_clicked(bool checked)
{
ui->textEdit->setFontUnderline(checked);
ui->textEdit->setFocus();
}
void chat::on_textcolor_clicked()
{
color = QColorDialog::getColor(color,this);
if(color.isValid())
{
ui->textEdit->setTextColor(color);
ui->textEdit->setFocus();
}
}
void chat::on_close_clicked()
{
sendMessage(ParticipantLeft);
a = 1;
ui->textBrowser->clear();
//is_opened = true;
// this->is_opened = false;
close();
ui->~chat();
//this->close();
/*delete ui;
ui = 0;*/
}
void chat::on_send_clicked()
{
sendMessage(Message);
QString localHostName = QHostInfo::localHostName();
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
ui->textBrowser->setTextColor(Qt::blue);
ui->textBrowser->setCurrentFont(QFont("Times New Roman",12));
ui->textBrowser->append("[ " +localHostName+" ] "+ time);
ui->textBrowser->append(message);
// is_opened = true;
}
void chat::on_sendfile_clicked()
{
server->show();
server->initServer();
}
widget.ui--xml
Widget
0
0
788
468
灞€鍩熺綉鑱婂ぉ
1
-
6
QLayout::SetDefaultConstraint
-
0
2
QFrame::Sunken
false
-
-
0
0
1
25
-
0
0
0
25
true
3
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
鍔犵矖
false
...
:/image/textbold.png :/image/textbold.png
24
24
true
true
-
鍊炬枩
false
...
:/image/textitalic.png :/image/textitalic.png
24
24
true
true
-
涓嬪垝绾?/string>
false
...
:/image/textunder.png :/image/textunder.png
24
24
true
true
-
瀛椾綋棰滆壊
false
...
:/image/textcolor.png :/image/textcolor.png
24
24
false
true
-
浼犻€佹枃浠?/string>
false
...
:/image/fileopen.png :/image/fileopen.png
24
24
false
true
-
淇濆瓨鑱婂ぉ璁板綍
false
...
:/image/Floppy.png :/image/Floppy.png
24
24
false
true
-
娓呯┖鑱婂ぉ璁板綍
false
...
:/image/Bin (empty).png :/image/Bin (empty).png
24
24
false
true
-
0
1
瀹嬩綋
12
-
-
Qt::Horizontal
40
20
-
100
25
鍏抽棴(&C)
-
100
25
鍙戦€?&S)
-
-
鍦ㄧ嚎鐢ㄦ埛淇℃伅鍒楄〃
QFrame::StyledPanel
QAbstractItemView::NoEditTriggers
QAbstractItemView::SingleSelection
QAbstractItemView::SelectRows
false
鐢ㄦ埛鍚?/string>
:/image/User.png
涓绘満鍚?/string>
IP鍦板潃
-
-
0
0
鍦ㄧ嚎鐢ㄦ埛锛?浜?/string>
-
Qt::Horizontal
30
20
TcpServer
0
0
350
180
鏂囦欢浼犻€?/string>
30
90
291
23
0
10
10
331
71
Agency FB
12
75
true
璇烽€夋嫨瑕佸彂閫佺殑鏂囦欢锛?/string>
Qt::AlignCenter
60
140
75
23
鎵撳紑
240
140
75
23
閫€鍑?/string>
150
140
75
23
鍙戦€?/string>
TcpClient
0
0
350
180
鏂囦欢浼犻€?/string>
20
90
311
23
0
140
140
75
23
鍙栨秷
240
140
75
23
鍏抽棴
20
10
321
71
Agency FB
12
75
true
绛夊緟鎺ユ敹鏂囦欢... ...
Qt::AlignCenter
chat
0
0
431
401
Dialog
10
40
411
351
6
QLayout::SetDefaultConstraint
-
0
2
QFrame::Sunken
false
-
-
0
0
1
25
-
0
0
0
25
true
3
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
鍔犵矖
false
...
:/image/textbold.png :/image/textbold.png
24
24
true
true
-
鍊炬枩
false
...
:/image/textitalic.png :/image/textitalic.png
24
24
true
true
-
涓嬪垝绾?/string>
false
...
:/image/textunder.png :/image/textunder.png
24
24
true
true
-
瀛椾綋棰滆壊
false
...
:/image/textcolor.png :/image/textcolor.png
24
24
false
true
-
浼犻€佹枃浠?/string>
false
...
:/image/fileopen.png :/image/fileopen.png
24
24
false
true
-
淇濆瓨鑱婂ぉ璁板綍
false
...
:/image/Floppy.png :/image/Floppy.png
24
24
false
true
-
娓呯┖鑱婂ぉ璁板綍
false
...
:/image/Bin (empty).png :/image/Bin (empty).png
24
24
false
true
-
0
1
瀹嬩綋
12
-
-
Qt::Horizontal
40
20
-
100
25
鍏抽棴(&C)
-
100
25
鍙戦€?&S)
10
10
411
21
-