实现功能:
尚存BUG:
保存消息记录时还不能保存图片数据。
Client 客户端登录界面代码
- 如果密码输入三次错误、密码输入栏会自动锁死
- 因为初学时为了理解学习、此界面没有使用UI设计师设计、而是采用纯代码编辑
- 默认自动弹出虚拟键盘、如果点击输入栏以外的位置会隐藏虚拟键盘
#include "longinwindow.h"
#include "ui_longinwindow.h"
#include
LonginWindow::LonginWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::LonginWindow)
{
ui->setupUi(this);
//this->setStyleSheet("background-color: rgb(255, 255, 255);");
this->setStyleSheet("LonginWindow{border-image: url(:/new/prefix1/1.jpg);}");
//this->show();
usrline=new QLineEdit(this);
//指定输入框显示的位置
usrline->setGeometry(100,20,250,30);
usrline->show();
//创建一个输入框框对象
passline = new QLineEdit (this);
//隐藏输入的密码
passline->setEchoMode(QLineEdit::Password);
//指定输入框显示的位置
passline->setGeometry(100,80,250,30);
passline->show();
usrline->installEventFilter(this); //给用户输入栏添加事件过滤器
passline->installEventFilter(this);
//创建一个标签表示用户名
usrlb =new QLabel(this);
//QPalette pa;
//定义字体对象
QFont myfont;
myfont.setPixelSize(20); //设置字体大小
myfont.setFamily("KaiTi"); //将字体设置为楷体
//myfont.setBold(75); //也能设置字体加粗,只是会报错截断
myfont.setWeight(75); //设置字体加粗
usrlb->setStyleSheet("color:red;"); //将字体设置为红色
//color: rgb(255, 0, 0); //设置字体颜色
usrlb->setFont(myfont);
usrlb->setText("用户:");
usrlb->setGeometry(10,20,50,30);
usrlb->show();
//创建一个标签表示密码
passlb = new QLabel("密码: ",this);
myfont2.setPixelSize(20);
passlb->setStyleSheet("color:red;"); //将字体设置为红色
passlb->setFont(myfont2);
passlb->setGeometry(10,80,50,30); //设置标签位置
passlb->show();
//登陆按钮
lgbt = new QPushButton(QIcon(":/new/prefix1/2.jpg"),"登陆",this);
lgbt->setGeometry(140,150,70,30);
lgbt->show();
//注册按钮
resbt = new QPushButton(QIcon(":/new/prefix1/3.jpg"),"注册",this);
resbt->setGeometry(270,150,70,30);
resbt->show();
connect(lgbt, SIGNAL(clicked(bool)), this ,SLOT(LonginBtSlot()));
}
LonginWindow::~LonginWindow()
{
delete ui;
delete usrline;
delete passline;
delete usrlb;
//QFont myfont;
//QFont myfont2;
delete passlb;
delete lgbt;
delete resbt;
}
bool LonginWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::FocusIn)
{
ui->widget->show();
}
else if(event->type() == QEvent::KeyPress)
{
QKeyEvent *kE = (QKeyEvent *)event;
if (kE->key() == Qt::Key_Enter)
{
ui->widget->hide();
}
}
else if(event->type() ==QEvent::FocusOut)
{
ui->widget->hide();
}
return QMainWindow::eventFilter(watched,event);
}
void LonginWindow::LonginBtSlot()
{
qDebug()<<"我已经点击了登录按钮: ";
static int num=0; //记住输入错误的次数
QString usrname=usrline->text();
QString pas=passline->text();
if(usrname=="xgh"&&pas=="123")
{
qDebug()<<"我已登录 ";
this->hide();
clientwin *clientw =new clientwin(this);
clientw->show();
}
else
{
num++;
}
if(num>3)
{
passline->setEnabled(false);
}
}
客户端登录功能界面设计
Client 客户端功能代码,区分图片和消息数据,项目过程中遇到发送大图片会出现只接收到一部分的情况;最后采用
QDataStream类解决
#include "clientwin.h"
#include "ui_clientwin.h"
#include
#include
#include "longinwindow.h"
clientwin::clientwin(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::clientwin)
{
ui->setupUi(this);
ui->widget->hide();
ui->chatedit->installEventFilter(this);
timer = new QTimer(this);
timer->start(1000);
timer->connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
qDebug()<<"定时器定时开始 ";
mysocket = new QTcpSocket();
mysocket->connectToHost(QHostAddress("192.168.24.151"), 10000);
connect(mysocket,SIGNAL(connected()),this,SLOT(onconnect()));
connect(mysocket,SIGNAL(disconnected()),this,SLOT(ondisconnect()));
connect(mysocket,SIGNAL(readyRead()),this,SLOT(onreadyread()));
//connect(mysocket,SIGNAL(error(QAbstractSocket::SocketError socketError)),this,SLOT(ondisconnect()));
connect(ui->friendlist,SIGNAL(itemSelectionChanged()),this,SLOT(on_selectchat()));
imageIndex=0;
savepacksize=0;
}
clientwin::~clientwin()
{
message_save_on_local();
delete ui;
delete timer;
delete mysocket;
}
/*
Html图片格式
这个是物理路径,如果是网站的话,用相对路径则为下面的:
这个为html文件和images同一目录的写法
这个为图片和html文件同一目录的写法
*/
void clientwin::onreadyread()
{
QObject *obj=this->sender();
QTcpSocket *socket=qobject_cast(obj);
//当前缓冲区里面数据的大小,收到的数据大小。
qint64 sizeNow=0;
do
{
sizeNow = socket->bytesAvailable();
QDataStream stream(socket);
if(savepacksize==0)
{
if(sizeNow> savepacksize;
}
//包不完整
if(sizeNow < savepacksize -4 ) //64位和32位的区别少了4个字节 处理了半包情况
{
return;
}
savepacksize=0;
//包已经完整
qDebug()<<"full pack";
QByteArray dataFull;
stream >> dataFull;
//判断剩下的字节数,是否会有粘包的情况。
sizeNow = socket->bytesAvailable();
QString dataTime=QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss:");
QString preindex = dataFull.mid(0,4);
if(preindex=="TXT:")
{
ui->textEdit->append(dataTime);
QString txtconcent=dataFull.mid(4);
ui->textEdit->append(txtconcent);
}
else if(preindex=="IMG:")
{
QString htmlTag=QString ("");
QString index=QString::number(imageIndex);
htmlTag=htmlTag.arg(index + ".png");
QFile file(index+".png");
file.open(QIODevice::WriteOnly);
file.write(dataFull.mid(4));
file.close();
imageIndex=imageIndex+1;
ui->textEdit->append(dataTime);
ui->textEdit->insertHtml(htmlTag);
}
else if(preindex=="RIP:") //如果接收到服务器发来的所有已经连接上服务器的客户端Ip端口号
{
qDebug()<<"服务器已经发来客户端IP信息 ";
int i;
int n=ui->friendlist->count();//获取item的总数
//删去所有item
for(int i=0;ifriendlist->takeItem(0); //这里是0,不是i,因为每移除一个item都会导致每个item的row发生变化
delete item;
}
QString tmpdata;
tmpdata=dataFull.mid(4);
if(!tmpdata.isEmpty())
{
QStringList clientlist =tmpdata.split(":");
for(i=0;ifriendlist->addItem(clientlist.at(i));
}
}
}
}while(sizeNow>0); //如果剩余的字节数大于0的话
}
void clientwin::onconnect()
{
qDebug()<<"我已经连接上服务器 ";
}
void clientwin::ondisconnect()
{
qDebug()<<"我已经断开了连接 ";
qDebug()<<"has disconnect";
//message_save_on_local();
qDebug()<<"111";
QObject *obj=this->sender();
QTcpSocket *socket=qobject_cast(obj); //强转
socket->deleteLater();
}
void clientwin::onerror(QAbstractSocket::SocketError socketError)
{
qDebug()<<"error "<chatedit->toPlainText();
if(text.isEmpty()) //判断如果输入框是空的返回不发送
return;
sendtextt="TXT:"+text.toLocal8Bit();
qDebug()<<"sendtextt "<seek(0);
stream<write(dataSend);
}
void clientwin::on_sendpicBt_clicked() //发送表情包按钮
{
qDebug()<<"我已经按了发送表情包按钮 ";
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
"/",
tr("Images (*.png *.xpm *.jpg)"));
if(fileName.isEmpty())
return;
QFile image(fileName);
image.open(QIODevice::ReadOnly);
QByteArray data="IMG:"+ image.readAll();
image.close();
//出现了丢包情况 封装包头
QByteArray dataSend; //封装的数据包
QDataStream stream(&dataSend,QIODevice::WriteOnly);
stream<<(quint32)0<< data;
stream.device()->seek(0);
stream<write(dataSend);
}
void clientwin::on_selectchat()
{
QString itemtextt;
QStringList list;
QByteArray dome2;
itemtextt=ui->friendlist->currentItem()->text();
qDebug()<<"item text "<seek(0);
stream<write(dataSend);
}
void clientwin::timerUpdate()
{
QDateTime time = QDateTime::currentDateTime();
QString str = time.toString("HH:mm:ss");
ui->lcdNumber->display(str);
}
bool clientwin::eventFilter(QObject *watched, QEvent *event) //配合事件过滤器使用
{
if (event->type() == QEvent::FocusIn)
{
ui->widget->show();
}
else if(event->type() == QEvent::KeyPress)
{
QKeyEvent *kE = (QKeyEvent *)event;
if (kE->key() == Qt::Key_Enter)
{
ui->widget->hide();
}
}
else if(event->type() ==QEvent::FocusOut)
{
ui->widget->hide();
}
return QMainWindow::eventFilter(watched,event);
}
void clientwin::message_save_on_local() //保存聊天记录到本地
{
QByteArray massage=ui->textEdit->toPlainText().toLocal8Bit();
QString filename=mysocket->peerAddress().toString()+".txt";
QFile history(filename);
history.open(QIODevice::ReadWrite|QIODevice::Append);
history.write(massage);
history.close();
}
void clientwin::on_friendBT_clicked()
{
//点击按钮连接上服务器
qDebug()<<"flash friend ";
QString scmd="wofasongleshengqingcmd";
QByteArray cmd="FLH:"+scmd.toLocal8Bit();
//出现了丢包情况 封装包头
QByteArray dataSend; //封装的数据包
QDataStream stream(&dataSend,QIODevice::WriteOnly);
stream<<(quint32)0<seek(0);
stream<write(dataSend);
}
void clientwin::on_catpicBt_clicked() //截图按钮
{
qDebug()<<"jie tu ";
QPixmap pix=QApplication::screens().at(0)->grabWindow(QWidget::winId());
//保存起来
QString savefilepath=QFileDialog::getSaveFileName(this);
//调用QPixmap中的save函数保存截图
pix.save(savefilepath);
}
void clientwin::on_paintBt_clicked() //画板
{
message_save_on_local(); //在断开连接的时候把消息记录保存下来
this->hide();
Painter *p=new Painter(this);
p->show();
}
void clientwin::on_backBt_clicked()
{
ui->textEdit->append("我已经点击了返回按钮");
qDebug()<<"我已经点击了返回按钮";
this->hide();
LonginWindow *ll =new LonginWindow(this);
ll->show();
}
void clientwin::on_historicBt_clicked()
{
QByteArray massage;
QString massagestr;
QString filename=mysocket->peerAddress().toString()+".txt";
QFile history(filename);
if(history.open(QIODevice::ReadOnly)==false)
{
return;
}
while(1)
{
massage.clear();
massage=history.read(100);
ui->textEdit->append(massage);
if(massage.length()<100)
break;
}
history.close();
}
下载完整代码地址
https://download.csdn.net/download/switchandcase/11983903