QT学习笔记——06-Day17_C++_QT

在学习QT总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

06-Day17_C++_QT

目录:
Qt案例笔记
1、对话框列表
2、简单的二人聊天Udp聊天程序
3、核心功能——群聊实现
4、新用户进入
5、用户离开
6、代码

 

Qt案例笔记

1、对话框列表

1)Toolbox群成员

2)内部,做出一个垂直布局

3)添加按钮

  图标、文字、图标大小、风格、文字图标都显示、按钮保存到QVector容器中

(1)右击项目名,在弹出的快捷菜单中选择“添加新文件...”菜单项,在弹出的对话框中选择“Qt”选项。选择Qt设计师界面类,单击“Choose...”按钮;

界面模板选择Widget,点击下一步

类名填写 DialogList (可以起其他名称)点击下一步

在汇总中单击“完成”按钮,系统会为我们添加“dialoglist.h”头文件和“dialoglist.cpp”源文件以及dialoglist.ui设计文件

(2)资源导入

(3)聊天窗口搭建

2、简单的二人聊天Udp聊天程序

 

1)UdpSocket  (在.pro中添加network)

2)new出套接字

3)绑定端口

4)书写报文,writeDatagram

5)ReadyRead 监听信号

6)读取报文

7)报文长度 qint64 size = udp->pendingDatagramSize();

8)同步聊天记录

新建工程:选择“QWidget”,勾选“显示主界面”(默认勾选)

在.pro中更改:

 1 #-------------------------------------------------
 2 #
 3 # Project created by QtCreator 2020-06-24T08:48:03
 4 #
 5 #-------------------------------------------------
 6 
 7 QT       += core gui network
 8 
 9 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 
11 TARGET = QUdpDemo
12 TEMPLATE = app
13 
14 
15 SOURCES += main.cpp\
16         udp1.cpp \
17     udp2.cpp
18 
19 HEADERS  += udp1.h \
20     udp2.h
21 
22 FORMS    += udp1.ui \
23     udp2.ui
24 
25 CONFIG += c++11

udp1.ui中设计界面

udp1.h中修改如下:

 1 #ifndef UDP1_H
 2 #define UDP1_H
 3 
 4 #include <QWidget>
 5 #include<QUdpSocket>//在.pro中添加network
 6 
 7 namespace Ui {
 8 class Udp1;
 9 }
10 
11 class Udp1 : public QWidget
12 {
13     Q_OBJECT
14 
15 public:
16     explicit Udp1(QWidget *parent = 0);
17     ~Udp1();
18 
19 private:
20     Ui::Udp1 *ui;
21 
22 public:
23     //套接字
24     QUdpSocket* udp;
25 
26 };
27 
28 #endif // UDP1_H

udp1.cpp中修改如下:

 1 #include "udp1.h"
 2 #include "ui_udp1.h"
 3 
 4 Udp1::Udp1(QWidget *parent) :
 5     QWidget(parent),
 6     ui(new Ui::Udp1)
 7 {
 8     ui->setupUi(this);
 9 
10     //初始化属性
11     ui->myPort->setText("8888");
12     ui->toPort->setText("9999");
13     ui->toIp->setText("127.0.0.1");
14 
15     //创建套接字
16     udp = new QUdpSocket(this);
17 
18     //绑定自身端口号,QString转int——.toInt()
19     udp->bind(ui->myPort->text().toInt());
20 
21     //点击发送按钮,发送报文
22     connect(ui->sendBtn,&QPushButton::clicked,[=](){
23         //书写报文(参数1:内容,参数2:对方Ip,参数3:对方端口)
24        udp->writeDatagram(ui->input->toPlainText().toUtf8(),QHostAddress(ui->toIp->text()),ui->toPort->text().toInt());
25     //QString转QByteArray:QString转char*的中间就是转QByteArray——.toUtf8()
26        ui->record->append("my Say:"+ui->input->toPlainText());
27 
28        //清空输入框
29        ui->input->clear();
30 
31     });
32 
33     //接收数据
34     connect(udp,&QUdpSocket::readyRead,[=](){
35 
36         //获取报文长度
37         qint64 size = udp->pendingDatagramSize();
38 
39         QByteArray array = QByteArray(size, 0);
40 
41         //读取报文
42         udp->readDatagram(array.data(), size);
43 
44         //将数据同步到聊天记录中
45         ui->record->append(array);
46 
47     });
48 
49 
50 
51 }
52 
53 Udp1::~Udp1()
54 {
55     delete ui;
56 }

