From 8725cf2da61391f6ccc29e2e126aef90d7772651 Mon Sep 17 00:00:00 2001 From: wanghaoyu <1580258873@qq.com> Date: Mon, 14 Apr 2025 09:00:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E5=9B=9B=E5=8C=BB?= =?UTF-8?q?=E5=A4=A7=E5=85=89=E7=94=B5=E5=90=8A=E8=88=B1=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + src/CMakeLists.txt | 6 +- src/commandwidget.cpp | 468 +++++++++++ src/commandwidget.h | 113 +++ src/commandwidget.ui | 1349 ++++++++++++++++++++++++++++--- src/communicationsettingdlg.cpp | 90 ++- src/communicationsettingdlg.h | 8 + src/communicationsettingdlg.ui | 598 ++++++++++---- src/mainwindow.cpp | 117 +++ src/mainwindow.h | 18 + src/mainwindow.ui | 11 +- src/resources/images/c.png | Bin 0 -> 7851 bytes src/resources/images/circle.png | Bin 0 -> 5970 bytes src/resources/res.qrc | 2 + src/streamaddrsettingsdlg.cpp | 9 + src/streamaddrsettingsdlg.h | 3 + src/utils/CUdpSocket.cpp | 74 ++ src/utils/CUdpSocket.h | 41 + src/utils/protocolPodTJ.cpp | 123 +++ src/utils/protocolPodTJ.h | 28 + src/utils/switchbutton.cpp | 201 +++++ src/utils/switchbutton.h | 70 ++ 22 files changed, 3056 insertions(+), 276 deletions(-) create mode 100644 src/resources/images/c.png create mode 100644 src/resources/images/circle.png create mode 100644 src/utils/CUdpSocket.cpp create mode 100644 src/utils/CUdpSocket.h create mode 100644 src/utils/protocolPodTJ.cpp create mode 100644 src/utils/protocolPodTJ.h create mode 100644 src/utils/switchbutton.cpp create mode 100644 src/utils/switchbutton.h diff --git a/.gitignore b/.gitignore index 16a004e..aaf9aab 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,6 @@ CMakeLists.txt.user* .rcc/ .uic/ /build*/ +.vs/ +*.json +/out/ \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ef4ecb7..0ac9992 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,9 @@ qt_add_executable(VideoClient videoControl.h videoControl.ui videoControl.cpp wprogressbar.h wprogressbar.cpp webmapwidget.h webmapwidget.cpp - + utils/CUdpSocket.cpp utils/CUdpSocket.h + utils/protocolPodTJ.cpp utils/protocolPodTJ.h + utils/switchbutton.h utils/switchbutton.cpp ) qt6_add_resources(VideoClient "resources" @@ -28,7 +30,7 @@ set(FFMPEG_DIR ${3RDPARTY_DIR}/ffmpeg) # add_subdirectory(shared) add_subdirectory(video) add_subdirectory(3rdparty) - +# add_subdirectory(utils) target_link_libraries(VideoClient PRIVATE diff --git a/src/commandwidget.cpp b/src/commandwidget.cpp index 829c58b..1a9ddcf 100644 --- a/src/commandwidget.cpp +++ b/src/commandwidget.cpp @@ -1,6 +1,8 @@ #include "commandwidget.h" #include "ui_commandwidget.h" +#include +#include "utils/switchbutton.h" CommandWidget::CommandWidget(QWidget *parent) : QWidget(parent), ui(new Ui::CommandWidget) { @@ -13,6 +15,10 @@ CommandWidget::CommandWidget(QWidget *parent) } else { qDebug() << "绑定 UDP 套接字失败"; } + + //创建自定义套接字 + m_CUdpSocket = new CUdpSocket(this); + initmUdpParam(); } CommandWidget::~CommandWidget() { @@ -78,6 +84,21 @@ void CommandWidget::buttonResponse(quint8 cmd) { } } +void CommandWidget::receiveUavTypeIndex(int index) +{ + switch (index) + { + case FP98: + ui->cmdStackedWidget->setCurrentWidget(ui->stackedWidgetPage1); + break; + case MEDICAL_UNIVERSITY: + ui->cmdStackedWidget->setCurrentWidget(ui->stackedWidgePage2); + break; + default: + break; + } +} + void CommandWidget::on_pushButton_clicked() { buttonResponse(0x75); } @@ -145,3 +166,450 @@ void CommandWidget::on_pushButton_16_clicked() { void CommandWidget::on_pushButton_15_clicked() { buttonResponse(0xC9); } + + +/** 武汉天进吊舱 */ +void CommandWidget::on_pushButton_left_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7000"), + m_protocolPodTJ.cmdLeft(ui->cmdSlider->value()))); +} + + +void CommandWidget::on_pushButton_left_released() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7000"), + QByteArray::fromHex("00000000"))); +} + + +void CommandWidget::on_pushButton_right_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7000"), + m_protocolPodTJ.cmdRight(ui->cmdSlider->value()))); +} + + +void CommandWidget::on_pushButton_right_released() +{ + on_pushButton_left_released(); +} + + +void CommandWidget::on_pushButton_up_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7000"), + m_protocolPodTJ.cmdUp(ui->cmdSlider->value()))); +} + + +void CommandWidget::on_pushButton_up_released() +{ + on_pushButton_left_released(); +} + +void CommandWidget::on_pushButton_down_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7000"), + m_protocolPodTJ.cmdDown(ui->cmdSlider->value()))); +} + +void CommandWidget::on_pushButton_down_released() +{ + on_pushButton_left_released(); +} + + +void CommandWidget::on_pushButton_center_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7100"))); +} + + +void CommandWidget::on_pushButton_guid_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7200"), + m_protocolPodTJ.digitalGuid(ui->guidLineEdit->text().toInt(), ui->poseLineEdit->text().toInt()))); +} + + +void CommandWidget::on_pushButton_pose_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7C00"), + m_protocolPodTJ.digitalGuid(ui->guidLineEdit->text().toInt(), ui->poseLineEdit->text().toInt()))); +} + + +void CommandWidget::on_pushButton_directL_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7A00"))); +} + + +void CommandWidget::on_pushButton_directS_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7B00"))); +} + + +void CommandWidget::on_pushButton_lookDown_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7300"))); +} + + +void CommandWidget::on_pushButton_packUp_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7400"))); +} + +void CommandWidget::on_pushButton_scanning_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7900"))); +} + + +void CommandWidget::on_pushButton_close_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7500"))); +} + +void CommandWidget::on_comboBox1_activated(int index) +{ + if (index >= 0) + { + QByteArray data = ui->comboBox1->currentData().toByteArray(); + //qDebug() << data.toHex(); + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("2300"),data)); + } +} + +void CommandWidget::on_comboBox2_activated(int index) +{ + if (index >= 0) + { + QByteArray data = ui->comboBox2->currentData().toByteArray(); + //qDebug() << data.toHex(); + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("2500"), data)); + + } +} + +void CommandWidget::on_pushButton_videoSwitch_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("3100"))); +} + +void CommandWidget::on_pushButton_video_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("3300"))); +} + +void CommandWidget::on_pushButton_photo_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("3200"))); +} + +void CommandWidget::on_pushButton_zoomp_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4500"), + m_protocolPodTJ.cmdZoom(0x01,ui->comboBox3->currentIndex()))); +} + +void CommandWidget::on_pushButton_zoomp_released() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4500"))); +} + +void CommandWidget::on_pushButton_zoomd_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4500"), + m_protocolPodTJ.cmdZoom(0x02, ui->comboBox3->currentIndex()))); +} + +void CommandWidget::on_pushButton_zoomd_released() +{ + on_pushButton_zoomp_released(); +} + +void CommandWidget::on_pushButton_focusP_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4500"), + m_protocolPodTJ.cmdZoom(0x03, ui->comboBox3->currentIndex()))); +} + +void CommandWidget::on_pushButton_focusP_released() +{ + on_pushButton_zoomp_released(); +} + +void CommandWidget::on_pushButton_focusD_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4500"), + m_protocolPodTJ.cmdZoom(0x04, ui->comboBox3->currentIndex()))); +} + +void CommandWidget::on_pushButton_focusD_released() +{ + on_pushButton_zoomp_released(); +} + +void CommandWidget::on_pushButton_auto_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4500"), + m_protocolPodTJ.cmdZoom(0x05, 0x00))); +} + +void CommandWidget::on_pushButton_auto_released() +{ + on_pushButton_zoomp_released(); +} + +void CommandWidget::on_pushButton_contrastP_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4100"), + QByteArray::fromHex("01010000"))); +} + +void CommandWidget::on_pushButton_contrastD_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4100"), + QByteArray::fromHex("01020000"))); +} + +void CommandWidget::on_pushButton_lightP_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4100"), + QByteArray::fromHex("02010000"))); +} + +void CommandWidget::on_pushButton_lightD_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4100"), + QByteArray::fromHex("02020000"))); +} + +void CommandWidget::on_comboBox4_activated(int index) +{ + if (index >= 0) + { + QByteArray data = ui->comboBox4->currentData().toByteArray(); + //qDebug() << data.toHex(); + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4A00"), data)); + } +} + +void CommandWidget::on_pushButton_zoomp_2_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("5000"), + QByteArray::fromHex("0F000000"))); +} + +void CommandWidget::on_pushButton_zoomp_2_released() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("5000"), + QByteArray::fromHex("00000000"))); +} + +void CommandWidget::on_pushButton_zoomd_2_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("5000"), + QByteArray::fromHex("10000000"))); +} + +void CommandWidget::on_pushButton_zoomd_2_released() +{ + on_pushButton_zoomp_2_released(); +} + +void CommandWidget::on_pushButton_contrastP_2_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("5A00"))); +} + +void CommandWidget::on_pushButton_contrastD_2_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("5A00"), + QByteArray::fromHex("01000000"))); +} + +void CommandWidget::on_pushButton_color_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("5300"))); +} + +void CommandWidget::on_comboBox5_activated(int index) +{ + if (index >= 0) + { + QByteArray data = ui->comboBox5->currentData().toByteArray(); + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("5300"), data)); + } +} + +void CommandWidget::on_pushButton_distance_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("3D00"))); +} + +void CommandWidget::on_pushButton_distanceC_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("3E00"), + m_protocolPodTJ.cmdLaser(ui->comboBox6->currentIndex() + 1))); +} + +void CommandWidget::on_pushButton_distanceS_pressed() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("3F00"))); +} + +void CommandWidget::on_cmdLineEdit_textChanged(const QString text) +{ + qDebug() << text; + if (text.toInt() < 10)//数据小于10不响应 + { + return; + } + ui->cmdSlider->setMaximum(text.toInt()); +} + +void CommandWidget::setPodIPConfig(NetworkIPStruct networkIP, bool isConnect) +{ + qDebug() << "ip设置槽函数调用了"; + + if (!isConnect) + { + m_CUdpSocket->close(); + return; + } + + if (m_CUdpSocket->close()) + { + if (!m_CUdpSocket->bind(networkIP.localIP, networkIP.localPort)) + { + qDebug() << "端口号绑定失败"; + } + + //绑定目标IP Port + m_CUdpSocket->setTargetInfo(networkIP.remoteIP, networkIP.remotePort); + } + +} + +void CommandWidget::setMoveParm(QPointF size) +{ + int x = std::clamp(static_cast(size.x() / 10), -60, 60); + int y = std::clamp(static_cast(-size.y() / 10), -60, 60); + qDebug() << "缩减之后的屏幕滑动参数==>" << "x:" << x << "y:" << y; + + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("7000"), + m_protocolPodTJ.cmdServo(x, y))); +} + + +void CommandWidget::stopServo() +{ + on_pushButton_left_released(); +} + +void CommandWidget::setTargetTracking(double dir, double pitch) +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("3A00"), + m_protocolPodTJ.targetTracking(static_cast(std::round(dir)), static_cast(std::round(pitch))))); +} + +void CommandWidget::setStopTracking() +{ + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("3B00"))); +} + +/***武汉天进吊舱控制***/ +void CommandWidget::initmUdpParam() +{ + if (!m_CUdpSocket->bind("172.10.0.249", 10001)) + { + qDebug() << "端口号绑定失败"; + } + + //绑定目标IP Port + m_CUdpSocket->setTargetInfo("172.10.0.249", 10000); + + QIntValidator* validator = new QIntValidator(0, 100, this); + ui->cmdLineEdit->setValidator(validator); + ui->cmdLineEdit->setText("40"); + ui->cmdSlider->setValue(20); + + //AI开关 + connect(ui->switchButton1, &WBSwitchButton::sigSwitchChanged, this, [=](bool onOroff){ + if (onOroff) //开关打开 + { + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("9100"), + QByteArray::fromHex("01000000"))); + } + else + { + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("9100"))); + } + }); + + ui->comboBox1->addItem("16 * 16", QByteArray::fromHex("01000000")); + ui->comboBox1->addItem("32 * 32", QByteArray::fromHex("02000000")); + ui->comboBox1->addItem("64 * 64", QByteArray::fromHex("03000000")); + ui->comboBox1->addItem("128 * 128", QByteArray::fromHex("04000000")); + + ui->comboBox2->addItem("红外", QByteArray::fromHex("00000000")); + ui->comboBox2->addItem("可见光", QByteArray::fromHex("01000000")); + ui->comboBox2->addItem("上下分屏", QByteArray::fromHex("02000000")); + ui->comboBox2->addItem("画中画1", QByteArray::fromHex("03000000")); + ui->comboBox2->addItem("画中画2", QByteArray::fromHex("04000000")); + ui->comboBox2->addItem("左右分屏", QByteArray::fromHex("05000000")); + + ui->comboBox3->setCurrentIndex(4); + + //低照度 + connect(ui->btn_light, &WBSwitchButton::sigSwitchChanged, this, [=](bool onOroff) { + if (onOroff) //开关打开 + { + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4B00"), + QByteArray::fromHex("01000000"))); + } + else + { + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4B00"))); + } + }); + + //电子稳像 + connect(ui->btn_stable, &WBSwitchButton::sigSwitchChanged, this, [=](bool onOroff) { + if (onOroff) //开关打开 + { + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4100"), + QByteArray::fromHex("04010000"))); + } + else + { + m_CUdpSocket->sendData(ProtocolPodTJ::encode(QByteArray::fromHex("4100"), + QByteArray::fromHex("04020000"))); + } + }); + + //图像去雾 + ui->comboBox4->addItem("关", QByteArray::fromHex("00000000")); + ui->comboBox4->addItem("低", QByteArray::fromHex("01000000")); + ui->comboBox4->addItem("中", QByteArray::fromHex("02000000")); + ui->comboBox4->addItem("强", QByteArray::fromHex("03000000")); + + //伪彩选择 + ui->comboBox5->addItem("白热", QByteArray::fromHex("01000000")); + ui->comboBox5->addItem("黑热", QByteArray::fromHex("01010000")); + ui->comboBox5->addItem("蓝红黄", QByteArray::fromHex("01020000")); + ui->comboBox5->addItem("紫红黄", QByteArray::fromHex("01030000")); + ui->comboBox5->addItem("蓝绿红", QByteArray::fromHex("01040000")); + ui->comboBox5->addItem("彩虹1", QByteArray::fromHex("01050000")); + ui->comboBox5->addItem("彩虹2", QByteArray::fromHex("01060000")); + ui->comboBox5->addItem("黑-红", QByteArray::fromHex("01070000")); + ui->comboBox5->addItem("墨绿-红", QByteArray::fromHex("01080000")); + ui->comboBox5->addItem("蓝绿红-粉", QByteArray::fromHex("01090000")); + ui->comboBox5->addItem("混合色", QByteArray::fromHex("010A0000")); + ui->comboBox5->addItem("红头", QByteArray::fromHex("010B0000")); +} \ No newline at end of file diff --git a/src/commandwidget.h b/src/commandwidget.h index f042863..4b83908 100644 --- a/src/commandwidget.h +++ b/src/commandwidget.h @@ -6,6 +6,8 @@ #include "communicationsettingdlg.h" #include "global.h" +#include "utils/CUdpSocket.h" +#include "utils/protocolPodTJ.h" typedef struct struProtocalKB { quint8 head[2]; // 帧头0x @@ -71,6 +73,12 @@ const quint16 CRC8TAB[256] = { 0x0082, 0x00B3, 0x00E0, 0x00D1, 0x0046, 0x0077, 0x0024, 0x0015, 0x003B, 0x000A, 0x0059, 0x0068, 0x00FF, 0x00CE, 0x009D, 0x00AC}; +enum uav_type +{ + FP98=0, + MEDICAL_UNIVERSITY=5 +}; + namespace Ui { class CommandWidget; } @@ -122,18 +130,123 @@ private slots: void on_pushButton_15_clicked(); + /*武汉天进吊舱控制*/ + void on_pushButton_left_pressed(); + void on_pushButton_left_released(); + + void on_pushButton_right_pressed(); + void on_pushButton_right_released(); + + void on_pushButton_up_pressed(); + void on_pushButton_up_released(); + + void on_pushButton_down_pressed(); + void on_pushButton_down_released(); + + void on_pushButton_center_pressed(); + + //姿态指引 + void on_pushButton_guid_pressed(); + void on_pushButton_pose_pressed(); + + //航向锁定 + void on_pushButton_directL_pressed(); + //航向随动 + void on_pushButton_directS_pressed(); + //垂直下视 + void on_pushButton_lookDown_pressed(); + //镜头收藏 + void on_pushButton_packUp_pressed(); + //扫描 + void on_pushButton_scanning_pressed(); + //关伺服 + void on_pushButton_close_pressed(); + //设置检测模板 + void on_comboBox1_activated(int index); + //显示模式 + void on_comboBox2_activated(int index); + //视频切换 + void on_pushButton_videoSwitch_pressed(); + //开始录像 + void on_pushButton_video_pressed(); + //拍照 + void on_pushButton_photo_pressed(); + //可见光变倍+ + void on_pushButton_zoomp_pressed(); + void on_pushButton_zoomp_released(); + //可见光变倍- + void on_pushButton_zoomd_pressed(); + void on_pushButton_zoomd_released(); + //可见光变焦+ + void on_pushButton_focusP_pressed(); + void on_pushButton_focusP_released(); + //可见光变焦- + void on_pushButton_focusD_pressed(); + void on_pushButton_focusD_released(); + //自动对焦 + void on_pushButton_auto_pressed(); + void on_pushButton_auto_released(); + //对比度 + void on_pushButton_contrastP_pressed(); + void on_pushButton_contrastD_pressed(); + //亮度 + void on_pushButton_lightP_pressed(); + void on_pushButton_lightD_pressed(); + //图像去雾 + void on_comboBox4_activated(int index); + //红外变倍+ + void on_pushButton_zoomp_2_pressed(); + void on_pushButton_zoomp_2_released(); + //红外变倍- + void on_pushButton_zoomd_2_pressed(); + void on_pushButton_zoomd_2_released(); + //对比度 + void on_pushButton_contrastP_2_pressed(); + void on_pushButton_contrastD_2_pressed(); + //伪彩循环切换 + void on_pushButton_color_pressed(); + //伪彩选择 + void on_comboBox5_activated(int index); + //单次测距 + void on_pushButton_distance_pressed(); + //连续测距 + void on_pushButton_distanceC_pressed(); + //停止测距 + void on_pushButton_distanceS_pressed(); + + void on_cmdLineEdit_textChanged(const QString text); + private: Ui::CommandWidget *ui; QUdpSocket *m_commandUdpSocket = nullptr; QString m_remoteIP; int m_remotePort; + CUdpSocket* m_CUdpSocket = nullptr; + ProtocolPodTJ m_protocolPodTJ; unsigned char getCrc(quint8 *data, quint8 length); ProtocalKB EncodeCommandCmd(quint8 cmd); bool writeBufferToClient(const QByteArray &data); void buttonResponse(quint8 cmd); + + void initmUdpParam(); + +public slots: + void receiveUavTypeIndex(int index); + + //设置通信IP及Port 连接udp + void setPodIPConfig(NetworkIPStruct networkIP, bool isConnect); +public: + //设置窗口传递参数 + void setMoveParm(QPointF size); + //伺服停止 + void stopServo(); + //目标跟踪 + void setTargetTracking(double dir, double pitch); + //停止跟踪 + void setStopTracking(); }; #endif // COMMANDWIDGET_H diff --git a/src/commandwidget.ui b/src/commandwidget.ui index daed3d5..2007436 100644 --- a/src/commandwidget.ui +++ b/src/commandwidget.ui @@ -7,7 +7,7 @@ 0 0 295 - 541 + 819 @@ -30,7 +30,7 @@ 0 - + #frame{ border: 1px solid white; @@ -43,175 +43,1322 @@ QFrame::Shadow::Raised - - - 2 - - - 0 - - - 2 - - - 0 - - - + + 1 + + + + + 2 + + + 0 + + + 2 + + + 0 + + + + + 6 + + + 8 + + + 6 + + + 6 + + + 14 + + + + + 红外小 + + + + + + + 画中画开 + + + + + + + 画中画关 + + + + + + + 4-6图拼接 + + + + + + + 图像切换 + + + + + + + 变焦推远 + + + + + + + 变焦拉近 + + + + + + + 吊舱 + + + + + + + 红外大 + + + + + + + 复位 + + + + + + + 扫描 + + + + + + + 锁定 + + + + + + + 俯仰+ + + + + + + + 方位+ + + + + + + + 方位- + + + + + + + 俯仰- + + + + + + + 0-3图拼接 + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 219 + + + + + + + + + + + 10 + 70 + 110 + 110 + + + - 6 + 0 - 8 + 0 - 6 + 0 - 6 + 0 - 14 + 0 - - - - 红外小 - - - - - + + - 画中画开 + - + - 画中画关 + - - + + - 4-6图拼接 + - - + + - 图像切换 + - - + + - 变焦推远 + - - - - 变焦拉近 + + + + + + 32 + 20 + 191 + 22 + + + + /*滑块的样式*/ +QSlider::groove:horizontal { +border: 1px solid #64AA64; +background: #64AA64; +height: 2px; +border-radius: 1px; +padding-left:0px; +padding-right:0px; +} + +/*滑块经过的颜色:前面的颜色*/ +QSlider::sub-page:horizontal { +background: #64AA64; +border: 1px solid #64AA64; +height: 2px; +border-radius: 2px; +} + +QSlider::add-page:horizontal { +background: #EAEAEA; +border: 0px solid #EAEAEA; +height: 2px; +border-radius: 2px; +} +QSlider::handle:horizontal +{ + background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, + stop:0.6 #64AA64,stop:0.98409 rgba(255, 255, 255, 255)); + + width: 15px; + margin-top: -6px; + margin-bottom: -6px; + border-radius: 5px; +} + +QSlider::handle:horizontal:hover { + background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, + stop:0.6 #64AA64,stop:0.98409 rgba(255, 255, 255, 255)); + + width: 15px; + margin-top: -6px; + margin-bottom: -6px; + border-radius: 5px; +} + + + Qt::Orientation::Horizontal + + + + + + 230 + 20 + 31 + 21 + + + + + + + 130 + 50 + 61 + 24 + + + + 数字引导 + + + + + + 200 + 50 + 61 + 24 + + + + 姿态引导 + + + + + + 160 + 90 + 31 + 21 + + + + + + + 230 + 90 + 31 + 21 + + + + + + + 128 + 90 + 31 + 21 + + + + 方位: + + + + + + 198 + 90 + 31 + 21 + + + + 俯仰: + + + + + + 130 + 120 + 61 + 24 + + + + 航向锁定 + + + + + + 200 + 120 + 61 + 24 + + + + 航向随动 + + + + + + 130 + 150 + 61 + 24 + + + + 垂直下视 + + + + + + 200 + 150 + 61 + 24 + + + + 镜头收藏 + + + + + + 130 + 180 + 61 + 24 + + + + 扫描 + + + + + + 200 + 180 + 61 + 24 + + + + 关伺服 + + + + + + 0 + 210 + 281 + 51 + + + + 检测跟踪 + + + + 0 + + + 2 + + + 0 + + + 5 + + + 0 + + + + + + 16777215 + 20 + - - - - - 吊舱 + 检测框: - - - - - - 红外大 + + Qt::AlignmentFlag::AlignCenter - - - - 复位 + + + + + 40 + 20 + - - - - 扫描 + + + + + 16777215 + 20 + - - - - - 锁定 + 模板大小 - - - - - - 俯仰+ + + Qt::AlignmentFlag::AlignCenter + + + + + + + + + 0 + 260 + 281 + 61 + + + + 视频 + + - - - 方位+ - - + - - + + + + + 60 + 0 + + - 方位- + 开始录像 - - + + + + + 60 + 0 + + - 俯仰- + 视频切换 - - + + - 0-3图拼接 + 拍照 - - - - - Qt::Orientation::Vertical + + + + + 0 + 320 + 281 + 171 + + + + 可见光 + + + + + 10 + 56 + 60 + 24 + + + + + 60 + 0 + + + + 变倍+ + + + + + + 73 + 56 + 60 + 24 + + + + + 60 + 0 + + + + 变焦+ + + + + + + 136 + 56 + 60 + 24 + - + + + 60 + 0 + + + + 对比度+ + + + + + + 199 + 56 + 72 + 24 + + + + + 60 + 0 + + + + 亮度+ + + + + + + 10 + 85 + 60 + 24 + + + + + 60 + 0 + + + + 变倍- + + + + + + 73 + 85 + 60 + 24 + + + + + 60 + 0 + + + + 变焦- + + + + + + 136 + 85 + 60 + 24 + + + + + 60 + 0 + + + + 对比度- + + + + + + 199 + 85 + 72 + 24 + + + + + 60 + 0 + + + + 亮度- + + + + + + 10 + 29 + 60 + 16 + + + + + 60 + 0 + + + + + 60 + 20 + + + + 速度: + + + Qt::AlignmentFlag::AlignCenter + + + + + + 73 + 27 + 45 + 24 + + + + 0 + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + + + 136 + 29 + 60 + 16 + + + + + 60 + 0 + + + + + 60 + 20 + + + + 透雾: + + + Qt::AlignmentFlag::AlignCenter + + + + + + 199 + 27 + 72 + 24 + + + + + + + 10 + 116 + 71 + 16 + + + + + 60 + 0 + + + + + 80 + 20 + + + + 夜间模式: + + + Qt::AlignmentFlag::AlignCenter + + + + + + 90 + 116 + 40 + 20 + + + + + 40 + 20 + + + + + + + 10 + 143 + 71 + 16 + + + + + 60 + 0 + + + + + 80 + 20 + + + + 电子稳像: + + + Qt::AlignmentFlag::AlignCenter + + + + + + 90 + 143 + 40 + 20 + + + + + 40 + 20 + + + + + + + 136 + 114 + 75 + 24 + + + + + 60 + 0 + + + + 自动对焦 + + + + + + + 0 + 20 + 31 + 21 + + + + 速度: + + + + + + 0 + 490 + 281 + 91 + + + + 红外 + + + + + 10 + 20 + 60 + 24 + + + + + 60 + 24 + + + + + 16777215 + 24 + + + + 变倍+ + + + + + + 10 + 50 + 60 + 24 + + + + + 60 + 24 + + + + + 16777215 + 24 + + + + 变倍- + + + + + + 73 + 20 + 60 + 24 + + + + + 60 + 24 + + + + + 16777215 + 24 + + + + 对比度+ + + + + + + 73 + 50 + 60 + 24 + + + + + 60 + 24 + + + + + 16777215 + 24 + + + + 对比度- + + + + + + 140 + 20 + 40 + 20 + + + 20 - 219 + 0 - - - + + + 40 + 20 + + + + 伪彩: + + + Qt::AlignmentFlag::AlignCenter + + + + + + 180 + 20 + 91 + 24 + + + + + + + + + + 180 + 50 + 91 + 24 + + + + + 60 + 24 + + + + + 16777215 + 24 + + + + 伪彩循环切换 + + + + + + + 0 + 590 + 281 + 61 + + + + 激光 + + + + + 10 + 20 + 60 + 24 + + + + + 60 + 24 + + + + 单次测距 + + + + + + 73 + 20 + 60 + 24 + + + + + 60 + 24 + + + + 连续测距 + + + + + + 135 + 20 + 31 + 24 + + + + + 0 + 24 + + + + 1 + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + + + 210 + 20 + 60 + 24 + + + + + 60 + 24 + + + + 停止测距 + + + + + + 170 + 20 + 35 + 24 + + + + + 35 + 24 + + + + + 60 + 20 + + + + 次/秒 + + + Qt::AlignmentFlag::AlignCenter + + + + + + + WBSwitchButton + QWidget +
utils/switchbutton.h
+ 1 +
+
diff --git a/src/communicationsettingdlg.cpp b/src/communicationsettingdlg.cpp index 3e66ebb..f8deb52 100644 --- a/src/communicationsettingdlg.cpp +++ b/src/communicationsettingdlg.cpp @@ -18,6 +18,90 @@ CommunicationSettingDlg::~CommunicationSettingDlg() { void CommunicationSettingDlg::showEvent(QShowEvent *event) { setSaveSettingParms(); + setPodIniSetting(); +} + + +bool CommunicationSettingDlg::isValidIP() +{ + QHostAddress addrLocal(ui->podLocalIP->currentText()); + QHostAddress addrremote(ui->podRemoteIPEdit->text()); + + if (addrLocal.isNull() || addrLocal.protocol() != QAbstractSocket::IPv4Protocol) + { + emit sendErrorMessage("本地IP格式错误!", 2); + return false; + } + + if (addrremote.isNull() || addrremote.protocol() != QAbstractSocket::IPv4Protocol) + { + emit sendErrorMessage("远端IP格式错误!", 2); + return false; + } + + if (ui->podLocalPort->value() == 0 || ui->podRemotePort->value() == 0) + { + emit sendErrorMessage("请输入正确的端口号!", 2); + return false; + } + return true; +} + +void CommunicationSettingDlg::savePodIniSetting() +{ + g_networkSettingInfo->setValue("PodSetting/localIP", + ui->podLocalIP->currentText()); + g_networkSettingInfo->setValue("PodSetting/remoteIP", + ui->podRemoteIPEdit->text()); + g_networkSettingInfo->setValue("PodSetting/localPort", + ui->podLocalPort->value()); + g_networkSettingInfo->setValue("PodSetting/remotePort", + ui->podRemotePort->value()); +} + +void CommunicationSettingDlg::setPodIniSetting() +{ + ui->podRemoteIPEdit->setText( + g_networkSettingInfo->value("PodSetting/remoteIP", "192.168.1.160").toString()); + ui->podRemotePort->setValue( + g_networkSettingInfo->value("PodSetting/remotePort", 10000).toInt()); + ui->podLocalPort->setValue( + g_networkSettingInfo->value("PodSetting/localPort", 10001).toInt()); + + QString localIP = + g_networkSettingInfo->value("PodSetting/localIP").toString(); + for (int i = 0; i < ui->podLocalIP->count(); ++i) { + if (localIP == ui->podLocalIP->itemText(i)) { + ui->podLocalIP->setCurrentIndex(i); + } + } +} + + +void CommunicationSettingDlg::on_podConnectBtn_clicked() +{ + if (!isValidIP()) { return; } + + savePodIniSetting(); + + NetworkIPStruct networkIP; + if (!_commIsConnect)//断开时点击连接 + { + _commIsConnect = true;//状态为连接 + networkIP.localIP = ui->podLocalIP->currentText(); + networkIP.remoteIP = ui->podRemoteIPEdit->text(); + networkIP.localPort = ui->podLocalPort->value(); + networkIP.remotePort = ui->podRemotePort->value(); + emit sendPodData(networkIP, _commIsConnect); + ui->podConnectBtn->setText("断开"); + } + else + { + _commIsConnect = false;//状态为连接 + emit sendPodData(networkIP, _commIsConnect); + ui->podConnectBtn->setText("连接"); + } + } void CommunicationSettingDlg::initCombobox() { @@ -31,10 +115,14 @@ void CommunicationSettingDlg::initNetworkSetting() { QStringList localIPList; getLocalIP(localIPList); ui->localIP->addItems(localIPList); + ui->podLocalIP->addItems(localIPList); ui->remoteIPEdit->setText(QStringLiteral("223.0.0.1")); ui->remotePort->setValue(8080); ui->localPort->setValue(8082); + + ui->podRemotePort->setValue(10000); + ui->podLocalPort->setValue(10001); } void CommunicationSettingDlg::setSaveSettingParms() { @@ -64,7 +152,7 @@ void CommunicationSettingDlg::setSaveSettingParms() { QString localIP = g_networkSettingInfo->value(groupName + "/localIP").toString(); - for (int i = 0; i < ui->dataSourceCombox->count(); ++i) { + for (int i = 0; i < ui->localIP->count(); ++i) { if (localIP == ui->localIP->itemText(i)) { ui->localIP->setCurrentIndex(i); } diff --git a/src/communicationsettingdlg.h b/src/communicationsettingdlg.h index 2ae4dfd..a3f733c 100644 --- a/src/communicationsettingdlg.h +++ b/src/communicationsettingdlg.h @@ -23,9 +23,11 @@ protected: signals: void sendErrorMessage(QString message, int type); + void sendPodData(NetworkIPStruct networkIP, bool isConnect); private slots: void on_saveSettingBtn_clicked(); + void on_podConnectBtn_clicked(); private: void initCombobox(); @@ -34,8 +36,14 @@ private: void setSaveSettingParms(); + bool isValidIP(); + + void savePodIniSetting(); + + void setPodIniSetting(); private: Ui::CommunicationSettingDlg *ui; + bool _commIsConnect{ false }; }; #endif // COMMUNICATIONSETTINGDLG_H diff --git a/src/communicationsettingdlg.ui b/src/communicationsettingdlg.ui index aa2fb4f..a87f1e7 100644 --- a/src/communicationsettingdlg.ui +++ b/src/communicationsettingdlg.ui @@ -6,192 +6,450 @@ 0 0 - 307 - 275 + 600 + 350 + + + 600 + 350 + + + + + 600 + 350 + + Dialog - - - 4 - - - 4 + + + + 20 + 10 + 551 + 171 + - - 4 + + + 10 + - - 4 + + 网络设置 - - - - - 10 - - - - 网络设置 - - + + + 4 + + + 2 + + + 4 + + + 2 + + + 4 - - 2 - 4 - - 2 - - - - - 4 - - - 4 - - - 7 - - - - - - 10 - - - - 本地IP: - - - - - - - - - - - - - - 10 - - - - 网络IP: - - - - - - - 数据来源: - - - - - - - - - - - 10 - - - - 网络端口: - - - - - - - QAbstractSpinBox::ButtonSymbols::NoButtons - - - 65534 - - - - - - - - 10 - - - - 本地端口: - - - - - - - QAbstractSpinBox::ButtonSymbols::NoButtons - - - 65534 - - - - + + 6 + + + + + + 100 + 0 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 65534 + + + + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 65534 + + + + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 20 + + + + + + + + + 150 + 16777215 + + + + 数据来源: + + + + + + + + 50 + 16777215 + + + + + 10 + + + + 网络IP: + + + + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + + 10 + + + + 网络端口: + + + + + + + + + + + 10 + + + + 保存设置 + + + + + + + + + + + 50 + 16777215 + + + + + 10 + + + + 本地IP: + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + + 10 + + + + 本地端口: + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 100 + 20 + + + + + + - - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - - 10 - - - - 保存设置 - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - + + + + + + + 20 + 190 + 551 + 131 + + + + 吊舱网络设置 + + + + + + + 100 + 16777215 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 65534 + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + + 10 + + + + 本地端口: + + + + + + + + 0 + 0 + + + + + + + + + 100 + 16777215 + + + + + + + 连接 + + + + + + + + + + + + + + 50 + 16777215 + + + + + 10 + + + + 本地IP: + + + + + + + + 100 + 16777215 + + + + QAbstractSpinBox::ButtonSymbols::NoButtons + + + 65534 + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + + 10 + + + + 远端端口: + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter + + + + + + + + 50 + 16777215 + + + + + 10 + + + + 远端P: + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 20 + + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 20 + + + + + + diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5f2a291..b73dc88 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -59,8 +59,10 @@ MainWindow::MainWindow(QWidget *parent) initChangeVideoLayoutConnection(); initHideButton(); + initWidget(); setSavedVideoDir(); + initPodParam(); // ui->stackedWidget->setCurrentIndex(1); // ui->videoWidget1->play(list.at(0)); // ui->videoWidget2->play(list.at(0)); @@ -123,6 +125,8 @@ void MainWindow::initSignalConnection() { connect(ui->videoControlWidget, &VideoControl::stopVideoSignal, this, &MainWindow::closeVideoSlot); + + connect(&streamAddrSettingsDlg, &StreamAddrSettingsDlg::sendUavTypeIndex, ui->commandWidget, &CommandWidget::receiveUavTypeIndex); } void MainWindow::initNotifyMessageConnection() { @@ -132,6 +136,8 @@ void MainWindow::initNotifyMessageConnection() { &MainWindow::showMessageSlots); connect(ui->commandWidget, &CommandWidget::sendErrorMessage, this, &MainWindow::showMessageSlots); + connect(&settingDlg, &CommunicationSettingDlg::sendErrorMessage, this, + &MainWindow::showMessageSlots); } void MainWindow::initChangeVideoLayoutConnection() { @@ -319,6 +325,11 @@ void MainWindow::initHideButton() { &MainWindow::hideCommandWidgetSlot); } +void MainWindow::initWidget() +{ + ui->commandWidget->receiveUavTypeIndex(g_networkSettingInfo->value("NetworkStreamSettings/uavType").toInt()); +} + void MainWindow::showSettingDlgSlot() { settingDlg.exec(); } @@ -506,3 +517,109 @@ void MainWindow::showMap3DSlot() { m_mapWidget->show(); } } + +void MainWindow::initPodParam() +{ + _wheelStopTime = new QTimer(this); + _wheelStopTime->setInterval(300); + _wheelStopTime->setSingleShot(true); + + firstLocation = new QLabel(this); + firstLocation->setPixmap(QPixmap(":/images/c.png")); + firstLocation->setScaledContents(true); + firstLocation->resize(30, 30); + firstLocation->setStyleSheet("border: none; background: transparent;"); + firstLocation->hide(); + + lastLocation = new QLabel(this); + lastLocation->setPixmap(QPixmap(":/images/circle.png")); + lastLocation->setScaledContents(true); + lastLocation->resize(25, 25); + lastLocation->setStyleSheet("border: none; background: transparent;"); + lastLocation->hide(); + + connect(&settingDlg, &CommunicationSettingDlg::sendPodData, ui->commandWidget, &CommandWidget::setPodIPConfig); +} + +void MainWindow::mousePressEvent(QMouseEvent* event) +{ + if (ui->videoWidget->underMouse()) + { + if (event->button() == Qt::LeftButton) + { + //记录鼠标按下位置 + _dragStartPositon = event->pos(); + //QPointF b = event->globalPosition(); + qDebug() << "局部坐标" << "x" << _dragStartPositon.x() << "y" << _dragStartPositon.y(); + //qDebug() << "全局坐标" << "x" << b.x() << "y" << b.y(); + _dragFlag = true; + } + else if (event->button() == Qt::RightButton) + { + //鼠标右键取消目标跟踪 + ui->commandWidget->setStopTracking(); + qDebug() << "取消跟踪"; + } + } +} + +void MainWindow::mouseMoveEvent(QMouseEvent* event) +{ + if (_dragFlag)//点击并且移动 + { + QPointF diff = event->pos() - _dragStartPositon; + qDebug() << "x:" << diff.x() << "y:" << diff.y(); + ui->commandWidget->setMoveParm(diff); + + if (qAbs(diff.x()) > 5 || qAbs(diff.y()) > 5)//像素点超过5ptx才算移动,否则为跟踪 + { + _moveFlag = true; + firstLocation->move((_dragStartPositon - QPoint(firstLocation->width() / 2, firstLocation->height() / 2)).toPoint()); + lastLocation->move(event->pos() - QPoint(lastLocation->width() / 2, lastLocation->height() / 2)); + firstLocation->show(); + lastLocation->show(); + } + + QPointF widgetPos = mapFromGlobal(event->globalPosition()); + + //如果移动的时候超过了画面显示区域,则自动退出伺服控制 + if (!ui->videoWidget->rect().contains(widgetPos.toPoint())) + { + _moveFlag = false; + _dragFlag = false; + + ui->commandWidget->stopServo(); + firstLocation->hide(); + lastLocation->hide(); + } + } +} + +void MainWindow::mouseReleaseEvent(QMouseEvent* event) +{ + if (ui->videoWidget->underMouse()) + { + if (event->button() == Qt::LeftButton && _moveFlag) + { + _moveFlag = false; + + ui->commandWidget->stopServo(); + + firstLocation->hide(); + lastLocation->hide(); + } + else if (event->button() == Qt::LeftButton && _dragFlag) + { + // 目标跟踪 + QPointF sPoint1 = event->globalPosition(); + QPointF widgetPoint = ui->videoWidget->mapFromGlobal(sPoint1); + double a = ui->videoWidget->width(); + double b = ui->videoWidget->height(); + double dir = 1920 / a * widgetPoint.rx() - 960; + double pitch = -(1080 / b * widgetPoint.ry() - 540); + + ui->commandWidget->setTargetTracking(dir, pitch); + qDebug() << "=========>目标跟踪" << " dir:" << dir << " pitch:" << pitch << " a:" << a << " b:" << b; + } + } +} diff --git a/src/mainwindow.h b/src/mainwindow.h index 0412624..1022393 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -22,6 +22,7 @@ #include "windowsx.h" #pragma comment(lib, "user32.lib") #endif +#include namespace QWK { class WidgetWindowAgent; @@ -68,6 +69,7 @@ private: void setSavedVideoDir(); void initHideButton(); + void initWidget(); private slots: void showSettingDlgSlot(); @@ -92,5 +94,21 @@ private: QToolButton *hideCommandWidgetBtn = nullptr; WebMapWidget *m_mapWidget = nullptr; + + //˻ + int _delta{0}; //ֹ + QTimer* _wheelStopTime; + QPointF _dragStartPositon; //¼ǰľֲ + bool _dragFlag{false}; //¼ʼ־ + bool _moveFlag{false}; //¼ڻеı־ + QLabel* firstLocation; + QLabel* lastLocation; + + void initPodParam(); +public: + void mousePressEvent(QMouseEvent* event) override; // ¼ + void mouseMoveEvent(QMouseEvent* event) override; // ¼ + void mouseReleaseEvent(QMouseEvent* event) override; + }; #endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 51eb3aa..9249638 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -105,7 +105,14 @@ - + + + + 300 + 0 + + + @@ -115,7 +122,7 @@ 0 0 1388 - 24 + 33 diff --git a/src/resources/images/c.png b/src/resources/images/c.png new file mode 100644 index 0000000000000000000000000000000000000000..a5543982bf4e5a7cf57ea38193ae90242861a1bd GIT binary patch literal 7851 zcmbVx_ct8g7p*dwL6}jZGlQZ5xtWL z;`zS+;JqL2y=$Fy?p=GGyVfat$Gp*e^@Na?5DN?I$!irwoyT+He+!8JxYz2}6<}d8 zdc0PIz4b9YG9e8xR?08*b^X>d8;0YY+7hZZdCV?C|HkMt_92!moLss^2{I^JNID)m zN6779v?=F&5L~QxCY}CvgxndTr37W909*;m%sS?*fBvxD@LJRv?U9zk-tBrUmCM%> z!7g?3xkt=(qvs1jC2~is|7Iq@+a~BDcO!}Hf(Ag0^GYd%)`=JgKeUw99B6411v94y z5W_xQ3IeH7SrX=8x2O;U*xIIzgAxE+Avv13W$%O3qr?A;1w4u?)6HReLa}5|Qv5j$ zZ9nos#Lh$5;!jk{iq6Hivxf@CDnizG0_E=n9$e$U=BG7D|7%DR-!`x`@Q?oC#3Oz) zf1J^mx5ck$*uxxMwpqW7@u6+CdtUlX6C{KCO;S^iF#4s_mYTz{wGbOi`6-i5eB%pN zccLIPH2Z4%;NdnE=Bgq6WfG0{@1AW;DpZ1(BLYuz5}8+8Ny2 zS8d1n{~?UgpAfP*kx*-M5t)S-(>4(|^G$O2qJ`qbBSi%5udG#OOH`gJ9*46VeT|w4 z7{qi{NZg~I=GfPSGf!yab708pgF?T;^XO(2(D1wAcD3{ip>zM_o?(_Ut0Jxo{hvs6 z7cF8~;y^Qdst+r>29K4JPLCe{nxQJ)7`!ITplsMCEj6Oh_7g&W01S|uFU#4{f9hyW zB1O6i){OtbBB|iT2+NRxjBfsPd6ffInoiZ&AaeX>3H9)s=NPuQuh`b!N%prCU0o}j zIF9EQML$z9@%|BD`So{`kmU=d_ovhQVr&l)-I@OMU~2@+su4V&keh-F_36+>dKE`V zl}A|tFQN3j&b;If^sDJJKyi|-X*FH!<7-?rbfTq#?t@+uJdpnO!13#*eU3Sksz@wV zDoJzt*!9O=a3UzEq) zl@4NqeacX6w|~(mYk~2INQBy`QSy8Al<@ga3}!eYCfbaPSyW88gCt5XNkSNj4qn7` zVBBhL5!*S z^<$a4E<#?EroIDkF6&U|BhiV+7b}qPdiunlHC#&MXlXL#yfL6tJfzFdR`-J$2SY21 z%GoE_GOd1fyjHqq^N5(qt{Caad3B-V+F6gQhURRtD1fFJjuzRGtDBw&s*tMoXZdqC z=kz2|;LLq*uxW)(EM;4fO<1URN~*^ey_cIkrXxs|DI_%{#RQ!Ke0{WQyu4m+z_Zol z7;M5xB;PbKonR28qPDJ24D$y-I=QdcfF1#&c2M=(9A>#me#L4tnfbJPm*gBg)#Q{P zn|@g4YYSm{cz@dxC`gb>bzBz*MQ@4Yp=_B~tF!JGvs@p)k}7o{{)d-a3*_E-4Fzz? zda=aU(~srR#lEKPNTKu4kh!zSJ28U-DqoMke3CTtzVEl_AN;5@A5J_Tjf{s?j|pr= z9{MM;gvf(aO-Dt#mKL(@A;3znGZ;Q9Z$CQMZ5JTQE}gS(?+m zS6eFappTUBKBzqEr-$_-q5_o$1G?NB40`)BJW!{c2lFfeS3pPT-mA^?1_(dtk+`F{ z1^W$beSFTa*_t}DT%4R;VWpxbLQnC1q-i-|lL}QDz8F_jx_%y9&iHO zdq#_JE^v=qS=70s6(IUSN_{-n7q!cYsG_GU2Y}87dy*)Z2qH~0@55A2-=h=s{teA> zGf7@FDD3*bb@5M!lp&cX+Tojx1%jw)nT`SR#wShuS4ieTML#!%Sm$q!7U3OEB~5*I zz|pP~i+Yl<{Vuv+!*uBc94^VVHAvrhrzXCp4=v+#NMNdbh`d zO`|r~DgQbvZLRmY^PwV@f8M)I|Lam`OP}DD>`Q1ncG;WeLYpzm`yRiNf{*srcjoqD z3UM-hDgl-MtMiBZ0avrD<>7OMV~2P9`3X{fmyGT*Ej)ey%8-0*MnqS$yPSrC=U7sL z)@QRc!9m&?1v(&9^SH(m5r#!gLdoN}najYrP0w<7@p439Xf>mC$t9m1{_SKA$u-0B zGI^m&8s+w~(BOXkjryv8Qc9}>Gs!lW0haP>O=`w&_rlKN4+XwWV@kA-DKp{Ma|gVq zfhELp=MC_Ds~SCPsE8&+v80p2AmU*?m!h?G6E8F~%A*Hb1_7Ma2F3pLj#;Ve&LGJY zy#C5*hSQ~dEW*9`fy`{ocbi<;S~Y!iBGcouOkoPME+Opu%s*wI9~MBuG*ai>x}pAO zPLoAvCVC@ql5Bj7QVP3y6I<_*!zFAf3(xuHZm)p@BFY zNud(dLY8g3niM$mx@W16^<@XPA*i-wLJOcm=MslX7Jj0I+yJ-h9^C2)VZC#iiS^gK z*E7Z}-Roh*C)yef^B8=pJ-HH$#_ZWEv~F*$4wIBG4Kn+^8uPoG=1BZ(59^7co*tKv zol%A9#=!*$uv5Lyxzf>=v4vhYzH3JR5iN~wqZ0rr6E@XBex{gAlRc6x$|?=cgPTFJ zLYHmPo^4R9;+wauv!}@6?M-ym15E0#37OP2y#PL~761nA$UWPAFndcHk{qBKX%K2G z{G$C=ru>zv>wqO@WSZAc^y|Tp*?=x+Q6YJ0cZUH#D5Zmda-($G9Ljol z6Xw}Wx?7U;H4Njt5<6E*4Dj9WoS~!OF7>IO(Dhmw8a?)Z zyCg_pIH<(Phw0_>f>fj^G6Ti#fRM^vLlnQd~zvW$w z(cvJRi}iN5u%HC$w^OPW?g~}GZ>+7?|1&y`$LNxKVP@<~*{qnJCM2+HCL`(Hwe~3e zkU96XznN%n!uCRAMGXZlSxr3!_|qTYMETS=&rm)A28vV`sQI$@UAPt-0N7C4j>bDD z?h;<$dEp;eU^ioaaXYl(>N86hkR0F*m8Q;o>dODU{KnVE9>Y0jp}S}XXqnP`{aT8* zz?lUIBroI756FXfwW+XHO$~+nEWFX(*?2oC=F!VqL=HQpzco9fzjZ*Hg2)vsjF1MK zY)V+qtw+HFr2CS0ML~u&898$=EzPFEeui3Wwv{#J(u0;%(FaWf>QtP;`S-lBtLQYSzGtg(|TmQXFDp z-AZM{A8Pu6^IjYokhs&?GRc6z4zXO;l4v@VbP|3dxxJ#E!MHo7#nGi+nX$CWkJhv^ zdObko`d|COEN)%|Ba_1vp*1s@Lxo!?B>BJhlE|f!?Viwgq`{pwvKo*9!gEj!R6f&l zs!M(nSMZ`hfW<5eDvq=^mr;%WA4D9H9;#5`LnDJ^G;aOVL*6H9r|aE=CthaVGS|31ro5D2N1wnLm2h1l z|3jR*B}dtGzRi-nCI*@RJAD4k53Sgbhe%C|RspjE=dd5Tjr)H`6&Haq=XM9OEvdZ>7q zTkf?m&0oJv7}HovWlY7#-K;W=x2<8!~vwhE{W6~B*UUs;Ja2blnD-BHMKSN5k1 zZ1$Rr@EC41Np90WX2GMq$C2YzRX8T3dY;5~kq(`4a>3#ZBv))Na&ObM+b`@^C`352 z>>_-Yv-h?~pIWSBZD!+b^oD1h6bQmp4K$b*t(~$J_=Wctku(XzR|83V>Eav?7xcw) zlRfK`1r>_3Wb7(JJ-yZ-rAV;0N)PWn?+kO7)6K|2{dZbPnL6B0xQ$k(u_w~LztmWg ziO2yo8Wqf?_D>V?p3Nn9HSL&mNjj~o$^H!1lCXH!@i!@XcGom^J|}6jhdUscLmgZv z97Izv&>vnp|N7{dXUK~@obf7UAAvSSKb5MM3M#PD&fj8l1;8?5NMempb{G7;OBQh^ zsM+gWMJd;*Y6UD=|7zb)Snv6Os$T8{Lq={&;B{UDabOS?Ris~d2L*k*Dqr354KB^* zgoxl-kP(F|0x;<8N4G}MC$N&$bSkh^f%`v-T){@9#>pslR)fn2jp~!sa!@0nF{bs*NxehqQrZ3jU!HBkW`c)=(fyE%-3B{hz!t353K3vL)*iLR|3a>)1** z07v%}Bfz6qy9;cu7hWLG((FVTh`gkgPe_-7ufuXg>S!pw~*wvr=JPQ&|RLz^dQA&h<0 zvASmSGvW&!Oc=N~^a8Z!!8w-JviVcLTXiYna2WFONE3sT6q$=0#^XOe8M_}BSlfTB z>y=}kz*a_&)s8AZK}KnPw;ItJ7Tl^8K@T%nk&XY|Nu|b(n(lg2;FE21=Ipfe>0_^9 z!l!#wg(hf>-96j+lWZ{kd#J&<<~g~642~h5jd%db9oTa~SM-GzfJQ3H+@9?(U+of+ zEq%qTjeKeq8?Yujb0}vLku>RGxM*~ zCQxLKT9210A!1%fYD%^F$4@X_-0xl|lXQs^r+eX(>zwc>YQcYxB+A+pjciOxoOKCsz+>7FZEK zt50pW(aRd+tuEz8uX+;`C{S)}VA#p+QbVh+o{CAJ*K-`I;UaTc0ie1+Sz}#d%zEVd zO;pc>wgJ`4=t3Ix>l*aeNa@D}L&aQ_C%PG8ikl~0dWkB2r~Lduh-P@VkeFe^kAB%- zY%?%1vgieh0)a-NUY5*Fi5)~Io(vCX6P>#42t9mw`?KZkxBQM|!*Bvr+}q?4)|Kry{q`xiyT1U6Lu)(=Dhw^_s1i>N`#|)}AnFA??r?Wp1 zdg+?UTihwCYe1!!Ji6M}O`OZh4A*#f=WFFP31Gsp9~B3ir<0S#C)q#1#_skv#e*LX z^P7s{^5Bt^{JS}o1!%ZdYHb6H?{F5ev&#k_&m5OvBbzRNaC&89>;4-bJAN_2gLfV? z89h$3Y2dPs*xhuy3f{HvYd!~W9uDc=Vwq&%U{i6+m@S3ePc?<;K^zK%ykvM0sx=k+ zz&Xlbh8Rkwue;7)B|SJfmxMTI{P|Cb)5tA51L46xNEV|XRV#+0<;^220nfJB4yg4#b0DC%TRtu`4NH=HdBv9Ql zEk6a)S#z)^D;)NRAc~nxuGN%UDcmQhJUf?P5+5-4*_lX#yK{67bS*mm(7A%$PZ~Ww za^2!l;s$b%Lq|itj;6ZW|pv3j7r# zf9;kK@d{Gaf6b3?2|XHM46H($;?wN>A!^EAFIgAItk@IQHpD7ieYUvwRVhw{YtU?N zY7a$lF5tWO*(t6+YHviEMl_y{w^N4m=+O5pO{D%QopDuWA9CvH-w1Qw7TA1psWM2@ z8|^TUfKJlJ8X>}y2OKj4jOGRte>nCH&o zAoxC%QD}$@Y(o^#`#3iu>1guPuKbEcp4fL((0@#nYH?$4^L9nCIY3sNI5X9m`P=Kw zr7pb2{e1~NHe@$IL;fGETp$}@4#4phlFp?@w`HK<*O6t(FEH}i!Fu0j;JWP^ryrA=gUa76 zcDUYWWP36zgro@k{A*jkc*GUz1=t*(3T(4%L>KCnHJeQA)C%mMzZ1J}epy5(G4@nM zqyI0`L)5YZ%1?e9{ehddwTD$Oo~GmJwtfYxL<>6*aU71(O{(V~fs>7$;>-k4Mq<_I zIq{)-?LDEvd;zT{FjM$7$4H&j^G33nfa=qY4{w*A#W;BXHJ`$h5SA9tUo89w;2K0^ z#+pTCzRP=742-C}`bbbo-_P7WVaULbJsryY0@c4ye!7b)K)xMCzp|_o?fY~tL7evUpsq*#;RrR&!#k5&xtxM{=v_UH7Ff-`$zc~ z$M>UIMk%k3^(42VzAM5fdi0M^L><<+j;W#+!re=jf>5-@ZC*d@<)s=8y7xH`U>1gr z00|&xini%sjAcoMN`d9Xp(5{GqF_;f3abe}8W2#7{K|XqvM=lipUjZOE4Ge<%pW!@cF{?I*aU;zH3M zBJa%%HF*!2Oyb=X@;Fc8r_70dr=q2W!<@(94xY!8hcerNz-fj?ffRtRZ#W)m+e=k2{1c;6#48~3qeYxXsoyUu2q;?hv@JgqZh43|Qaai| z)V4nL=YfEJ^~dac@!RP{HXt@ z!O{x?I}`?LpvP{{TUk&c%qoibE68sQj}HGomIu=C`pP$6_9<(RA~e=(B~8UTd2`hN E0kwFxUjP6A literal 0 HcmV?d00001 diff --git a/src/resources/images/circle.png b/src/resources/images/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..06f5c53a32adedbe283ed062c247582b3ca00cfe GIT binary patch literal 5970 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 f#^Sf;hl)6uO~j-x22_Pk2gH2D7j7qltr literal 0 HcmV?d00001 diff --git a/src/resources/res.qrc b/src/resources/res.qrc index 424cc77..81a54a3 100644 --- a/src/resources/res.qrc +++ b/src/resources/res.qrc @@ -37,5 +37,7 @@ images/play1.75X.png images/play1X.png images/play2X.png + images/c.png + images/circle.png diff --git a/src/streamaddrsettingsdlg.cpp b/src/streamaddrsettingsdlg.cpp index 564e61f..42b6380 100644 --- a/src/streamaddrsettingsdlg.cpp +++ b/src/streamaddrsettingsdlg.cpp @@ -14,6 +14,7 @@ StreamAddrSettingsDlg::StreamAddrSettingsDlg(QWidget *parent) uavTypeList.append("FP981C"); uavTypeList.append("FP981CS"); uavTypeList.append("FP981A"); + uavTypeList.append("四医大"); ui->uavTypeCombox->insertItems(0, uavTypeList); // ui->pushStreamIPCombox->insertItem(0, QStringLiteral("航天飞鹏服务器")); @@ -157,3 +158,11 @@ void StreamAddrSettingsDlg::on_pushStreamBtn_clicked() { ui->pushStreamBtn->setDisabled(false); } + +void StreamAddrSettingsDlg::on_uavTypeCombox_activated(int index) +{ + qDebug() << index; + g_networkSettingInfo->setValue("NetworkStreamSettings/uavType", + ui->uavTypeCombox->currentIndex()); + emit sendUavTypeIndex(index); +} diff --git a/src/streamaddrsettingsdlg.h b/src/streamaddrsettingsdlg.h index 4cfbc2c..25a1517 100644 --- a/src/streamaddrsettingsdlg.h +++ b/src/streamaddrsettingsdlg.h @@ -22,6 +22,7 @@ protected: signals: void startPullStreamSignal(bool bPull); void startPushStreamSignal(bool bPush); + void sendUavTypeIndex(int index); private slots: void on_pushStreamIPCombox_currentIndexChanged(int index); @@ -32,6 +33,8 @@ private slots: void on_pushStreamBtn_clicked(); + void on_uavTypeCombox_activated(int index); + private: void initSavedParms(); void saveParms(); diff --git a/src/utils/CUdpSocket.cpp b/src/utils/CUdpSocket.cpp new file mode 100644 index 0000000..c256dcb --- /dev/null +++ b/src/utils/CUdpSocket.cpp @@ -0,0 +1,74 @@ +#include "CUdpSocket.h" + +CUdpSocket::CUdpSocket(QObject* parent) : QObject(parent) +{ + //创建UDP套接字内存空间 + m_sock = new QUdpSocket; + // 连接数据读取信号槽 + connect(m_sock, &QUdpSocket::readyRead, this, &CUdpSocket::on_readyReadData); +} + +CUdpSocket::~CUdpSocket() +{ + // 释放UDP套接字内存空间 + m_sock->close(); + delete m_sock; +} + +bool CUdpSocket::bind(QString ip, ushort port) +{ + // 返回绑定函数返回值 + + if (!m_sock->bind(QHostAddress(ip), port)) + { + qDebug() << "Bind failed:" << m_sock->errorString(); + isSocketBind = false; + return false; + } + isSocketBind = true; + return true; +} + +void CUdpSocket::sendData(QByteArray data) +{ + // 发送传入的数据到指定的信息的位置 + if (isSocketBind) + { + m_sock->writeDatagram(data, m_hostAddr, m_port); + } +} + +void CUdpSocket::setTargetInfo(QString ip, quint16 port) +{ + // 存储传入的IP和端口号 + m_hostAddr = QHostAddress(ip); + m_port = port; +} + +bool CUdpSocket::close() +{ + m_sock->close(); + if (m_sock->state() == QUdpSocket::UnconnectedState) { + qDebug() << "Socket 已成功关闭"; + return true; + } + + qDebug() << "Socket 关闭失败,当前状态:" << m_sock->state(); + return false; +} + +void CUdpSocket::on_readyReadData() +{ + // 通过函数判断当前是否有等待读取的数据并循环获取 + while (m_sock->hasPendingDatagrams()) + { + //创建数据存储容器,并设置长度为将接收的数据长度 + QByteArray data; + data.resize(m_sock->pendingDatagramSize()); + //读取数据并保存信息发送者的地址和ip(方便发送时指定发送位置) + m_sock->readDatagram(data.data(), data.size(), &m_hostAddr, &m_port); + //发送接收数据的信号 + emit recvDataSignal(data); + } +} + diff --git a/src/utils/CUdpSocket.h b/src/utils/CUdpSocket.h new file mode 100644 index 0000000..5d4865d --- /dev/null +++ b/src/utils/CUdpSocket.h @@ -0,0 +1,41 @@ +#ifndef CUDPSOCKET_H +#define CUDPSOCKET_H + +#include +#include +#include +class CUdpSocket : public QObject +{ Q_OBJECT +public: + explicit CUdpSocket(QObject* parent = nullptr); + ~CUdpSocket(); + + //绑定本机的ip和端口号信息 + bool bind(QString ip, ushort port); + + //通过该函数发送数据 + void sendData(QByteArray data); + + //设置目标主机的ip和端口号 + void setTargetInfo(QString ip, quint16 port); + + //关闭socket + bool close(); + +signals: + //通过该信号传递接收到的数据 + void recvDataSignal(QString data); + +public slots: + //读取数据的槽函数 + void on_readyReadData(); + +private: + QUdpSocket* m_sock; //UDP套接字指针 + QHostAddress m_hostAddr; //保存目标的地址对象 + quint16 m_port; //保存目标的端口号(类型一致) + + bool isSocketBind{false}; //数据绑定成功or失败 +}; + +#endif \ No newline at end of file diff --git a/src/utils/protocolPodTJ.cpp b/src/utils/protocolPodTJ.cpp new file mode 100644 index 0000000..30c19f0 --- /dev/null +++ b/src/utils/protocolPodTJ.cpp @@ -0,0 +1,123 @@ +#include "protocolPodTJ.h" + +QByteArray ProtocolPodTJ::encode(const QByteArray& cmd, const QByteArray& loadData) +{ + QByteArray buffer; + + // ֡ͷ + buffer.append(0xFB); + buffer.append(0x2C); + buffer.append(0xAA); + + // ָ֡2ֽ + ݣ + quint8 length = 2 + loadData.size(); + buffer.append(length); + + // ָλǰ + buffer.append(cmd); + + // + buffer.append(loadData); + + // У飨֡ʼ һֽڣ + quint8 xorSum = calculateXOR(buffer, 3, buffer.size() - 1); + buffer.append(xorSum); + + return buffer; +} + +QByteArray ProtocolPodTJ::cmdLeft(uint16_t sliderValue) +{ + QByteArray param(4, 0x00); + //Сǰ + param[0] = -sliderValue & 0xFF; + param[1] = ((-sliderValue >> 8) & 0xFF); + return param; +} + +QByteArray ProtocolPodTJ::cmdRight(uint16_t sliderValue) +{ + QByteArray param(4, 0x00); + //Сǰ + param[0] = sliderValue & 0xFF; + param[1] = ((sliderValue >> 8) & 0xFF); + return param; +} + +QByteArray ProtocolPodTJ::cmdUp(uint16_t sliderValue) +{ + QByteArray param(4, 0x00); + //Сǰ + param[2] = sliderValue & 0xFF; + param[3]= ((sliderValue >> 8) & 0xFF); + return param; +} + +QByteArray ProtocolPodTJ::cmdDown(uint16_t sliderValue) +{ + QByteArray param(4, 0x00); + //Сǰ + param[2] = -sliderValue & 0xFF; + param[3] = ((-sliderValue >> 8) & 0xFF); + return param; +} + +QByteArray ProtocolPodTJ::cmdZoom(uint8_t model, uint8_t speed) +{ + QByteArray param(4, 0x00); + //Сǰ + param[0] = model; + param[1] = speed; + return param; +} + +QByteArray ProtocolPodTJ::cmdLaser(uint8_t fre) +{ + QByteArray param(4, 0x00); + //Сǰ + param[0] = fre; + return param; +} + +QByteArray ProtocolPodTJ::digitalGuid(uint8_t directionAngle, uint8_t pitchAngle) +{ + QByteArray param(4, 0x00); + //Сǰ + param[0] = (directionAngle * 100) & 0xFF; + param[1] = (((directionAngle * 100) >> 8) & 0xFF); + param[2] = (pitchAngle * 100) & 0xFF; + param[3] = (((pitchAngle * 100) >> 8) & 0xFF); + return param; +} + +QByteArray ProtocolPodTJ::cmdServo(int pointX, int pointY) +{ + QByteArray param(4, 0x00); + //Сǰ + param[0] = pointX & 0xFF; + param[1] = ((pointX >> 8) & 0xFF); + param[2] = pointY & 0xFF; + param[3] = ((pointY >> 8) & 0xFF); + return param; +} + +QByteArray ProtocolPodTJ::targetTracking(uint16_t dir, uint16_t pitch) +{ + QByteArray param(4, 0x00); + //Сǰ + param[0] = dir & 0xFF; + param[1] = ((dir >> 8) & 0xFF); + param[2] = pitch & 0xFF; + param[3] = ((pitch >> 8) & 0xFF); + return param; +} + +//У +quint8 ProtocolPodTJ::calculateXOR(const QByteArray& data, int begin, int end) +{ + quint8 xorVal = 0; + for (int i = begin; i <= end; ++i) { + xorVal ^= static_cast(data[i]); + } + return xorVal; +} diff --git a/src/utils/protocolPodTJ.h b/src/utils/protocolPodTJ.h new file mode 100644 index 0000000..0caab4d --- /dev/null +++ b/src/utils/protocolPodTJ.h @@ -0,0 +1,28 @@ +#include +class ProtocolPodTJ +{ +public: + static QByteArray encode(const QByteArray& cmd, const QByteArray& loadData = QByteArray::fromHex("00000000")); + + +public: + //ָ + QByteArray cmdLeft(uint16_t sliderValue); + QByteArray cmdRight(uint16_t sliderValue); + QByteArray cmdUp(uint16_t sliderValue); + QByteArray cmdDown(uint16_t sliderValue); + QByteArray cmdZoom(uint8_t model, uint8_t speed); + QByteArray cmdLaser(uint8_t fre); + + // + QByteArray digitalGuid(uint8_t directionAngle, uint8_t pitchAngle); + + //ŷ + QByteArray cmdServo(int pointX, int pointY); + + //Ŀ + QByteArray targetTracking(uint16_t dir, uint16_t pitch); + +private: + static quint8 calculateXOR(const QByteArray& data, int begin, int end); +}; diff --git a/src/utils/switchbutton.cpp b/src/utils/switchbutton.cpp new file mode 100644 index 0000000..347cd3e --- /dev/null +++ b/src/utils/switchbutton.cpp @@ -0,0 +1,201 @@ +#include "switchbutton.h" +#include + +WBSwitchButton::WBSwitchButton(QWidget* parent) + : QWidget{ parent } +{ + +} + +bool WBSwitchButton::getSwitch() { + return mOnOff; +} + +void WBSwitchButton::setSwitch(bool onoff) { + if (mWaitSigModel) return; + /// ״̬л + mOnOff = onoff; + /// ź + sigSwitchChanged(mOnOff); + /// -ɫ + QPropertyAnimation* colorAnimation = new QPropertyAnimation(this, "pBackColor"); + colorAnimation->setDuration(mAnimationPeriod); + colorAnimation->setStartValue(mBackColor); + colorAnimation->setEndValue(mOnOff ? mBackOnColor : mBackOffColor); + colorAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //ֹͣɾ + /// -ذťλ + QVariantAnimation* posAnimation = new QVariantAnimation(this); + posAnimation->setDuration(mAnimationPeriod); + posAnimation->setStartValue(mButtonRect.topLeft()); + posAnimation->setEndValue(mOnOff ? mRightPos : mLeftPos); + connect(posAnimation, &QPropertyAnimation::valueChanged, [=](const QVariant& value) { + mButtonRect.moveTo(value.toPointF()); + update(); + }); + posAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //ֹͣɾ +} + +void WBSwitchButton::setSwitchForWaitModel(bool onoff) +{ + if (!mWaitSigModel) return; + if (mOnOff == onoff) { + /// ʾֵδıаťλö + QVariantAnimation* posAnimation = new QVariantAnimation(this); + posAnimation->setDuration(mAnimationPeriod); + posAnimation->setStartValue(mOnOff ? mLeftPos : mRightPos); + posAnimation->setEndValue(mOnOff ? mRightPos : mLeftPos); + connect(posAnimation, &QVariantAnimation::valueChanged, [=](const QVariant& value) { + mButtonRect.moveTo(value.toPointF()); + update(); + }); + posAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //ֹͣɾ + return; + } + /// ״̬л + mOnOff = onoff; + /// ź + sigSwitchChanged(mOnOff); + /// бɫ + QPropertyAnimation* colorAnimation = new QPropertyAnimation(this, "pBackColor"); + colorAnimation->setDuration(mAnimationPeriod); + colorAnimation->setStartValue(mBackColor); + colorAnimation->setEndValue(mOnOff ? mBackOnColor : mBackOffColor); + colorAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //ֹͣɾ + connect(colorAnimation, &QPropertyAnimation::valueChanged, [=](const QVariant& value) { + update(); + }); +} + +void WBSwitchButton::setEnabled(bool enable) { + QWidget::setEnabled(enable); + mEnable = enable; + emit sigEnableChanged(mEnable); + update(); +} + +bool WBSwitchButton::getEnabled() +{ + return mEnable; +} + +void WBSwitchButton::setAnimationPeriod(int period) { + mAnimationPeriod = period; +} + +void WBSwitchButton::setPrecisionClick(bool flag) { + mPrecisionClickFlagh = flag; +} + +void WBSwitchButton::setWaitModel(bool flag) +{ + mWaitSigModel = flag; +} + +void WBSwitchButton::setButtonColor(QColor color) { + mButtonColor = color; + update(); +} + +void WBSwitchButton::setBackOnColor(QColor color) { + mBackOnColor = color; + update(); +} + +void WBSwitchButton::setBackOffColor(QColor color) { + mBackOffColor = color; + update(); +} + +void WBSwitchButton::setEdgeColor(QColor color) { + mEdgeColor = color; + update(); +} + +void WBSwitchButton::paintEvent(QPaintEvent* event) { + Q_UNUSED(event) + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setPen(Qt::NoPen); + + /// ƱԵɫ + QPainterPath path; + path.addRect(this->rect()); + path.addRoundedRect(this->rect(), mRadius, mRadius); + path.setFillRule(Qt::OddEvenFill); + painter.setBrush(mEdgeColor); + painter.drawPath(path); + + /// Ʊɫ + painter.setBrush(mBackColor); + painter.drawRoundedRect(this->rect(), mRadius, mRadius); + + /// Բΰť + painter.setBrush(mButtonColor); + painter.drawEllipse(mButtonRect); + + /// ưťӰ + painter.setBrush(Qt::NoBrush); + QColor color(Qt::black); + int count = (this->height() - mButtonRect.height()) / 2; + float stepColor = (0.15 - 0.0) / count; + for (int i = mButtonRect.height() / 2 + 1; i < this->height() / 2; i++) { + color.setAlphaF(0.15 - stepColor * (i - mButtonRect.height() / 2)); + painter.setPen(color); + painter.drawEllipse(mButtonRect.center(), i, i); + } + + /// ʧʾһɲ + if (!mEnable) { + QColor disable(Qt::black); + disable.setAlphaF(0.5); + painter.setBrush(disable); + painter.drawRoundedRect(this->rect(), mRadius, mRadius); + } +} + +void WBSwitchButton::resizeEvent(QResizeEvent* event) { + Q_UNUSED(event) + /// °ťСԲǴСλ + int size = qMin(this->width(), this->height()); + mRadius = size / 2; + float width = size * 3 / 4; + float border = (size - width) / 2; + mLeftPos = QPoint(border, border); + mRightPos = QPoint(this->width() - border - width, border); + mButtonRect.setWidth(width); + mButtonRect.setHeight(width); + mButtonRect.moveTo(mOnOff ? mRightPos : mLeftPos); + mBackColor = mOnOff ? mBackOnColor : mBackOffColor; + update(); +} + +void WBSwitchButton::mouseReleaseEvent(QMouseEvent* event) { + if (mWaitSigModel) { + /// аťλö + QVariantAnimation* posAnimation = new QVariantAnimation(this); + posAnimation->setDuration(mAnimationPeriod); + posAnimation->setStartValue(mOnOff ? mRightPos : mLeftPos); + posAnimation->setEndValue(mOnOff ? mLeftPos : mRightPos); + connect(posAnimation, &QVariantAnimation::valueChanged, [=](const QVariant& value) { + mButtonRect.moveTo(value.toPointF()); + update(); + }); + posAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //ֹͣɾ + return; + } + if (!mEnable) return; + if (mButtonRect.contains(event->pos()) || !mPrecisionClickFlagh) { + setSwitch(!mOnOff); + } +} + +void WBSwitchButton::enterEvent(QEvent* event) { + Q_UNUSED(event) + mHover = true; +} + +void WBSwitchButton::leaveEvent(QEvent* event) { + Q_UNUSED(event) + mHover = false; +} + diff --git a/src/utils/switchbutton.h b/src/utils/switchbutton.h new file mode 100644 index 0000000..df71292 --- /dev/null +++ b/src/utils/switchbutton.h @@ -0,0 +1,70 @@ +#ifndef WBSWITCHBUTTON_H +#define WBSWITCHBUTTON_H + +#include +#include +#include +#include +#include +#include + +/// +/// \brief 基础控件-Switch开关按钮 +/// +class WBSwitchButton : public QWidget +{ + Q_OBJECT +public: + Q_PROPERTY(QColor pBackColor MEMBER mBackColor) //新增背景颜色属性,用于动画 + + explicit WBSwitchButton(QWidget* parent = nullptr); + bool getSwitch(); /// 获取开关状态 + +public slots: + void setSwitch(bool onoff); /// 设置开关状态,default:0 + void setEnabled(bool enable); /// 设置使能状态,default:1 + bool getEnabled(); /// 获取使能状态 + void setAnimationPeriod(int period); /// 设置切换状态周期 + void setPrecisionClick(bool flag); /// 设置精确点击,即只有点中按钮的时候才开关 + void setWaitModel(bool flag); /// 设置等待模式,点击后不会主动切换开关,需要setSwitch + void setSwitchForWaitModel(bool onoff); /// 设置开关状态,default:0 + + void setButtonColor(QColor color); /// 设置开关(圆形按钮)颜色 + void setBackOnColor(QColor color); /// 设置背景颜色-开 + void setBackOffColor(QColor color); /// 设置背景颜色-关 + void setEdgeColor(QColor color); /// 设置边缘颜色,默认透明 + +signals: + void sigEnableChanged(bool enable); /// 使能状态变化信号 + void sigSwitchChanged(bool onoff); /// 开关状态变化信号 + +protected: + void paintEvent(QPaintEvent* event); + void resizeEvent(QResizeEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + void enterEvent(QEvent* event); + void leaveEvent(QEvent* event); + +private: + bool mOnOff{ 0 }; //开关状态 + bool mEnable{ 1 }; //使能状态 + bool mPrecisionClickFlagh{ 0 }; //精确点击标志位 + bool mWaitSigModel{ 0 }; //等待模式,点击后按钮位置会进行切换,但是颜色需要等待外部信号变动 + bool mAnimationOnOff{ 1 }; //动画开关,default:1 + bool mHover{ 0 }; + + QColor mButtonColor{ Qt::white }; //开关(圆形按钮)颜色 + QColor mBackColor{ Qt::red }; + QColor mEdgeColor{ Qt::transparent }; //边缘颜色 + QRectF mButtonRect; //开关按钮rect + int mRadius{ 8 }; // 开关外观边缘圆角 + + int mAnimationPeriod{ 200 }; //动画周期 + QPointF mRightPos; // 动画位置-开 + QPointF mLeftPos; // 动画位置-关 + QColor mBackOnColor{ Qt::green }; //背景颜色-开 + QColor mBackOffColor{ Qt::darkGray }; //背景颜色-关 +}; + +#endif // WBSWITCHBUTTON_H +