本次整个项目的开发基于Qt Creator 5.14.2进行的开发与调试,主要通信功能采用UDPSocket完成,是我学习Qt过程中联系的小案例,过程中遇到的bug和完整代码会尽量展现出来,关于Qt以及其安装流程在CSDN里面有很多大佬写的教程,十分详细!!!



- #ifndef DIALOGLIST_H
- #define DIALOGLIST_H
- #include
- #include
-
-
- namespace Ui {
- class DialogList;
- }
-
- class DialogList : public QWidget
- {
- Q_OBJECT
-
- public:
- explicit DialogList(QWidget *parent = nullptr);
- ~DialogList();
- QVector<bool> isshow; //判断当前窗口是否已被显示出
-
-
-
- private:
- Ui::DialogList *ui;
- };
-
- #endif // DIALOGLIST_H
- #include "dialoglist.h"
- #include "ui_dialoglist.h"
- #include
- #include
- #include
- #include
- #include
-
-
- DialogList::DialogList(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::DialogList)
- {
- ui->setupUi(this);
- setWindowIcon(QPixmap(":/images/校标.png"));
- //容器保存10个toolbutton
- QVector
toolvector; - //记录头像图名加入泛型集合
- QList
name; - name<<"copy.Image"<<"cut.Image"<<"Hearts"<<"new.Image"<<"open.Image"<<"paste.Image"<<"print.Image"
- <<"printPreview.Image"<<"save.Image"<<"校标";
-
-
- //在toolbox容器中动态生成toolbutton按钮
- for (int i=0;i
size();i++) - {
- QToolButton *btn = new QToolButton;
- btn->setText(name[i]);
- QString str = QString(":/images/"+name[i]+".png");
- btn->setIcon(QPixmap(str));
- btn->setIconSize(QSize(72,72));
- btn->setAutoRaise(true);
- btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- ui->vLayout->addWidget(btn);
- //将创建的10个toolbutton全部放入容器保存
- toolvector.push_back (btn);
- isshow.push_back(false);
- }
- //对10个toolbutton添加信号和槽函数
- for (int i=0;i
size();i++) - {
- connect (toolvector[i],&QToolButton::clicked,[=](){
- if(isshow[i]==true)
- {
- QMessageBox::warning(this,"警告","当前窗口已被打开");
- return;
- }
- else
- {
- isshow[i]=true;
- Widget *widget = new Widget(0,toolvector[i]->text());
- widget->setWindowTitle(toolvector[i]->text());
- widget->setWindowIcon(toolvector[i]->icon());
- widget->show();
-
- connect (widget,&Widget::closeWidget,[=](){
- isshow[i]=false;
- });
- }
- });
-
- }
-
-
- }
-
- DialogList::~DialogList()
- {
- delete ui;
- }
- #ifndef WIDGET_H
- #define WIDGET_H
- #include
- #include
- #include
-
-
- QT_BEGIN_NAMESPACE
- namespace Ui { class Widget; }
- QT_END_NAMESPACE
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- Widget(QWidget *parent,QString name);
- ~Widget();
-
- private:
- Ui::Widget *ui;
-
-
- signals:
- //关闭窗口发送关闭信号
- void closeWidget();
- public:
- //窗口关闭事件
- void closeEvent(QCloseEvent *);
-
- public:
- enum MsgType{Msg,UsrEnter,UsrLeft};
- void sendMsg(MsgType type); //广播UDP消息
- void usrEnter(QString usrname); //新用户进入
- void usrLeft(QString usrname,QString time); //处理用户离开
- QString getUsr(); //获取用户名
- QString getMsg(); //获取聊天信息
- private:
- QUdpSocket *udpSocket; //UDP套接字
- qint16 port; //端口
- QString Uname; //用户名
- void ReceiveMsg(); //接收UDP消息
-
- };
- #endif // WIDGET_H
- #include "widget.h"
- #include "ui_widget.h"
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- Widget::Widget(QWidget *parent,QString name)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
- udpSocket = new QUdpSocket(this);
- //用户名获取
- Uname=name;
- //端口号获取
- this->port=9999;
- //绑定端口号 共享地址 和 断线重连
- udpSocket->bind(port,QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
-
- //发送新用户进入
- sendMsg(UsrEnter);
-
- //点击按钮发送信息
- connect (ui->sendbtn,&QPushButton::clicked,[=](){
- sendMsg(Msg);
- });
- //监听别人发送的数据
- connect (udpSocket,&QUdpSocket::readyRead,this,&Widget::ReceiveMsg);
-
- //退出程序
- connect (ui->quitbtn,&QPushButton::clicked,[=](){
- this->close();
- });
-
- /辅助功能///
- //设置字体
- connect(ui->fontComboBox,&QFontComboBox::currentFontChanged,[=](const QFont &font){
- ui->msgtextEdit->setFont(font);
- });
- //设置字号[应用函数指针]
- void(QComboBox:: *p)(const QString &text) =&QComboBox::currentIndexChanged;
- connect(ui->sizecomboBox, p ,[=](const QString &text){
- ui->msgtextEdit->setFontPointSize(text.toDouble());
- ui->msgtextEdit->setFocus();
- });
- //加粗
- connect(ui->Boldbtn,&QToolButton::clicked,[=](bool checked){
- if (checked)
- {
- ui->msgtextEdit->setFontWeight(QFont::Bold);
- }
- else
- {
- ui->msgtextEdit->setFontWeight(QFont::Normal);
- }
- });
- //倾斜
- connect(ui->Itabtn,&QToolButton::clicked,[=](bool checked){
- if (checked)
- {
- ui->msgtextEdit->setFontItalic(true);
- }
- else
- {
- ui->msgtextEdit->setFontItalic(false);
- }
- });
- //下划线
- connect(ui->underlinebtn,&QToolButton::clicked,[=](bool checked){
- if (checked)
- {
- ui->msgtextEdit->setFontUnderline(true);
- }
- else
- {
- ui->msgtextEdit->setFontUnderline(false);
- }
- });
- //字体颜色
- connect(ui->colorbtn,&QToolButton::clicked,[=](){
- QColor color = QColorDialog::getColor(Qt::red);
- ui->msgtextEdit->setTextColor(color);
- });
- //清空删除聊天记录
- connect(ui->deletebtn,&QToolButton::clicked,[=](){
- ui->msgBrowser->clear();
- });
- //保存聊天记录
- connect(ui->savebtn,&QToolButton::clicked,[=](){
- if (ui->msgBrowser->document ()->isEmpty())
- {
- QMessageBox::warning(this,"警告","聊天记录不能为空");
- return;
- }
- else
- {
- QString savepath = QFileDialog::getSaveFileName (this,"save","聊天记录","(*.txt)");
- if (savepath.isEmpty())
- {
- QMessageBox::warning(this,"警告","路径不能为空");
- return;
- }
- else
- {
- QFile file(savepath);
- file.open(QIODevice::WriteOnly | QIODevice::Text);
- QTextStream stream(&file);
- stream << ui->msgBrowser->toPlainText();
- file.close();
- QMessageBox::information (this,"Tip","保存成功");
- }
- }
- });
-
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
- //窗口关闭事件
- void Widget::closeEvent(QCloseEvent *)
- {
- emit this->closeWidget();
- //发送用户离开
- sendMsg(UsrLeft);
- //关闭套接字
- udpSocket->close ();
- udpSocket->destroyed ();
- }
- //广播UDP消息
- void Widget::sendMsg(MsgType type)
- {
- QByteArray array=QByteArray(10000,0);
- QDataStream stream(&array,QIODevice::WriteOnly);
- //第一段 获取信息类型 第二段 用户名
- stream<
getUsr(); - switch (type)
- {
- case Msg:
- //如果输入框为空,则提示警告
- if (ui->msgtextEdit->toPlainText()=="") {
- QMessageBox::warning(this,"Tip Message","输入框不允许为空",QMessageBox::Close);
- return;
- }
- //第三段 合并获取到的消息
- stream<<getMsg();
- break;
- case UsrEnter: //用户进入信息
-
- break;
- case UsrLeft: //用户离开信息
-
- break;
- default:
- break;
- }
-
- //书写报文 广播发送
- udpSocket->writeDatagram(array,QHostAddress::Broadcast,port);
- }
-
- //新用户进入
- void Widget::usrEnter(QString usrname)
- {
- bool isempty = ui->usrtableWidget->findItems (usrname,Qt::MatchExactly).isEmpty();
- if (isempty)
- {
- ui->msgBrowser->setTextColor (Qt::gray);
- ui->msgBrowser->append (usrname+" 上线了!");
- QTableWidgetItem *usr = new QTableWidgetItem(usrname);
- ui->usrtableWidget->insertRow(0);
- ui->usrtableWidget->setItem(0,0,usr);
- QString online = QString("在线人数为:%1").arg(ui->usrtableWidget->rowCount());
- ui->label->setText (online);
- //把自身信息广播出去
- sendMsg (UsrEnter);
- }
-
- }
-
- //处理用户离开
- void Widget::usrLeft(QString usrname,QString time)
- {
- bool isempty = ui->usrtableWidget->findItems (usrname,Qt::MatchExactly).isEmpty();
- if (!isempty)
- {
- int r = ui->usrtableWidget->findItems(usrname,Qt::MatchExactly).first()->row();
- ui->usrtableWidget->removeRow(r);
- //追加聊天记录
- ui->msgBrowser->setTextColor(Qt::gray);
- ui->msgBrowser->append (QString("%1 at %2 离开").arg (usrname).arg(time));
- //在线人数更新
- ui->label->setText (QString("在线人数为:%1").arg(ui->usrtableWidget->rowCount()));
- }
-
- }
- //获取用户名
- QString Widget::getUsr()
- {
- return this->Uname;
- }
- //获取聊天信息
- QString Widget::getMsg()
- {
- QString str = ui->msgtextEdit->toHtml();
- ui->msgtextEdit->clear();
- ui->msgtextEdit->setFocus();
- return str;
- }
- //接收UDP消息
- void Widget::ReceiveMsg()
- {
- //拿到数据报文
- qint64 size = udpSocket->pendingDatagramSize();
- QByteArray array=QByteArray(10000,0);
- udpSocket->readDatagram(array.data(),size);
- //解析数据
- QDataStream stream(&array,QIODevice::ReadOnly);
- int msgType;
- QString usrName;
- QString msg;
- QString time = QDateTime::currentDateTime().toString ("yyyy-MM-dd hh:mm:ss");
- stream>>msgType;
- switch (msgType)
- {
- case Msg: //普通聊天
- {
- stream>>usrName>>msg;
- //追加聊天记录
- ui->msgBrowser->setTextColor(Qt::blue);
- ui->msgBrowser->append("["+usrName+"]"+time);
- ui->msgBrowser->append(msg);
- break;
- }
- case UsrEnter:
- {
- stream>>usrName;
- usrEnter(usrName);
- break;
- }
- case UsrLeft:
- {
- stream>>usrName;
- QString time = QDateTime::currentDateTime().toString ("yyyy-MM-dd hh:mm:ss");
- usrLeft(usrName,time);
- break;
- }
- default:
- break;
- }
- }

关键核心易出错部分,解析:
1.针对有重载的信号或槽函数,使用时要注意用到函数指针 void(作用域::*p)(int a) =&...
- //设置字号[应用函数指针]
- void(QComboBox:: *p)(const QString &text) =&QComboBox::currentIndexChanged;
- connect(ui->sizecomboBox, p ,[=](const QString &text){
- ui->msgtextEdit->setFontPointSize(text.toDouble());
- ui->msgtextEdit->setFocus();
- });
2.写文本文件到本地,将指定文本保存到本地:
- QString savepath = QFileDialog::getSaveFileName (this,"save","聊天记录","(*.txt)");
- if (savepath.isEmpty())
- {
- QMessageBox::warning(this,"警告","路径不能为空");
- return;
- }
- else
- {
- QFile file(savepath);
- file.open(QIODevice::WriteOnly | QIODevice::Text);
- QTextStream stream(&file);
- stream << ui->msgBrowser->toPlainText();
- file.close();
- QMessageBox::information (this,"Tip","保存成功");
- }
3. 广播UDP信息:
- //广播UDP消息
- void Widget::sendMsg(MsgType type)
- {
- QByteArray array=QByteArray(10000,0);
- QDataStream stream(&array,QIODevice::WriteOnly);
- //第一段 获取信息类型 第二段 用户名
- stream<
getUsr(); - switch (type)
- {
- case Msg:
- //如果输入框为空,则提示警告
- if (ui->msgtextEdit->toPlainText()=="") {
- QMessageBox::warning(this,"Tip Message","输入框不允许为空",QMessageBox::Close);
- return;
- }
- //第三段 合并获取到的消息
- stream<<getMsg();
- break;
- case UsrEnter: //用户进入信息
-
- break;
- case UsrLeft: //用户离开信息
-
- break;
- default:
- break;
- }
-
- //书写报文 广播发送
- udpSocket->writeDatagram(array,QHostAddress::Broadcast,port);
- }
4. 接收DUP信息:
- //接收UDP消息
- void Widget::ReceiveMsg()
- {
- //拿到数据报文
- qint64 size = udpSocket->pendingDatagramSize();
- QByteArray array=QByteArray(10000,0);
- udpSocket->readDatagram(array.data(),size);
- //解析数据
- QDataStream stream(&array,QIODevice::ReadOnly);
- int msgType;
- QString usrName;
- QString msg;
- QString time = QDateTime::currentDateTime().toString ("yyyy-MM-dd hh:mm:ss");
- stream>>msgType;
- switch (msgType)
- {
- case Msg: //普通聊天
- {
- stream>>usrName>>msg;
- //追加聊天记录
- ui->msgBrowser->setTextColor(Qt::blue);
- ui->msgBrowser->append("["+usrName+"]"+time);
- ui->msgBrowser->append(msg);
- break;
- }
- case UsrEnter:
- {
- stream>>usrName;
- usrEnter(usrName);
- break;
- }
- case UsrLeft:
- {
- stream>>usrName;
- QString time = QDateTime::currentDateTime().toString ("yyyy-MM-dd hh:mm:ss");
- usrLeft(usrName,time);
- break;
- }
- default:
- break;
- }
- }
5. 向控件TableWidget中插入内容(以下例子为插入指定的usrname):
- bool isempty = ui->usrtableWidget->findItems(usrname,Qt::MatchExactly).isEmpty();
- if (isempty)
- {
- QTableWidgetItem *usr = new QTableWidgetItem(usrname);
- ui->usrtableWidget->insertRow(0);
- ui->usrtableWidget->setItem(0,0,usr);
- }
后续其他练习实例同步更新,完结!