添加新文件:Qt—设计师界面类,

udp2.ui中设计界面:全部拷贝udp1.ui中设计界面

udp2.h中修改如下:(拷贝udp1.h)

 1 #ifndef UDP2_H
 2 #define UDP2_H
 3 
 4 #include <QWidget>
 5 #include<QUdpSocket>
 6 
 7 
 8 namespace Ui {
 9 class Udp2;
10 }
11 
12 class Udp2 : public QWidget
13 {
14     Q_OBJECT
15 
16 public:
17     explicit Udp2(QWidget *parent = 0);
18     ~Udp2();
19 
20 private:
21     Ui::Udp2 *ui;
22 
23 public:
24     QUdpSocket* udp;
25 
26 };
27 
28 #endif // UDP2_H

udp2.cpp中修改如下:(拷贝udp1.cpp)

 1 #include "udp2.h"
 2 #include "ui_udp2.h"
 3 
 4 Udp2::Udp2(QWidget *parent) :
 5     QWidget(parent),
 6     ui(new Ui::Udp2)
 7 {
 8     ui->setupUi(this);
 9 
10 
11     //初始化属性
12     ui->myPort->setText("9999");
13     ui->toPort->setText("8888");
14     ui->toIp->setText("127.0.0.1");
15 
16     //创建套接字
17     udp = new QUdpSocket(this);
18 
19     //绑定自身端口号
20     udp->bind(ui->myPort->text().toInt());
21 
22     //点击发送按钮,发送报文
23     connect(ui->sendBtn,&QPushButton::clicked,[=](){
24         //书写报文(参数1:内容,参数2:对方Ip,参数3:对方端口)
25        udp->writeDatagram(ui->input->toPlainText().toUtf8(),QHostAddress(ui->toIp->text()),ui->toPort->text().toInt());
26 
27        ui->record->append("my Say:"+ui->input->toPlainText());
28 
29        //清空输入框
30        ui->input->clear();
31 
32     });
33 
34     //接收数据
35     connect(udp,&QUdpSocket::readyRead,[=](){
36 
37         //获取报文长度
38         qint64 size = udp->pendingDatagramSize();
39 
40         QByteArray array = QByteArray(size, 0);
41 
42         //读取报文
43         udp->readDatagram(array.data(), size);
44 
45         //将数据同步到聊天记录中
46         ui->record->append(array);
47 
48     });
49 }
50 
51 Udp2::~Udp2()
52 {
53     delete ui;
54 }

在main.cpp中更改:

 1 #include "udp1.h"
 2 #include <QApplication>
 3 #include"udp2.h"
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     QApplication a(argc, argv);
 8     Udp1 w;
 9     w.show();
10 
11     Udp2 u2;
12     u2.show();
13 
14     return a.exec();
15 }

 

3、核心功能——群聊实现

1)通信套接字

2)bind(端口,共享地址|断线重连)

3)获取用户名

4)sndMsg(枚举(普通聊天,用户进入、离开))

5)发送3段数据(类型、用户名、具体内容)

6)书写报文,广播发送

7)接收:利用数据流,做分段

  解析:第一段(类型);把用户发送的内容追加到聊天记录中

 

4、新用户进入

1)提供新用户进入函数

2)更新右侧TableWidget

3)更新聊天记录

4)更新在线用户人数

 

5、用户离开

1)提供用户处理函数

2)更新右侧TableWidget

3)更新聊天记录

