commit 89b4182e6c17d949e50e794f81824129831d39d4 Author: Msy-msu <2200456405@qq.com> Date: Thu Jan 5 20:52:31 2023 +0800 first commit diff --git a/TcpClient.pro b/TcpClient.pro new file mode 100644 index 0000000..a04066e --- /dev/null +++ b/TcpClient.pro @@ -0,0 +1,39 @@ +QT += core gui network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + login.cpp \ + datamanager.cpp \ + mainwidget.cpp \ + protocol.cpp \ + signup.cpp \ + tcpclient.cpp + +HEADERS += \ + login.h \ + datamanager.h \ + mainwidget.h \ + protocol.h\ + signup.h \ + tcpclient.h + +FORMS += \ + login.ui \ + mainwidget.ui \ + signup.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +RESOURCES += \ + imgs/imgs.qrc diff --git a/TcpClient.pro.user b/TcpClient.pro.user new file mode 100644 index 0000000..fdb8bef --- /dev/null +++ b/TcpClient.pro.user @@ -0,0 +1,432 @@ + + + + + + EnvironmentId + {d3fed20c-1c94-44fc-8f6a-4dbf39b54775} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + false + true + false + 0 + true + true + 0 + 8 + true + false + 1 + true + true + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + + 0 + true + + -fno-delayed-template-parsing + + true + Builtin.BuildSystem + + true + true + Builtin.DefaultTidyAndClazy + 4 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 6.2.3 MinGW 64-bit + Desktop Qt 6.2.3 MinGW 64-bit + qt.qt6.623.win64_mingw_kit + 0 + 0 + 0 + + 0 + C:\Users\25761\Desktop\build-TcpClient-Desktop_Qt_6_2_3_MinGW_64_bit-Debug + C:/Users/25761/Desktop/build-TcpClient-Desktop_Qt_6_2_3_MinGW_64_bit-Debug + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + + C:\Users\25761\Desktop\build-TcpClient-Desktop_Qt_6_2_3_MinGW_64_bit-Release + C:/Users/25761/Desktop/build-TcpClient-Desktop_Qt_6_2_3_MinGW_64_bit-Release + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + + + 0 + C:\Users\25761\Desktop\build-TcpClient-Desktop_Qt_6_2_3_MinGW_64_bit-Profile + C:/Users/25761/Desktop/build-TcpClient-Desktop_Qt_6_2_3_MinGW_64_bit-Profile + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + true + + 2 + + TcpClient2 + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/25761/Desktop/tcpclient/TcpClient.pro + C:/Users/25761/Desktop/tcpclient/TcpClient.pro + false + true + true + false + true + C:/Users/25761/Desktop/build-TcpClient-Desktop_Qt_6_2_3_MinGW_64_bit-Debug + + 1 + + + + ProjectExplorer.Project.Target.1 + + Desktop + Desktop Qt 6.2.3 MSVC2019 64bit + Desktop Qt 6.2.3 MSVC2019 64bit + qt.qt6.623.win64_msvc2019_64_kit + 0 + 0 + 0 + + 0 + C:\Users\25761\Desktop\build-TcpClient-Desktop_Qt_6_2_3_MSVC2019_64bit-Debug + C:/Users/25761/Desktop/build-TcpClient-Desktop_Qt_6_2_3_MSVC2019_64bit-Debug + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + + C:\Users\25761\Desktop\build-TcpClient-Desktop_Qt_6_2_3_MSVC2019_64bit-Release + C:/Users/25761/Desktop/build-TcpClient-Desktop_Qt_6_2_3_MSVC2019_64bit-Release + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + + + 0 + C:\Users\25761\Desktop\build-TcpClient-Desktop_Qt_6_2_3_MSVC2019_64bit-Profile + C:/Users/25761/Desktop/build-TcpClient-Desktop_Qt_6_2_3_MSVC2019_64bit-Profile + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + true + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/25761/Desktop/TcpClient/TcpClient.pro + C:/Users/25761/Desktop/TcpClient/TcpClient.pro + false + true + true + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 2 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/datamanager.cpp b/datamanager.cpp new file mode 100644 index 0000000..c87c393 --- /dev/null +++ b/datamanager.cpp @@ -0,0 +1,69 @@ +#include "datamanager.h" + +DataManager::DataManager(QObject *parent) + : QObject{parent} +{ + qDebug() << "进入DataManager的构造函数"; + tcpclient = TCPClient::getInstance(); + connect(tcpclient,&TCPClient::TCPClientConnected,this,&DataManager::TCPClientConnected); + connect(tcpclient,&TCPClient::TCPClientDisconnected,this,&DataManager::TCPClientDisconnected); + tcpclient->configAndrun(); + tcpclient->setCallBack(recv_from_server); + protocol = Protocol::getInstance(); + +} + +DataManager* DataManager::getInstance() +{ + static DataManager datamanager_instance; + return &datamanager_instance; +} + +void DataManager::TCPClientConnected() +{ + connect_flag = true; + qDebug() << "emit connect_to_server successfully"; + emit connect_to_server(); +} + +void DataManager::TCPClientDisconnected() +{ + connect_flag = false; + qDebug() << "emit disconnect_from_server successfully"; + emit disconnect_from_server(); +} + +void DataManager::recv_from_server(QString &peerAddress, quint16 peerPort, QByteArray &data) +{ + // +} + +void DataManager::Register(QString username,QString password) +{ + +} + +void DataManager::signin_request(QString username,QString password) +{ + +} + +void DataManager::send_text(QString text) +{ + +} + +void DataManager::send_file_to_all(QByteArray file) +{ + +} + +void DataManager::send_file_private(QByteArray file,QString name) +{ + +} + +void DataManager::account_cancellation(QString username) +{ + +} diff --git a/datamanager.h b/datamanager.h new file mode 100644 index 0000000..705156b --- /dev/null +++ b/datamanager.h @@ -0,0 +1,48 @@ +#ifndef DATAMANAGER_H +#define DATAMANAGER_H + +#include +#include + +#include "protocol.h" +#include "tcpclient.h" + +class DataManager : public QObject +{ + Q_OBJECT +public: + explicit DataManager(QObject *parent = nullptr); + static void recv_from_server(QString &peerAddress,quint16 peerPort,QByteArray &data); + static DataManager* getInstance(); + +private: + Protocol *protocol; + TCPClient *tcpclient; + QString username; + QString password; + bool connect_flag = false; + +signals: + void connect_to_server(); + void disconnect_from_server(); + void signin_response(bool result); + void signup_response(bool result); + +public slots: + /*******ui界面********/ + void Register(QString username,QString password); + void signin_request(QString username,QString password); + + /******MAINWIDGET*****/ + void send_text(QString text); + void send_file_to_all(QByteArray file); + void send_file_private(QByteArray file,QString name); + void account_cancellation(QString username); + + /******TCPClient******/ + void TCPClientConnected(); + void TCPClientDisconnected(); + +}; + +#endif // DATAMANAGER_H diff --git a/imgs/background.png b/imgs/background.png new file mode 100644 index 0000000..8d8a990 Binary files /dev/null and b/imgs/background.png differ diff --git a/imgs/blue.png b/imgs/blue.png new file mode 100644 index 0000000..1d75deb Binary files /dev/null and b/imgs/blue.png differ diff --git a/imgs/close.png b/imgs/close.png new file mode 100644 index 0000000..6017c93 Binary files /dev/null and b/imgs/close.png differ diff --git a/imgs/icon.png b/imgs/icon.png new file mode 100644 index 0000000..9bf75cd Binary files /dev/null and b/imgs/icon.png differ diff --git a/imgs/imgs.qrc b/imgs/imgs.qrc new file mode 100644 index 0000000..ff709f0 --- /dev/null +++ b/imgs/imgs.qrc @@ -0,0 +1,8 @@ + + + background.png + blue.png + close.png + icon.png + + diff --git a/login.cpp b/login.cpp new file mode 100644 index 0000000..6b9f665 --- /dev/null +++ b/login.cpp @@ -0,0 +1,224 @@ +#include "login.h" +#include "ui_login.h" + +Login::Login(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::Login) +{ + /**********ui_init**********/ + ui->setupUi(this); + this->setWindowIcon(QIcon(":/icon.png")); + this->setWindowFlags(Qt::FramelessWindowHint); //无边框 + this->setAttribute(Qt::WA_TranslucentBackground); + new_closebutton(ui->close_btn,":/close.png", QSize(30, 30)); + + /********datamanager********/ + datamanager = DataManager::getInstance(); + connect(datamanager,&DataManager::signin_response,this,&Login::signin_response); + connect(datamanager,&DataManager::signup_response,this,&Login::signup_response); + connect(datamanager,&DataManager::connect_to_server,this,&Login::connected); + connect(datamanager,&DataManager::disconnect_from_server,this,&Login::disconnected); + connect(this,&Login::signin_request,datamanager,&DataManager::signin_request); + connect(this,&Login::Register,datamanager,&DataManager::Register); + +} + +Login::~Login() +{ + delete ui; +} + +void Login::paintEvent(QPaintEvent *event) +{ + //创建画家,指定绘图设备 + // QPainter painter(this); + //创建QPixmap对象 + // QPixmap pix; + //加载图片 + // pix.load(":/sources/xxx.png"); + //绘制背景图 + // painter.drawPixmap(0,0,this->width(),this->height(),pix); + + //绘制样式 + // QBitmap bmp(this->size()); + // bmp.fill(); + // QPainter painter(&bmp); + // painter.setPen(Qt::NoPen); + // painter.setBrush(Qt::black); + // painter.setRenderHint(QPainter::Antialiasing); + // painter.drawRoundedRect(bmp.rect(), 6, 6); + // setMask(bmp); + + QPixmap pix; + pix.load(":/background.png"); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; + + painter.setPen(Qt::transparent); + QRect rect = this->rect(); // rect为绘制大小 + rect.setWidth(rect.width() - 1); + rect.setHeight(rect.height() - 1); + painter.drawRoundedRect(rect, 10, 10); // 10为圆角角度 + painter.drawPixmap(rect, pix); //绘制背景图 + + // painter.setBrush(QBrush(QColor(255,245,225,240))); + // painter.setPen(Qt::transparent); + //也可用QPainterPath 绘制代替 painter.drawRoundedRect(rect, 15, 15); + // QPainterPath painterPath; + // painterPath.addRoundedRect(rect, 15, 15);//15为圆角角度 + // painter.drawPath(painterPath); + + //设置阴影 + QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this); + shadow->setOffset(0, 0); //设置阴影距离 + shadow->setColor(QColor("#87CEFA")); //设置阴影颜色 + shadow->setBlurRadius(10); //设置阴影圆角 + ui->btn_signin->setGraphicsEffect(shadow); + ui->btn_signup->setGraphicsEffect(shadow); +} + +void Login::new_closebutton(QPushButton* btn, QString position,QSize size) +{ + QPixmap pixmap; + pixmap.load(position); + btn->setIconSize(size); + btn->setStyleSheet("QPushButton{border-width: 1px;border-style: solid;border-radius:15px;background-color: rgb(64, 145, 252);}" + "QPushButton:hover{background-color:#999999;}"); + //设置图标 + btn->setIcon(pixmap); +} + +void Login::mousePressEvent(QMouseEvent *event) +{ + if (event->buttons() == Qt::LeftButton) + { + point = event->pos(); + } +} + +void Login::mouseMoveEvent(QMouseEvent *event) +{ + if (event->buttons() == Qt::LeftButton) + { + //当窗口最大化或最小化时也不进行触发 + if (Login::isMaximized() || Login::isMinimized()) + { + return; + } + else + { + //当在按钮之类需要鼠标操作的地方不进行触发(防误触) + if (ui->btn_signin->underMouse() || ui->btn_signup->underMouse()) + { + return; + } + else + { + Login::move(Login::mapToGlobal(event->pos() - point)); + } + } + } + event->accept(); +} + +void Login::on_btn_signin_clicked() +{ + if(connect_flag == true) + { + user = ui->lineEdit_username->text(); + passwd = ui->lineEdit_password->text(); + if(user.isEmpty() || passwd.isEmpty()) + { + QMessageBox::warning(this,tr("错误"),tr("用户名和密码不能为空!")); + } + emit signin_request(user,passwd); + } + else + { + QMessageBox::warning(this, "登录失败", "尚未连接服务器!"); + return; + } +} + +void Login::on_btn_signup_clicked() +{ + signup = new Signup(); + connect(signup,&Signup::show_login_ui,this,&Login::show_login_ui); + connect(signup,&Signup::Register,this,&Login::slot_Register); + this->hide(); + signup->show(); +} + +void Login::on_close_btn_clicked() +{ + this->close(); +} + +void Login::show_login_ui() +{ + this->show(); +} + +//等待服务器验证登陆数据 +void Login::signin_response(bool result) +{ + if(result == true) + { + mainwidget = new MainWidget(user); + connect(mainwidget,&MainWidget::send_text,datamanager,&DataManager::send_text); + connect(mainwidget,&MainWidget::send_file_private,datamanager,&DataManager::send_file_private); + connect(mainwidget,&MainWidget::send_file_to_all,datamanager,&DataManager::send_file_to_all); + connect(mainwidget,&MainWidget::account_cancellation,datamanager,&DataManager::account_cancellation); + connect(mainwidget,&MainWidget::exit_client,this,&Login::exit_client); + this->hide(); + mainwidget->show(); + } + else + { + QMessageBox::warning(this,tr("登录失败"),tr("用户名或密码错误!")); + } +} + +void Login::slot_Register(QString username,QString password) +{ + if(connect_flag == false) + { + QMessageBox::warning(signup, "注册失败", "尚未连接服务器!请连接服务器后重试"); + return; + } + emit Register(username,password); +} + +//等待服务器注册数据 +void Login::signup_response(bool result) +{ + if(result == true) + { + QString information = QString("请妥善保存您的用户名和密码!"); + QMessageBox::information(signup,tr("注册成功"),information); + } + else + { + QMessageBox::warning(signup,tr("错误"),tr("注册失败,请重试!")); + } +} + +//连接上服务器 +void Login::connected() +{ + qDebug() << "connect to server"; + connect_flag = true; +} + +//未连上服务器或服务器断开 +void Login::disconnected() +{ + qDebug() << "disconnect from server"; + connect_flag = false; +} + +void Login::exit_client() +{ + this->close(); +} diff --git a/login.h b/login.h new file mode 100644 index 0000000..d07f473 --- /dev/null +++ b/login.h @@ -0,0 +1,65 @@ +#ifndef LOGIN_H +#define LOGIN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mainwidget.h" +#include "signup.h" +#include "datamanager.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class Login; } +QT_END_NAMESPACE + +class Login : public QMainWindow +{ + Q_OBJECT + +public: + explicit Login(QWidget *parent = nullptr); + ~Login(); + void paintEvent(QPaintEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void new_closebutton(QPushButton* btn, QString position,QSize size); + +signals: + void signin_request(QString username,QString password); + void Register(QString username,QString password); + +private slots: + void on_btn_signin_clicked(); + void on_btn_signup_clicked(); + void on_close_btn_clicked(); + + void signin_response(bool result); + void signup_response(bool result); + void show_login_ui(); + void slot_Register(QString username,QString password); + void connected(); + void disconnected(); + void exit_client(); + +private: + Ui::Login *ui; + QPoint point; + QString user,passwd; + static Login login_instance; + Login *login; + Signup *signup; + MainWidget *mainwidget; + DataManager *datamanager; + bool connect_flag = false; + +}; + +#endif // LOGIN_H diff --git a/login.ui b/login.ui new file mode 100644 index 0000000..02b9b22 --- /dev/null +++ b/login.ui @@ -0,0 +1,162 @@ + + + Login + + + + 0 + 0 + 946 + 665 + + + + MainWindow + + + + + + 480 + 410 + 71 + 40 + + + + + 50 + 40 + + + + background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, +stop:1 rgba(64, 145, 252, 255), +stop:0 rgba(220, 255, 255, 255)); +color: rgb(255, 255, 255); + +border:0px groove gray;border-radius: +7px;padding:2px 4px; +font: 14pt "Candara"; + + + Sign in + + + + + + 450 + 270 + 289 + 45 + + + + + 0 + 45 + + + + background-color: rgb(247, 247, 247); +border:1px groove gray;border-radius: +7px;padding:2px 4px; +font: 12pt "Candara"; + + + Please input your ID + + + + + + 630 + 410 + 79 + 40 + + + + + 50 + 40 + + + + background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, +stop:1 rgba(64, 145, 252, 255), +stop:0 rgba(220, 255, 255, 255)); +color: rgb(255, 255, 255); + +border:0px groove gray;border-radius: +7px;padding:2px 4px; +font: 14pt "Candara"; + + + Sign up + + + + + + 820 + 140 + 31 + 31 + + + + + + + + + + 450 + 330 + 289 + 45 + + + + + 0 + 45 + + + + background-color: rgb(247, 247, 247); +border:1px groove gray;border-radius: +7px;padding:2px 4px; +font: 12pt "Candara"; + + + QLineEdit::Password + + + Please input your password + + + + + + 500 + 200 + 191 + 51 + + + + font: 87 20pt "Arial Black"; +background:transparent; + + + Login Now + + + + + + + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..05aeac6 --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "login.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Login w; + w.show(); + return a.exec(); +} diff --git a/mainwidget.cpp b/mainwidget.cpp new file mode 100644 index 0000000..92c88b1 --- /dev/null +++ b/mainwidget.cpp @@ -0,0 +1,232 @@ +#include "mainwidget.h" +#include "ui_mainwidget.h" + +MainWidget::MainWidget(QString username,QWidget *parent) : + QWidget(parent), + ui(new Ui::MainWidget) +{ + ui->setupUi(this); + this->setWindowIcon(QIcon(":/icon.png")); + this->setWindowTitle("TCP聊天室"); + ui->name_list->setEditTriggers(QAbstractItemView::NoEditTriggers); //不允许编辑 + ui->name_list->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + ui->name_list->verticalScrollBar()->setStyleSheet("QScrollBar{width:16px;}"); + ui->textEdit->setReadOnly(true); + ui->send_btn->setFocus(); + ui->send_btn->setDefault(true); + ui->msg_edit->installEventFilter(this);//设置完后自动调用其eventFilter函数 + this->username = username; +} + +MainWidget::~MainWidget() +{ + delete ui; +} + +void MainWidget::on_send_text_clicked() +{ + QString homePath = QDir::homePath(); + QString filePath = QFileDialog::getOpenFileName(this, tr("Open a file"), homePath, tr("All files (*.*)"), NULL, QFileDialog::DontResolveSymlinks); + + QString filename = filePath.section("/", -1); + + if (filename.isEmpty()) + return; + + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "发送文件", tr("Do you want to send \"%1\"?").arg(filename)); + + if (reply == QMessageBox::No) + return; + else + { + QString currentTime = QTime::currentTime().toString("H:mm A"); + ui->textEdit->append("" + username + " [" + currentTime + "] send a file \"" + filename + "\""); + + QString name = ui->msg_edit->text(); + if(name.isEmpty()) //群发 + { + this->sendFile(filePath,filename); + } + else //私发文件 + { + this->sendFile(filePath,filename,name); + } + QProgressDialog *progressDlg = new QProgressDialog(this); + progressDlg->setWindowModality(Qt::WindowModal); + progressDlg->setMinimumDuration(0); + progressDlg->setAttribute(Qt::WA_DeleteOnClose, true); + progressDlg->setWindowTitle(tr("上传文件")); + progressDlg->setLabelText(tr("正在上传......")); + progressDlg->setCancelButtonText(tr("取消")); + progressDlg->setRange(0, 8000); + for (int i = 1; i < 8000; i++) + { + progressDlg->setValue(i); + if (progressDlg->wasCanceled()) + { + break; + } + } + progressDlg->close(); + } +} + +void MainWidget::on_save_btn_clicked() +{ + QFile file("memory.txt"); + if (file.exists()) //文件存在 + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "提示", tr("是否覆盖之前的聊天记录?")); + if (reply == QMessageBox::No) + { + if (file.open(QIODevice::WriteOnly | QIODevice::Append)) + { + QTextStream stream(&file); + //转换为字符串 + QString str = ui->textEdit->toPlainText(); + str = "\n\n" + str; + //写入文本流 + stream << str; + //关闭文件 + file.close(); + } + } + else + { + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + QTextStream stream(&file); + //转换为字符串 + QString str = ui->textEdit->toPlainText(); + //写入文本流 + stream << str; + //关闭文件 + file.close(); + } + } + } + + else + { + QMessageBox::warning(this, "提示", tr("打开文件失败,已为您自动创建文件!")); + file.open(QIODevice::WriteOnly | QIODevice::Append); + } +} + +void MainWidget::on_send_btn_clicked() +{ + QString text; + text = ui->msg_edit->text(); + if(text.isEmpty()) + { + QMessageBox::warning(this, "发送失败", "输入不能为空!"); + return; + } + ui->msg_edit->clear(); + QString currentTime = QTime::currentTime().toString("H:m A"); + ui->textEdit->append("" + username + " [" + currentTime + "] : " + text + ""); + emit send_text(text); +} + + +void MainWidget::on_name_list_itemDoubleClicked(QListWidgetItem *item) +{ + QString client_name = ui->name_list->currentItem()->text(); + QString a = "@"; + a = a + client_name + " "; + ui->msg_edit->clear(); + ui->msg_edit->setText(a); +} + + +void MainWidget::on_exit_btn_clicked() +{ + QMessageBox::StandardButton response; + response = QMessageBox::question(this, "退出", tr("是否退出软件?")); + + if(response == QMessageBox::Yes) + { + emit exit_client(); + this->close(); + } + else + { + return; + } +} + + +void MainWidget::on_stop_clicked() +{ + QMessageBox::StandardButton response; + response = QMessageBox::question(this, "注销", tr("是否退出软件并注销账户?")); + + if(response == QMessageBox::Yes) + { + emit exit_client(); + emit account_cancellation(username); + this->close(); + } + else + { + return; + } +} + +void MainWidget::sendFile(QString filePath,QString filename,QString name) +{ + //通过fileTcpSocket发送文件 + + //发送的数据存入block中 + QByteArray block; + QFile file(filePath); + //打开文件,定义错误提醒 + if(!file.open(QIODevice::ReadOnly)){ + QMessageBox::warning(this,"","无法打开文件!"); + return; + } + //打开文件流,以写的方式打开 + QDataStream out(&block,QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_5_8); + QString command = filename+"\n"; + out << command; + //将数据读取到QByteArray + QByteArray dataOfFile = file.readAll(); + //关闭文件 + file.close(); + //放入block + block.append(dataOfFile); + + if(name.isEmpty()) //群发文件 + { + emit send_file_to_all(block); + } + + else //私发文件 + { + emit send_file_private(block,name); + } +} + +bool MainWidget::eventFilter(QObject *target, QEvent *event) +{ + if(target == ui->msg_edit) //可替换 + { + if(event->type() == QEvent::KeyPress)//回车键 + { + QKeyEvent *k = static_cast(event); + + if(k->key() == Qt::Key_Return || k->key() == Qt::Key_Enter) + { + on_send_btn_clicked(); //替换为需要响应的函数事件,以这里的按钮为例 + return true; + } + } + } + return QWidget::eventFilter(target,event); +} + + + diff --git a/mainwidget.h b/mainwidget.h new file mode 100644 index 0000000..50be97c --- /dev/null +++ b/mainwidget.h @@ -0,0 +1,54 @@ +#ifndef MAINWIDGET_H +#define MAINWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ui { +class MainWidget; +} + +class MainWidget : public QWidget +{ + Q_OBJECT + +public: + explicit MainWidget(QString username,QWidget *parent = nullptr); + ~MainWidget(); + void sendFile(QString filePath,QString filename,QString name = ""); + bool eventFilter(QObject *target, QEvent *event); + +signals: + void send_text(QString text); + void send_file_to_all(QByteArray file); + void send_file_private(QByteArray file,QString name); + void exit_client(); + void account_cancellation(QString username); + +private slots: + void on_send_text_clicked(); + + void on_save_btn_clicked(); + + void on_send_btn_clicked(); + + void on_name_list_itemDoubleClicked(QListWidgetItem *item); + + void on_exit_btn_clicked(); + + void on_stop_clicked(); + +private: + Ui::MainWidget *ui; + QString username; +}; + +#endif // MAINWIDGET_H diff --git a/mainwidget.ui b/mainwidget.ui new file mode 100644 index 0000000..ae4d1c9 --- /dev/null +++ b/mainwidget.ui @@ -0,0 +1,231 @@ + + + MainWidget + + + + 0 + 0 + 798 + 587 + + + + Form + + + + + 50 + 510 + 401 + 31 + + + + + + + 发送文件 + + + + + + + 保存聊天记录 + + + + + + + + + 520 + 510 + 211 + 31 + + + + + + + 退出聊天 + + + + + + + 注销用户 + + + + + + + + + 50 + 30 + 401 + 421 + + + + + + + 520 + 30 + 211 + 441 + + + + + + + font: 12pt "Arial Black"; + + + 在线用户列表 + + + + + + + QListWidget { outline: none; border:1px solid white; color: #696969;} + QListWidget::Item { width: 60px; height: 40px; } + QListWidget::Item:hover { background: #FFA500; color: white; } + QListWidget::item:selected { background: #FFC0CB; color: #DC143C; } + QListWidget::item:selected:!active { background: blue; } + +QScrollBar:vertical +{ + width:8px; + background:rgba(0,0,0,0%); + margin:0px,0px,0px,0px; + padding-top:16px; + padding-bottom:16px; +} +QScrollBar::handle:vertical +{ + width:8px; + background:rgba(0,0,0,25%); + border-radius:4px; + min-height:20; +} +QScrollBar::handle:vertical:hover +{ + width:8px; + background:rgba(0,0,0,50%); + border-radius:4px; + min-height:20; +} +/* +QScrollBar::add-line:vertical +{ + height:9px;width:8px; + subcontrol-position:bottom; +} +QScrollBar::sub-line:vertical +{ + height:9px;width:8px; + subcontrol-position:top; +} +QScrollBar::add-line:vertical:hover +{ + height:9px;width:8px; + subcontrol-position:bottom; +} +QScrollBar::sub-line:vertical:hover +{ + height:9px;width:8px; + subcontrol-position:top; +} + +QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical +{ + background:rgba(0,0,0,10%); + border-radius:4px; +}*/ + + + + 新建项目 + + + + + 新建项目 + + + + + 新建项目 + + + + + 新建项目 + + + + + 新建项目 + + + + + 新建项目 + + + + + 新建项目 + + + + + 新建项目 + + + + + 新建项目 + + + + + + + + + + 50 + 460 + 401 + 31 + + + + + + + + + + 发送 + + + + + + + + + diff --git a/protocol.cpp b/protocol.cpp new file mode 100644 index 0000000..98db9b4 --- /dev/null +++ b/protocol.cpp @@ -0,0 +1,152 @@ +#include "protocol.h" +#include +#include + +Protocol Protocol::protocol_instance; +Protocol::Protocol(QObject *parent) + : QObject{parent} +{ + +} + +Protocol::~Protocol() +{ + +} + +Protocol* Protocol::getInstance() +{ + return &protocol_instance; +} + +QByteArray Protocol::data_builder(QList &args) +{ + QJsonObject data; + switch(args[0].get_data_types()) + { + case MESSAGE: + { + if (args.length()==2) + { + data.insert("type","message"); + data.insert("data",args[1].get_string()); + } + else if (args.length()==3) + { + data.insert("type","message"); + data.insert("to_user",args[1].get_string()); + data.insert("data",args[2].get_string()); + } + break; + } + case FILE: + { + data.insert("type","file"); + data.insert("name",args[1].get_string()); + data.insert("data",args[2].get_string()); + break; + } + case REQUEST: + { + data.insert("type","request"); + data.insert("action",args[1].get_string()); + QList content = args[2].get_list(); + QJsonObject json_content; + for (int i=0; i users = args[2].get_list(); + QJsonArray json_users; + for (auto &user:users) + json_users.append(user); + data.insert("users",json_users); + break; + } + case RESPONSE: + { + data.insert("type","response"); + data.insert("action",args[1].get_string()); + QList content = args[2].get_list(); + QJsonObject json_content; + for (int i=0; i Protocol::data_parser(QByteArray data) +{ + QJsonDocument json_data = QJsonDocument::fromJson(data); + if (json_data["type"] == "message") + return qMakePair(MESSAGE,json_data.object()); + else if (json_data["type"] == "file") + return qMakePair(FILE,json_data.object()); + else if (json_data["type"] == "request") + return qMakePair(REQUEST,json_data.object()); + else if (json_data["type"] == "online_users") + return qMakePair(ONLINEUSERS,json_data.object()); + else if (json_data["type"] == "response") + return qMakePair(RESPONSE,json_data.object()); + else + return qMakePair(RESPONSE,json_data.object()); +} + +QByteArray Protocol::XOR_En_Decrypt(QString src) +{ + QByteArray result; + for(auto &i:src) + result.append(i.toLatin1() ^ cipher_word); + return result; +} + +QByteArray Protocol::Upper_Lower_En_Decrypt(QString src) +{ + QByteArray result; + for(auto &i:src) + { + if(i.isUpper()) + { + QChar word = i.toLower(); + result.append(word.toLatin1()); + } + else if (i.isLower()) + { + QChar word = i.toUpper(); + result.append(word.toLatin1()); + } + else + result.append(i.toLatin1()); + } + return result; +} + +QByteArray Protocol::data_encrypt(QByteArray src) +{ + QByteArray en_base64 = src.toBase64(); + QByteArray result = Upper_Lower_En_Decrypt(en_base64); + return XOR_En_Decrypt(result); +} + +QByteArray Protocol::data_decrypt(QByteArray src) +{ + QByteArray result = XOR_En_Decrypt(src); + result = Upper_Lower_En_Decrypt(result); + return QByteArray::fromBase64(result); +} + +void Protocol::set_data_cipher_word(char word) +{ + cipher_word = word; +} diff --git a/protocol.h b/protocol.h new file mode 100644 index 0000000..8181b40 --- /dev/null +++ b/protocol.h @@ -0,0 +1,59 @@ +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#include +#include + +class Protocol : public QObject +{ + Q_OBJECT +public: + static Protocol* getInstance(); + template + QByteArray data_maker(Type type, Args ...args) + { + QList args_list; + args_list.append(any_types(type)); + (void)std::initializer_list {(args_list.append(any_types(args)),0)...}; + return data_builder(args_list); + }; + enum data_types {MESSAGE,FILE,REQUEST,ONLINEUSERS,RESPONSE}; + QPair data_parser(QByteArray data); + QByteArray data_encrypt(QByteArray src); + void set_data_cipher_word(char word); + QByteArray data_decrypt(QByteArray src); +private: + char cipher_word = 'G'; + struct any_types { + enum type {String, Bool, Int, Data_types, List}; + any_types(int e) { m_data.INT = e; m_type = Int;} + any_types(QString e) { m_data.STRING = e; m_type = String;} + any_types(QList e) { m_data.LIST = e; m_type = List;} + any_types(bool e) { m_data.BOOL = e; m_type = Bool;} + any_types(data_types e) { m_data.DATA_TYPES = e; m_type = Data_types;} + type get_type() const { return m_type; } + int get_int() const { return m_data.INT; } + bool get_bool() const { return m_data.BOOL; } + data_types get_data_types() const { return m_data.DATA_TYPES; } + QString get_string() const { return m_data.STRING; } + QList get_list() const { return m_data.LIST; } + private: + type m_type; + struct { + int INT; + bool BOOL; + QString STRING; + QList LIST; + data_types DATA_TYPES; + } m_data; + }; + static Protocol protocol_instance; + explicit Protocol(QObject *parent = nullptr); + ~Protocol(); + QByteArray data_builder(QList &args); + QByteArray XOR_En_Decrypt(QString src); + QByteArray Upper_Lower_En_Decrypt(QString src); +signals: + +}; +#endif // PROTOCOL_H diff --git a/signup.cpp b/signup.cpp new file mode 100644 index 0000000..516da3f --- /dev/null +++ b/signup.cpp @@ -0,0 +1,103 @@ +#include "signup.h" +#include "ui_signup.h" + +Signup::Signup(QWidget *parent) : QWidget(parent), + ui(new Ui::Signup) +{ + ui->setupUi(this); + QPixmap *pix = new QPixmap(":/blue.png"); + QSize sz = ui->label_image->size(); + ui->label_image->setPixmap(pix->scaled(sz)); + + this->setWindowIcon(QIcon(":/icon.png")); + this->setWindowFlags(Qt::FramelessWindowHint); //无边框 + + //设置阴影 + QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this); + shadow->setOffset(-3, 0); + shadow->setColor(QColor("#888888")); + shadow->setBlurRadius(30); + ui->label_image->setGraphicsEffect(shadow); +} + +Signup::~Signup() +{ + delete ui; +} + +//返回登录按钮 +void Signup::on_btn_return_clicked() +{ + this->close(); + emit show_login_ui(); +} + +//注册按钮 +void Signup::on_btn_sure_clicked() +{ + QString username = ui->lineEdit_username->text(); + QString password = ui->lineEdit_passwd->text(); + QString surepass = ui->lineEdit_surepasswd->text(); + if (username.isEmpty() || password.isEmpty() || surepass.isEmpty()) + { + QMessageBox::warning(this, "注册失败", "输入不能为空!"); + } + + else + { + if (password == surepass) + { + emit Register(username,password); + } + else + { + QMessageBox::information(this, "用户注册", "两次密码输入不一致!"); + } + } +} + +void Signup::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; + + painter.setPen(Qt::transparent); + QRect rect = this->rect(); // rect为绘制大小 + rect.setWidth(rect.width() - 1); + rect.setHeight(rect.height() - 1); + painter.drawRoundedRect(rect, 10, 10); // 10为圆角角度 +} + +void Signup::mousePressEvent(QMouseEvent *event) +{ + if (event->buttons() == Qt::LeftButton) + { + point = event->pos(); + } +} + +void Signup::mouseMoveEvent(QMouseEvent *event) +{ + if (event->buttons() == Qt::LeftButton) + { + //当窗口最大化或最小化时也不进行触发 + if (Signup::isMaximized() || Signup::isMinimized()) + { + return; + } + else + { + //当在按钮之类需要鼠标操作的地方不进行触发(防误触) + if (ui->btn_sure->underMouse() || ui->btn_return->underMouse()) + { + return; + } + else + { + Signup::move(Signup::mapToGlobal(event->pos() - point)); //移动 + } + } + } + event->accept(); +} + diff --git a/signup.h b/signup.h new file mode 100644 index 0000000..d5d8147 --- /dev/null +++ b/signup.h @@ -0,0 +1,44 @@ +#ifndef SIGNUP_H +#define SIGNUP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ui { +class Signup; +} + +class Signup : public QWidget +{ + Q_OBJECT + +public: + explicit Signup(QWidget *parent = nullptr); + ~Signup(); + void paintEvent(QPaintEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + +signals: + void Register(QString username,QString password); + void show_login_ui(); + +private slots: + void on_btn_sure_clicked(); + void on_btn_return_clicked(); + +private: + Ui::Signup *ui; + QPoint point; +}; + +#endif // SIGNUP_H diff --git a/signup.ui b/signup.ui new file mode 100644 index 0000000..1e3d913 --- /dev/null +++ b/signup.ui @@ -0,0 +1,211 @@ + + + Signup + + + + 0 + 0 + 780 + 520 + + + + Form + + + + + 390 + -10 + 391 + 531 + + + + TextLabel + + + + + + 60 + 150 + 271 + 344 + + + + + + + font: 10.5pt "Arial"; + + + Username + + + + + + + + 0 + 40 + + + + font: 12pt "Arial"; + + + + + + + font: 11pt "Arial"; + + + Password + + + + + + + + 0 + 40 + + + + font: 12pt "Arial"; + + + + + + + font: 10.5pt "Arial"; + + + Ensure your password: + + + + + + + + 0 + 40 + + + + font: 12pt "Arial"; + + + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + 0 + 40 + + + + background-color: rgb(29, 123, 255); +color: rgb(255, 255, 255); +font: 26 10pt "Bahnschrift Light"; + + + Sure + + + + + + + + 0 + 40 + + + + background-color: rgb(29, 123, 255); +color: rgb(255, 255, 255); +font: 26 10pt "Bahnschrift Light"; + + + Return login + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 60 + 80 + 301 + 51 + + + + font: 87 20pt "Arial Black"; + + + Welcome to us! + + + + + + 60 + 50 + 161 + 31 + + + + font: 87 20pt "Arial Black"; + + + Hello + + + + + + diff --git a/tcpclient.cpp b/tcpclient.cpp new file mode 100644 index 0000000..334fcf0 --- /dev/null +++ b/tcpclient.cpp @@ -0,0 +1,101 @@ +#include "tcpclient.h" +#include +#include +#include + +using namespace std; +TCPClient TCPClient::tcpclient_instance; +QTcpSocket TCPClient::socket; + +TCPClient::TCPClient(QObject *parent) + : QObject{parent} +{ + +} + +TCPClient::~TCPClient() +{ + +} + +TCPClient* TCPClient::getInstance() +{ + return &tcpclient_instance; +} + +void TCPClient::configAndrun() +{ + qDebug() << "进入configandrun"; + socket.setSocketOption(QAbstractSocket::KeepAliveOption,1); + socket.connectToHost(server_ip, server_port); + connect(&socket,&QTcpSocket::connected,this,&TCPClient::connected); + connect(&socket,&QTcpSocket::disconnected,this,&TCPClient::disconnected); + connect(&socket,&QTcpSocket::readyRead,this,&TCPClient::readSocket); + qDebug() << "连接到服务器"; +} + +void TCPClient::sendToserver(QByteArray &data) +{ + if (socket.isOpen()) + { + socket.write(data); + socket.waitForBytesWritten(2000); + } +} + +void TCPClient::setServer(QString IP, qint16 port) +{ + server_ip = IP; + server_port = port; +} + +void TCPClient::connected() +{ + qDebug() << "1"; + emit TCPClientConnected(); + qDebug() << "emit TCPClientConnected successfully"; + QString addr_t = socket.peerAddress().toString(); + QByteArray addr = addr_t.toLocal8Bit(); + printf("Connected to server at %.*s:%d.\n",addr.size(),addr.data(),socket.peerPort()); +} + +void TCPClient::disconnected() +{ + emit TCPClientDisconnected(); + qDebug() << "emit TCPClientDisconnected successfully"; + printf("Disconnected from server.\n"); +} + +void TCPClient::readSocket() +{ + QByteArray recv; + while(socket.bytesAvailable())//循环接收 + { + recv += socket.readAll(); + if (!socket.waitForReadyRead(20))//超时停止接收 + { + /*QString error = sock->errorString(); + string error_t = error.toStdString(); + log_w("error:%d: %.*s", sock->error(),error_t.length(), error_t.data());*/ + break; + } + } + QString ip = socket.peerAddress().toString(); + string ip_t = ip.toStdString(); + printf("TCPC: Recvd from %.*s:%d\n", ip_t.length(), ip_t.data(), socket.peerPort()); + printf("TCPC Message:%.*s\n",recv.size(),(char *)recv.data()); + if (_callback != nullptr) + _callback(ip, socket.peerPort(),recv); +} + +void TCPClient::setCallBack(void (*callback)(QString &mac, quint16 port, QByteArray &data)) +{ + _callback = callback; +} + +void TCPClient::_sleep(int msec) +{ + QTime dieTime = QTime::currentTime().addMSecs(msec); + while( QTime::currentTime() < dieTime ) + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); +} diff --git a/tcpclient.h b/tcpclient.h new file mode 100644 index 0000000..9891567 --- /dev/null +++ b/tcpclient.h @@ -0,0 +1,37 @@ +#ifndef TCPCLIENT_H +#define TCPCLIENT_H + +#include +#include +#include + +class TCPClient : public QObject +{ + Q_OBJECT +public: + static TCPClient* getInstance(); + static void sendToserver(QByteArray &data); + void configAndrun(); + void setCallBack(void (*callback)(QString &ip, quint16 port, QByteArray &data)); + void setServer(QString IP, qint16 port); +private slots: + void readSocket(); + void connected(); + void disconnected(); +private: + explicit TCPClient(QObject *parent = nullptr); + ~TCPClient(); + static void _sleep(int msec); + static QTcpSocket socket; + static TCPClient tcpclient_instance; + QString server_ip = "127.0.0.1"; + qint16 server_port = 7890; + bool has_found = false; + void (*_callback) (QString &ip, quint16 port, QByteArray &data)=nullptr; +signals: + void TCPClientConnected(); + void TCPClientDisconnected(); + +}; + +#endif // TCPCLIENT_H