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) 编辑 收藏 举报