4)更新在线用户人数

5)在closeEvent事件中,发送用户离开消息

6)端口套接字断开

7)离开按钮处理

6、代码

dialoglist.h如下:

 1 #ifndef DIALOGLIST_H
 2 #define DIALOGLIST_H
 3 
 4 #include <QWidget>
 5 
 6 namespace Ui {
 7 class DialogList;
 8 }
 9 
10 class DialogList : public QWidget
11 {
12     Q_OBJECT
13 
14 public:
15     explicit DialogList(QWidget *parent = 0);
16     ~DialogList();
17 
18 private:
19     Ui::DialogList *ui;
20 
21     QVector<bool>isShow;
22 };
23 
24 #endif // DIALOGLIST_H

dialoglist.cpp如下:

 1 #include "dialoglist.h"
 2 #include "ui_dialoglist.h"
 3 #include<QToolButton>
 4 #include"widget.h"
 5 #include<QMessageBox>
 6 
 7 DialogList::DialogList(QWidget *parent) :
 8     QWidget(parent),
 9     ui(new Ui::DialogList)
10 {
11     ui->setupUi(this);
12 
13     //设置标题
14     setWindowTitle("MySelfQQ 2020");
15     //设置图标
16     setWindowIcon(QPixmap(":/images/qq.png"));
17 
18     //准备图标
19     QList<QString>nameList;
20     nameList << "水票奇缘" << "忆梦如澜" <<"北京出版人"<<"Cherry"<<"淡然"
21              <<"娇娇girl"<<"落水无痕"<<"青墨暖暖"<<"无语";
22 
23 
24     QStringList iconNameList; //图标资源列表
25     iconNameList << "spqy"<< "ymrl" <<"qq" <<"Cherry"<< "dr"
26                  <<"jj"<<"lswh"<<"qmnn"<<"wy";
27 
28     QVector<QToolButton*>vToolBtn;
29 //    QVector<bool>isShow;
30 
31     for(int i = 0; i < 9; i++)
32     {
33         //设置头像
34         QToolButton* btn = new QToolButton;
35         //设置文字
36         btn->setText(nameList[i]);
37         //设置头像
38         QString str = QString(":/images/%1.png").arg(iconNameList.at(i));
39         btn->setIcon(QPixmap(str));
40         //设置头像大小
41         btn->setIconSize(QPixmap(str).size());
42         //设置按钮风格,透明
43         btn->setAutoRaise(true);
44         //设置文字和图片一起显示
45         btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
46         //加到垂直布局中
47         ui->vLayout->addWidget(btn);
48         //容器保存住9个按钮,方便以后再次操作
49         vToolBtn.push_back(btn);
50         //9个标识默认初始化
51         isShow.push_back(false);
52 
53     }
54 
55     //对9个按钮,进行添加信号槽
56     for(int i = 0; i < vToolBtn.size(); i++)
57     {
58         connect(vToolBtn[i],&QToolButton::clicked,[=](){
59             //如果被打开了,就不要再次打开
60             if(isShow[i])
61             {
62                 QString str = QString("%1窗口已经被打开了").arg(vToolBtn[i]->text());
63                 QMessageBox::warning(this, "警告", str);
64                 return;
65             }
66             isShow[i] = true;
67 
68             //弹出聊天对话框
69             //构造聊天窗口时候,告诉这个窗口他的名字(参数1:顶层方式弹出,参数2:窗口名字)
70             //注意:Widget构造函数,并没有这两个参数
71             Widget* widget = new Widget(0,vToolBtn[i]->text());
72             //设置窗口标题
73             widget->setWindowTitle(vToolBtn[i]->text());
74             //设置头像
75             widget->setWindowIcon(vToolBtn[i]->icon());
76             //显示窗口
77             widget->show();
78 
79             connect(widget,&Widget::closeWidget,[=](){
80                 isShow[i] = false;
81             });
82 
83         });
84 
85     }
86 
87 
88 
89 }
90 
91 DialogList::~DialogList()
92 {
93     delete ui;
94 }

