本帖最后由 seattle^-^ 于 2019-12-10 21:52 编辑
大二课设课程结束了,来总结一下这次的实战QT开发。虽然代码不精致,但是也是笔者一个月的成果。喜欢的来看啊
先上两张本地测试的图片
首先是客户端
然后是服务端
然后接下来是效果图,服务端跟客户端放在一张图里了,图标取自网络,如有侵权,联系笔者。
然后接下来是测试图,时间紧迫,客户端只设置了一个账号,输入账号密码之后进入到此界面
好了,这些是我们小组的项目。写起来也很简单啊,采用QT开发C++语言。
QT开发的这种软件还是相对比较简单的啊。记录一下代码:客户端采用了QT提供的信号与槽,对各种点击事件发出信号,代码段做出反应。客户端的对话框代码段对信息文本的处理,来判断服务器转发的信息与自己的信息来做出不同的文本显示:[C++] 纯文本查看 复制代码 void qtchatmessage::paintEvent(QPaintEvent *) //画家
{
QPainter painter(this); //画家
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);//消锯齿
painter.setPen(Qt::NoPen); //画笔
painter.setBrush(QBrush(Qt::gray)); //画刷
if(m_userType == User_Type::User_He) { // 用户
//头像
painter.drawPixmap(m_iconLeftRect, m_leftPixmap);
//框加边
QColor col_KuangB(234, 234, 234);
painter.setBrush(QBrush(col_KuangB));
painter.drawRoundedRect(m_kuangLeftRect.x()-1,m_kuangLeftRect.y()-1,m_kuangLeftRect.width()+2,m_kuangLeftRect.height()+2,4,4);
//框
QColor col_Kuang(255,255,255);
painter.setBrush(QBrush(col_Kuang));
painter.drawRoundedRect(m_kuangLeftRect,4,4);
//三角
QPointF points[3] = {
QPointF(m_sanjiaoLeftRect.x(), 30),
QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 25),
QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 35),
};
QPen pen;
pen.setColor(col_Kuang);
painter.setPen(pen);
painter.drawPolygon(points, 3);
//三角加边
QPen penSanJiaoBian;
penSanJiaoBian.setColor(col_KuangB);
painter.setPen(penSanJiaoBian);
painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 24));
painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 36));
//内容
QPen penText;
penText.setColor(QColor(51,51,51));
painter.setPen(penText);
QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);
option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
painter.setFont(this->font());
painter.drawText(m_textLeftRect, m_msg,option);
} else if(m_userType == User_Type::User_Me) { // 自己
//头像
painter.drawPixmap(m_iconRightRect, m_rightPixmap); //画头像加头像的框架。框加图
//框
QColor col_Kuang(75,164,242); //颜料
painter.setBrush(QBrush(col_Kuang)); //设置画刷,参数为颜色
painter.drawRoundedRect(m_kuangRightRect,4,4); //画给定矩形框的圆角
//三角
QPointF points[3] = {
QPointF(m_sanjiaoRightRect.x()+m_sanjiaoRightRect.width(), 30), //给定的坐标构造点
QPointF(m_sanjiaoRightRect.x(), 25),
QPointF(m_sanjiaoRightRect.x(), 35),
};
QPen pen; //画笔
pen.setColor(col_Kuang);
painter.setPen(pen); //把pen给painter
painter.drawPolygon(points, 3); //绘制数组中的这三个点
//内容
QPen penText; //创建画笔
penText.setColor(Qt::white);
painter.setPen(penText); //笔给画家
QTextOption option(Qt::AlignLeft | Qt::AlignVCenter); //选项 左和水平居中
option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); //设置换行模式
painter.setFont(this->font()); //为画家选择字体
painter.drawText(m_textRightRect,m_msg,option); //往矩形框中按照option画入m_msg文本
}
}
接下来是客户端的送槽函数,用来获取输入的文本,对文本向绘图事件虚函数传递参数,然后向对话框显示文本。
[C++] 纯文本查看 复制代码 void aWidget::on_pushButton_clicked() //发送按钮的槽函数
{
QString str = ui->textEdit_2->toPlainText(); //获取发送区的内容
if(str == "")return;
tcpsocket->write(str.toUtf8().data()); //利用通信套接字向发送缓冲区写入数据
ui->textEdit_2->clear(); //清空发送区
qtchatmessage* messageW = new qtchatmessage(ui->listWidget->parentWidget()); //创建气泡
QListWidgetItem* item = new QListWidgetItem(ui->listWidget); //创建小部件,选项控件
dealMessage(messageW, item, str, qtchatmessage::User_Me); //处理创建的气泡
ui->listWidget->setCurrentRow(ui->listWidget->count()-1); //移动到最后一行
}
然后客户端设置事件过滤器,来过滤键盘操作,设置快捷键回车来点击发送按钮
[C++] 纯文本查看 复制代码 bool aWidget::eventFilter(QObject *target, QEvent *event){ //事件过滤器,不设置事件过滤器会被系统的函数自动过滤
if(target == ui->textEdit_2)
{
if(event->type() == QEvent::KeyPress) //按键盘事件
{
QKeyEvent *k = static_cast<QKeyEvent *>(event);
if(k->key() == Qt::Key_Return||k->key() == Qt::Key_Enter) //回车
{
aWidget::on_pushButton_clicked();
return true;
}
}
}
return QWidget::eventFilter(target,event);
}
接受函数采用QT提供的虚函数接受消息处理
[C++] 纯文本查看 复制代码 connect(tcpsocket, &QTcpSocket::readyRead,
[=]()
{
QByteArray str = tcpsocket->readAll(); //获取对方发送的数据
QString string = static_cast<QString>(str); //强转
if(record[0] == 'n'){
if(string == "yes"){record[0] = 'y'; w1.hide();this->show();}else return;
}
qtchatmessage* messageW = new qtchatmessage(ui->listWidget->parentWidget()); //创建气泡
QListWidgetItem* item = new QListWidgetItem(ui->listWidget); //创建小部件,选项控件
dealMessage(messageW, item, str, qtchatmessage::User_He); //处理创建的气泡
ui->listWidget->setCurrentRow(ui->listWidget->count()-1); //移动到最后一行
} ); //接受数据
客户端大致就这些。接下来总结一下服务端:
变量列表:[C++] 纯文本查看 复制代码 QTcpServer *tcpserver;
QTcpSocket *tcpsocket[13];
char flag[13]; //判断是否连接
char record[13]; //判断是否登录
void initMumber();
void initMumber_1();
void dealConnect();
void dealMessage(int i);
void dealRecord(int i); //处理登录
创建了十三个通信套接字,一个监听套接字。标志位变量。首先初始化各变量,包括监听套接字。
[C++] 纯文本查看 复制代码 void aWidget::initMumber(){
tcpserver = new QTcpServer(this);
tcpserver->listen(QHostAddress::Any, 6666);
aWidget::initMumber_1();
}
void aWidget::initMumber_1(){
for(int j = 0;j<13;j++){
flag[j] = 'n';
record[j] = 'n';
tcpsocket[j] = nullptr;
}
}
服务端的监听套接字,监听新连接,触发信号调用处理函数,设置标志位变量为已连接。
[C++] 纯文本查看 复制代码 void aWidget::dealConnect(){ //处理连接
for(int i = 0;i < 13;i++){
if(flag[i] == 'n'){
flag[i] = 'y';
tcpsocket[i] = tcpserver->nextPendingConnection(); //连接客户端
QString ip = tcpsocket[i]->peerAddress().toString(); //打印信息
quint16 port = tcpsocket[i]->peerPort();
QString temp = QString("[%1:%2]:接入服务").arg(ip).arg(port);
ui->textEdit->append(temp); //向服务器显示连接信息
connect(tcpsocket[i], &QTcpSocket::readyRead,[=](){aWidget::dealMessage(i);}); //监听是否来信息 //dealMessage函数的参数必须传局部变量,不能传全局变量。
break; //必须有break,否则会把通信套接字循环完的。 //随着i的变化Lambda表达式的函数体随着变化
}
}
int b; //不能写进for里面,因为有的退出了,套接字就不能用了
for (b = 0;b < 13;b++) {
if(flag[b] == 'n')break;
}
if(b == 13)
ui->textEdit->append("已经没有可用的套接字了");
}
入监听接受信息函数来分发信息,达到服务器转发信息的目的
[C++] 纯文本查看 复制代码 void aWidget::dealMessage(int i){ //把消息分发给所有在线客户
if(record[i] == 'n'){
aWidget::dealRecord(i);
return;
}
QByteArray array = tcpsocket[i]->readAll(); //获取内容
for(int j = 0;j<13;j++)
{
if(flag[j] != 'n'&&i != j)
{
tcpsocket[j]->write(array);
}
}
}
基本上TCP通信采用QT开发的基本流程就这些,还有一些细节的处理,项目中对气泡的处理参考了一下网络上的代码。其他调用函数我没写进去,需要的小伙伴说一声,我抽空上传到百度网盘。由于项目代码中涉及到一些隐私就没全部上传,所有的图片均取自于网络,如有侵权,联系笔者,立刻删除。新人第一次发帖,大家多多照顾。目前大二小菜鸟,希望和大家共同进步。加油啦~。
代码如果哪里有问题,大佬勿喷,笔者还是大二在校生。联系笔者,一定跟大家交流,共同进步。
要乖,那些错过的,咱们不要了。
|