├── Client
├── Client.pro
├── Client.pro.autosave
├── Client.pro.user
├── debugonoroff.h
├── document.qrc
├── main.cpp
├── protocolcommand.h
├── widget.cpp
├── widget.h
└── widget.ui
├── LICENSE
├── README.md
└── Server
├── Server_V2.pro
├── Server_V2.pro.autosave
├── Server_V2.pro.user
├── clientaddress.cpp
├── clientaddress.h
├── debugonoroff.h
├── documents.qrc
├── img.qrc
├── img
├── child.png
├── loading4.gif
└── teacher.png
├── main.cpp
├── myserver.cpp
├── myserver.h
├── mysocket.cpp
├── mysocket.h
├── mythread.cpp
├── mythread.h
├── protocolcommand.h
├── qnchatmessage.cpp
├── qnchatmessage.cpp.autosave
├── qnchatmessage.h
├── qnchatmessage.h.autosave
├── widget.cpp
├── widget.cpp.autosave
├── widget.h
├── widget.h.autosave
└── widget.ui
/Client/Client.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2018-08-01T11:57:10
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui
8 | QT += network
9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 |
11 | TARGET = Client
12 | TEMPLATE = app
13 |
14 |
15 | SOURCES += main.cpp\
16 | widget.cpp
17 |
18 | HEADERS += widget.h \
19 | debugonoroff.h \
20 | protocolcommand.h
21 |
22 | FORMS += widget.ui
23 |
24 | RESOURCES += \
25 | document.qrc
26 |
--------------------------------------------------------------------------------
/Client/Client.pro.autosave:
--------------------------------------------------------------------------------
1 | QT += core gui
2 | QT += network
3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
4 |
5 | TARGET = Client
6 | TEMPLATE = app
7 |
8 |
9 | SOURCES += main.cpp\
10 | widget.cpp
11 |
12 | HEADERS += widget.h \
13 | debugonoroff.h \
14 | protocolcommand.h
15 |
16 | FORMS += widget.ui
17 |
18 | RESOURCES += \
19 | document.qrc
20 |
--------------------------------------------------------------------------------
/Client/Client.pro.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EnvironmentId
7 | {801efd51-282a-4073-9e5f-4217bf3d15c6}
8 |
9 |
10 | ProjectExplorer.Project.ActiveTarget
11 | 0
12 |
13 |
14 | ProjectExplorer.Project.EditorSettings
15 |
16 | true
17 | false
18 | true
19 |
20 | Cpp
21 |
22 | CppGlobal
23 |
24 |
25 |
26 | QmlJS
27 |
28 | QmlJSGlobal
29 |
30 |
31 | 2
32 | UTF-8
33 | false
34 | 4
35 | false
36 | 80
37 | true
38 | true
39 | 1
40 | true
41 | false
42 | 0
43 | true
44 | true
45 | 0
46 | 8
47 | true
48 | 1
49 | true
50 | true
51 | true
52 | false
53 |
54 |
55 |
56 | ProjectExplorer.Project.PluginSettings
57 |
58 |
59 | true
60 |
61 |
62 |
63 | ProjectExplorer.Project.Target.0
64 |
65 | Desktop Qt 5.14.2 GCC 64bit
66 | Desktop Qt 5.14.2 GCC 64bit
67 | qt.qt5.5142.gcc_64_kit
68 | 0
69 | 0
70 | 0
71 |
72 | /home/leo/Desktop/NetworkFileTransfer-master/build-Client-Desktop_Qt_5_14_2_GCC_64bit-Debug
73 |
74 |
75 | true
76 | QtProjectManager.QMakeBuildStep
77 | true
78 |
79 | false
80 | false
81 | false
82 |
83 |
84 | true
85 | Qt4ProjectManager.MakeStep
86 |
87 | false
88 |
89 |
90 | false
91 |
92 | 2
93 | Build
94 | Build
95 | ProjectExplorer.BuildSteps.Build
96 |
97 |
98 |
99 | true
100 | Qt4ProjectManager.MakeStep
101 |
102 | true
103 | clean
104 |
105 | false
106 |
107 | 1
108 | Clean
109 | Clean
110 | ProjectExplorer.BuildSteps.Clean
111 |
112 | 2
113 | false
114 |
115 | Debug
116 | Qt4ProjectManager.Qt4BuildConfiguration
117 | 2
118 |
119 |
120 | /home/leo/Desktop/NetworkFileTransfer-master/build-Client-Desktop_Qt_5_14_2_GCC_64bit-Release
121 |
122 |
123 | true
124 | QtProjectManager.QMakeBuildStep
125 | false
126 |
127 | false
128 | false
129 | true
130 |
131 |
132 | true
133 | Qt4ProjectManager.MakeStep
134 |
135 | false
136 |
137 |
138 | false
139 |
140 | 2
141 | Build
142 | Build
143 | ProjectExplorer.BuildSteps.Build
144 |
145 |
146 |
147 | true
148 | Qt4ProjectManager.MakeStep
149 |
150 | true
151 | clean
152 |
153 | false
154 |
155 | 1
156 | Clean
157 | Clean
158 | ProjectExplorer.BuildSteps.Clean
159 |
160 | 2
161 | false
162 |
163 | Release
164 | Qt4ProjectManager.Qt4BuildConfiguration
165 | 0
166 |
167 |
168 | /home/leo/Desktop/NetworkFileTransfer-master/build-Client-Desktop_Qt_5_14_2_GCC_64bit-Profile
169 |
170 |
171 | true
172 | QtProjectManager.QMakeBuildStep
173 | true
174 |
175 | false
176 | true
177 | true
178 |
179 |
180 | true
181 | Qt4ProjectManager.MakeStep
182 |
183 | false
184 |
185 |
186 | false
187 |
188 | 2
189 | Build
190 | Build
191 | ProjectExplorer.BuildSteps.Build
192 |
193 |
194 |
195 | true
196 | Qt4ProjectManager.MakeStep
197 |
198 | true
199 | clean
200 |
201 | false
202 |
203 | 1
204 | Clean
205 | Clean
206 | ProjectExplorer.BuildSteps.Clean
207 |
208 | 2
209 | false
210 |
211 | Profile
212 | Qt4ProjectManager.Qt4BuildConfiguration
213 | 0
214 |
215 | 3
216 |
217 |
218 | 0
219 | Deploy
220 | Deploy
221 | ProjectExplorer.BuildSteps.Deploy
222 |
223 | 1
224 | ProjectExplorer.DefaultDeployConfiguration
225 |
226 | 1
227 |
228 |
229 | dwarf
230 |
231 | cpu-cycles
232 |
233 |
234 | 250
235 |
236 | -e
237 | cpu-cycles
238 | --call-graph
239 | dwarf,4096
240 | -F
241 | 250
242 |
243 | -F
244 | true
245 | 4096
246 | false
247 | false
248 | 1000
249 |
250 | true
251 |
252 | false
253 | false
254 | false
255 | false
256 | true
257 | 0.01
258 | 10
259 | true
260 | kcachegrind
261 | 1
262 | 25
263 |
264 | 1
265 | true
266 | false
267 | true
268 | valgrind
269 |
270 | 0
271 | 1
272 | 2
273 | 3
274 | 4
275 | 5
276 | 6
277 | 7
278 | 8
279 | 9
280 | 10
281 | 11
282 | 12
283 | 13
284 | 14
285 |
286 | 2
287 |
288 | Qt4ProjectManager.Qt4RunConfiguration:/home/leo/Desktop/NetworkFileTransfer-master/Client/Client.pro
289 | /home/leo/Desktop/NetworkFileTransfer-master/Client/Client.pro
290 |
291 | false
292 |
293 | false
294 | true
295 | true
296 | false
297 | false
298 | true
299 |
300 | /home/leo/Desktop/NetworkFileTransfer-master/build-Client-Desktop_Qt_5_14_2_GCC_64bit-Debug
301 |
302 | 1
303 |
304 |
305 |
306 | ProjectExplorer.Project.TargetCount
307 | 1
308 |
309 |
310 | ProjectExplorer.Project.Updater.FileVersion
311 | 22
312 |
313 |
314 | Version
315 | 22
316 |
317 |
318 |
--------------------------------------------------------------------------------
/Client/debugonoroff.h:
--------------------------------------------------------------------------------
1 | #ifndef DEBUGONOROFF_H
2 | #define DEBUGONOROFF_H
3 |
4 | //#define __DEBUG__
5 |
6 | #endif // DEBUGONOROFF_H
7 |
--------------------------------------------------------------------------------
/Client/document.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | Readme.txt
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Client/main.cpp:
--------------------------------------------------------------------------------
1 | #include "widget.h"
2 | #include
3 | #include
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication a(argc, argv);
7 | Widget w;
8 | w.show();
9 |
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/Client/protocolcommand.h:
--------------------------------------------------------------------------------
1 | #ifndef PROTOCOLCOMMAND_H
2 | #define PROTOCOLCOMMAND_H
3 |
4 | #define _TRANSFER_ACK_ 0x0F00 //传输成功应答命令
5 | #define _TRANSFER_FILE_ 0x0F01 //传输文件命令
6 | #define _TRANSFER_LIST_ 0x0F02 //同步文件列表命令
7 | #define _DOWNLOAD_FILE_ 0x0F03 //下载文件命令
8 |
9 |
10 | #endif // PROTOCOLCOMMAND_H
11 |
--------------------------------------------------------------------------------
/Client/widget.cpp:
--------------------------------------------------------------------------------
1 | #include "widget.h"
2 | #include "ui_widget.h"
3 | #include "debugonoroff.h"
4 | #include "protocolcommand.h"
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | Widget::Widget(QWidget *parent) :
14 | QWidget(parent),
15 | ui(new Ui::Widget)
16 | {
17 | ui->setupUi(this);
18 |
19 | this->setWindowTitle(tr("局域网文件传输客户端"));
20 | flag = false;
21 | SYNFlag = 0;
22 | DOWNFlag = 0;
23 | /*文件发送相关初始化*/
24 | transferData.payloadSize = 64*1024; //每次发送64kb
25 |
26 | transferData.bytesWritten = 0;
27 | transferData.bytesToWrite = 0;
28 |
29 | clearVariation();
30 | FILE *fp;
31 | if((fp = fopen("/home/leo/Desktop/NetworkFileTransfer-master/FileList/FILELIST.txt","w+"))==NULL)
32 | {
33 | qDebug()<<"Clear FILELIST.TXT error!";
34 | }
35 | fclose(fp);
36 | tcpSocket = new QTcpSocket();
37 | ui->ClientConnectPB->setText(tr("连接"));
38 | ui->DownloadPB->setEnabled(false);
39 | connect(tcpSocket,&QTcpSocket::readyRead,this,&Widget::receiveFile);
40 | connect(tcpSocket,&QTcpSocket::bytesWritten,this,&Widget::receiveFile);
41 | connect(tcpSocket,&QTcpSocket::disconnected,this,&Widget::socketDisconnected);
42 | }
43 |
44 | Widget::~Widget()
45 | {
46 | delete ui;
47 | }
48 |
49 | void Widget::on_ClientConnectPB_clicked()
50 | {
51 | if(ui->ClientConnectPB->text()==tr("连接"))
52 | {
53 | /*断开所有的连接*/
54 | tcpSocket->abort();
55 | /*连接服务器*/
56 | tcpSocket->connectToHost(ui->ClientLineEdit->text(),8888);
57 | /*等待连接成功*/
58 | if(!tcpSocket->waitForConnected(30000))
59 | {
60 | qDebug()<<"Connection failed!";
61 | return ;
62 | }
63 | flag = true;
64 | qDebug()<<"Connect successfully!";
65 | ui->ClientConnectPB->setEnabled(true);
66 | ui->ClientConnectPB->setText(tr("断开"));
67 | }
68 | else
69 | {
70 | flag = false;
71 | /*断开连接*/
72 | tcpSocket->disconnectFromHost();
73 | /*修改按键的内容*/
74 | ui->ClientConnectPB->setText(tr("连接"));
75 | }
76 | }
77 |
78 | void Widget::sendFile(QString path)
79 | {
80 | #if defined __DEBUG__
81 | qDebug()<<"Socket send file name is"<open(QFile::ReadOnly))
87 | {
88 | qDebug()<size();
93 | #if defined __DEBUG__
94 | qDebug()<<"发送文件的内容大小"<seek(0);
112 | /*填充实际的存储空间*/
113 | sendOut << transferData.totalBytes<<_TRANSFER_FILE_
114 | <write(transferData.inOrOutBlock);
123 | #if defined __DEBUG__
124 | //qDebug()<0)
134 | {
135 | /*发送文件内容部分*/
136 | transferData.inOrOutBlock = transferData.localFile->readAll();
137 | tcpSocket->write(transferData.inOrOutBlock);
138 | transferData.inOrOutBlock.resize(0);
139 | }
140 | transferData.localFile->close();
141 | }
142 |
143 | void Widget::receiveFile()
144 | {
145 | /*标志变量:下载标志变量 同步文件列表标志变量 传输文件标志变量*/
146 | int downflag = 0 , synfilelistflag = 0, transferfileflag = 0;
147 | qint32 temp;
148 | /*如果没有数据可读,就直接返回*/
149 | if(tcpSocket->bytesAvailable()<=0)
150 | {
151 | return;
152 | }
153 | QDataStream in(tcpSocket);
154 | in.setVersion(QDataStream::Qt_5_7);
155 | /*提取出总的大小、命令、文件名字的大小、文件名信息*/
156 | if(transferData.bytesReceived <= sizeof(qint64)*3)
157 | {
158 | if(tcpSocket->bytesAvailable()>=sizeof(qint64)*3
159 | &&(transferData.fileNameSize==0))
160 | {
161 | /*从套接字中提取总大小信息、命令、文件名字大小*/
162 | in >> transferData.totalBytes >> transferData.command
163 | >> transferData.fileNameSize >> temp;
164 | transferData.bytesReceived += sizeof(qint64)*3;
165 | #if defined __DEBUG__
166 | qDebug()<< "文件以及头信息总大小"<bytesAvailable()>=transferData.fileNameSize
172 | &&transferData.fileNameSize!=0)
173 | {
174 | /*提取接收的文件名字*/
175 | in >> transferData.fileName;
176 | transferData.bytesReceived += transferData.fileNameSize;
177 | #if defined __DEBUG__
178 | qDebug()<<"receive file name is"<bytesAvailable())
184 | {
185 | qDebug()<<"socket have data!";
186 | }
187 | #endif
188 | }
189 | }
190 | switch(transferData.command)
191 | {
192 | case _TRANSFER_FILE_ :
193 | {
194 | transferfileflag = 1;
195 | if(transferData.fileNameSize != 0)
196 | {
197 | if(SYNFlag == 1)
198 | {
199 | tempFileName = "./FileList/";
200 | }
201 | else if(DOWNFlag == 1)
202 | {
203 | tempFileName = "./DownloadFile/";
204 | }
205 | else
206 | {
207 | tempFileName = "./ClientFile/";
208 | }
209 | tempFileName += transferData.fileName;
210 | /*创建本地文件*/
211 | transferData.localFile = new QFile(tempFileName);
212 | if(!transferData.localFile->open(QFile::WriteOnly))
213 | {
214 | qDebug()<<"open local file error!";
215 | return;
216 | }
217 | }
218 | }
219 | case _TRANSFER_ACK_ :
220 | {
221 | qDebug()<<"Send file success!";
222 | }
223 | break;
224 | default:
225 | qDebug()<<"Receive command nulity!";
226 | }
227 | if(transferData.bytesReceived < transferData.totalBytes)
228 | {
229 | transferData.bytesReceived += tcpSocket->bytesAvailable();
230 | transferData.inOrOutBlock = tcpSocket->readAll();
231 | transferData.localFile->write(transferData.inOrOutBlock);
232 | transferData.inOrOutBlock.resize(0);
233 | }
234 | if(transferData.bytesReceived == transferData.totalBytes)
235 | {
236 | clearVariation();
237 | if(transferfileflag == 1)
238 | {
239 | transferfileflag = 0;
240 | transferData.localFile->close();
241 | qDebug()<<"Receive file success!";
242 | }
243 | else if(synfilelistflag == 1)
244 | {
245 | synfilelistflag = 0;
246 | qDebug()<<"Request file list success!";
247 | }
248 | else if(downflag == 1)
249 | {
250 | downflag = 0;
251 | qDebug()<<"Download file success!";
252 | }
253 | }
254 | }
255 | void Widget::on_pushButton_clicked()
256 | {
257 | SYNFlag = 0;
258 | DOWNFlag = 0;
259 | transferData.fileName = QFileDialog::getOpenFileName(this);
260 | if(!transferData.fileName.isEmpty())
261 | {
262 | qDebug()<listWidget->clear(); //每同步之前需要先进行清除工作
288 | while(input.readLineInto(&line)) //把所有文件名进行显示
289 | {
290 | ui->listWidget->addItem(line);
291 | }
292 | }
293 |
294 |
295 | //void Widget::displayFile(QTreeWidgetItem *parent,int num)
296 | //{
297 | // QTreeWidgetItem *root,*item;
298 | // int i = 0;
299 | // while(fread(&dirInfo,sizeof(struct DirInformation),1,fp))
300 | // {
301 | // if((dirInfo.topDir==1)&&(dirInfo.isDirectory==1))//添加顶层目录
302 | // {
303 | //#ifdef __DEBUG__
304 | // qDebug()<<"This root directory!";
305 | //#endif
306 | // root = new QTreeWidgetItem(ui->treeWidget);
307 | // root->setText(i++,QString(dirInfo.dirName));
308 | // parent = root;
309 | // //this->displayFile(root,0);
310 | // }
311 | // else if((dirInfo.isDirectory==1)&&(dirInfo.topDir==0))
312 | // {
313 | // item = new QTreeWidgetItem();
314 | // item->setText(num++,QString(dirInfo.dirName));
315 | //#ifdef __DEBUG__
316 | // qDebug()<<"num ="<addChild(item);
319 | // displayFile(item,0);
320 | // }
321 | // else if((dirInfo.isFile==1)&&(dirInfo.topDir==0))
322 | // {
323 | //#ifdef __DEBUG__
324 | // qDebug()<<"num ="<setText(num++,QString(dirInfo.fileName));
328 | // }
329 | // }
330 | //}
331 | //void Widget::DfsFolder(std::string path,int layer)
332 | //{
333 | // _finddata_t file_info;
334 | // std::string current_path=path+"/*.*"; //也可以用/*来匹配所有
335 | // int handle=_findfirst(current_path.c_str(),&file_info);
336 | // /*返回值为-1则查找失败*/
337 | // if(-1==handle)
338 | // {
339 | // std::cout<<"cannot match the path"<ClientLineEdit->clear();
377 | ui->ClientConnectPB->setText(tr("连接"));
378 | }
379 |
380 | void Widget::on_SynFilePtn_clicked()
381 | {
382 |
383 | QString tempFileName;
384 | //tempFileName = "./FileList/";
385 | /*初始化发送字节为0*/
386 | clearVariation();
387 | SYNFlag = 1;
388 | QDataStream sendOut(&transferData.inOrOutBlock,QIODevice::WriteOnly);
389 |
390 | /*设置版本*/
391 | sendOut.setVersion(QDataStream::Qt_5_7);
392 | QString currentfilename;
393 | currentfilename = " ";
394 | /*保留总大小信息空间、文件名大小信息空间、然后输入文件名*/
395 | sendOut << qint64(0) << qint64(0) << qint64(0) << currentfilename;
396 | /*总的大小是包含总大小信息、文件名大小信息、文件名和实际文件大小的总和*/
397 | transferData.totalBytes += transferData.inOrOutBlock.size();
398 |
399 | sendOut.device()->seek(0);
400 | /*填充实际的存储空间*/
401 | sendOut << transferData.totalBytes << _TRANSFER_LIST_
402 | << qint64((transferData.inOrOutBlock.size()-sizeof(qint64)*3));
403 |
404 | qint64 sum = tcpSocket->write(transferData.inOrOutBlock);
405 | transferData.bytesToWrite = transferData.totalBytes - sum;
406 | #if defined __DEBUG__
407 | qDebug()<<"sum"<listWidget->count())
415 | {
416 | ui->DownloadPB->setEnabled(true);
417 | }
418 | else
419 | {
420 | ui->DownloadPB->setEnabled(false);
421 | }
422 | // this->displayFileListToWidget();
423 | }
424 |
425 |
426 | void Widget::sleep(int ms)
427 | {
428 | QTime dieTime = QTime::currentTime().addMSecs(ms);
429 | while(QTime::currentTime()< dieTime)
430 | QCoreApplication::processEvents(QEventLoop::AllEvents,100);
431 | }
432 |
433 | void Widget::on_DownloadPB_clicked()
434 | {
435 | SYNFlag = 0;
436 | DOWNFlag = 1;
437 | //tempFileName = "./DownloadFile/";
438 | /*获得要下载的文件名字*/
439 | QString downloadfile = ui->listWidget->currentItem()->text();
440 | if(downloadfile.isEmpty())
441 | return;
442 | transferData.fileName = downloadfile;
443 | #if defined __DEBUG__
444 | qDebug()<<"发送数据的总大小"<seek(0);
458 | /*填充实际的存储空间*/
459 | sendOut << transferData.totalBytes << _DOWNLOAD_FILE_
460 | << qint64((transferData.inOrOutBlock.size()-sizeof(qint64)*3));
461 | int sum = tcpSocket->write(transferData.inOrOutBlock);
462 | transferData.bytesToWrite = transferData.totalBytes - sum;
463 | #if defined __DEBUG__
464 | qDebug()<<"sum"<
5 |
6 | /*类的前置声明*/
7 | class QFileDialog;
8 | class QFile;
9 | class QTcpSocket;
10 | class QTreeWidgetItem;
11 | namespace Ui {
12 | class Widget;
13 | }
14 |
15 | class Widget : public QWidget
16 | {
17 | Q_OBJECT
18 |
19 | public:
20 | explicit Widget(QWidget *parent = 0);
21 | ~Widget();
22 | void sleep(int ms); //延时函数
23 | void sendFile(QString path); //文件头信息发送函数
24 | void clearVariation(); //初始化变量
25 | void diaplayFileListForListWidget();
26 | //void displayFile(QTreeWidgetItem *parent,int num); //递归显示文件列表
27 | private slots:
28 | void receiveFile(); //文件接收函数
29 | void socketDisconnected(); //断开连接槽函数
30 | void on_ClientConnectPB_clicked(); //请求连接槽函数
31 | void on_SynFilePtn_clicked(); //文件同步槽函数
32 | void on_pushButton_clicked(); //上传文件槽函数
33 | void on_DownloadPB_clicked(); //下载文件按钮
34 |
35 | private:
36 | Ui::Widget *ui;
37 | QTcpSocket *tcpSocket; //套接字变量
38 | QString message; //存放数据大小信息
39 | bool flag; //是否可以同步目录列表,true可是同步,false不可以
40 | int SYNFlag; //请求文件同步标志位
41 | int DOWNFlag; //下载文件标志位
42 | QString tempFileName;
43 | struct rcvOrSendDataPack{
44 | /*共用部分*/
45 | QFile *localFile; //存放本地文件
46 | qint64 totalBytes; //存放总大小信息
47 | QString fileName; //存放文件名
48 | QByteArray inOrOutBlock; //数据缓冲区
49 | /*发送相关*/
50 | qint64 bytesWritten; //已经发送数据大小
51 | qint64 bytesToWrite; //剩余数据的大小
52 | qint64 payloadSize; //每次发送数据的大小
53 | int command; //发送命令
54 | /*接收相关*/
55 | qint64 bytesReceived; //已收到数据的大小
56 | qint64 fileNameSize; //文件名的大小信息
57 | };
58 | struct rcvOrSendDataPack transferData; //数据结构体
59 |
60 | struct DirInformation{
61 | char fileName[260]; //文件名字
62 | char dirName[260]; //目录名字
63 | unsigned int isDirectory; //是否是目录
64 | unsigned int isFile; //是否是文件
65 | unsigned int topDir; //是否是顶层目录
66 | };
67 | struct DirInformation dirInfo;
68 | };
69 |
70 | #endif // WIDGET_H
71 |
--------------------------------------------------------------------------------
/Client/widget.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Widget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 429
10 | 471
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 | Widget
21 |
22 |
23 | -
24 |
25 |
-
26 |
27 |
-
28 |
29 |
-
30 |
31 |
32 | -
33 |
34 |
35 | 连接/断开
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 | 上传文件
45 |
46 |
47 |
48 | -
49 |
50 |
-
51 |
52 |
53 |
54 | 0
55 | 0
56 |
57 |
58 |
59 | 同步文件列表
60 |
61 |
62 |
63 | -
64 |
65 |
66 |
67 | 0
68 | 0
69 |
70 |
71 |
72 | 下载
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | -
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 chlinfeng1997
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Linux基于QT的局域网多线程数据传输系统(客户端+服务器):
2 |
3 | 在进行数据传输的过程中可以选择TCP或者UDP协议,TCP虽然相对而言比较复杂,具有三次握手进行连接以及四次分手断开连接,但具备可靠性,被大公司广泛使用,因此设计一种基于TCP的多线程数据传输系统来进行通信。展示效果:https://www.bilibili.com/video/BV1FK4y1M7Cq
4 |
5 |
6 | # 客户端:
7 | 1)登陆注册功能:点击账号登录,输入账号以及密码,与Mysql数据库中保存的账号信息进行校验,完成登录;点击账号注册,输入账号、密码、重复输入密码,向Mysql数据库中添加新的账号信息,完成注册,账号登录界面如图3-3所示,账号注册界面如图3-4所示。
8 | 2) 连接服务器功能:在IP框中输入IP地址,在PORT框中输入服务器端口号即可完成Socket连接;
9 | 3)上传文件功能:点击上传文件按钮,并将当前文件显示到文件信息中;
10 | 4)清除文件功能:在每个文件导入后,点击清除文件按钮,即可清空文件信息;
11 | 5)传输文件功能:点击传输文件按钮,即可通过TCP协议将文件传输到服务器上;
12 | 6)传输消息功能:在消息信息栏输入要传输的消息之后,点击传输消息,即可通过TCP协议进行传输;
13 | 7)显示消息功能:在完成消息传输之后,会在右边的消息对话中显示传输的消息信息;
14 | 8)清空功能:如果需要清除传输的消息,点击清空消息,即可将消息信息框内的信息清空。
15 | 9)运行日志显示功能:当客户端与服务器成功连接以及连接失败,客户端主动断开连接,客户端被动断开连接,客户端发送文件,客户端接收文件都会在运行日志栏中显示当前的时间以及操作。
16 |
17 | # 服务器:
18 | 1)显示连接客户端信息功能:在客户端状态一栏可以显示连接上的客户端信息,包括客户端IP地址以及端口,同时点击断开连接,即可断开对应的客户端;
19 | 2)选择文件功能:点击选择文件按钮,并将当前文件显示到文件信息中;
20 | 3)删除文件功能:在每个文件导入后,点击删除文件按钮,即可清空文件信息;
21 | 4)传输文件功能:点击传输文件按钮,即可通过TCP协议将文件传输到所有客户端上;
22 | 5)传输消息功能:在消息信息栏输入要传输的消息之后,点击传输消息,即可通过TCP协议进行传输;
23 | 6)显示消息功能:在完成消息传输之后,会在右边的消息对话中显示传输的消息信息;
24 | 7)清空功能:如果需要清除传输的消息,点击清空消息,即可将消息信息框内的信息清空。
25 | 8)运行日志显示功能:当客户端与服务器成功连接,服务器主动断开连接,客户端主动断开连接,服务器发送文件,服务器接收文件都会在运行日志栏中显示当前的时间以及操作。
26 |
--------------------------------------------------------------------------------
/Server/Server_V2.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2018-08-06T18:00:22
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui
8 | QT += network
9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 |
11 | TARGET = Server_V2
12 | TEMPLATE = app
13 |
14 |
15 | SOURCES += main.cpp\
16 | clientaddress.cpp \
17 | qnchatmessage.cpp \
18 | widget.cpp \
19 | myserver.cpp \
20 | mysocket.cpp \
21 | mythread.cpp
22 |
23 | HEADERS += widget.h \
24 | clientaddress.h \
25 | myserver.h \
26 | mysocket.h \
27 | mythread.h \
28 | debugonoroff.h \
29 | protocolcommand.h \
30 | qnchatmessage.h
31 |
32 | FORMS += widget.ui
33 |
34 | RESOURCES += \
35 | documents.qrc \
36 | img.qrc
37 |
--------------------------------------------------------------------------------
/Server/Server_V2.pro.autosave:
--------------------------------------------------------------------------------
1 | QT += core gui
2 | QT += network
3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
4 |
5 | TARGET = Server_V2
6 | TEMPLATE = app
7 |
8 |
9 | SOURCES += main.cpp\
10 | clientaddress.cpp \
11 | qnchatmessage.cpp \
12 | widget.cpp \
13 | myserver.cpp \
14 | mysocket.cpp \
15 | mythread.cpp
16 |
17 | HEADERS += widget.h \
18 | clientaddress.h \
19 | myserver.h \
20 | mysocket.h \
21 | mythread.h \
22 | debugonoroff.h \
23 | protocolcommand.h \
24 | qnchatmessage.h
25 |
26 | FORMS += widget.ui
27 |
28 | RESOURCES += \
29 | documents.qrc \
30 | img.qrc
31 |
--------------------------------------------------------------------------------
/Server/Server_V2.pro.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EnvironmentId
7 | {801efd51-282a-4073-9e5f-4217bf3d15c6}
8 |
9 |
10 | ProjectExplorer.Project.ActiveTarget
11 | 0
12 |
13 |
14 | ProjectExplorer.Project.EditorSettings
15 |
16 | true
17 | false
18 | true
19 |
20 | Cpp
21 |
22 | CppGlobal
23 |
24 |
25 |
26 | QmlJS
27 |
28 | QmlJSGlobal
29 |
30 |
31 | 2
32 | UTF-8
33 | false
34 | 4
35 | false
36 | 80
37 | true
38 | true
39 | 1
40 | true
41 | false
42 | 0
43 | true
44 | true
45 | 0
46 | 8
47 | true
48 | 1
49 | true
50 | true
51 | true
52 | false
53 |
54 |
55 |
56 | ProjectExplorer.Project.PluginSettings
57 |
58 |
59 | true
60 |
61 |
62 |
63 | ProjectExplorer.Project.Target.0
64 |
65 | Desktop Qt 5.14.2 GCC 64bit
66 | Desktop Qt 5.14.2 GCC 64bit
67 | qt.qt5.5142.gcc_64_kit
68 | 0
69 | 0
70 | 0
71 |
72 | /home/leo/Desktop/build-Server_V2-Desktop_Qt_5_14_2_GCC_64bit-Debug
73 |
74 |
75 | true
76 | QtProjectManager.QMakeBuildStep
77 | true
78 |
79 | false
80 | false
81 | false
82 |
83 |
84 | true
85 | Qt4ProjectManager.MakeStep
86 |
87 | false
88 |
89 |
90 | false
91 |
92 | 2
93 | Build
94 | Build
95 | ProjectExplorer.BuildSteps.Build
96 |
97 |
98 |
99 | true
100 | Qt4ProjectManager.MakeStep
101 |
102 | true
103 | clean
104 |
105 | false
106 |
107 | 1
108 | Clean
109 | Clean
110 | ProjectExplorer.BuildSteps.Clean
111 |
112 | 2
113 | false
114 |
115 | Debug
116 | Qt4ProjectManager.Qt4BuildConfiguration
117 | 2
118 |
119 |
120 | /home/leo/Desktop/build-Server_V2-Desktop_Qt_5_14_2_GCC_64bit-Release
121 |
122 |
123 | true
124 | QtProjectManager.QMakeBuildStep
125 | false
126 |
127 | false
128 | false
129 | true
130 |
131 |
132 | true
133 | Qt4ProjectManager.MakeStep
134 |
135 | false
136 |
137 |
138 | false
139 |
140 | 2
141 | Build
142 | Build
143 | ProjectExplorer.BuildSteps.Build
144 |
145 |
146 |
147 | true
148 | Qt4ProjectManager.MakeStep
149 |
150 | true
151 | clean
152 |
153 | false
154 |
155 | 1
156 | Clean
157 | Clean
158 | ProjectExplorer.BuildSteps.Clean
159 |
160 | 2
161 | false
162 |
163 | Release
164 | Qt4ProjectManager.Qt4BuildConfiguration
165 | 0
166 |
167 |
168 | /home/leo/Desktop/build-Server_V2-Desktop_Qt_5_14_2_GCC_64bit-Profile
169 |
170 |
171 | true
172 | QtProjectManager.QMakeBuildStep
173 | true
174 |
175 | false
176 | true
177 | true
178 |
179 |
180 | true
181 | Qt4ProjectManager.MakeStep
182 |
183 | false
184 |
185 |
186 | false
187 |
188 | 2
189 | Build
190 | Build
191 | ProjectExplorer.BuildSteps.Build
192 |
193 |
194 |
195 | true
196 | Qt4ProjectManager.MakeStep
197 |
198 | true
199 | clean
200 |
201 | false
202 |
203 | 1
204 | Clean
205 | Clean
206 | ProjectExplorer.BuildSteps.Clean
207 |
208 | 2
209 | false
210 |
211 | Profile
212 | Qt4ProjectManager.Qt4BuildConfiguration
213 | 0
214 |
215 | 3
216 |
217 |
218 | 0
219 | Deploy
220 | Deploy
221 | ProjectExplorer.BuildSteps.Deploy
222 |
223 | 1
224 | ProjectExplorer.DefaultDeployConfiguration
225 |
226 | 1
227 |
228 |
229 | dwarf
230 |
231 | cpu-cycles
232 |
233 |
234 | 250
235 |
236 | -e
237 | cpu-cycles
238 | --call-graph
239 | dwarf,4096
240 | -F
241 | 250
242 |
243 | -F
244 | true
245 | 4096
246 | false
247 | false
248 | 1000
249 |
250 | true
251 |
252 | false
253 | false
254 | false
255 | false
256 | true
257 | 0.01
258 | 10
259 | true
260 | kcachegrind
261 | 1
262 | 25
263 |
264 | 1
265 | true
266 | false
267 | true
268 | valgrind
269 |
270 | 0
271 | 1
272 | 2
273 | 3
274 | 4
275 | 5
276 | 6
277 | 7
278 | 8
279 | 9
280 | 10
281 | 11
282 | 12
283 | 13
284 | 14
285 |
286 | 2
287 |
288 | Qt4ProjectManager.Qt4RunConfiguration:/home/leo/Desktop/Server_V2/Server_V2.pro
289 | /home/leo/Desktop/Server_V2/Server_V2.pro
290 |
291 | false
292 |
293 | false
294 | true
295 | true
296 | false
297 | false
298 | true
299 |
300 | /home/leo/Desktop/build-Server_V2-Desktop_Qt_5_14_2_GCC_64bit-Debug
301 |
302 | 1
303 |
304 |
305 |
306 | ProjectExplorer.Project.TargetCount
307 | 1
308 |
309 |
310 | ProjectExplorer.Project.Updater.FileVersion
311 | 22
312 |
313 |
314 | Version
315 | 22
316 |
317 |
318 |
--------------------------------------------------------------------------------
/Server/clientaddress.cpp:
--------------------------------------------------------------------------------
1 | #include "clientaddress.h"
2 |
3 | clientAddress::clientAddress(QString IP, int Port)
4 | {
5 | clientIP = IP;
6 | clientPort = Port;
7 | QLabel *clientImg = new QLabel(this);
8 | QPixmap pixmap(":/img/child.png");
9 | QPixmap scaledPixmap = pixmap.scaled(QSize(32,32), Qt::KeepAspectRatio);
10 | clientImg->setPixmap(scaledPixmap);
11 | clientImg->move(9,9);
12 | QLabel *clientIPLocation = new QLabel(this);
13 | clientIPLocation->setText("IP : " + IP);
14 | clientIPLocation->move(50,15);
15 | QLabel *clientPortLocation = new QLabel(this);
16 | clientPortLocation->setText("Port : " + QString::number(Port));
17 | clientPortLocation->move(210,15);
18 | QPushButton *disconnectionButton = new QPushButton(this);
19 | disconnectionButton->setText("断开连接");
20 | disconnectionButton->setFixedWidth(140);
21 | disconnectionButton->move(310,9);
22 | connect(disconnectionButton, &QPushButton::clicked, [=](){
23 | emit clientAddressSignal(IP, clientPort);
24 | });
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/Server/clientaddress.h:
--------------------------------------------------------------------------------
1 | #ifndef CLIENTADDRESS_H
2 | #define CLIENTADDRESS_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | class clientAddress : public QWidget
9 | {
10 | Q_OBJECT
11 | public:
12 | // explicit clientAddress(QWidget *parent = nullptr);
13 | clientAddress(QString IP, int Port);
14 |
15 | int clientAddressIndex = 0; //保存该clientAddress的索引
16 | QLabel *isloadLabel;
17 | QString clientIP;
18 | int clientPort;
19 |
20 | signals:
21 | void clientAddressSignal(QString IP, int clientPort);
22 | };
23 |
24 | #endif // CLIENTADDRESS_H
25 |
--------------------------------------------------------------------------------
/Server/debugonoroff.h:
--------------------------------------------------------------------------------
1 | #ifndef DEBUGONOROFF_H
2 | #define DEBUGONOROFF_H
3 |
4 | //#define __DEBUG__
5 |
6 | #endif // DEBUGONOROFF_H
7 |
--------------------------------------------------------------------------------
/Server/documents.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | Readme.txt
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Server/img.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | img/child.png
4 | img/loading4.gif
5 | img/teacher.png
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Server/img/child.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chlinfeng1997/MultiThreadDataTransmission/bfb3c21126c05c2804a4d98e75d4ccbcade7ac17/Server/img/child.png
--------------------------------------------------------------------------------
/Server/img/loading4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chlinfeng1997/MultiThreadDataTransmission/bfb3c21126c05c2804a4d98e75d4ccbcade7ac17/Server/img/loading4.gif
--------------------------------------------------------------------------------
/Server/img/teacher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chlinfeng1997/MultiThreadDataTransmission/bfb3c21126c05c2804a4d98e75d4ccbcade7ac17/Server/img/teacher.png
--------------------------------------------------------------------------------
/Server/main.cpp:
--------------------------------------------------------------------------------
1 | #include "widget.h"
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication a(argc, argv);
7 | Widget w;
8 | w.show();
9 |
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/Server/myserver.cpp:
--------------------------------------------------------------------------------
1 | #include "myserver.h"
2 |
3 | Myserver::Myserver(QObject *parent)
4 | {
5 | socketNum = 0;
6 | /*获得当前widget对象*/
7 | widget = dynamic_cast(parent);
8 | }
9 |
10 | Myserver::~Myserver()
11 | {
12 |
13 | }
14 |
15 | void Myserver::incomingConnection(qintptr socketDescriptor)
16 | {
17 | /*添加连接的客户端到链表中*/
18 | socketList.append(socketDescriptor);
19 | /*每建立一个客户端请求客户端数量加一*/
20 | socketNum++;
21 | if(socketNum>3)
22 | socketNum = 1;
23 |
24 | /*创建一个线程用于执行与客户端的工作*/
25 | Mythread *thread = new Mythread(socketDescriptor,socketNum,0);
26 | threadList.append(thread);
27 | /*关联线程断开客户端连接信号和GUI更新界面槽函数*/
28 | connect(thread,&Mythread::closeClientConnectSignal,widget,&Widget::closeClientConnectSlot);
29 | /*添加客户端IP到GUI中进行显示*/
30 | // connect(thread,&Mythread::addClientIPToGUISignal,widget,&Widget::addClientIPTGUISlot);
31 | /*更改消息传输状态到GUI中进行显示*/
32 | connect(thread,&Mythread::sendStateDisplaySignal,widget,&Widget::sendStateDisplaySlot);
33 | /*添加客户端消息到GUI中进行显示*/
34 | connect(thread,&Mythread::sendInfoDisplaySignal,widget,&Widget::sendInfoDisplaySlot);
35 | /*发送文件信号发送至线程*/
36 | connect(widget,&Widget::sendFileWidgetSignal,thread,&Mythread::sendFileSlot);
37 | /*发送消息信号发送至线程*/
38 | connect(widget,&Widget::sendInfoWidgetSignal,thread,&Mythread::sendInfoSlot);
39 | /*服务器端主动断开连接*/
40 | // connect(widget,&Widget::clientDiconnectSignal,this,&Myserver::clientDisconnectSlot);
41 | connect(widget,&Widget::clientAddressWidgetSignal,this,&Myserver::clientDisconnectSlot);
42 | /*启动线程*/
43 | thread->start();
44 | /*添加日志*/
45 | connect(thread,&Mythread::displayInfoToGUISignal,widget,&Widget::displayInfoTGUISlot);
46 | }
47 |
48 | void Myserver::clientDisconnectSlot(int ID)
49 | {
50 | /*服务器端主动断开客户端的连接根据断开的客户端编号与其线程关联槽函数*/
51 | // qDebug() << "套接字";
52 | // qDebug() << ID;
53 | // for(int i = 0; i < threadList.size(); i++)
54 | // {
55 | // qDebug() << threadList.at(i);
56 | // }
57 | QMetaObject::Connection dis = QObject::connect(this,&Myserver::clientDisconnectSignal,
58 | threadList[ID],&Mythread::clientDisconnectSlot);
59 | emit clientDisconnectSignal();
60 | // threadList[ID-1]->disconnect();
61 | /*取消信号槽*/
62 | disconnect(dis);
63 | /*从客户端套接字列表中移除套接字*/
64 | socketList.removeAt(ID);
65 | /*从线程列表中移除线程*/
66 | Mythread * deleteThread = threadList.takeAt(ID);
67 | /*关闭线程*/
68 | deleteThread->exit(0);
69 | deleteThread->wait();
70 | // qDebug() << socketList.size();
71 | // qDebug() << threadList.size();
72 | // qDebug() << "套接字now";
73 | // for(int i = 0; i < socketList.size(); i++)
74 | // {
75 | // qDebug() << socketList.at(i);
76 | // }
77 | }
78 |
--------------------------------------------------------------------------------
/Server/myserver.h:
--------------------------------------------------------------------------------
1 | #ifndef MYSERVER_H
2 | #define MYSERVER_H
3 |
4 | #include
5 | #include
6 |
7 | #include "widget.h"
8 | #include "mythread.h"
9 | #include "debugonoroff.h"
10 | #include "clientaddress.h"
11 | class Widget;
12 | class Mythread;
13 | class Myserver : public QTcpServer
14 | {
15 | Q_OBJECT
16 | public:
17 | Myserver(QObject *parent);
18 | ~Myserver();
19 | /*存储建立链接的客户端套接字*/
20 | QListsocketList;
21 | /*存储线程*/
22 | QListthreadList;
23 | /*存储客户端IP地址*/
24 | QListsocketIP;
25 | /*记录客户端数量*/
26 | int socketNum;
27 | protected:
28 | void incomingConnection(qintptr socketDescriptor);
29 | signals:
30 | /*客户端被动断开连接信号*/
31 | void clientDisconnectSignal();
32 | public slots:
33 | /*客户端被动断开连接槽函数*/
34 | void clientDisconnectSlot(int ID);
35 | private:
36 | Widget *widget; //指向GUI的指针
37 | };
38 |
39 | #endif // MYSERVER_H
40 |
--------------------------------------------------------------------------------
/Server/mysocket.cpp:
--------------------------------------------------------------------------------
1 | #include "mysocket.h"
2 | #include
3 | #include "protocolcommand.h"
4 | #include
5 | #include
6 | Mysocket::Mysocket(int socket, int ID,QObject *parent)
7 | :QTcpSocket(parent), socketDescriptor(socket)
8 | {
9 | socketID = ID;
10 | clearVariation();
11 | QObject::connect(this,&Mysocket::readyRead,this,&Mysocket::reveiveData);
12 | }
13 |
14 | Mysocket::~Mysocket()
15 | {
16 |
17 | }
18 |
19 | void Mysocket::sendFile(QString path)
20 | {
21 | /*初始化发送字节为0*/
22 | transferData.bytesWritten = 0;
23 | transferData.fileName = path;
24 | transferData.localFile = new QFile(path);
25 | if(!transferData.localFile->open(QFile::ReadOnly))
26 | {
27 | qDebug()<size();//获取文件大小
32 |
33 | QDataStream sendOut(&transferData.inOrOutBlock,QIODevice::WriteOnly);
34 |
35 | sendOut.setVersion(QDataStream::Qt_5_7); //设置版本
36 | /*获得文件名称*/
37 | QString currentFilename = transferData.fileName.right(transferData.fileName.size()
38 | -transferData.fileName.lastIndexOf('/')-1);
39 |
40 | /*保留总大小信息空间、命令、文件名大小信息空间、然后输入文件名*/
41 | sendOut << qint64(0) << qint64(0) << qint64(0)<< currentFilename;
42 | /*总的大小*/
43 | transferData.totalBytes += transferData.inOrOutBlock.size();
44 |
45 | sendOut.device()->seek(0);
46 | /*填充实际的存储空间*/
47 | sendOut << transferData.totalBytes<<_TRANSFER_FILE_
48 | <0)
57 | {
58 | /*发送文件内容部分*/
59 | transferData.inOrOutBlock = transferData.localFile->readAll();
60 | write(transferData.inOrOutBlock);
61 | transferData.inOrOutBlock.resize(0);
62 | }
63 | transferData.localFile->close();
64 | emit sendStateDisplaySignal("服务器发送文件成功", "");
65 | }
66 |
67 | void Mysocket::sendMSG(QString msg, QString IPAddress)
68 | {
69 | emit sendStateDisplaySignal("服务器开始发送消息", msg);
70 | /*确保连接依然有效*/
71 | if(!isValid())
72 | {
73 | qDebug()<<"Already disconnected!";
74 | return;
75 | }
76 | qDebug() << msg;
77 | transferData.totalBytes = 0;
78 | /*使用数据流写入数据*/
79 | QDataStream outPut(&transferData.inOrOutBlock,QIODevice::WriteOnly);
80 | outPut.setVersion(QDataStream::Qt_5_7);
81 | transferData.totalBytes = msg.toUtf8().size();
82 | // qDebug() << transferData.totalBytes;
83 |
84 | /*保留总大小信息空间、命令、文件名大小信息空间、然后输入文件名*/
85 | outPut << qint64(0) << qint64(0) << qint64(0) << msg << IPAddress;
86 | // qDebug() << transferData.inOrOutBlock;
87 | // qDebug() << msg;
88 | // qDebug() << IPAddress << "6666";
89 | /*消息的总大小*/
90 | transferData.totalBytes += transferData.inOrOutBlock.size();
91 | /*定位到数据流的开始位置*/
92 | outPut.device()->seek(0);
93 | /*填充实际的存储空间*/
94 | outPut << transferData.totalBytes<<_TRANSFER_INFO_
95 | <0)
104 | // {
105 | // /*发送文件内容部分*/
106 | // transferData.inOrOutBlock = transferData.localFile->readAll();
107 | // write(transferData.inOrOutBlock);
108 | // transferData.inOrOutBlock.resize(0);
109 | // }
110 | // else
111 | // {
112 | // transferData.inOrOutBlock.resize(0);
113 | // }
114 |
115 | }
116 |
117 | void Mysocket::reveiveData()
118 | {
119 | /*标志变量:下载标志变量 同步文件列表标志变量 传输文件标志变量*/
120 | int transferfileflag = 0;
121 | QString ip;
122 | qint32 temp;
123 | /*如果没有数据可读,就直接返回*/
124 | if(bytesAvailable()<=0)
125 | {
126 | return;
127 | }
128 |
129 | QDataStream in(this);
130 | in.setVersion(QDataStream::Qt_5_14);
131 |
132 | /*提取出总的大小、命令、文件名字的大小、文件名信息*/
133 | if(transferData.bytesReceived <= sizeof(qint64)*3)
134 | {
135 |
136 | if(bytesAvailable()>=sizeof(qint64)*3
137 | &&(transferData.fileNameSize==0))
138 | {
139 | /*从套接字中提取总大小信息、命令、文件名字大小*/
140 | in >> transferData.totalBytes >> transferData.command
141 | >> transferData.fileNameSize >> temp;
142 | transferData.bytesReceived += sizeof(qint64)*3;
143 |
144 | }
145 | if(bytesAvailable()>=transferData.fileNameSize
146 | &&transferData.fileNameSize!=0)
147 | {
148 | /*提取接收的文件名字*/
149 | in >> transferData.fileName >> ip;
150 | transferData.bytesReceived += transferData.fileNameSize;
151 |
152 | }
153 | }
154 | switch(transferData.command)
155 | {
156 | case _TRANSFER_FILE_ :
157 | {
158 | transferfileflag = 1;
159 | if(transferData.fileNameSize != 0)
160 | {
161 | QString tempfilename("/home/leo/Desktop/ReceiveFile/");
162 | tempfilename += transferData.fileName;
163 | /*创建本地文件*/
164 | transferData.localFile = new QFile(tempfilename);
165 | if(!transferData.localFile->open(QFile::WriteOnly))
166 | {
167 | qDebug()<<"open local file error!";
168 | return;
169 | }
170 | if(transferData.bytesReceived < transferData.totalBytes)
171 | {
172 | transferData.bytesReceived += bytesAvailable();
173 | transferData.inOrOutBlock = readAll();
174 | transferData.localFile->write(transferData.inOrOutBlock);
175 | transferData.inOrOutBlock.resize(0);
176 | }
177 | if(transferData.bytesReceived == transferData.totalBytes)
178 | {
179 | clearVariation();
180 | if(transferfileflag == 1)
181 | {
182 | transferfileflag = 0;
183 | transferData.localFile->close();
184 | qDebug()<<"Receive file success!";
185 | emit sendStateDisplaySignal("服务器接收文件成功", "");
186 | }
187 | }
188 | }
189 | }
190 | break;
191 | case _TRANSFER_INFO_ :
192 | {
193 | QString clientInfo = transferData.fileName;
194 | // QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
195 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
196 | // ui->textEdit->append(current_date + " —— " + "客户端接收消息成功");
197 | // QMessageBox::about(NULL, "服务器消息", serverInfo);
198 | emit sendInfoDisplaySignal(clientInfo, ip);
199 | transferData.bytesReceived = 0;
200 | transferData.fileNameSize = 0;
201 | transferData.inOrOutBlock.resize(0);
202 | qDebug()<<"Receive info success!";
203 | }
204 | break;
205 | default:
206 | qDebug()<<"Receive command nulity!";
207 | break;
208 | }
209 | }
210 |
211 | void Mysocket::clientDisconnectSlot()
212 | {
213 | this->disconnectFromHost();
214 | this->close();
215 | // emit clientDisconnectSignal();
216 | }
217 |
218 | void Mysocket::clearVariation()
219 | {
220 | transferData.totalBytes = 0;
221 | transferData.bytesReceived = 0;
222 | transferData.fileNameSize = 0;
223 | transferData.inOrOutBlock.resize(0);
224 | transferData.payloadSize = 1024 * 64; //每次发送64kb
225 | transferData.bytesWritten = 0;
226 | transferData.bytesToWrite = 0;
227 | }
228 |
229 | QString Mysocket::findDownloadFile(QString path, QString fileName)
230 | {
231 | if(path.isEmpty()||fileName.isEmpty())
232 | return QString();
233 | QDir dir;
234 | QStringList filters;
235 | filters << fileName;
236 | dir.setPath(path);
237 | dir.setNameFilters(filters);
238 | QDirIterator iter(dir,QDirIterator::Subdirectories);
239 | while(iter.hasNext())
240 | {
241 | iter.next();
242 | QFileInfo info = iter.fileInfo();
243 | if(info.isFile())
244 | {
245 | return info.absoluteFilePath();
246 | }
247 | }
248 | return QString();
249 | }
250 |
--------------------------------------------------------------------------------
/Server/mysocket.h:
--------------------------------------------------------------------------------
1 | #ifndef MYSOCKET_H
2 | #define MYSOCKET_H
3 |
4 | #include
5 | #include "debugonoroff.h"
6 | #include
7 |
8 |
9 | class Mysocket : public QTcpSocket
10 | {
11 | Q_OBJECT
12 | public:
13 | Mysocket(int socket,int ID,QObject *parent = 0);
14 | ~Mysocket();
15 | /*发送文件*/
16 | void sendFile(QString path);
17 | /*发送消息*/
18 | void sendMSG(QString msg, QString IPAddress);
19 | /*初始化变量*/
20 | void clearVariation();
21 | /*查找要下载的文件*/
22 | QString findDownloadFile(QString path,QString fileName);
23 | signals:
24 | void clientDisconnectSignal();
25 | /*发送状态在GUI中显示*/
26 | void sendStateDisplaySignal(QString msg, QString info);
27 | /*发送消息在GUI中显示*/
28 | void sendInfoDisplaySignal(QString clientInfo, QString ip);
29 | public slots:
30 | /*数据接收槽函数*/
31 | void reveiveData();
32 | /*断开连接*/
33 | void clientDisconnectSlot();
34 | private:
35 | /*客户端编号*/
36 | int socketID;
37 | int socketDescriptor;
38 | /*数据协议包*/
39 | struct rcvOrSendDataPack{
40 | /*共用部分*/
41 | QFile *localFile; //存放本地文件
42 | qint64 totalBytes; //存放总大小信息
43 | QString fileName; //存放文件名
44 | QByteArray inOrOutBlock; //数据缓冲区
45 | /*发送相关*/
46 | qint64 bytesWritten; //已经发送数据大小
47 | qint64 bytesToWrite; //剩余数据的大小
48 | qint64 payloadSize; //每次发送数据的大小
49 | /*接收相关*/
50 | qint64 bytesReceived; //已收到数据的大小
51 | qint64 fileNameSize; //文件名的大小信息
52 | int command; //接收的命令
53 | };
54 | struct rcvOrSendDataPack transferData; //数据结构体
55 | };
56 |
57 | #endif // MYSOCKET_H
58 |
--------------------------------------------------------------------------------
/Server/mythread.cpp:
--------------------------------------------------------------------------------
1 | #include "mythread.h"
2 | #include
3 | #include
4 | #include "debugonoroff.h"
5 | #include "protocolcommand.h"
6 | Mythread::Mythread(int socketDes,int ID,QObject *parent):
7 | QThread(parent), socketDescriptor(socketDes)
8 | {
9 | clientID = ID;
10 | socketDescriptor = socketDes;
11 | }
12 |
13 | void Mythread::run()
14 | {
15 | /*保存客户端IP地址*/
16 | QString clientIP;
17 | /*保存客户端状态*/
18 | int clientState;
19 | /*创建套接字对象*/
20 | Mysocket *socket = new Mysocket(socketDescriptor,clientID,0);
21 | /*设置服务器监听到来的客户端的套接字描述符*/
22 | if(!socket->setSocketDescriptor(socketDescriptor))
23 | return;
24 |
25 | QObject::connect(socket,&Mysocket::disconnected,this,&Mythread::closeClientConnectSlot);
26 | QObject::connect(socket,&Mysocket::sendStateDisplaySignal,this,&Mythread::sendStateDisplaySlot);
27 | QObject::connect(socket,&Mysocket::sendInfoDisplaySignal,this,&Mythread::sendInfoDisplaySlot);
28 | QObject::connect(this,&Mythread::sendFileSignal,socket,&Mysocket::sendFile);
29 | QObject::connect(this,&Mythread::sendInfoSignal,socket,&Mysocket::sendMSG);
30 | QObject::connect(this,&Mythread::clientDisconnectSignal,socket,&Mysocket::clientDisconnectSlot);
31 | /*获得客户端的IP地址*/
32 | clientIP = socket->peerAddress().toString();
33 | /*获得客户端的端口号*/
34 | clientPort = socket->peerPort();
35 | clientState = socket->state();
36 |
37 | if(!clientIP.isEmpty())
38 | {
39 | /*只保留32位的点分十进制IP值*/
40 | clientIP = clientIP.right(clientIP.length()-7);
41 | clientIp = clientIP;
42 | current_date_time = QDateTime::currentDateTime();
43 | /*回传客户端IP地址和ID到GUI显示信号*/
44 | emit addClientIPToGUISignal(clientIP,clientPort,clientID,clientState);
45 | emit displayInfoToGUISignal(clientIP,clientPort,clientState,current_date_time);
46 | }
47 | else
48 | {
49 | qDebug()<< "Get client IP failed!";
50 | }
51 |
52 | exec();
53 | }
54 |
55 | void Mythread::closeClientConnectSlot()
56 | {
57 | /*向GUI发射套接字断开连接信号更新界面*/
58 | current_date_time = QDateTime::currentDateTime();
59 | emit closeClientConnectSignal(clientIp, clientPort, current_date_time);
60 | }
61 |
62 | void Mythread::clientDisconnectSlot()
63 | {
64 | /*关闭线程*/
65 | // this->quit();
66 | emit clientDisconnectSignal();
67 | }
68 |
69 | void Mythread::sendStateDisplaySlot(QString msg, QString info)
70 | {
71 | emit sendStateDisplaySignal(msg, info);
72 | }
73 |
74 | void Mythread::sendInfoDisplaySlot(QString clientInfo, QString ip)
75 | {
76 | emit sendInfoDisplaySignal(clientInfo, ip);
77 | }
78 |
79 | void Mythread::sendFileSlot(QString filename)
80 | {
81 | emit sendFileSignal(filename);
82 | }
83 |
84 | void Mythread::sendInfoSlot(QString info)
85 | {
86 | emit sendInfoSignal(info, clientIp);
87 | }
88 |
--------------------------------------------------------------------------------
/Server/mythread.h:
--------------------------------------------------------------------------------
1 | #ifndef MYTHREAD_H
2 | #define MYTHREAD_H
3 |
4 | #include
5 | #include
6 | #include "mysocket.h"
7 | #include "debugonoroff.h"
8 |
9 | class Mythread : public QThread
10 | {
11 | Q_OBJECT
12 | public:
13 | Mythread(int socketDes,int ID,QObject *parent);
14 | protected:
15 | void run();
16 | signals:
17 | /*添加客户端IP地址到GUI*/
18 | void addClientIPToGUISignal(QString CIP, int CPort, int ID, int state);
19 | /*客户端主动断开连接信号*/
20 | void closeClientConnectSignal(QString clientIp, int clientPort, QDateTime current_date_time);
21 | /*客户端被动断开连接*/
22 | void clientDisconnectSignal();
23 | /*获得文件列表信号*/
24 | void getFileListSignal(QString filelist);
25 | /*发送文件信号*/
26 | void sendFileSignal(QString filename);
27 | /*发送消息信号*/
28 | void sendInfoSignal(QString info, QString IPAddress);
29 | /*显示日志信号*/
30 | void displayInfoToGUISignal(QString CIP,int CPort,int state,QDateTime current_time);
31 | /*发送状态显示到GUI*/
32 | void sendStateDisplaySignal(QString msg, QString info);
33 | /*发送消息显示到GUI*/
34 | void sendInfoDisplaySignal(QString clientInfo, QString ip);
35 | public slots:
36 | /*客户端主动断开连接槽*/
37 | void closeClientConnectSlot();
38 | /*客户端被动断开连接槽函数*/
39 | void clientDisconnectSlot();
40 | /*发送文件槽函数*/
41 | void sendFileSlot(QString filename);
42 | /*发送消息槽函数*/
43 | void sendInfoSlot(QString info);
44 | /*发送状态显示到GUI槽函数*/
45 | void sendStateDisplaySlot(QString msg, QString info);
46 | /*发送消息显示到GUI槽函数*/
47 | void sendInfoDisplaySlot(QString clientInfo, QString ip);
48 | private:
49 | Mysocket *socket;
50 | /*记录客户端数量*/
51 | int clientID;
52 | /*记录客户端IP*/
53 | QString clientIp;
54 | /*记录客户端端口号*/
55 | int clientPort;
56 | quintptr socketDescriptor;
57 | QDateTime current_date_time;
58 |
59 | struct rcvOrSendDataPack{
60 | /*共用部分*/
61 | QFile *localFile; //存放本地文件
62 | qint64 totalBytes; //存放总大小信息
63 | QString fileName; //存放文件名
64 | QByteArray inOrOutBlock; //数据缓冲区
65 | /*发送相关*/
66 | qint64 bytesWritten; //已经发送数据大小
67 | qint64 bytesToWrite; //剩余数据的大小
68 | qint64 payloadSize; //每次发送数据的大小
69 | /*接收相关*/
70 | qint64 bytesReceived; //已收到数据的大小
71 | qint64 fileNameSize; //文件名的大小信息
72 | qint64 command; //接收的命令
73 | };
74 | struct rcvOrSendDataPack transferData; //数据结构体
75 | };
76 |
77 | #endif // MYTHREAD_H
78 |
--------------------------------------------------------------------------------
/Server/protocolcommand.h:
--------------------------------------------------------------------------------
1 | #ifndef PROTOCOLCOMMAND_H
2 | #define PROTOCOLCOMMAND_H
3 |
4 | #define _TRANSFER_ACK_ 0x0F00 //传输成功应答命令
5 | #define _TRANSFER_FILE_ 0x0F01 //传输文件命令
6 | #define _TRANSFER_LIST_ 0x0F02 //同步文件列表命令
7 | #define _DOWNLOAD_FILE_ 0x0F03 //下载文件命令
8 | #define _TRANSFER_INFO_ 0x0F04 //传输消息命令
9 |
10 |
11 | #endif // PROTOCOLCOMMAND_H
12 |
--------------------------------------------------------------------------------
/Server/qnchatmessage.cpp:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 沙振宇
5 | # CreateTime: 2018-07-23
6 | # UpdateTime: 2019-12-27
7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现
8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
10 | #
11 | #-------------------------------------------------*/
12 | #include "qnchatmessage.h"
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | QNChatMessage::QNChatMessage(QWidget *parent, QString serverIP) : QWidget(parent)
23 | {
24 | QFont te_font = this->font();
25 | te_font.setFamily("MicrosoftYaHei");
26 | te_font.setPointSize(12);
27 | serverIPAddress = serverIP;
28 | get_local_Ip();
29 | // te_font.setWordSpacing(0);
30 | // te_font.setLetterSpacing(QFont::PercentageSpacing,0);
31 | // te_font.setLetterSpacing(QFont::PercentageSpacing, 100); //300%,100为默认 //设置字间距%
32 | // te_font.setLetterSpacing(QFont::AbsoluteSpacing, 0); //设置字间距为3像素 //设置字间距像素值
33 | this->setFont(te_font);
34 | m_leftPixmap = QPixmap(":/img/child.png");
35 | m_rightPixmap = QPixmap(":/img/teacher.png");
36 |
37 | m_loadingMovie = new QMovie(this);
38 | m_loadingMovie->setFileName(":/img/loading4.gif");
39 | m_loading = new QLabel(this);
40 | m_loading->setMovie(m_loadingMovie);
41 | m_loading->resize(16,16);
42 | m_loading->setAttribute(Qt::WA_TranslucentBackground , true);
43 | m_loading->setAutoFillBackground(false);
44 | }
45 |
46 | void QNChatMessage::get_local_Ip()
47 | {
48 | QList ipAddressesList = QNetworkInterface::allAddresses();
49 | // use the first non-localhost IPv4 address
50 | for (int i = 0; i < ipAddressesList.size(); ++i) {
51 | qDebug()<hide();
67 | m_loadingMovie->stop();
68 | m_isSending = true;
69 | }
70 |
71 | void QNChatMessage::setText(QString text, QString time, QSize allSize, QNChatMessage::User_Type userType)
72 | {
73 | m_msg = text;
74 | m_userType = userType;
75 | m_time = time;
76 | m_curTime = QDateTime::fromTime_t(time.toInt()).toString("hh:mm");
77 | m_allSize = allSize;
78 | if(userType == User_Me) {
79 | if(!m_isSending) {
80 | m_loading->move(m_kuangRightRect.x() - m_loading->width() - 10, m_kuangRightRect.y()+m_kuangRightRect.height()/2- m_loading->height()/2);
81 | m_loading->show();
82 | m_loadingMovie->start();
83 | }
84 | } else {
85 | m_loading->hide();
86 | }
87 |
88 | this->update();
89 | }
90 |
91 | QSize QNChatMessage::fontRect(QString str)
92 | {
93 | m_msg = str;
94 | int minHei = 30;
95 | int iconWH = 40;
96 | int iconSpaceW = 20;
97 | int iconRectW = 5;
98 | int iconTMPH = 10;
99 | int sanJiaoW = 6;
100 | int kuangTMP = 20;
101 | int textSpaceRect = 12;
102 | m_nameWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW);
103 | m_kuangWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW);
104 | m_textWidth = m_kuangWidth - 2 * textSpaceRect;
105 | m_spaceWid = this->width() - m_textWidth;
106 | m_iconLeftRect = QRect(iconSpaceW, iconTMPH, iconWH, iconWH);
107 | m_iconRightRect = QRect(this->width() - iconSpaceW - iconWH, iconTMPH, iconWH, iconWH);
108 |
109 | QSize size = getRealString(m_msg); // 整个的size
110 | QFontMetrics fontMetrics(QFont("Microsoft YaHei", 8, QFont::Normal));
111 | int clientIPWidth = fontMetrics.horizontalAdvance(ipAddress);
112 | int serverIPWidth = fontMetrics.horizontalAdvance(serverIPAddress);
113 | qDebug() << "fontRect Size:" << size << clientIPWidth;
114 | int hei = size.height() < minHei ? minHei : size.height();
115 | /*三角形*/
116 | m_sanjiaoLeftRect = QRect(iconWH+iconSpaceW+iconRectW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight);
117 | m_sanjiaoRightRect = QRect(this->width() - iconRectW - iconWH - iconSpaceW - sanJiaoW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight);
118 |
119 | if(size.width() < (m_textWidth+m_spaceWid)) {
120 | m_nameLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4, serverIPWidth + 10, m_lineHeight/4*2.5);
121 | m_nameRightRect.setRect(this->width()-iconWH - iconSpaceW - iconRectW - sanJiaoW - clientIPWidth,
122 | m_lineHeight/4, clientIPWidth + 10, m_lineHeight/4*2.5);
123 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*4, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight);
124 | m_kuangRightRect.setRect(this->width() - size.width() + m_spaceWid - 2*textSpaceRect - iconWH - iconSpaceW - iconRectW - sanJiaoW,
125 | m_lineHeight/4*4, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight);
126 | } else {
127 | m_nameLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4, serverIPWidth + 10, m_lineHeight/4*2.5);
128 | m_nameRightRect.setRect(this->width()-iconWH - iconSpaceW - iconRectW - sanJiaoW - clientIPWidth, m_lineHeight/4, clientIPWidth + 10, m_lineHeight/4*2.5);
129 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*4, m_kuangWidth, hei-m_lineHeight);
130 | m_kuangRightRect.setRect(iconWH + kuangTMP + iconSpaceW + iconRectW - sanJiaoW, m_lineHeight/4*4, m_kuangWidth, hei-m_lineHeight);
131 | }
132 | /*消息框*/
133 | m_textLeftRect.setRect(m_kuangLeftRect.x()+textSpaceRect,m_kuangLeftRect.y()+iconTMPH,
134 | m_kuangLeftRect.width()-2*textSpaceRect,m_kuangLeftRect.height()-2*iconTMPH);
135 | m_textRightRect.setRect(m_kuangRightRect.x()+textSpaceRect,m_kuangRightRect.y()+iconTMPH,
136 | m_kuangRightRect.width()-2*textSpaceRect,m_kuangRightRect.height()-2*iconTMPH);
137 |
138 | return QSize(size.width(), hei);
139 | }
140 |
141 | QSize QNChatMessage::getRealString(QString src)
142 | {
143 | QFontMetricsF fm(this->font());
144 | m_lineHeight = fm.lineSpacing();
145 | int nCount = src.count("\n");
146 | int nMaxWidth = 0;
147 | if(nCount == 0) {
148 | nMaxWidth = qCeil(fm.width(src));
149 | QString value = src;
150 | if(nMaxWidth > m_textWidth) {
151 | qDebug() << "2222";
152 | nMaxWidth = m_textWidth;
153 | int size = m_textWidth / fm.width(" ");
154 | int num = fm.width(value) / m_textWidth;
155 | num = ( fm.width(value) ) / m_textWidth;
156 | nCount += num;
157 | QString temp = "";
158 | for(int i = 0; i < num; i++) {
159 | temp += value.mid(i*size, (i+1)*size) + "\n";
160 | }
161 | src.replace(value, temp);
162 | }
163 | } else {
164 | for(int i = 0; i < (nCount + 1); i++) {
165 | QString value = src.split("\n").at(i);
166 | nMaxWidth = qCeil(fm.width(value)) > nMaxWidth ? qCeil(fm.width(value)) : nMaxWidth;
167 | if(fm.width(value) > m_textWidth) {
168 | nMaxWidth = m_textWidth;
169 | int size = m_textWidth / fm.width(" ");
170 | int num = fm.width(value) / m_textWidth;
171 | num = ((i+num)*fm.width(" ") + fm.width(value)) / m_textWidth;
172 | nCount += num;
173 | QString temp = "";
174 | for(int i = 0; i < num; i++) {
175 | temp += value.mid(i*size, (i+1)*size) + "\n";
176 | }
177 | src.replace(value, temp);
178 | }
179 | }
180 | }
181 | return QSize(nMaxWidth+m_spaceWid, (nCount + 1) * m_lineHeight+2*m_lineHeight);
182 | }
183 |
184 | void QNChatMessage::paintEvent(QPaintEvent *event)
185 | {
186 | Q_UNUSED(event);
187 |
188 | QPainter painter(this);
189 | painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);//消锯齿
190 | painter.setPen(Qt::NoPen);
191 | painter.setBrush(QBrush(Qt::gray));
192 |
193 | if(m_userType == User_Type::User_She) { // 用户
194 | //头像
195 | // painter.drawRoundedRect(m_iconLeftRect,m_iconLeftRect.width(),m_iconLeftRect.height());
196 | painter.drawPixmap(m_iconLeftRect, m_leftPixmap);
197 |
198 | //框加边
199 | QColor col_KuangB(234, 234, 234);
200 | painter.setBrush(QBrush(col_KuangB));
201 | painter.drawRoundedRect(m_kuangLeftRect.x()-1,m_kuangLeftRect.y()-1,m_kuangLeftRect.width()+2,m_kuangLeftRect.height()+2,4,4);
202 | //框
203 | QColor col_Kuang(255,255,255);
204 | painter.setBrush(QBrush(col_Kuang));
205 | painter.drawRoundedRect(m_kuangLeftRect,4,4);
206 |
207 | //三角
208 | QPointF points[3] = {
209 | QPointF(m_sanjiaoLeftRect.x(), 30),
210 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 25),
211 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 35),
212 | };
213 | QPen pen;
214 | pen.setColor(col_Kuang);
215 | painter.setPen(pen);
216 | painter.drawPolygon(points, 3);
217 |
218 | //三角加边
219 | QPen penSanJiaoBian;
220 | penSanJiaoBian.setColor(col_KuangB);
221 | painter.setPen(penSanJiaoBian);
222 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 24));
223 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 36));
224 |
225 | //内容
226 | QPen penText;
227 | penText.setColor(QColor(51,51,51));
228 | painter.setPen(penText);
229 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);
230 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
231 | painter.setFont(this->font());
232 | painter.drawText(m_textLeftRect, m_msg,option);
233 |
234 | QPen penName;
235 | penName.setColor(QColor(192,192,192));
236 | painter.setPen(penName);
237 | QTextOption optionName(Qt::AlignLeft | Qt::AlignVCenter);
238 | optionName.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
239 | painter.setFont(QFont("Microsoft YaHei", 8, QFont::Normal));
240 | painter.drawText(m_nameLeftRect, serverIPAddress, optionName);
241 | } else if(m_userType == User_Type::User_Me) { // 自己
242 | //头像
243 | // painter.drawRoundedRect(m_iconRightRect,m_iconRightRect.width(),m_iconRightRect.height());
244 | painter.drawPixmap(m_iconRightRect, m_rightPixmap);
245 |
246 | //框
247 | QColor col_Kuang(75,164,242);
248 | painter.setBrush(QBrush(col_Kuang));
249 | painter.drawRoundedRect(m_kuangRightRect,4,4);
250 |
251 | //三角
252 | QPointF points[3] = {
253 | QPointF(m_sanjiaoRightRect.x()+m_sanjiaoRightRect.width(), 30),
254 | QPointF(m_sanjiaoRightRect.x(), 25),
255 | QPointF(m_sanjiaoRightRect.x(), 35),
256 | };
257 | QPen pen;
258 | pen.setColor(col_Kuang);
259 | painter.setPen(pen);
260 | painter.drawPolygon(points, 3);
261 |
262 | //内容
263 | QPen penText;
264 | penText.setColor(Qt::white);
265 | painter.setPen(penText);
266 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);
267 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
268 | painter.setFont(this->font());
269 | painter.drawText(m_textRightRect,m_msg,option);
270 |
271 | QPen penName;
272 | penName.setColor(QColor(192,192,192));
273 | painter.setPen(penName);
274 | QTextOption optionName(Qt::AlignLeft | Qt::AlignVCenter);
275 | optionName.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
276 | painter.setFont(QFont("Microsoft YaHei", 8, QFont::Normal));
277 | painter.drawText(m_nameRightRect, ipAddress, optionName);
278 | } else if(m_userType == User_Type::User_Time) { // 时间
279 | QPen penText;
280 | penText.setColor(QColor(153,153,153));
281 | painter.setPen(penText);
282 | QTextOption option(Qt::AlignCenter);
283 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
284 | QFont te_font = this->font();
285 | te_font.setFamily("MicrosoftYaHei");
286 | te_font.setPointSize(10);
287 | painter.setFont(te_font);
288 | painter.drawText(this->rect(),m_curTime,option);
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/Server/qnchatmessage.cpp.autosave:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 沙振宇
5 | # CreateTime: 2018-07-23
6 | # UpdateTime: 2019-12-27
7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现
8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
10 | #
11 | #-------------------------------------------------*/
12 | #include "qnchatmessage.h"
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | QNChatMessage::QNChatMessage(QWidget *parent, QString serverIP) : QWidget(parent)
23 | {
24 | QFont te_font = this->font();
25 | te_font.setFamily("MicrosoftYaHei");
26 | te_font.setPointSize(12);
27 | serverIPAddress = serverIP;
28 | get_local_Ip();
29 | // te_font.setWordSpacing(0);
30 | // te_font.setLetterSpacing(QFont::PercentageSpacing,0);
31 | // te_font.setLetterSpacing(QFont::PercentageSpacing, 100); //300%,100为默认 //设置字间距%
32 | // te_font.setLetterSpacing(QFont::AbsoluteSpacing, 0); //设置字间距为3像素 //设置字间距像素值
33 | this->setFont(te_font);
34 | m_leftPixmap = QPixmap(":/img/child.png");
35 | m_rightPixmap = QPixmap(":/img/teacher.png");
36 |
37 | m_loadingMovie = new QMovie(this);
38 | m_loadingMovie->setFileName(":/img/loading4.gif");
39 | m_loading = new QLabel(this);
40 | m_loading->setMovie(m_loadingMovie);
41 | m_loading->resize(16,16);
42 | m_loading->setAttribute(Qt::WA_TranslucentBackground , true);
43 | m_loading->setAutoFillBackground(false);
44 | }
45 |
46 | void QNChatMessage::get_local_Ip()
47 | {
48 | QList ipAddressesList = QNetworkInterface::allAddresses();
49 | // use the first non-localhost IPv4 address
50 | for (int i = 0; i < ipAddressesList.size(); ++i) {
51 | qDebug()<hide();
67 | m_loadingMovie->stop();
68 | m_isSending = true;
69 | }
70 |
71 | void QNChatMessage::setText(QString text, QString time, QSize allSize, QNChatMessage::User_Type userType)
72 | {
73 | m_msg = text;
74 | m_userType = userType;
75 | m_time = time;
76 | m_curTime = QDateTime::fromTime_t(time.toInt()).toString("hh:mm");
77 | m_allSize = allSize;
78 | if(userType == User_Me) {
79 | if(!m_isSending) {
80 | m_loading->move(m_kuangRightRect.x() - m_loading->width() - 10, m_kuangRightRect.y()+m_kuangRightRect.height()/2- m_loading->height()/2);
81 | m_loading->show();
82 | m_loadingMovie->start();
83 | }
84 | } else {
85 | m_loading->hide();
86 | }
87 |
88 | this->update();
89 | }
90 |
91 | QSize QNChatMessage::fontRect(QString str)
92 | {
93 | m_msg = str;
94 | int minHei = 30;
95 | int iconWH = 40;
96 | int iconSpaceW = 20;
97 | int iconRectW = 5;
98 | int iconTMPH = 10;
99 | int sanJiaoW = 6;
100 | int kuangTMP = 20;
101 | int textSpaceRect = 12;
102 | m_nameWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW);
103 | m_kuangWidth = this->width() - kuangTMP - 2*(iconWH+iconSpaceW+iconRectW);
104 | m_textWidth = m_kuangWidth - 2 * textSpaceRect;
105 | m_spaceWid = this->width() - m_textWidth;
106 | m_iconLeftRect = QRect(iconSpaceW, iconTMPH, iconWH, iconWH);
107 | m_iconRightRect = QRect(this->width() - iconSpaceW - iconWH, iconTMPH, iconWH, iconWH);
108 |
109 | QSize size = getRealString(m_msg); // 整个的size
110 | QFontMetrics fontMetrics(QFont("Microsoft YaHei", 8, QFont::Normal));
111 | int clientIPWidth = fontMetrics.horizontalAdvance(ipAddress);
112 | int serverIPWidth = fontMetrics.horizontalAdvance(serverIPAddress);
113 | qDebug() << "fontRect Size:" << size << clientIPWidth;
114 | int hei = size.height() < minHei ? minHei : size.height();
115 | /*三角形*/
116 | m_sanjiaoLeftRect = QRect(iconWH+iconSpaceW+iconRectW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight);
117 | m_sanjiaoRightRect = QRect(this->width() - iconRectW - iconWH - iconSpaceW - sanJiaoW, m_lineHeight/2, sanJiaoW, hei - m_lineHeight);
118 |
119 | if(size.width() < (m_textWidth+m_spaceWid)) {
120 | m_nameLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4, serverIPWidth + 10, m_lineHeight/4*2.5);
121 | m_nameRightRect.setRect(this->width()-iconWH - iconSpaceW - iconRectW - sanJiaoW - clientIPWidth,
122 | m_lineHeight/4, clientIPWidth + 10, m_lineHeight/4*2.5);
123 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*4, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight);
124 | m_kuangRightRect.setRect(this->width() - size.width() + m_spaceWid - 2*textSpaceRect - iconWH - iconSpaceW - iconRectW - sanJiaoW,
125 | m_lineHeight/4*4, size.width()-m_spaceWid+2*textSpaceRect, hei-m_lineHeight);
126 | } else {
127 | m_nameLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4, serverIPWidth + 10, m_lineHeight/4*2.5);
128 | m_nameRightRect.setRect(this->width()-iconWH - iconSpaceW - iconRectW - sanJiaoW - clientIPWidth, m_lineHeight/4, clientIPWidth + 10, m_lineHeight/4*2.5);
129 | m_kuangLeftRect.setRect(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), m_lineHeight/4*4, m_kuangWidth, hei-m_lineHeight);
130 | m_kuangRightRect.setRect(iconWH + kuangTMP + iconSpaceW + iconRectW - sanJiaoW, m_lineHeight/4*4, m_kuangWidth, hei-m_lineHeight);
131 | }
132 | /*消息框*/
133 | m_textLeftRect.setRect(m_kuangLeftRect.x()+textSpaceRect,m_kuangLeftRect.y()+iconTMPH,
134 | m_kuangLeftRect.width()-2*textSpaceRect,m_kuangLeftRect.height()-2*iconTMPH);
135 | m_textRightRect.setRect(m_kuangRightRect.x()+textSpaceRect,m_kuangRightRect.y()+iconTMPH,
136 | m_kuangRightRect.width()-2*textSpaceRect,m_kuangRightRect.height()-2*iconTMPH);
137 |
138 | return QSize(size.width(), hei);
139 | }
140 |
141 | QSize QNChatMessage::getRealString(QString src)
142 | {
143 | QFontMetricsF fm(this->font());
144 | m_lineHeight = fm.lineSpacing();
145 | int nCount = src.count("\n");
146 | int nMaxWidth = 0;
147 | if(nCount == 0) {
148 | nMaxWidth = qCeil(fm.width(src));
149 | QString value = src;
150 | if(nMaxWidth > m_textWidth) {
151 | qDebug() << "2222";
152 | nMaxWidth = m_textWidth;
153 | int size = m_textWidth / fm.width(" ");
154 | int num = fm.width(value) / m_textWidth;
155 | num = ( fm.width(value) ) / m_textWidth;
156 | nCount += num;
157 | QString temp = "";
158 | for(int i = 0; i < num; i++) {
159 | temp += value.mid(i*size, (i+1)*size) + "\n";
160 | }
161 | src.replace(value, temp);
162 | }
163 | } else {
164 | for(int i = 0; i < (nCount + 1); i++) {
165 | QString value = src.split("\n").at(i);
166 | nMaxWidth = qCeil(fm.width(value)) > nMaxWidth ? qCeil(fm.width(value)) : nMaxWidth;
167 | if(fm.width(value) > m_textWidth) {
168 | nMaxWidth = m_textWidth;
169 | int size = m_textWidth / fm.width(" ");
170 | int num = fm.width(value) / m_textWidth;
171 | num = ((i+num)*fm.width(" ") + fm.width(value)) / m_textWidth;
172 | nCount += num;
173 | QString temp = "";
174 | for(int i = 0; i < num; i++) {
175 | temp += value.mid(i*size, (i+1)*size) + "\n";
176 | }
177 | src.replace(value, temp);
178 | }
179 | }
180 | }
181 | return QSize(nMaxWidth+m_spaceWid, (nCount + 1) * m_lineHeight+2*m_lineHeight);
182 | }
183 |
184 | void QNChatMessage::paintEvent(QPaintEvent *event)
185 | {
186 | Q_UNUSED(event);
187 |
188 | QPainter painter(this);
189 | painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);//消锯齿
190 | painter.setPen(Qt::NoPen);
191 | painter.setBrush(QBrush(Qt::gray));
192 |
193 | if(m_userType == User_Type::User_Consumer) { // 用户
194 | //头像
195 | // painter.drawRoundedRect(m_iconLeftRect,m_iconLeftRect.width(),m_iconLeftRect.height());
196 | painter.drawPixmap(m_iconLeftRect, m_leftPixmap);
197 |
198 | //框加边
199 | QColor col_KuangB(234, 234, 234);
200 | painter.setBrush(QBrush(col_KuangB));
201 | painter.drawRoundedRect(m_kuangLeftRect.x()-1,m_kuangLeftRect.y()-1,m_kuangLeftRect.width()+2,m_kuangLeftRect.height()+2,4,4);
202 | //框
203 | QColor col_Kuang(255,255,255);
204 | painter.setBrush(QBrush(col_Kuang));
205 | painter.drawRoundedRect(m_kuangLeftRect,4,4);
206 |
207 | //三角
208 | QPointF points[3] = {
209 | QPointF(m_sanjiaoLeftRect.x(), 30),
210 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 25),
211 | QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 35),
212 | };
213 | QPen pen;
214 | pen.setColor(col_Kuang);
215 | painter.setPen(pen);
216 | painter.drawPolygon(points, 3);
217 |
218 | //三角加边
219 | QPen penSanJiaoBian;
220 | penSanJiaoBian.setColor(col_KuangB);
221 | painter.setPen(penSanJiaoBian);
222 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 24));
223 | painter.drawLine(QPointF(m_sanjiaoLeftRect.x() - 1, 30), QPointF(m_sanjiaoLeftRect.x()+m_sanjiaoLeftRect.width(), 36));
224 |
225 | //内容
226 | QPen penText;
227 | penText.setColor(QColor(51,51,51));
228 | painter.setPen(penText);
229 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);
230 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
231 | painter.setFont(this->font());
232 | painter.drawText(m_textLeftRect, m_msg,option);
233 |
234 | QPen penName;
235 | penName.setColor(QColor(192,192,192));
236 | painter.setPen(penName);
237 | QTextOption optionName(Qt::AlignLeft | Qt::AlignVCenter);
238 | optionName.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
239 | painter.setFont(QFont("Microsoft YaHei", 8, QFont::Normal));
240 | painter.drawText(m_nameLeftRect, serverIPAddress, optionName);
241 | } else if(m_userType == User_Type::User_Me) { // 自己
242 | //头像
243 | // painter.drawRoundedRect(m_iconRightRect,m_iconRightRect.width(),m_iconRightRect.height());
244 | painter.drawPixmap(m_iconRightRect, m_rightPixmap);
245 |
246 | //框
247 | QColor col_Kuang(75,164,242);
248 | painter.setBrush(QBrush(col_Kuang));
249 | painter.drawRoundedRect(m_kuangRightRect,4,4);
250 |
251 | //三角
252 | QPointF points[3] = {
253 | QPointF(m_sanjiaoRightRect.x()+m_sanjiaoRightRect.width(), 30),
254 | QPointF(m_sanjiaoRightRect.x(), 25),
255 | QPointF(m_sanjiaoRightRect.x(), 35),
256 | };
257 | QPen pen;
258 | pen.setColor(col_Kuang);
259 | painter.setPen(pen);
260 | painter.drawPolygon(points, 3);
261 |
262 | //内容
263 | QPen penText;
264 | penText.setColor(Qt::white);
265 | painter.setPen(penText);
266 | QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);
267 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
268 | painter.setFont(this->font());
269 | painter.drawText(m_textRightRect,m_msg,option);
270 |
271 | QPen penName;
272 | penName.setColor(QColor(192,192,192));
273 | painter.setPen(penName);
274 | QTextOption optionName(Qt::AlignLeft | Qt::AlignVCenter);
275 | optionName.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
276 | painter.setFont(QFont("Microsoft YaHei", 8, QFont::Normal));
277 | painter.drawText(m_nameRightRect, ipAddress, optionName);
278 | } else if(m_userType == User_Type::User_Time) { // 时间
279 | QPen penText;
280 | penText.setColor(QColor(153,153,153));
281 | painter.setPen(penText);
282 | QTextOption option(Qt::AlignCenter);
283 | option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
284 | QFont te_font = this->font();
285 | te_font.setFamily("MicrosoftYaHei");
286 | te_font.setPointSize(10);
287 | painter.setFont(te_font);
288 | painter.drawText(this->rect(),m_curTime,option);
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/Server/qnchatmessage.h:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 沙振宇
5 | # CreateTime: 2018-07-23
6 | # UpdateTime: 2019-12-27
7 | # Info: Qt5气泡式聊天框——QListWidget+QPainter实现
8 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
9 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
10 | #
11 | #-------------------------------------------------*/
12 | #ifndef QNCHATMESSAGE_H
13 | #define QNCHATMESSAGE_H
14 |
15 | #include
16 |
17 | class QPaintEvent;
18 | class QPainter;
19 | class QLabel;
20 | class QMovie;
21 |
22 | class QNChatMessage : public QWidget
23 | {
24 | Q_OBJECT
25 | public:
26 | explicit QNChatMessage(QWidget *parent = nullptr, QString serverIP = "127.0.0.1");
27 |
28 | enum User_Type{
29 | User_System,//系统
30 | User_Me, //自己
31 | User_She, //用户
32 | User_Time, //时间
33 | };
34 | void setTextSuccess();
35 | void setText(QString text, QString time, QSize allSize, User_Type userType);
36 |
37 | QSize getRealString(QString src);
38 | QSize fontRect(QString str);
39 |
40 | inline QString text() {return m_msg;}
41 | inline QString time() {return m_time;}
42 | inline User_Type userType() {return m_userType;}
43 | void get_local_Ip();
44 | protected:
45 | void paintEvent(QPaintEvent *event);
46 | private:
47 | QString m_msg;
48 | QString m_time;
49 | QString m_curTime;
50 | QString ipAddress; //本机IP地址
51 | QString serverIPAddress;
52 | QSize m_allSize;
53 | User_Type m_userType = User_System;
54 |
55 | int m_nameWidth;
56 | int m_kuangWidth;
57 | int m_textWidth;
58 | int m_spaceWid;
59 | int m_lineHeight;
60 |
61 | QRect m_iconLeftRect;
62 | QRect m_iconRightRect;
63 | QRect m_sanjiaoLeftRect;
64 | QRect m_sanjiaoRightRect;
65 | QRect m_nameLeftRect;
66 | QRect m_nameRightRect;
67 | QRect m_kuangLeftRect;
68 | QRect m_kuangRightRect;
69 | QRect m_textLeftRect;
70 | QRect m_textRightRect;
71 | QPixmap m_leftPixmap;
72 | QPixmap m_rightPixmap;
73 | QLabel* m_loading = Q_NULLPTR;
74 | QMovie* m_loadingMovie = Q_NULLPTR;
75 | bool m_isSending = false;
76 | };
77 |
78 | #endif // QNCHATMESSAGE_H
79 |
--------------------------------------------------------------------------------
/Server/qnchatmessage.h.autosave:
--------------------------------------------------------------------------------
1 | #ifndef QNCHATMESSAGE_H
2 | #define QNCHATMESSAGE_H
3 |
4 | #include
5 |
6 | class QPaintEvent;
7 | class QPainter;
8 | class QLabel;
9 | class QMovie;
10 |
11 | class QNChatMessage : public QWidget
12 | {
13 | Q_OBJECT
14 | public:
15 | explicit QNChatMessage(QWidget *parent = nullptr, QString serverIP = "127.0.0.1");
16 |
17 | enum User_Type{
18 | User_System,//系统
19 | User_Me, //自己
20 | User_Consumer, //用户
21 | User_Time, //时间
22 | };
23 | void setTextSuccess();
24 | void setText(QString text, QString time, QSize allSize, User_Type userType);
25 |
26 | QSize getRealString(QString src);
27 | QSize fontRect(QString str);
28 |
29 | inline QString text() {return m_msg;}
30 | inline QString time() {return m_time;}
31 | inline User_Type userType() {return m_userType;}
32 | void get_local_Ip();
33 | protected:
34 | void paintEvent(QPaintEvent *event);
35 | private:
36 | QString m_msg;
37 | QString m_time;
38 | QString m_curTime;
39 | QString ipAddress; //本机IP地址
40 | QString serverIPAddress;
41 | QSize m_allSize;
42 | User_Type m_userType = User_System;
43 |
44 | int m_nameWidth;
45 | int m_kuangWidth;
46 | int m_textWidth;
47 | int m_spaceWid;
48 | int m_lineHeight;
49 |
50 | QRect m_iconLeftRect;
51 | QRect m_iconRightRect;
52 | QRect m_sanjiaoLeftRect;
53 | QRect m_sanjiaoRightRect;
54 | QRect m_nameLeftRect;
55 | QRect m_nameRightRect;
56 | QRect m_kuangLeftRect;
57 | QRect m_kuangRightRect;
58 | QRect m_textLeftRect;
59 | QRect m_textRightRect;
60 | QPixmap m_leftPixmap;
61 | QPixmap m_rightPixmap;
62 | QLabel* m_loading = Q_NULLPTR;
63 | QMovie* m_loadingMovie = Q_NULLPTR;
64 | bool m_isSending = false;
65 | };
66 |
67 | #endif // QNCHATMESSAGE_H
68 |
--------------------------------------------------------------------------------
/Server/widget.cpp:
--------------------------------------------------------------------------------
1 | #include "widget.h"
2 | #include "clientaddress.h"
3 | #include "ui_widget.h"
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | //#include "seekfile.h"
17 |
18 | Widget::Widget(QWidget *parent) :
19 | QWidget(parent),
20 | ui(new Ui::Widget)
21 | {
22 | ui->setupUi(this);
23 | setWindowTitle(tr("局域网文件传输服务器"));
24 | /*清空列表文件*/
25 | if((fp = fopen("/home/leo/Desktop/NetworkFileTransfer-master/FileList/FILELIST.txt","w+"))==NULL)
26 | {
27 | qDebug()<<"Clear FILELIST.TXT error!";
28 | }
29 | fclose(fp);
30 | server = new Myserver(this);
31 | server->listen(QHostAddress::Any, 8888);
32 | closeCommand = 0;
33 | ui->textEdit->document()->setMaximumBlockCount(100);
34 | // ui->ClientPB1->setEnabled(false);
35 | // ui->ClientPB2->setEnabled(false);
36 | // ui->ClientPB3->setEnabled(false);
37 | // /*为三个按键安装事件过滤器*/
38 | // ui->ClientPB1->installEventFilter(this);
39 | // ui->ClientPB2->installEventFilter(this);
40 | // ui->ClientPB3->installEventFilter(this);
41 |
42 | // ui->LBstate1->setText(tr("断开"));
43 | // ui->LBstate2->setText(tr("断开"));
44 | // ui->LBstate3->setText(tr("断开"));
45 |
46 | ui->pushButton->setEnabled(false);
47 |
48 | connect(ui->pushButton,&QPushButton::clicked,this,&Widget::fileTranferButtonSlot);
49 | connect(ui->AddFilePB,&QPushButton::clicked,this,&Widget::addFilePBSlot);
50 | // connect(ui->DelFilePB,&QPushButton::clicked,this,&Widget::deleteFileListItem);
51 | connect(ui->DelFilePB,&QPushButton::clicked,this,&Widget::deleteFile);
52 | /*服务器端主动断开连接*/
53 | connect(this,&Widget::clientDiconnectSignal,server, &Myserver::clientDisconnectSlot);
54 | connect(ui->InfoPushButton,&QPushButton::clicked,this,&Widget::infoTranferButtonSlot);
55 | connect(ui->DelInfoPB,&QPushButton::clicked,this,&Widget::deleteInfo);
56 | // connect(ui->listWidget,&QAbstractItemView::doubleClicked,this,&Widget::doubleClickedItem);
57 | }
58 |
59 | Widget::~Widget()
60 | {
61 | delete ui;
62 | }
63 |
64 | void Widget::dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type)
65 | {
66 | messageW->setFixedWidth(ui->listWidget->width()-10);
67 | QSize size = messageW->fontRect(text);
68 | item->setSizeHint(size);
69 | messageW->setText(text, time, size, type);
70 | ui->listWidget->setItemWidget(item, messageW);
71 | }
72 |
73 | void Widget::dealMessageTime(QString curMsgTime)
74 | {
75 | bool isShowTime = false;
76 | if(ui->listWidget->count() > 0) {
77 | QListWidgetItem* lastItem = ui->listWidget->item(ui->listWidget->count() - 1);
78 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(lastItem);
79 | int lastTime = messageW->time().toInt();
80 | int curTime = curMsgTime.toInt();
81 | qDebug() << "curTime lastTime:" << curTime - lastTime;
82 | isShowTime = ((curTime - lastTime) > 60); // 两个消息相差一分钟
83 | // isShowTime = true;
84 | } else {
85 | isShowTime = true;
86 | }
87 | if(isShowTime) {
88 | QNChatMessage* messageTime = new QNChatMessage(ui->listWidget->parentWidget());
89 | QListWidgetItem* itemTime = new QListWidgetItem(ui->listWidget);
90 |
91 | QSize size = QSize(ui->listWidget->width()-10, 40);
92 | messageTime->resize(size);
93 | itemTime->setSizeHint(size);
94 | messageTime->setText(curMsgTime, curMsgTime, size, QNChatMessage::User_Time);
95 | ui->listWidget->setItemWidget(itemTime, messageTime);
96 | }
97 | }
98 |
99 | void Widget::resizeEvent(QResizeEvent *event)
100 | {
101 | Q_UNUSED(event);
102 |
103 | for(int i = 0; i < ui->listWidget->count(); i++) {
104 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i));
105 | QListWidgetItem* item = ui->listWidget->item(i);
106 |
107 | dealMessage(messageW, item, messageW->text(), messageW->time(), messageW->userType());
108 | }
109 | }
110 |
111 | void Widget::closeClientConnectSlot(QString clientIp, int clientPort, QDateTime current_date_time)
112 | {
113 | /*判断是哪个客户端断开,并做相应的清除工作*/
114 | qDebug() << "#";
115 | for(int i = 0; i < IPOrder.size(); i++)
116 | {
117 | qDebug() << IPOrder.at(i) << " ";
118 | }
119 | qDebug() << index << " ";
120 | qDebug() << clientIp << " ";
121 | closeFlag_current *= -1;
122 | int deleteIndex = IPOrder.indexOf(clientIp);
123 | // qDebug() << QString::number(deleteIndex);
124 | QListWidgetItem *item = ui->clientListWidget->takeItem(deleteIndex);
125 | delete item;
126 | IPOrder.remove(deleteIndex);
127 | index--;
128 | // QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss");
129 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
130 | // ui->textEdit->append(current_date + " —— IP: " + clientIp + " 断开连接");
131 | if(closeFlag_previous * closeFlag_current == -1)
132 | {
133 | QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss");
134 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
135 | ui->textEdit->append(current_date + " —— IP: " + clientIp + " Port: " + QString::number(clientPort) + " 客户端断开连接");
136 | }
137 | server->socketNum--;
138 | closeFlag_previous = closeFlag_current;
139 | }
140 |
141 | void Widget::addFilePBSlot()
142 | {
143 | /*打开目录获得文件目录*/
144 | // dirPath = QFileDialog::getExistingDirectory(this,0,"./");
145 | dirPath = QFileDialog::getOpenFileName(this, "选择文件", "./", "(*.*)");
146 | QDir dir(dirPath);
147 | if(dirPath.isEmpty())
148 | return;
149 | ui->lineEdit->setText(dirPath);
150 | ui->pushButton->setEnabled(true);
151 | }
152 | void Widget::getSendFileList(QString path)
153 | {
154 | // FILE *fp;
155 | // /*已追加的方式打开文件*/
156 | // fp = fopen("./FileList/FILELIST.TXT","at+");
157 | // if(fp == NULL)
158 | // {
159 | // qDebug()<<"Open FILELIST.TXT failed!";
160 | // return;
161 | // }
162 | QFile filelist("./FileList/FILELIST.TXT");
163 | QTextStream out(&filelist);
164 | if(!filelist.open(QFile::WriteOnly|QFile::Text))
165 | {
166 | qDebug()<<"write FILELIST.TXT error!"<lineEdit->setText("");
236 | ui->pushButton->setEnabled(false);
237 | }
238 |
239 | void Widget::deleteInfo()
240 | {
241 | info.clear();
242 | ui->textEdit_2->setText("");
243 | }
244 |
245 | //void Widget::deleteFileListItem()
246 | //{
247 | // /*获得当前选中项,并删除*/
248 | // QListWidgetItem *item = ui->listWidget->currentItem();
249 | // delete item;
250 | //}
251 |
252 | //void Widget::doubleClickedItem()
253 | //{
254 | // /*获得双击项文本*/
255 | // QString str = ui->listWidget->currentItem()->text();
256 | //#if defined __DEBUG__
257 | // qDebug()<<"双击项文本内容str为"<getSendFileList(dirPath);
270 | //// fp = fopen("./FileList/FILELIST.TXT","ab");
271 | //// if(fp == NULL)
272 | //// {
273 | //// qDebug()<<"Open FILELIST.TXT failed!";
274 | //// return;
275 | //// }
276 | //// this->DfsFolder(dirPath.toStdString(),0);
277 | //// fclose(fp);
278 | // QStringList nameFilters;
279 | // nameFilters << "*";
280 | // QFileInfoList files = dir.entryInfoList(nameFilters,QDir::AllEntries,QDir::DirsFirst);
281 | // ui->listWidget->clear();
282 | // if(str=="..") //当返回上一级目录时,只显示目录不显示文件
283 | // {
284 | // for(int i =0 ;ilistWidget->addItem(tmp);
292 | // }
293 | // }
294 | // }
295 | // else
296 | // {
297 | // for(int i =0 ;ilistWidget->addItem(tmp);
305 | // }
306 | // if(tmpFileInfo.isFile()) //显示文件
307 | // {
308 | // ui->listWidget->addItem(tmp);
309 | // }
310 | // }
311 | // }
312 | //}
313 |
314 | void Widget::fileTranferButtonSlot()
315 | {
316 | // QString fileName = QFileDialog::getOpenFileName(this);
317 | //#if defined __DEBUG__
318 | // qDebug()<<"Open file's name is"<socketNum > 0)
326 | {
327 | emit sendFileWidgetSignal(dirPath);
328 | }
329 | else
330 | {
331 | ui->textEdit->append("当前无客户端连接,传输文件无效!");
332 | }
333 | }
334 |
335 | void Widget::infoTranferButtonSlot()
336 | {
337 | info = ui->textEdit_2->toPlainText();
338 | qDebug() << info;
339 | if(info.size() > 0)
340 | {
341 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳
342 | qDebug()<<"addMessage" << info << time << ui->listWidget->count();
343 | dealMessageTime(time);
344 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), ipAddress);
345 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
346 | dealMessage(messageW, item, info, time, QNChatMessage::User_Me);
347 | // else {
348 | // if(clientInfo != "") {
349 | // dealMessageTime(time);
350 |
351 | // QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget());
352 | // QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
353 | // dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_She);
354 | // }
355 | // }
356 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1);
357 | emit sendInfoWidgetSignal(info);
358 | }
359 | else
360 | {
361 | ui->textEdit->append("无消息输入,传输消息无效!");
362 | }
363 | }
364 |
365 | //void Widget::addClientIPTGUISlot(QString CIP,int CPort, int ID,int state)
366 | //{
367 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
368 | // if((ID == 1)&&(state==QAbstractSocket::ConnectedState))
369 | // {
370 | // ui->LBDisplayIP1->setText(CIP);
371 | // ui->LBDisplayPort1->setText(QString::number(CPort));
372 | // ui->LBstate1->setText(tr("连接"));
373 | // ui->ClientPB1->setEnabled(true);
374 | // }
375 | // else if((ID == 2)&&(state==QAbstractSocket::ConnectedState))
376 | // {
377 | // ui->LBDisplayIP2->setText(CIP);
378 | // ui->LBDisplayPort2->setText(QString::number(CPort));
379 | // ui->LBstate2->setText(tr("连接"));
380 | // ui->ClientPB2->setEnabled(true);
381 | // }
382 | // else if((ID == 3)&&(state==QAbstractSocket::ConnectedState))
383 | // {
384 | // ui->LBDisplayIP3->setText(CIP);
385 | // ui->LBDisplayPort3->setText(QString::number(CPort));
386 | // ui->LBstate3->setText(tr("连接"));
387 | // ui->ClientPB3->setEnabled(true);
388 | // }
389 | //}
390 |
391 | void Widget::displayInfoTGUISlot(QString CIP,int CPort,int state,QDateTime current_time)
392 | {
393 | QString current_date = current_time.toString("yyyy.MM.dd hh:mm:ss");
394 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
395 | if(state==QAbstractSocket::ConnectedState)
396 | {
397 | ui->textEdit->append(current_date + " —— IP: " + CIP + " Port: " + QString::number(CPort) + " 客户端成功连接");
398 | }
399 | IPOrder.append(CIP);
400 | index++;
401 | QListWidgetItem * item = new QListWidgetItem(ui->clientListWidget);
402 | QSize size = item->sizeHint();
403 | item->setSizeHint(QSize(300, 50));
404 | ui->clientListWidget->addItem(item);
405 | clientAddress * client = new clientAddress(CIP, CPort);
406 | client->setParent(ui->clientListWidget);
407 | client->setSizeIncrement(size.width(), 56);
408 | ui->clientListWidget->setItemWidget(item, client);
409 | connect(client, &clientAddress::clientAddressSignal, this, &Widget::clientAddressSlot);
410 | }
411 |
412 | void Widget::clientAddressSlot(QString IP, int clientPort)
413 | {
414 | int deleteIndex = IPOrder.indexOf(IP);
415 | closeFlag_current *= -1;
416 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
417 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
418 | ui->textEdit->append(current_date + " —— IP: " + IP + " Port: " + QString::number(clientPort) + " 服务器断开连接");
419 | emit clientAddressWidgetSignal(deleteIndex);
420 | }
421 |
422 | void Widget::sendStateDisplaySlot(QString msg, QString info)
423 | {
424 | if(msg == "服务器开始发送消息")
425 | {
426 | /*消息框*/
427 | // QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳
428 | // qDebug()<<"addMessage" << info << time << ui->listWidget->count();
429 | // dealMessageTime(time);
430 | // QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), IPAddress);
431 | // QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
432 | // dealMessage(messageW, item, info, time, QNChatMessage::User_Me);
433 | //// else {
434 | //// if(clientInfo != "") {
435 | //// dealMessageTime(time);
436 |
437 | //// QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget());
438 | //// QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
439 | //// dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_She);
440 | //// }
441 | //// }
442 | // ui->listWidget->setCurrentRow(ui->listWidget->count()-1);
443 | }
444 | else if(msg == "服务器发送消息成功")
445 | {
446 | qDebug() << "6666666";
447 | /*暂停发送消息状态*/
448 | qDebug() << ui->listWidget->count();
449 | qDebug() << info;
450 | for(int i = ui->listWidget->count() - 1; i > 0; i--) {
451 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i));
452 | if(messageW->text() == info) {
453 | qDebug() << "7777777";
454 | messageW->setTextSuccess();
455 | }
456 | }
457 |
458 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
459 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
460 | ui->textEdit->append(current_date + " —— " + msg);
461 | }
462 | else
463 | {
464 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
465 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
466 | ui->textEdit->append(current_date + " —— " + msg);
467 | }
468 | }
469 |
470 | void Widget::sendInfoDisplaySlot(QString clientInfo, QString ip)
471 | {
472 |
473 | /*消息框*/
474 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳
475 | qDebug()<<"addMessage" << clientInfo << time << ui->listWidget->count();
476 | if(clientInfo != "") {
477 | dealMessageTime(time);
478 |
479 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), ip);
480 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
481 | dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_She);
482 | }
483 |
484 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1);
485 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
486 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
487 | ui->textEdit->append(current_date + " —— " + "服务器接收消息成功");
488 | // QMessageBox::about(NULL, "客户端消息", clientInfo);
489 | }
490 |
491 | /*深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件*/
492 | //void Widget::DfsFolder(std::string path,int layer)
493 | //{
494 | // _finddata_t file_info;
495 | // std::string current_path=path+"/*.*"; //也可以用/*来匹配所有
496 | // int handle=_findfirst(current_path.c_str(),&file_info);
497 | // /*返回值为-1则查找失败*/
498 | // if(-1==handle)
499 | // {
500 | // std::cout<<"cannot match the path"<
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | //#include "seekfile.h"
17 |
18 | Widget::Widget(QWidget *parent) :
19 | QWidget(parent),
20 | ui(new Ui::Widget)
21 | {
22 | ui->setupUi(this);
23 | setWindowTitle(tr("局域网文件传输服务器"));
24 | /*清空列表文件*/
25 | if((fp = fopen("/home/leo/Desktop/NetworkFileTransfer-master/FileList/FILELIST.txt","w+"))==NULL)
26 | {
27 | qDebug()<<"Clear FILELIST.TXT error!";
28 | }
29 | fclose(fp);
30 | server = new Myserver(this);
31 | server->listen(QHostAddress::Any, 8888);
32 | closeCommand = 0;
33 | ui->textEdit->document()->setMaximumBlockCount(100);
34 | // ui->ClientPB1->setEnabled(false);
35 | // ui->ClientPB2->setEnabled(false);
36 | // ui->ClientPB3->setEnabled(false);
37 | // /*为三个按键安装事件过滤器*/
38 | // ui->ClientPB1->installEventFilter(this);
39 | // ui->ClientPB2->installEventFilter(this);
40 | // ui->ClientPB3->installEventFilter(this);
41 |
42 | // ui->LBstate1->setText(tr("断开"));
43 | // ui->LBstate2->setText(tr("断开"));
44 | // ui->LBstate3->setText(tr("断开"));
45 |
46 | ui->pushButton->setEnabled(false);
47 |
48 | connect(ui->pushButton,&QPushButton::clicked,this,&Widget::fileTranferButtonSlot);
49 | connect(ui->AddFilePB,&QPushButton::clicked,this,&Widget::addFilePBSlot);
50 | // connect(ui->DelFilePB,&QPushButton::clicked,this,&Widget::deleteFileListItem);
51 | connect(ui->DelFilePB,&QPushButton::clicked,this,&Widget::deleteFile);
52 | /*服务器端主动断开连接*/
53 | connect(this,&Widget::clientDiconnectSignal,server, &Myserver::clientDisconnectSlot);
54 | connect(ui->InfoPushButton,&QPushButton::clicked,this,&Widget::infoTranferButtonSlot);
55 | connect(ui->DelInfoPB,&QPushButton::clicked,this,&Widget::deleteInfo);
56 | // connect(ui->listWidget,&QAbstractItemView::doubleClicked,this,&Widget::doubleClickedItem);
57 | }
58 |
59 | Widget::~Widget()
60 | {
61 | delete ui;
62 | }
63 |
64 | void Widget::dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type)
65 | {
66 | messageW->setFixedWidth(ui->listWidget->width()-10);
67 | QSize size = messageW->fontRect(text);
68 | item->setSizeHint(size);
69 | messageW->setText(text, time, size, type);
70 | ui->listWidget->setItemWidget(item, messageW);
71 | }
72 |
73 | void Widget::dealMessageTime(QString curMsgTime)
74 | {
75 | bool isShowTime = false;
76 | if(ui->listWidget->count() > 0) {
77 | QListWidgetItem* lastItem = ui->listWidget->item(ui->listWidget->count() - 1);
78 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(lastItem);
79 | int lastTime = messageW->time().toInt();
80 | int curTime = curMsgTime.toInt();
81 | qDebug() << "curTime lastTime:" << curTime - lastTime;
82 | isShowTime = ((curTime - lastTime) > 60); // 两个消息相差一分钟
83 | // isShowTime = true;
84 | } else {
85 | isShowTime = true;
86 | }
87 | if(isShowTime) {
88 | QNChatMessage* messageTime = new QNChatMessage(ui->listWidget->parentWidget());
89 | QListWidgetItem* itemTime = new QListWidgetItem(ui->listWidget);
90 |
91 | QSize size = QSize(ui->listWidget->width()-10, 40);
92 | messageTime->resize(size);
93 | itemTime->setSizeHint(size);
94 | messageTime->setText(curMsgTime, curMsgTime, size, QNChatMessage::User_Time);
95 | ui->listWidget->setItemWidget(itemTime, messageTime);
96 | }
97 | }
98 |
99 | void Widget::resizeEvent(QResizeEvent *event)
100 | {
101 | Q_UNUSED(event);
102 |
103 | for(int i = 0; i < ui->listWidget->count(); i++) {
104 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i));
105 | QListWidgetItem* item = ui->listWidget->item(i);
106 |
107 | dealMessage(messageW, item, messageW->text(), messageW->time(), messageW->userType());
108 | }
109 | }
110 |
111 | void Widget::closeClientConnectSlot(QString clientIp, int clientPort, QDateTime current_date_time)
112 | {
113 | /*判断是哪个客户端断开,并做相应的清除工作*/
114 | qDebug() << "#";
115 | for(int i = 0; i < IPOrder.size(); i++)
116 | {
117 | qDebug() << IPOrder.at(i) << " ";
118 | }
119 | qDebug() << index << " ";
120 | qDebug() << clientIp << " ";
121 | closeFlag_current *= -1;
122 | int deleteIndex = IPOrder.indexOf(clientIp);
123 | // qDebug() << QString::number(deleteIndex);
124 | QListWidgetItem *item = ui->clientListWidget->takeItem(deleteIndex);
125 | delete item;
126 | IPOrder.remove(deleteIndex);
127 | index--;
128 | // QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss");
129 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
130 | // ui->textEdit->append(current_date + " —— IP: " + clientIp + " 断开连接");
131 | if(closeFlag_previous * closeFlag_current == -1)
132 | {
133 | QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss");
134 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
135 | ui->textEdit->append(current_date + " —— IP: " + clientIp + " Port: " + QString::number(clientPort) + " 客户端断开连接");
136 | }
137 | server->socketNum--;
138 | closeFlag_previous = closeFlag_current;
139 | }
140 |
141 | void Widget::addFilePBSlot()
142 | {
143 | /*打开目录获得文件目录*/
144 | // dirPath = QFileDialog::getExistingDirectory(this,0,"./");
145 | dirPath = QFileDialog::getOpenFileName(this, "选择文件", "./", "(*.*)");
146 | QDir dir(dirPath);
147 | if(dirPath.isEmpty())
148 | return;
149 | ui->lineEdit->setText(dirPath);
150 | ui->pushButton->setEnabled(true);
151 | }
152 | void Widget::getSendFileList(QString path)
153 | {
154 | // FILE *fp;
155 | // /*已追加的方式打开文件*/
156 | // fp = fopen("./FileList/FILELIST.TXT","at+");
157 | // if(fp == NULL)
158 | // {
159 | // qDebug()<<"Open FILELIST.TXT failed!";
160 | // return;
161 | // }
162 | QFile filelist("./FileList/FILELIST.TXT");
163 | QTextStream out(&filelist);
164 | if(!filelist.open(QFile::WriteOnly|QFile::Text))
165 | {
166 | qDebug()<<"write FILELIST.TXT error!"<lineEdit->setText("");
236 | ui->pushButton->setEnabled(false);
237 | }
238 |
239 | void Widget::deleteInfo()
240 | {
241 | info.clear();
242 | ui->textEdit_2->setText("");
243 | }
244 |
245 | //void Widget::deleteFileListItem()
246 | //{
247 | // /*获得当前选中项,并删除*/
248 | // QListWidgetItem *item = ui->listWidget->currentItem();
249 | // delete item;
250 | //}
251 |
252 | //void Widget::doubleClickedItem()
253 | //{
254 | // /*获得双击项文本*/
255 | // QString str = ui->listWidget->currentItem()->text();
256 | //#if defined __DEBUG__
257 | // qDebug()<<"双击项文本内容str为"<getSendFileList(dirPath);
270 | //// fp = fopen("./FileList/FILELIST.TXT","ab");
271 | //// if(fp == NULL)
272 | //// {
273 | //// qDebug()<<"Open FILELIST.TXT failed!";
274 | //// return;
275 | //// }
276 | //// this->DfsFolder(dirPath.toStdString(),0);
277 | //// fclose(fp);
278 | // QStringList nameFilters;
279 | // nameFilters << "*";
280 | // QFileInfoList files = dir.entryInfoList(nameFilters,QDir::AllEntries,QDir::DirsFirst);
281 | // ui->listWidget->clear();
282 | // if(str=="..") //当返回上一级目录时,只显示目录不显示文件
283 | // {
284 | // for(int i =0 ;ilistWidget->addItem(tmp);
292 | // }
293 | // }
294 | // }
295 | // else
296 | // {
297 | // for(int i =0 ;ilistWidget->addItem(tmp);
305 | // }
306 | // if(tmpFileInfo.isFile()) //显示文件
307 | // {
308 | // ui->listWidget->addItem(tmp);
309 | // }
310 | // }
311 | // }
312 | //}
313 |
314 | void Widget::fileTranferButtonSlot()
315 | {
316 | // QString fileName = QFileDialog::getOpenFileName(this);
317 | //#if defined __DEBUG__
318 | // qDebug()<<"Open file's name is"<socketNum > 0)
326 | {
327 | emit sendFileWidgetSignal(dirPath);
328 | }
329 | else
330 | {
331 | ui->textEdit->append("当前无客户端连接,传输文件无效!");
332 | }
333 | }
334 |
335 | void Widget::infoTranferButtonSlot()
336 | {
337 | info = ui->textEdit_2->toPlainText();
338 | qDebug() << info;
339 | if(info.size() > 0)
340 | {
341 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳
342 | qDebug()<<"addMessage" << info << time << ui->listWidget->count();
343 | dealMessageTime(time);
344 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), ipAddress);
345 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
346 | dealMessage(messageW, item, info, time, QNChatMessage::User_Me);
347 | // else {
348 | // if(clientInfo != "") {
349 | // dealMessageTime(time);
350 |
351 | // QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget());
352 | // QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
353 | // dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_Consumer);
354 | // }
355 | // }
356 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1);
357 | emit sendInfoWidgetSignal(info);
358 | }
359 | else
360 | {
361 | ui->textEdit->append("无消息输入,传输消息无效!");
362 | }
363 | }
364 |
365 | //void Widget::addClientIPTGUISlot(QString CIP,int CPort, int ID,int state)
366 | //{
367 | // /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
368 | // if((ID == 1)&&(state==QAbstractSocket::ConnectedState))
369 | // {
370 | // ui->LBDisplayIP1->setText(CIP);
371 | // ui->LBDisplayPort1->setText(QString::number(CPort));
372 | // ui->LBstate1->setText(tr("连接"));
373 | // ui->ClientPB1->setEnabled(true);
374 | // }
375 | // else if((ID == 2)&&(state==QAbstractSocket::ConnectedState))
376 | // {
377 | // ui->LBDisplayIP2->setText(CIP);
378 | // ui->LBDisplayPort2->setText(QString::number(CPort));
379 | // ui->LBstate2->setText(tr("连接"));
380 | // ui->ClientPB2->setEnabled(true);
381 | // }
382 | // else if((ID == 3)&&(state==QAbstractSocket::ConnectedState))
383 | // {
384 | // ui->LBDisplayIP3->setText(CIP);
385 | // ui->LBDisplayPort3->setText(QString::number(CPort));
386 | // ui->LBstate3->setText(tr("连接"));
387 | // ui->ClientPB3->setEnabled(true);
388 | // }
389 | //}
390 |
391 | void Widget::displayInfoTGUISlot(QString CIP,int CPort,int state,QDateTime current_time)
392 | {
393 | QString current_date = current_time.toString("yyyy.MM.dd hh:mm:ss");
394 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
395 | if(state==QAbstractSocket::ConnectedState)
396 | {
397 | ui->textEdit->append(current_date + " —— IP: " + CIP + " Port: " + QString::number(CPort) + " 客户端成功连接");
398 | }
399 | IPOrder.append(CIP);
400 | index++;
401 | QListWidgetItem * item = new QListWidgetItem(ui->clientListWidget);
402 | QSize size = item->sizeHint();
403 | item->setSizeHint(QSize(300, 50));
404 | ui->clientListWidget->addItem(item);
405 | clientAddress * client = new clientAddress(CIP, CPort);
406 | client->setParent(ui->clientListWidget);
407 | client->setSizeIncrement(size.width(), 56);
408 | ui->clientListWidget->setItemWidget(item, client);
409 | connect(client, &clientAddress::clientAddressSignal, this, &Widget::clientAddressSlot);
410 | }
411 |
412 | void Widget::clientAddressSlot(QString IP, int clientPort)
413 | {
414 | int deleteIndex = IPOrder.indexOf(IP);
415 | closeFlag_current *= -1;
416 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
417 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
418 | ui->textEdit->append(current_date + " —— IP: " + IP + " Port: " + QString::number(clientPort) + " 服务器断开连接");
419 | emit clientAddressWidgetSignal(deleteIndex);
420 | }
421 |
422 | void Widget::sendStateDisplaySlot(QString msg, QString info)
423 | {
424 | if(msg == "服务器开始发送消息")
425 | {
426 | /*消息框*/
427 | // QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳
428 | // qDebug()<<"addMessage" << info << time << ui->listWidget->count();
429 | // dealMessageTime(time);
430 | // QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), IPAddress);
431 | // QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
432 | // dealMessage(messageW, item, info, time, QNChatMessage::User_Me);
433 | //// else {
434 | //// if(clientInfo != "") {
435 | //// dealMessageTime(time);
436 |
437 | //// QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget());
438 | //// QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
439 | //// dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_Consumer);
440 | //// }
441 | //// }
442 | // ui->listWidget->setCurrentRow(ui->listWidget->count()-1);
443 | }
444 | else if(msg == "服务器发送消息成功")
445 | {
446 | qDebug() << "6666666";
447 | /*暂停发送消息状态*/
448 | qDebug() << ui->listWidget->count();
449 | qDebug() << info;
450 | for(int i = ui->listWidget->count() - 1; i > 0; i--) {
451 | QNChatMessage* messageW = (QNChatMessage*)ui->listWidget->itemWidget(ui->listWidget->item(i));
452 | if(messageW->text() == info) {
453 | qDebug() << "7777777";
454 | messageW->setTextSuccess();
455 | }
456 | }
457 |
458 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
459 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
460 | ui->textEdit->append(current_date + " —— " + msg);
461 | }
462 | else
463 | {
464 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
465 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
466 | ui->textEdit->append(current_date + " —— " + msg);
467 | }
468 | }
469 |
470 | void Widget::sendInfoDisplaySlot(QString clientInfo, QString ip)
471 | {
472 |
473 | /*消息框*/
474 | QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //时间戳
475 | qDebug()<<"addMessage" << clientInfo << time << ui->listWidget->count();
476 | if(clientInfo != "") {
477 | dealMessageTime(time);
478 |
479 | QNChatMessage* messageW = new QNChatMessage(ui->listWidget->parentWidget(), ip);
480 | QListWidgetItem* item = new QListWidgetItem(ui->listWidget);
481 | dealMessage(messageW, item, clientInfo, time, QNChatMessage::User_Consumer);
482 | }
483 |
484 | ui->listWidget->setCurrentRow(ui->listWidget->count()-1);
485 | /*判断连接的客户端数量,并根据连接的客户端信息进行界面更新*/
486 | QString current_date = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss");
487 | ui->textEdit->append(current_date + " —— " + "服务器接收消息成功");
488 | // QMessageBox::about(NULL, "客户端消息", clientInfo);
489 | }
490 |
491 | /*深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件*/
492 | //void Widget::DfsFolder(std::string path,int layer)
493 | //{
494 | // _finddata_t file_info;
495 | // std::string current_path=path+"/*.*"; //也可以用/*来匹配所有
496 | // int handle=_findfirst(current_path.c_str(),&file_info);
497 | // /*返回值为-1则查找失败*/
498 | // if(-1==handle)
499 | // {
500 | // std::cout<<"cannot match the path"<
5 | #include "myserver.h"
6 | #include "debugonoroff.h"
7 | #include "qnchatmessage.h"
8 | class string;
9 | class QEvent;
10 | class Myserver;
11 | class QListWidgetItem;
12 | namespace Ui {
13 | class Widget;
14 | }
15 |
16 |
17 | class Widget : public QWidget
18 | {
19 | Q_OBJECT
20 |
21 | public:
22 | explicit Widget(QWidget *parent = 0);
23 | ~Widget();
24 | /*重新实现事件过滤器函数*/
25 | // bool eventFilter(QObject *watched, QEvent *event);
26 | /*消息框*/
27 | void dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type);
28 | void dealMessageTime(QString curMsgTime);
29 | /*获得发送文件列表*/
30 | void getSendFileList(QString path);
31 | protected:
32 | void resizeEvent(QResizeEvent *event);
33 | /*深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件*/
34 | // void DfsFolder(std::string path,int layer);
35 | /*层次遍历当前目录下的文件夹及子文件夹下的文件*/
36 | // bool TraverseFiles(std::string path,int &file_num);
37 | signals:
38 | /*客户端主动断开连接信号*/
39 | void closeClientConnectSignal(int disconnectCommand);
40 | /*客户端被动断开连接信号*/
41 | void clientDiconnectSignal(int ID);
42 | /*获得文件列表信号*/
43 | void getFileListSignal(QString filelist);
44 | /*发送文件信号*/
45 | void sendFileWidgetSignal(QString filename);
46 | /*发送消息信号*/
47 | void sendInfoWidgetSignal(QString info);
48 | /*服务器发送断开信号*/
49 | void clientAddressWidgetSignal(int deleteIndex);
50 | public slots:
51 | /*添加客户端连接信息到界面中*/
52 | // void addClientIPTGUISlot(QString CIP,int CPort,int ID,int state);
53 | /*客户端主动断开连接*/
54 | void closeClientConnectSlot(QString clientIp, int clientPort, QDateTime current_date_time);
55 | /*添加文件夹*/
56 | void addFilePBSlot();
57 | /*删除文件列表条目*/
58 | void deleteFile();
59 | /*显示日志信息*/
60 | void displayInfoTGUISlot(QString CIP,int CPort,int state,QDateTime current_time);
61 | // void deleteFileListItem();
62 | // /*List Widget双击事件槽函数*/
63 | // void doubleClickedItem();
64 | /*删除消息内容*/
65 | void deleteInfo();
66 | /*传输文件按钮槽函数*/
67 | void fileTranferButtonSlot();
68 | /*消息传输按钮槽函数*/
69 | void infoTranferButtonSlot();
70 | /*发送状态在GUI中显示*/
71 | void sendStateDisplaySlot(QString msg, QString info);
72 | /*发送消息在GUI中显示*/
73 | void sendInfoDisplaySlot(QString clientInfo, QString ip);
74 | /*服务器主动断开槽函数*/
75 | void clientAddressSlot(QString IP, int clientPort);
76 | private:
77 | Ui::Widget *ui;
78 | /*断开客户端连接命令,1表示断开*/
79 | int closeCommand;
80 | /*存储添加的文件夹路径*/
81 | QString dirPath;
82 | /*文件列表指针*/
83 | FILE *fp;
84 | /*传输的消息内容*/
85 | QString info;
86 | /*本机IP*/
87 | QString ipAddress;
88 | QVector IPOrder; //记录listWidget_2里的客户端IP地址
89 | int index = 0; //记录listWidget_2当前索引
90 | /*断开连接 服务器 0 客户端 1*/
91 | int closeFlag_previous = 1;
92 | int closeFlag_current = 1;
93 | Myserver *server;
94 | /*目录列表存储结构体*/
95 | struct DirInformation{
96 | char fileName[260]; //文件名字
97 | char dirName[260]; //目录名字
98 | unsigned int isDirectory; //是否是目录
99 | unsigned int isFile; //是否是文件
100 | unsigned int topDir; //是否是顶层目录
101 | };
102 | struct DirInformation dirInfo;
103 | /*是目录*/
104 | void ISDir()
105 | {
106 | dirInfo.topDir = 0;
107 | strcpy(dirInfo.fileName," ");
108 | dirInfo.isDirectory = 1;
109 | dirInfo.isFile = 0;
110 | }
111 | /*是文件*/
112 | void ISFile()
113 | {
114 | dirInfo.topDir = 0;
115 | strcpy(dirInfo.dirName," ");
116 | dirInfo.isDirectory = 0;
117 | dirInfo.isFile = 1;
118 | }
119 |
120 | };
121 |
122 | #endif // WIDGET_H
123 |
--------------------------------------------------------------------------------
/Server/widget.h.autosave:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------
2 | #
3 | # Project created by QtCreator
4 | # Author: 打代码的小陈
5 | # Info: Qt5局域网多线程数据传输(服务端)实现
6 | # Url:https://shazhenyu.blog.csdn.net/article/details/81505832
7 | # Github:https://github.com/ShaShiDiZhuanLan/Demo_MessageChat_Qt
8 | #
9 | #-------------------------------------------------*/
10 | #ifndef WIDGET_H
11 | #define WIDGET_H
12 |
13 | #include
14 | #include "myserver.h"
15 | #include "debugonoroff.h"
16 | #include "qnchatmessage.h"
17 | class string;
18 | class QEvent;
19 | class Myserver;
20 | class QListWidgetItem;
21 | namespace Ui {
22 | class Widget;
23 | }
24 |
25 |
26 | class Widget : public QWidget
27 | {
28 | Q_OBJECT
29 |
30 | public:
31 | explicit Widget(QWidget *parent = 0);
32 | ~Widget();
33 | /*重新实现事件过滤器函数*/
34 | // bool eventFilter(QObject *watched, QEvent *event);
35 | /*消息框*/
36 | void dealMessage(QNChatMessage *messageW, QListWidgetItem *item, QString text, QString time, QNChatMessage::User_Type type);
37 | void dealMessageTime(QString curMsgTime);
38 | /*获得发送文件列表*/
39 | void getSendFileList(QString path);
40 | protected:
41 | void resizeEvent(QResizeEvent *event);
42 | /*深度优先递归遍历当前目录下文件夹和文件及子文件夹和文件*/
43 | // void DfsFolder(std::string path,int layer);
44 | /*层次遍历当前目录下的文件夹及子文件夹下的文件*/
45 | // bool TraverseFiles(std::string path,int &file_num);
46 | signals:
47 | /*客户端主动断开连接信号*/
48 | void closeClientConnectSignal(int disconnectCommand);
49 | /*客户端被动断开连接信号*/
50 | void clientDiconnectSignal(int ID);
51 | /*获得文件列表信号*/
52 | void getFileListSignal(QString filelist);
53 | /*发送文件信号*/
54 | void sendFileWidgetSignal(QString filename);
55 | /*发送消息信号*/
56 | void sendInfoWidgetSignal(QString info);
57 | /*服务器发送断开信号*/
58 | void clientAddressWidgetSignal(int deleteIndex);
59 | public slots:
60 | /*添加客户端连接信息到界面中*/
61 | // void addClientIPTGUISlot(QString CIP,int CPort,int ID,int state);
62 | /*客户端主动断开连接*/
63 | void closeClientConnectSlot(QString clientIp, int clientPort, QDateTime current_date_time);
64 | /*添加文件夹*/
65 | void addFilePBSlot();
66 | /*删除文件列表条目*/
67 | void deleteFile();
68 | /*显示日志信息*/
69 | void displayInfoTGUISlot(QString CIP,int CPort,int state,QDateTime current_time);
70 | // void deleteFileListItem();
71 | // /*List Widget双击事件槽函数*/
72 | // void doubleClickedItem();
73 | /*删除消息内容*/
74 | void deleteInfo();
75 | /*传输文件按钮槽函数*/
76 | void fileTranferButtonSlot();
77 | /*消息传输按钮槽函数*/
78 | void infoTranferButtonSlot();
79 | /*发送状态在GUI中显示*/
80 | void sendStateDisplaySlot(QString msg, QString info);
81 | /*发送消息在GUI中显示*/
82 | void sendInfoDisplaySlot(QString clientInfo, QString ip);
83 | /*服务器主动断开槽函数*/
84 | void clientAddressSlot(QString IP, int clientPort);
85 | private:
86 | Ui::Widget *ui;
87 | /*断开客户端连接命令,1表示断开*/
88 | int closeCommand;
89 | /*存储添加的文件夹路径*/
90 | QString dirPath;
91 | /*文件列表指针*/
92 | FILE *fp;
93 | /*传输的消息内容*/
94 | QString info;
95 | /*本机IP*/
96 | QString ipAddress;
97 | QVector IPOrder; //记录listWidget_2里的客户端IP地址
98 | int index = 0; //记录listWidget_2当前索引
99 | /*断开连接 服务器 0 客户端 1*/
100 | int closeFlag_previous = 1;
101 | int closeFlag_current = 1;
102 | Myserver *server;
103 | /*目录列表存储结构体*/
104 | struct DirInformation{
105 | char fileName[260]; //文件名字
106 | char dirName[260]; //目录名字
107 | unsigned int isDirectory; //是否是目录
108 | unsigned int isFile; //是否是文件
109 | unsigned int topDir; //是否是顶层目录
110 | };
111 | struct DirInformation dirInfo;
112 | /*是目录*/
113 | void ISDir()
114 | {
115 | dirInfo.topDir = 0;
116 | strcpy(dirInfo.fileName," ");
117 | dirInfo.isDirectory = 1;
118 | dirInfo.isFile = 0;
119 | }
120 | /*是文件*/
121 | void ISFile()
122 | {
123 | dirInfo.topDir = 0;
124 | strcpy(dirInfo.dirName," ");
125 | dirInfo.isDirectory = 0;
126 | dirInfo.isFile = 1;
127 | }
128 |
129 | };
130 |
131 | #endif // WIDGET_H
132 |
--------------------------------------------------------------------------------
/Server/widget.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Widget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 832
10 | 699
11 |
12 |
13 |
14 | Widget
15 |
16 |
17 |
18 |
19 | 14
20 | 11
21 | 808
22 | 677
23 |
24 |
25 |
26 | -
27 |
28 |
-
29 |
30 |
31 |
32 | 0
33 | 0
34 |
35 |
36 |
37 | 客户端状态:
38 |
39 |
40 |
41 | -
42 |
43 |
44 | -
45 |
46 |
47 |
48 | 0
49 | 0
50 |
51 |
52 |
53 | 文件信息:
54 |
55 |
56 |
57 | -
58 |
59 |
60 | -
61 |
62 |
-
63 |
64 |
-
65 |
66 |
67 | 选择文件
68 |
69 |
70 |
71 | -
72 |
73 |
74 | 删除文件
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | -
83 |
84 |
85 | 传输文件
86 |
87 |
88 |
89 | -
90 |
91 |
92 | 消息信息:
93 |
94 |
95 |
96 | -
97 |
98 |
99 |
100 | 16777215
101 | 100
102 |
103 |
104 |
105 |
106 | -
107 |
108 |
-
109 |
110 |
111 | 传输消息
112 |
113 |
114 |
115 | -
116 |
117 |
118 | 清空消息
119 |
120 |
121 |
122 |
123 |
124 | -
125 |
126 |
127 | 运行日志:
128 |
129 |
130 |
131 | -
132 |
133 |
134 |
135 |
136 | -
137 |
138 |
-
139 |
140 |
141 | 消息对话:
142 |
143 |
144 |
145 | -
146 |
147 |
148 |
149 | 330
150 | 0
151 |
152 |
153 |
154 |
155 | 330
156 | 16777215
157 |
158 |
159 |
160 | QListWidget{background-color: rgb(247, 247, 247); color:rgb(51,51,51); border: 1px solid rgb(247, 247, 247);outline:0px;}
161 | QListWidget::Item{background-color: rgb(247, 247, 247);}
162 | QListWidget::Item:hover{background-color: rgb(247, 247, 247); }
163 | QListWidget::item:selected{
164 | background-color: rgb(247, 247, 247);
165 | color:black;
166 | border: 1px solid rgb(247, 247, 247);
167 | }
168 | QListWidget::item:selected:!active{border: 1px solid rgb(247, 247, 247); background-color: rgb(247, 247, 247); color:rgb(51,51,51); }
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
--------------------------------------------------------------------------------