widget.h如下:

 1 #ifndef WIDGET_H
 2 #define WIDGET_H
 3 
 4 #include <QWidget>
 5 #include<QUdpSocket>
 6 
 7 namespace Ui {
 8 class Widget;
 9 }
10 
11 class Widget : public QWidget
12 {
13     Q_OBJECT
14 
15 public:
16     enum MsgType{Msg,UsrEnter,UsrLeft};
17 
18 public:
19     explicit Widget(QWidget *parent, QString name);
20     ~Widget();
21 
22 private:
23     Ui::Widget *ui;
24 
25 signals:
26     //关闭窗口,发送关闭信息
27     void closeWidget();
28 public:
29     //关闭事件
30     void closeEvent(QCloseEvent*);
31 
32 public:
33    void sndMsg(MsgType type); //广播UDP消息
34    void usrEnter(QString username);//处理新用户加入
35    void usrLeft(QString usrname,QString time); //处理用户离开
36    QString getUsr(); //获取用户名
37    QString getMsg(); //获取聊天信息
38 
39    void ReceiveMessage();   //接收UDP消息
40 private:
41    QUdpSocket * udpSocket; //udp套接字
42    qint16 port; //端口
43    QString uName; //用户名
44 
45 
46 
47 };
48 
49 #endif // WIDGET_H

