php网站建设的几个流程,移动网站建设学习,wordpress文章限时,男女做那个视频的网站目录功能结构adSever.promain.cpptcp_MSG.h 共用Tcp传输信息adsever.h 服务器adsever.cpp 服务器addate.h 时间处理addate.cpp 时间处理adtcp.h 客户端Socket处理adtcp.cpp 客户端Socket处理client.h 客户端信息类client.cpp 客户端信息类admsglist.h 信息记录模块admsglist.cp…
目录功能结构adSever.promain.cpptcp_MSG.h 共用Tcp传输信息adsever.h 服务器adsever.cpp 服务器addate.h 时间处理addate.cpp 时间处理adtcp.h 客户端Socket处理adtcp.cpp 客户端Socket处理client.h 客户端信息类client.cpp 客户端信息类admsglist.h 信息记录模块admsglist.cpp 信息记录模块weather.h 天气信息模块weather.cpp 天气信息模块ui效果源码难点下位机Qt广告机客户端下位机 功能
客户端列表下位机广告图片广播天气信息多选点播消息提醒广播日期显示模块 可以显示jpg、jpeg、png、bmp。可以从电脑上拖动图到窗口并显示出来或者打开文件选择 重载实现dragEnterEvent拖拽、dropEvent拖拽放下、resizeEvent窗口大小改变 发送消息历史记录及右键复制消息 结构 adSever.pro
QT core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11TARGET adSever
TEMPLATE appSOURCES main.cpp\addate.cpp \admsglist.cpp \adsever.cpp \adtcp.cpp \client.cpp \weather.cppHEADERS adsever.h \addate.h \admsglist.h \adtcp.h \client.h \tcp_MSG.h \weather.hFORMS adsever.uiRESOURCES \res.qrcmain.cpp
#include adsever.h
#include QApplication
#include QDebug
int main(int argc, char *argv[])
{QApplication a(argc, argv);// 判断当前运行环境是否为Linux或Windows。
#ifdef Q_OS_LINUXqDebug() Current OS is Linux;
#elif defined(Q_OS_WIN)qDebug() Current OS is Windows;
#elseqDebug() Unknown OS;
#endifAdSever w;w.show();return a.exec();
}tcp_MSG.h 共用Tcp传输信息
#ifndef TCP_MSG_H
#define TCP_MSG_H
#includeQMetaType
#define tcp_MSG_txt_NUM 256
#define tcp_MSG_city_NUM 32
#define tcp_MSG_weather_NUM 128
#define tcp_MSG_path_NUM 128
#define tcp_MSG_photo_NUM 1280*800
#pragma pack(1) //设置结构体为1字节对齐
typedef struct
{int type;// 消息类型char txt[tcp_MSG_txt_NUM];// 文字信息char city[tcp_MSG_city_NUM];// 城市char area[tcp_MSG_city_NUM];// 地区char weather[tcp_MSG_weather_NUM];// 天气char fileName[tcp_MSG_path_NUM];// 文件名int index; // 编号int allAd_Num;// 总数int fileSize;// 文件大小
}tcp_MSG;
#pragma pack() //结束结构体对齐设置
Q_DECLARE_METATYPE(tcp_MSG)
// 实现对象的元编程功能。它可以用来定义宏类型和函数以支持将元数据与类型关联起来。它还可以用来实现类型安全性类型转换和序列化功能。
//宏来注册tcp_MSG类型enum MsgType{Init0, // 初始化WEATHER, //天气MASSEGE,// 留言VIDEO, // 视频AD_add, // 添加广告AD_delete, // 删除广告Write_back,//回复
};#pragma pack(1) //设置结构体为1字节对齐
typedef struct
{int type;// 消息类型int state;// 状态 0不发送 1发送char id[32];// id
}tcp_backMSG;
#pragma pack() //结束结构体对齐设置
Q_DECLARE_METATYPE(tcp_backMSG)
//宏来注册tcp_backMSG类型#pragma pack(1) //设置结构体为1字节对齐
typedef struct
{int type;// 消息类型char photo[tcp_MSG_photo_NUM];
}tcp_Image;
#pragma pack() //结束结构体对齐设置
Q_DECLARE_METATYPE(tcp_Image)
//宏来注册tcp_Image类型#endif // TCP_MSG_Hadsever.h 服务器
#ifndef ADSEVER_H
#define ADSEVER_H#include QMainWindow
#include QClipboard
#include QMessageBox
#include QFile
#include QFileInfo
#include QFileDialog
#include QMovie
#include QDragEnterEvent
#include QDropEvent
#include QMimeData
#include adtcp.h
#include addate.h
#include tcp_MSG.h
#include string.h
#include admsglist.h
#include weather.hnamespace Ui {
class AdSever;
}class AdSever : public QMainWindow
{Q_OBJECTpublic:explicit AdSever(QWidget *parent 0);~AdSever();void dragEnterEvent(QDragEnterEvent *event)override;//拖进事件void dropEvent(QDropEvent *event)override;// 拖进放下事件void resizeEvent(QResizeEvent *event)override;//用于在窗口大小改变时处理事件QString GetLocalIP();// 获取本地IPvoid InitStatusBar();// 初始化底部状态栏private slots:void on_clear_msg_bt_clicked();// 清空void on_broast_msg_bt_clicked();// 广播void on_set_city_bt_clicked();//设置地区void GUI_WarningMsg(QString title,QString text,QString buttons,QString defaultButton);//设置警报void on_add_ad_bt_clicked();// 添加广告void on_delete_ad_bt_clicked();// 删除广告void qListWidget_clicked(const QModelIndex index);//广告列表点击void on_ad_sendAdd_bt_clicked();// 发送添加void on_ad_sendDelete_bt_clicked();// 发送删除private:Ui::AdSever *ui;AdTcp *tcpsever;AdDate *date;AdMsgList *msgList;QPixmap pixmap;QVectorQString photoPath;//存放照片相对路径的容器int num; //照片张数QLabel *mLocalIP;
};#endif // ADSEVER_H
adsever.cpp 服务器
#include adsever.h
#include ui_adsever.hAdSever::AdSever(QWidget *parent) :QMainWindow(parent),ui(new Ui::AdSever)
{ui-setupUi(this);this-setWindowIcon(QIcon(:/server.webp));ui-centralWidget-setLayout(ui-horizontalLayout_5);ui-horizontalLayout_5-setContentsMargins(5,5,5,5);date new AdDate(ui-date_lb);//时间date-start();//更新时间tcpsever new AdTcp(ui-client_lw);// 客户端列表下位机connect(tcpsever, SIGNAL(GUI_WarningSignal(QString,QString,QString,QString)), this, SLOT(GUI_WarningMsg(QString,QString,QString,QString)));msgListnew AdMsgList(ui-msg_lw);// 已经发送消息列表实现右键复制{// 广告模块this-setAcceptDrops(true);//设置允许向窗口拖入图片ui-video_lb-setAlignment(Qt::AlignCenter); //居中显示//自适应的labelpixmap充满窗口后无法缩小只能放大ui-video_lb-setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored);// Ignored忽略//不显示行向滚动条子项文本过长自动显示...ui-ad_lw-setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);num0; //照片张数connect(ui-ad_lw,SIGNAL(clicked(const QModelIndex )),this,SLOT(qListWidget_clicked(const QModelIndex )));// 内容是否自动缩放参数true自动缩放ui-video_lb-setScaledContents(true);//显示图片的全部}InitStatusBar();// 初始化底部状态栏
}AdSever::~AdSever()
{delete ui;
}//拖进事件
void AdSever::dragEnterEvent(QDragEnterEvent *event)
{// 如果文件的后缀名是jpg、jpeg、bmp或png则接受拖放事件否则忽略拖放事件QStringList acceptedFileTypes;acceptedFileTypes.append(jpg);acceptedFileTypes.append(jpeg);acceptedFileTypes.append(bmp);acceptedFileTypes.append(png);// 用于检查拖放的数据是否包含URL,并且获取拖放事件中的URL数量1if(event-mimeData()-hasUrls()event-mimeData()-urls().count()1){// 获取拖放事件中的第一个URL的本地文件路径QFileInfo file(event-mimeData()-urls().at(0).toLocalFile());// 检查文件的后缀名是否在接受的文件类型列表中;获取文件的后缀名并将其转换为小写字母if(acceptedFileTypes.contains(file.suffix().toLower())){event-acceptProposedAction();//表明用户可以在窗口部件上拖放对象[接受拖放事件的操作]}}
}// 拖进放下事件
void AdSever::dropEvent(QDropEvent *event)
{// 获取拖放事件中的第一个URL的本地文件路径QFileInfo file(event-mimeData()-urls().at(0).toLocalFile());qDebug()绝对路径:file.absoluteFilePath();//从文件中加载图片参数file.absoluteFilePath()表示文件的绝对路径load()返回一个bool值表示是否加载成功if(pixmap.load(file.absoluteFilePath())){// 将图片缩放到指定大小参数ui-label-size()表示缩放的大小Qt::KeepAspectRatio表示保持图片的宽高比Qt::SmoothTransformation表示使用平滑缩放算法ui-video_lb-setPixmap(pixmap.scaled(ui-video_lb-size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));ui-videoname_lb-setText(file.absolutePath());//显示打开的文件的绝对路径,这不包括文件名。photoPath.append(file.absoluteFilePath());// 把图片的路径装到容器中QListWidgetItem *item new QListWidgetItem(QIcon(file.absoluteFilePath()),file.fileName());//建立文件缩小图标item-setToolTip(file.fileName());// tip提示item-setTextAlignment(Qt::AlignCenter);//设置item项中的文字位置ui-ad_lw-addItem(item);//把图片相对路径显示到窗口中}else{// 错误消息框QMessageBox::critical(this,tr(Error),tr(The image file count not be read));}
}//用于在窗口大小改变时处理事件
int i0;
void AdSever::resizeEvent(QResizeEvent *event)
{Q_UNUSED(event);//忽略编译器发出的警告表明变量event未使用qDebug()窗口大小改变:i;if(!pixmap.isNull()){qDebug();ui-video_lb-setPixmap(pixmap.scaled(ui-video_lb-size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));}
}// 获取本地IP
QString AdSever::GetLocalIP()
{QListQHostAddress listQNetworkInterface::allAddresses();foreach(QHostAddress address,list){if(address.protocol()QAbstractSocket::IPv4Protocol){qDebug()address.toString();return address.toString();}}return ;
}// 初始化底部状态栏
void AdSever::InitStatusBar()
{mLocalIPnew QLabel(this);mLocalIP-setMinimumWidth(230);QString ip GetLocalIP();mLocalIP-setText(本地IP:tr(font color\red\%1/font).arg(ip));ui-statusBar-addWidget(mLocalIP);
}// 清空
void AdSever::on_clear_msg_bt_clicked()
{ui-msg_te-clear();
}// 广播
void AdSever::on_broast_msg_bt_clicked()
{// 获取文本内容QString info ui-msg_te-toPlainText();if(!info.isEmpty())// 是否空的{tcp_MSG msg{};msg.typeMsgType::MASSEGE;strcpy(msg.txt,info.toUtf8().data());// memcpy(msg.txt,info.toUtf8().data(),info.toUtf8().length());memset(msg.city,0,sizeof(msg.city));memset(msg.area,0,sizeof(msg.area));memset(msg.weather,0,sizeof(msg.weather));qDebug()广播发送信息info;tcpsever-broadcastMsg(msg);QListWidgetItem *item new QListWidgetItem(QString(QTime::currentTime().toString(hh:mm:ss)\tinfo));item-setToolTip(info);// tip提示item-setTextAlignment(Qt::AlignLeft);//设置item项中的文字位置ui-msg_lw-addItem(item);ui-msg_te-clear();}
}//设置地区
void AdSever::on_set_city_bt_clicked()
{if(ui-client_lw-selectedItems().isEmpty()){QMessageBox::warning(this,提示,请选择下位机);return;}if(ui-city_cb-currentText().isEmpty()||ui-distict_cb-currentText().isEmpty()){QMessageBox::warning(this,提示,请选择城市和地区);return;}// 获取文本内容QString city ui-city_cb-currentText();QString area ui-distict_cb-currentText();QString weather ui-weather_lb-text();tcp_MSG msg{};msg.typeMsgType::WEATHER;memset(msg.txt,0,sizeof(msg.txt));strcpy(msg.city,city.toUtf8().data());strcpy(msg.area,area.toUtf8().data());strcpy(msg.weather,weather.toUtf8().data());qDebug()发送天气;tcpsever-MultiSelectUnicastMsg(msg);}//设置警报
void AdSever::GUI_WarningMsg(QString title, QString text, QString buttons, QString defaultButton)
{Q_UNUSED(buttons)//忽略编译器发出的警告表明变量event未使用Q_UNUSED(defaultButton)QMessageBox::warning(this,title,text);return;
}// 添加广告
void AdSever::on_add_ad_bt_clicked()
{QFileDialog dialog(this);//文件选择窗口dialog.setNameFilter(tr(Images (*.jpg *.jpeg *.bmp *.png)));// 过滤器dialog.setFileMode(QFileDialog::AnyFile);//设置文件模式(文件/文件夹)任意文件无论是否存在QStringList fileNames;if (dialog.exec())fileNames dialog.selectedFiles();// 存所有选择的文件if(!fileNames.isEmpty()){if(pixmap.load(fileNames[0])){qDebug()文件名:fileNames[0];ui-video_lb-setPixmap(pixmap.scaled(ui-video_lb-size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));QFileInfo file(fileNames[0]);ui-videoname_lb-setText(file.absolutePath());//显示打开的文件的绝对路径,这不包括文件名。photoPath.append(file.absoluteFilePath());// 把图片的路径装到容器中QListWidgetItem *item new QListWidgetItem(QIcon(file.absoluteFilePath()),file.fileName());//建立文件缩小图标item-setToolTip(file.fileName());// tip提示item-setTextAlignment(Qt::AlignCenter);//设置item项中的文字位置ui-ad_lw-addItem(item);//把图片相对路径显示到窗口中}}
}
// 删除广告
void AdSever::on_delete_ad_bt_clicked()
{int deleteNum ui-ad_lw-row(ui-ad_lw-currentItem()); //获取当前点击的内容的行号if(deleteNum0)return;QListWidgetItem *itemui-ad_lw-takeItem(deleteNum);//删除该列表项delete item;//手工再释放该列表项占用的资源photoPath.takeAt(deleteNum);ui-video_lb-clear();qDebug()删除图片:deleteNum;
}//广告列表点击
void AdSever::qListWidget_clicked(const QModelIndex index)
{Q_UNUSED(index);//忽略编译器发出的警告表明变量event未使用num ui-ad_lw-row(ui-ad_lw-currentItem()); //获取当前点击的内容的行号qDebug()点击播放图片:num;QString tempDir;tempDir.clear();tempDirphotoPath.at(num); //从容器中找到要播放的照片的相对路径pixmap.load(tempDir);// 更新全局图片ui-video_lb-setPixmap(pixmap.scaled(ui-video_lb-size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));//显示图片
}// 发送添加
void AdSever::on_ad_sendAdd_bt_clicked()
{if(ui-client_lw-selectedItems().isEmpty()){QMessageBox::warning(this,提示,请选择下位机);return;}if(ui-ad_lw-selectedItems().isEmpty()){QMessageBox::warning(this,提示,请选择图片);return;}tcpsever-Ad_SendAction(MsgType::AD_add,photoPath.at(num),num,photoPath.count());
}// 发送删除
void AdSever::on_ad_sendDelete_bt_clicked()
{if(ui-client_lw-selectedItems().isEmpty()){QMessageBox::warning(this,提示,请选择下位机);return;}if(ui-ad_lw-selectedItems().isEmpty()){QMessageBox::warning(this,提示,请选择图片);return;}tcpsever-Ad_SendAction(MsgType::AD_delete,photoPath.at(num),num,photoPath.count());
}addate.h 时间处理
#ifndef ADDATE_H
#define ADDATE_H#include QTime
#include QDate
#include QLabel
#include QTimerclass AdDate : public QObject
{Q_OBJECT
public:AdDate(QLabel *_mlabel, QObject *parent 0);~AdDate();void start();// 定时器开启
public slots:void updateTime();// 定时器1s超时执行一次
private:QLabel *mlabel;QTimer *mtimer;
};#endif // ADDATE_Haddate.cpp 时间处理
#include addate.hAdDate::AdDate(QLabel *_mlabel, QObject *parent):QObject(parent)
{mlabel _mlabel;mtimer new QTimer;connect(mtimer, SIGNAL(timeout()), this, SLOT(updateTime()));mlabel-setAlignment(Qt::AlignCenter);// 居中QFont font;font.setFamilies(QStringList(微软雅黑));font.setPixelSize(30);mlabel-setFont(font);}AdDate::~AdDate()
{delete mtimer;
}void AdDate::start()
{mtimer-start(1000);
}void AdDate::updateTime()
{QString time QTime::currentTime().toString(hh:mm:ss)\nQDate::currentDate().toString(yy/MM/dd ddd);mlabel-setText(time);
}
adtcp.h 客户端Socket处理
#ifndef ADTCP_H
#define ADTCP_H#include QTcpServer
#include QTcpSocket
#include QHostAddress
#include QMessageBox
#include QList
#include QListWidget
#include QBuffer
#include QFileInfo
#include QTime
#include QNetworkInterface
#include client.h
#include tcp_MSG.hclass AdTcp : public QTcpServer
{Q_OBJECT
public:AdTcp(QListWidget *_client_lw, QObject *parent 0);~AdTcp();void broadcastMsg(tcp_MSG msg);// 文字 广播下发void MultiSelectUnicastMsg(tcp_MSG msg);// 天气 多选单播下发void Ad_SendAction(int action,QString path,int index,int allAd_Num);// 广告发送操作signals:void GUI_WarningSignal(QString title,QString text,QString buttons,QString defaultButton);//设置警报
public slots:void newClient();// 新的客户端连接void read_back();//读取客户端上传IDvoid rmClient();//删除客户端private:QListClient * *client_list;QListWidget *client_lw;QByteArray sendImage;
};#endif // ADTCP_H\adtcp.cpp 客户端Socket处理
#include adtcp.h
#include QDebug
#includeQVariant// QTcpSocket会自动处理大小端问题AdTcp::AdTcp(QListWidget *_client_lw, QObject *parent) :QTcpServer(parent)
{//注册tcp_MSG类型qRegisterMetaTypetcp_MSG(tcp_MSG);// 监听任意地址8888端口if(!listen(QHostAddress::Any, 8888)){//QMessageBox::warning(this, 服务器启动失败);close();}client_list new QListClient *;client_lw _client_lw;//设置多选项client_lw-setSelectionMode(QAbstractItemView::ExtendedSelection);// 每当有新的连接可用connect(this, SIGNAL(newConnection()), this, SLOT(newClient()));qDebug()init tcp;// connect(this, SIGNAL(), this, SLOT(newClient()));// connect(this, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(newClient()));
}AdTcp::~AdTcp()
{delete client_list;close();
}// 新的客户端连接
void AdTcp::newClient()
{Client *new_client new Client;// 与客户端链接,动态创建socket对象new_client-msocket this-nextPendingConnection();// 等待连接的//作为已连接的QTcpSocket对象返回下一个挂起连接/* 每当有新的输入数据时就会发出这个信号。请记住新传入的数据只报告一次;如果您不读取所有数据这个类会缓冲数据您可以稍后读取它但是除非新数据到达否则不会发出信号。*/connect(new_client-msocket, SIGNAL(readyRead()), this, SLOT(read_back()));// 该信号在套接字断开连接时发出connect(new_client-msocket, SIGNAL(disconnected()), this, SLOT(rmClient()));client_list-append(new_client);
}//读取客户端上传ID
void AdTcp::read_back()
{// 返回此信号的 发送对象QTcpSocket *getSocketqobject_castQTcpSocket *(sender());//读取缓冲区数据QByteArray buffer getSocket-readAll();//client_list-last()-msocket-readAll();// 读取最后客户端(也就是最新的)tcp_backMSG *msg(tcp_backMSG *)buffer.data(); //强转为结构体需要用结构体指针接收qDebug()消息类型msg-type;if(msg-typeMsgType::Initmsg-state0){QString id(msg-id);client_list-last()-id id;client_lw-addItem(id);// 添加项到 客户端列表下位机}else if(msg-typeMsgType::Write_backmsg-state1){qDebug()收到回复;// 记录开始时间QTime startTime QTime::currentTime();getSocket-write(sendImage);// 用于等待发送的数据被写入到网络套接字描述符中这样就可以确保数据完全被发送出去//该函数会阻塞程序继续执行直到数据被完全发送出去if (getSocket-waitForBytesWritten()){getSocket-flush(); //释放socket缓存}// 记录结束时间QTime endTime QTime::currentTime();// 计算运行时间int milsec startTime.msecsTo(endTime);qDebug()发送消耗时间milsec毫秒;}
}// 文字 广播下发
void AdTcp::broadcastMsg(tcp_MSG msg)
{QByteArray sendTcpData;//使用字节数组,将结构体转为字符数组发送的是字符数组数据在传输过程中都是byte类型的//直接sizeofsenddata内存会变小设置了对齐方式解决sendTcpData.resize(sizeof(tcp_MSG));//将封装好的结构体转为QByteArray数组因为传输都是Byte类型memcpy(sendTcpData.data(),msg,sizeof(tcp_MSG));int count client_list-size();qDebug()广播下发数量count;for(int i 0; i count; i){client_list-at(i)-msocket-write(sendTcpData);//往套接字缓存中写入数据并发送client_list-at(i)-msocket-flush(); //释放socket缓存}
}// 天气 多选单播下发
void AdTcp::MultiSelectUnicastMsg(tcp_MSG msg)
{QByteArray sendTcpData;//使用字节数组,将结构体转为字符数组发送的是字符数组数据在传输过程中都是byte类型的//直接sizeofsenddata内存会变小设置了对齐方式解决sendTcpData.resize(sizeof(tcp_MSG));//将封装好的结构体转为QByteArray数组因为传输都是Byte类型memcpy(sendTcpData.data(),msg,sizeof(tcp_MSG));if(client_list-size()!client_lw-count()){emit GUI_WarningSignal(提示,客户端存储数量出错,NULL,NULL);return;}QListQListWidgetItem * selectedItems client_lw-selectedItems();for (auto item : selectedItems){int index client_lw-row(item);qDebug() 选定 item: item-text();client_list-at(index)-msocket-write(sendTcpData);client_list-at(index)-msocket-flush();}
}// 广告发送操作
void AdTcp::Ad_SendAction(int action, QString path, int index, int allAd_Num)
{QByteArray sendTcpData;//使用字节数组,将结构体转为字符数组发送的是字符数组数据在传输过程中都是byte类型的//直接sizeofsenddata内存会变小设置了对齐方式解决sendTcpData.resize(sizeof(tcp_MSG));tcp_MSG msg{};msg.typeaction;QFileInfo file(path);strcpy(msg.fileName,file.fileName().toUtf8().data());msg.indexindex;msg.allAd_NumallAd_Num;if(actionMsgType::AD_add){QImage image(path);QByteArray byteArray;QBuffer buffer(byteArray);buffer.open(QIODevice::WriteOnly);//获取文件的后缀名并将其转换为大写字母qDebug()图片格式file.suffix().toUpper().toStdString().c_str();image.save(buffer,file.suffix().toUpper().toStdString().c_str()); //将图片保存为PNG/JPG等格式sendImage byteArray.toBase64();qDebug()图片size:sendImage.size();msg.fileSizesendImage.size();buffer.close();}else if(actionMsgType::AD_delete){}//将封装好的结构体转为QByteArray数组因为传输都是Byte类型memcpy(sendTcpData.data(),msg,sizeof(tcp_MSG));QListQListWidgetItem * selectedItems client_lw-selectedItems();for (auto item : selectedItems){int index client_lw-row(item);qDebug() 发送 item: item-text();client_list-at(index)-msocket-write(sendTcpData);client_list-at(index)-msocket-flush();}
}// 删除客户端
void AdTcp::rmClient()
{qDebug()客户端断开;// 返回此信号的 发送对象QTcpSocket *getSocketqobject_castQTcpSocket *(sender());// if(client_list-first()-msocket-isSequential())
// {
// client_lw-clear();
// }for(int i0;iclient_list-count();i){if(getSocketclient_list-at(i)-msocket){if(client_list-count()client_lw-count()){QListWidgetItem *itemclient_lw-takeItem(i);//删除该列表项delete item;//手工再释放该列表项占用的资源}client_list-takeAt(i);getSocket-deleteLater();//延时释放}}
}client.h 客户端信息类
#ifndef CLIENT_H
#define CLIENT_H#include QObject
#include QString
#include QTcpSocketclass Client
{// Q_OBJECT
public:explicit Client(QObject *parent 0);QString id;QTcpSocket *msocket;};#endif // CLIENT_Hclient.cpp 客户端信息类
#include client.hClient::Client(QObject *parent)
{Q_UNUSED(parent)//忽略编译器发出的警告表明变量event未使用msocket new QTcpSocket;
}admsglist.h 信息记录模块
#ifndef ADMSGLIST_H
#define ADMSGLIST_H#include QListWidget
#include QObject
#include QAction
#include QClipboard
#include QDebug
#include QApplication
class AdMsgList : public QObject
{Q_OBJECT
public:AdMsgList(QListWidget *_mlistWidget, QObject *parent 0);~AdMsgList();
private slots:void onCopyTriggered();// 触发Copy
private:QListWidget *mlistWidget;};#endif // ADMSGLIST_Hadmsglist.cpp 信息记录模块
#include admsglist.hAdMsgList::AdMsgList(QListWidget *_mlistWidget, QObject *parent):QObject(parent)
{mlistWidget_mlistWidget;//不显示行向滚动条子项文本过长自动显示...mlistWidget-setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);mlistWidget-setContextMenuPolicy(Qt::ActionsContextMenu);//设置右键菜单QAction *copyAction new QAction(Copy, mlistWidget);copyAction-setShortcut(QKeySequence::Copy); //设置快捷键mlistWidget-addAction(copyAction);//连接action的triggered信号和槽函数connect(copyAction, SIGNAL(triggered()), this, SLOT(onCopyTriggered()));
}AdMsgList::~AdMsgList()
{}
// 触发Copy
void AdMsgList::onCopyTriggered()
{//获取当前actionQAction *action qobject_castQAction*(sender());if (actionmlistWidget-currentItem()){//获取要复制的内容QString content mlistWidget-currentItem()-toolTip();qDebug()mlistWidget-currentRow()行获取要复制的内容:content;//将内容复制到剪贴板QClipboard *clipboard QApplication::clipboard();clipboard-setText(content);}
}weather.h 天气信息模块
#ifndef WEATHER_H
#define WEATHER_H#include QObject
#include QLabel
#include QComboBoxclass Weather : public QObject
{Q_OBJECT
public:explicit Weather(QLabel *_wlabel,QComboBox *_cityComboBox,QComboBox *_areaComboBox,QObject *parent 0);signals:public slots:void showWeather(QString weather);private:QLabel *weather_label;QComboBox *city_comboBox;QComboBox *area_comboBox;
};#endif // WEATHER_Hweather.cpp 天气信息模块
#include weather.hWeather::Weather(QLabel *_wlabel,QComboBox *_cityComboBox,QComboBox *_areaComboBox,QObject *parent) :QObject(parent)
{weather_label _wlabel;city_comboBox _cityComboBox;area_comboBox _areaComboBox;
}void Weather::showWeather(QString weather)
{weather_label-setText(weather);
}ui 效果 源码 有道云 难点
QTcpSocket发送和接收使用 自定义 信息结构体 结构体需要1字节对齐 ,参考Qt 利用TCP/IP socket通信 发送与接收结构体简单通信协议解析 发送
QByteArray sendTcpData;
//使用字节数组,将结构体转为字符数组发送的是字符数组数据在传输过程中都是byte类型的
//直接sizeofsenddata内存会变小设置了对齐方式解决
sendTcpData.resize(sizeof(tcp_MSG));//将封装好的结构体转为QByteArray数组因为传输都是Byte类型
memcpy(sendTcpData.data(),msg,sizeof(tcp_MSG));socket-write(sendTcpData);接收
//读取缓冲区数据
QByteArray buffer readAll();tcp_MSG *msg(tcp_MSG *)buffer.data(); //强转为结构体需要用结构体指针接收发送图片 QTcpSocket 的默认缓存区大小是 64KB65536字节 图片一般比较大需要循环接收校验发送长度和接收长度 因为QTcpSocket是一个基于字节流的套接字它只能传输二进制数据。而图片文件是一种二进制文件不能直接传输。因此需要将图片文件转换为一种可传输的文本格式如Base64编码。 Base64编码是一种将二进制数据转换为ASCII字符的编码方式。它将每3个字节转换为4个字符因此可以将任何二进制数据转换为一种文本格式方便传输 本项目发送图片使用 先 服务器下发消息类型,客户端回复并开启图片接收 服务器 再 把图片发给 回复的客户端 发送
*在adtcp.cpp的Ad_SendAction()中先下发消息类型
{QFileInfo file(path);QImage image(path);QByteArray byteArray;QBuffer buffer(byteArray);buffer.open(QIODevice::WriteOnly);//获取文件的后缀名并将其转换为大写字母image.save(buffer,file.suffix().toUpper().toStdString().c_str()); //将图片保存为PNG/JPG等格式sendImage byteArray.toBase64();msg.fileSizesendImage.size();buffer.close();
}*在adtcp.cpp的read_back()中先下发消息类型
{// 返回此信号的 发送对象QTcpSocket *getSocketqobject_castQTcpSocket *(sender());//读取缓冲区数据QByteArray buffer getSocket-readAll();//client_list-last()-msocket-readAll();// 读取最后客户端(也就是最新的)tcp_backMSG *msg(tcp_backMSG *)buffer.data(); //强转为结构体需要用结构体指针接收else if(msg-typeMsgType::Write_backmsg-state1){getSocket-write(sendImage);// 用于等待发送的数据被写入到网络套接字描述符中这样就可以确保数据完全被发送出去//该函数会阻塞程序继续执行直到数据被完全发送出去if (getSocket-waitForBytesWritten()){getSocket-flush(); //释放socket缓存}}}接收
* 在adsocket.cpp的readMsg()先回复并开启图片接收
{//读取缓冲区数据QByteArray buffer readAll();tcp_MSG *msg(tcp_MSG *)buffer.data(); //强转为结构体需要用结构体指针接收needFileSizemsg-fileSize;// 需要接收图片大小QByteArray sendTcpData;//使用字节数组,将结构体转为字符数组发送的是字符数组数据在传输过程中都是byte类型的//直接sizeofsenddata内存会变小设置了对齐方式解决sendTcpData.resize(sizeof(tcp_backMSG));tcp_backMSG backMsg{};strcpy(backMsg.id,id.toUtf8().data());backMsg.state1;backMsg.typeMsgType::Write_back;//将封装好的结构体转为QByteArray数组因为传输都是Byte类型memcpy(sendTcpData.data(),backMsg,sizeof(tcp_backMSG));this-write(sendTcpData);// 回复
}* 在adsocket.cpp的readMsg()图片接收
{QByteArray buffer readAll();qDebug()需要接收大小needFileSize;currentReceiveSizebuffer.size();currentReceiveBytebuffer;//当前累计接收大小if(needFileSizecurrentReceiveSize){qDebug()图片接收完成;QByteArray Ret_bytearray QByteArray::fromBase64(currentReceiveByte);QBuffer buffer(Ret_bytearray);buffer.open(QIODevice::WriteOnly);QPixmap imageresult;imageresult.loadFromData(Ret_bytearray);QImage picimageresult.toImage();}
}