widget.cpp如下:

  1 #include "widget.h"
  2 #include "ui_widget.h"
  3 #include<QDataStream>
  4 #include<QMessageBox>
  5 #include<QDateTime>
  6 #include<QColorDialog>
  7 #include<QFileDialog>
  8 #include<QTextStream>
  9 
 10 Widget::Widget(QWidget *parent, QString name) :
 11     QWidget(parent),
 12     ui(new Ui::Widget)
 13 {
 14     ui->setupUi(this);
 15 
 16     //初始化操作
 17 
 18     udpSocket = new QUdpSocket(this);
 19     //用户名获取
 20     uName = name;
 21     //端口号
 22     this->port = 9999;
 23 
 24     //绑定端口号,绑定模式(共享地址|断线重连)
 25     udpSocket->bind(this->port,QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
 26 
 27     //发送新用户进入
 28     sndMsg(UsrEnter);
 29 
 30     //点击发送按钮发送消息
 31     connect(ui->sendBtn,&QPushButton::clicked,[=](){
 32         sndMsg(Msg);
 33     });
 34 
 35     //监听别人发送的数据
 36     connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::ReceiveMessage);
 37 
 38     //点击退出按钮,实现关闭窗口
 39     connect(ui->exitBtn,&QPushButton::clicked,[=](){
 40         this->close();
 41     });
 42 
 43 
 44     // //////////////////////辅助功能/////////
 45     //设置字体
 46     connect(ui->fontCbx,&QFontComboBox::currentFontChanged,[=](const QFont &font){
 47         ui->msgTxtEdit->setCurrentFont(font);
 48         ui->msgTxtEdit->setFocus();
 49     });
 50 
 51     //设置字号
 52     void (QComboBox:: * cbxSingal)(const QString &text) = &QComboBox::currentIndexChanged;
 53     connect(ui->sizeCbx,cbxSingal,this,[=](const QString &text){
 54         ui->msgTxtEdit->setFontPointSize(text.toDouble());
 55         ui->msgTxtEdit->setFocus();
 56     });
 57 
 58     //加粗
 59     connect(ui->boldTBtn,&QToolButton::clicked,this,[=](bool checked){
 60         if(checked)
 61         {
 62             ui->msgTxtEdit->setFontWeight(QFont::Bold);
 63         }
 64         else
 65         {
 66             ui->msgTxtEdit->setFontWeight(QFont::Normal);
 67         }
 68         ui->msgTxtEdit->setFocus();
 69     });
 70 
 71     //倾斜
 72     connect(ui->italicTBtn,&QToolButton::clicked,this,[=](bool checked){
 73 
 74         ui->msgTxtEdit->setFontItalic(checked);
 75 
 76         ui->msgTxtEdit->setFocus();
 77     });
 78 
 79     //下划线
 80     connect(ui->underlineTBtn,&QToolButton::clicked,this,[=](bool checked){
 81 
 82         ui->msgTxtEdit->setFontUnderline(checked);
 83 
 84         ui->msgTxtEdit->setFocus();
 85     });
 86 
 87     //文本颜色
 88     connect(ui->colorTBtn,&QToolButton::clicked,this,[=](){
 89         QColor color = QColorDialog::getColor(color,this); //color对象可以在widget.h中定义私有成员
 90         if(color.isValid())
 91         {
 92             ui->msgTxtEdit->setTextColor(color);
 93             ui->msgTxtEdit->setFocus();
 94         }
 95     });
 96 
 97     //保存聊天记录
 98     connect(ui->saveTBtn,&QToolButton::clicked,this,[=](){
 99         if(ui->msgBrowser->document()->isEmpty())
100         {
101             QMessageBox::warning(this,"警告","聊天记录为空,无法保存!",QMessageBox::Ok);
102             return;
103         }
104         else
105         {
106             QString fName = QFileDialog::getSaveFileName(this,"保存聊天记录","聊天记录","(*.txt)");
107             if(!fName.isEmpty())
108             {
109                 //保存名称不为空,再做保存操作
110                 QFile file(fName);
111                 //打开模式追加换行
112                 file.open(QIODevice::WriteOnly | QFile::Text);
113 
114                 QTextStream stream(&file);
115                 stream << ui->msgBrowser->toPlainText();
116                 file.close();
117             }
118         }
119     });
120 
121     //清空聊天记录
122     connect(ui->clearTBtn,&QToolButton::clicked,[=](){
123         ui->msgBrowser->clear();
124     });
125 
126 
127 }
128 
129 //接收UDP消息
130 void Widget::ReceiveMessage()
131 {
132     //拿到数据报文
133     //获取长度
134     qint64 size = udpSocket->pendingDatagramSize();
135 
136     QByteArray array = QByteArray(size,0);
137     udpSocket->readDatagram(array.data(),size);
138 
139     //解析数据
140     //第一段:类型,第二段:用户名,第三段:内容
141     QDataStream stream(&array, QIODevice::ReadOnly);
142 
143     int msgType;//读取到类型
144     QString usrName;//读取到用户名
145     QString msg;//读取到内容
146 
147     //获取当前时间
148     QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
149 
150     stream >> msgType;
151 
152     switch (msgType) {
153     case Msg://普通聊天
154         stream >> usrName >> msg;
155 
156         //追加聊天记录
157         ui->msgBrowser->setTextColor(Qt::blue);
158         ui->msgBrowser->append("["+ usrName + "]" + time);
159         ui->msgBrowser->append(msg);
160 
161         break;
162     case UsrEnter:
163 
164         stream >> usrName;
165         usrEnter(usrName);
166 
167 
168         break;
169     case UsrLeft:
170         stream >> usrName;
171         usrLeft(usrName,time);
172 
173         break;
174     default:
175         break;
176     }
177 
178 
179 
180 
181 
182 }
183 
184 //处理用户离开
185 void Widget::usrLeft(QString usrname,QString time)
186 {
187     //更新右侧TableWidget
188     bool isEmpty1 = ui->usrTb1Widget->findItems(usrname,Qt::MatchExactly).isEmpty();
189     if(!isEmpty1)
190     {
191         int row = ui->usrTb1Widget->findItems(usrname,Qt::MatchExactly).first()->row();
192         ui->usrTb1Widget->removeRow(row);
193 
194         //追加聊天记录
195         ui->msgBrowser->setTextColor(Qt::gray);
196         ui->msgBrowser->append(QString("%1 于 %2 离开").arg(usrname).arg(time));
197         //在线人数更新
198         ui->usrNumLb1->setText(QString("在线用户:%1人").arg(ui->usrTb1Widget->rowCount()));
199 
200     }
201 
202 }
203 
204 //处理新用户加入
205 void Widget::usrEnter(QString usrname)
206 {
207 
208     //更新右侧TableWidget
209     bool isEmpty = ui->usrTb1Widget->findItems(usrname,Qt::MatchExactly).isEmpty();
210     if(isEmpty)
211     {
212 
213         QTableWidgetItem* usr = new QTableWidgetItem(usrname);
214 
215         //插入行
216         ui->usrTb1Widget->insertRow(0);
217         ui->usrTb1Widget->setItem(0,0,usr);
218 
219         //追加聊天记录
220         ui->msgBrowser->setTextColor(Qt::gray);
221         ui->msgBrowser->append(QString("%1 上线了").arg(usrname));
222         //在线人数更新
223         ui->usrNumLb1->setText(QString("在线用户:%1人").arg(ui->usrTb1Widget->rowCount()));
224 
225 
226 
227         //把自身信息广播出去???
228         //sndMsg(UsrEnter);
229 
230     }
231 
232 }
233 
234 
235 
236 //广播UDP消息
237 void Widget::sndMsg(MsgType type)
238 {
239     //发送的消息分为3种类型
240     //发送的数据做分段处理:第一段(类型),第二段(用户名),第三段(具体内容)
241 
242     QByteArray array;
243 
244     QDataStream stream(&array,QIODevice::WriteOnly);
245 
246     stream << type << getUsr();//第一段内容添加到流中,第二段(用户名)
247 
248     switch (type) {
249     case Msg: //普通消息发送
250 
251         if(ui->msgTxtEdit->toPlainText() == "")//判断如果用户没有输入内容,不发任何消息
252         {
253             QMessageBox::warning(this,"警告","发送内容不能为空") ;
254             return;
255         }
256         //第三段数据,具体说的话
257         stream << getMsg();
258 
259         break;
260     case UsrEnter://新用户进入消息
261 
262         break;
263     case UsrLeft://用户离开消息
264 
265         break;
266 
267     default:
268         break;
269     }
270 
271     //书写报文,广播发送(255.255.255.255)
272     udpSocket->writeDatagram(array,QHostAddress::Broadcast,port);
273 
274 
275 }
276 
277 //获取用户名
278 QString Widget::getUsr()
279 {
280     return this->uName;
281 }
282 
283 
284 //获取聊天信息
285 QString Widget::getMsg()
286 {
287     QString str = ui->msgTxtEdit->toHtml();
288 
289     //清空输入框
290     ui->msgTxtEdit->clear();
291     ui->msgTxtEdit->setFocus();//让光标定位回输入框
292 
293     return str;
294 }
295 
296 
297 
298 void Widget::closeEvent(QCloseEvent* e)
299 {
300     emit this->closeWidget();
301 
302     sndMsg(UsrLeft);
303     //断开套接字
304     udpSocket->close();
305     udpSocket->destroyed();
306 
307     QWidget::closeEvent(e);//其他事情交给父类处理
308 }
309 
310 
311 Widget::~Widget()
312 {
313     delete ui;
314 }

main.cpp如下:

 1 #include "widget.h"
 2 #include <QApplication>
 3 #include"dialoglist.h"
 4 
 5 
 6 int main(int argc, char *argv[])
 7 {
 8     QApplication a(argc, argv);
 9 //    Widget w;
10 //    w.show();
11 
12     DialogList list;
13     list.show();
14 
15     return a.exec();
16 }

注意:

Qt5.5目前Issue:

1)进入:对于新进入的用户,新用户列表未更新,加入sndMsg(UsrEnter);会陷入死循环,解决不了!!!
2)退出:对于最早进入的用户,退出,后来的用户检测不到,列表未更新

 

在学习QT总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

posted on 2020-06-23 19:18  Alliswell_WP  阅读(286)  评论(0编辑  收藏  举报

导航