469 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "Version.h"
#include <QImage>
#include <QStringList>
#include <QDebug>
#include <QVBoxLayout>
#include <QMessageBox>
#include <QStatusBar>
#include <QLabel>
#include "VrLog.h"
#include "VrSimpleLog.h"
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonDocument>
#include <QDateTime>
#include <thread>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 设置窗口图标
this->setWindowIcon(QIcon(":/resource/logo.png"));
// 设置状态栏字体
QFont statusFont = statusBar()->font();
statusFont.setPointSize(12);
statusBar()->setFont(statusFont);
// 设置状态栏颜色和padding
statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }");
// 隐藏标题栏
setWindowFlags(Qt::FramelessWindowHint);
// 启动后自动最大化显示
this->showMaximized();
// 初始化时隐藏label_work
ui->label_work->setVisible(false);
ui->btn_start->setVisible(false);
ui->btn_stop->setVisible(false);
// 创建组合控件
// m_gridWithTable = new ImageGridWithTableWidget();
m_gridView = new ImageGridWidget();
m_deviceStatusWidget = new DeviceStatusWidget();
m_tearingDataTableWidget = new TearingDataTableWidget();
// 将设备状态widget添加到frame_dev中
QVBoxLayout* frameResultImageLayout = new QVBoxLayout(ui->detect_result);
frameResultImageLayout->setContentsMargins(0, 0, 0, 0);
frameResultImageLayout->addWidget(m_gridView);
// 将TearingDataTableWidget添加到detect_data中
QVBoxLayout* frameDataLayout = new QVBoxLayout(ui->detect_data);
frameDataLayout->setContentsMargins(0, 0, 0, 0);
frameDataLayout->addWidget(m_tearingDataTableWidget);
QVBoxLayout* frameDevLayout = new QVBoxLayout(ui->device_status);
frameDevLayout->setContentsMargins(0, 0, 0, 0);
frameDevLayout->addWidget(m_deviceStatusWidget);
// 初始化Presenter
m_presenter = new BeltTearingPresenter();
// 将设备状态控件与Presenter关联
m_presenter->setStatusUpdate(this);
// 连接服务器数据接收信号
connect(m_presenter, &BeltTearingPresenter::serverDataReceived, this, &MainWindow::onServerDataReceived);
// 连接设备点击信号到重新检测槽函数
connect(m_deviceStatusWidget, &DeviceStatusWidget::deviceClicked, this, &MainWindow::onDeviceClicked);
// 设置版本信息显示
setupVersionDisplay();
// 设置表格最大行数限制,防止内存占用过大
if (m_tearingDataTableWidget) {
m_tearingDataTableWidget->setMaximumRows(100);
}
m_presenter->Init();
}
MainWindow::~MainWindow()
{
if(m_gridWithTable){
delete m_gridWithTable;
m_gridWithTable = nullptr;
}
if (m_deviceStatusWidget) {
delete m_deviceStatusWidget;
m_deviceStatusWidget = nullptr;
}
if (m_tearingDataTableWidget) {
delete m_tearingDataTableWidget;
m_tearingDataTableWidget = nullptr;
}
if (m_versionLabel) {
delete m_versionLabel;
m_versionLabel = nullptr;
}
if (m_dialogAlgoarg) {
delete m_dialogAlgoarg;
m_dialogAlgoarg = nullptr;
}
if (m_presenter) {
delete m_presenter;
m_presenter = nullptr;
}
delete ui;
}
void MainWindow::resizeEvent(QResizeEvent* event)
{
QMainWindow::resizeEvent(event);
// 获取窗口大小
QSize size = event->size();
int width = size.width();
int height = size.height();
// 调整title_group (groupBox) 宽度
ui->title_group->setGeometry(0, 0, width, 120);
// 调整btn_hide和btn_close位置
ui->btn_hide->move(width - 158, 32);
ui->btn_close->move(width - 79, 32);
// 调整detect_result控件
int detectResultWidth = width - 560 - 40 - 10; // 为两侧控件留出空间
int detectResultHeight = height - 160; // 减去标题栏高度
ui->detect_result->setGeometry(20, 140, detectResultWidth, detectResultHeight);
// 调整detect_data控件
int detectDataWidth = 560; // 保持宽度不变
int detectDataHeight = height - 140 - 160 - 10; // 减去标题栏和底部控件高度
ui->detect_data->setGeometry(20 + detectResultWidth + 10, 140, detectDataWidth, detectDataHeight);
// 调整device_status控件
int deviceStatusWidth = 560; // 保持宽度不变
int deviceStatusHeight = 140; // 保持高度不变
ui->device_status->setGeometry(20 + detectResultWidth + 10, height - 160, deviceStatusWidth, deviceStatusHeight);
}
void MainWindow::resizeToFitContent() {
if (!m_gridWithTable || m_gridWithTable->columnCount() == 0) {
return;
}
// 计算网格总宽度(列数 * 格子宽度 + 边距)
int gridWidth = m_gridWithTable->columnCount() * m_gridWithTable->tileBaseSize().width() + 32;
// 加上表格宽度
int totalWidth = gridWidth + 260;
// 计算总高度(行数 * 格子高度 + 边距)
int totalHeight = m_gridWithTable->rowCount() * m_gridWithTable->tileBaseSize().height() + 32;
// 设置窗口大小
resize(totalWidth, totalHeight);
}
void MainWindow::on_btn_hide_clicked()
{
// 最小化窗口
this->showMinimized();
}
void MainWindow::on_btn_close_clicked()
{
// 关闭应用程序
this->close();
}
void MainWindow::on_btn_test_clicked()
{
}
void MainWindow::on_btn_camera_clicked()
{
if(nullptr == ui_dialognetconfig){
ui_dialognetconfig = new DialogNetConfig(this);
// 连接信号
connect(ui_dialognetconfig, &DialogNetConfig::configSaved, this, &MainWindow::onConfigSaved);
}
ui_dialognetconfig->show();
}
void MainWindow::on_btn_algo_config_clicked()
{
if (!m_presenter) {
QMessageBox::warning(this, "错误", "系统未初始化完成!");
return;
}
auto serverInfos = m_presenter->getServerInfos();
auto beltTearingConfig = m_presenter->getBeltTearingConfig();
if (serverInfos.isEmpty() || !beltTearingConfig) {
QMessageBox::warning(this, "错误", "无可用服务器或配置接口!");
return;
}
if (!m_dialogAlgoarg) {
m_dialogAlgoarg = new DialogAlgoarg(beltTearingConfig, serverInfos, this);
// 连接参数变化信号
connect(m_dialogAlgoarg, &DialogAlgoarg::parametersChanged, this, &MainWindow::onParametersChanged);
// 连接服务器数据请求信号
connect(m_dialogAlgoarg, &DialogAlgoarg::requestServerData, this, &MainWindow::onRequestServerData);
}
m_dialogAlgoarg->Init();
m_dialogAlgoarg->show();
}
void MainWindow::onParametersChanged(const QString& serverName, const QByteArray& paramData)
{
if (m_presenter) {
m_presenter->sendParametersToServer(ByteDataType::WriteConfig, serverName, paramData);
}
// 添加空指针检查防止在m_tearingDataTableWidget为nullptr时崩溃
if (m_tearingDataTableWidget) {
m_tearingDataTableWidget->clearData();
}
}
void MainWindow::onRequestServerData(const QString& serverName)
{
if (!m_presenter) {
return;
}
// 通过Presenter发送请求到服务器
bool success = m_presenter->sendParametersToServer(ByteDataType::ReadConfig, serverName, QByteArray());
if (success) {
statusBar()->showMessage("已向服务器 " + serverName + " 发送数据请求");
} else {
statusBar()->showMessage("向服务器 " + serverName + " 发送请求失败");
}
}
void MainWindow::onServerDataReceived(const QString& serverName, const QJsonObject& data)
{
// 如果算法参数对话框存在,将数据传递给它
if (m_dialogAlgoarg) {
m_dialogAlgoarg->onServerDataReceived(serverName, data);
}
// 更新状态栏
statusBar()->showMessage("从服务器 " + serverName + " 获取参数完成");
}
// 设备点击事件处理槽函数
void MainWindow::onDeviceClicked(const QString& deviceAlias)
{
// 获取设备显示名称
QString deviceName = deviceAlias;
if (m_presenter) {
deviceName = m_presenter->getServerDisplayName(deviceAlias);
if (deviceName.isEmpty()) {
deviceName = deviceAlias;
}
}
// 创建自定义的确认对话框
QMessageBox msgBox(this);
msgBox.setWindowTitle("重新检测确认");
msgBox.setText(QString("确定要对设备 \"%1\" 进行重新检测吗?").arg(deviceName));
msgBox.setIcon(QMessageBox::Question);
// 设置白色字体样式
msgBox.setStyleSheet("QLabel { color: white; } QPushButton { color: white; }");
// 添加中文按钮
QPushButton *yesButton = msgBox.addButton("", QMessageBox::YesRole);
QPushButton *noButton = msgBox.addButton("", QMessageBox::NoRole);
// 显示对话框并获取用户选择
msgBox.exec();
// 如果用户确认重新检测
if (msgBox.clickedButton() == yesButton) {
// 调用Presenter的ResetDetect方法进行重新检测传递设备别名
if (m_presenter) {
m_presenter->ResetDetect(deviceAlias);
}
// 清空检测数据表格
if (m_tearingDataTableWidget) {
m_tearingDataTableWidget->clearData();
}
// 更新状态栏信息
statusBar()->showMessage(QString("已启动对设备 \"%1\" 的重新检测").arg(deviceName));
}
}
void MainWindow::onConfigSaved()
{
// 重新初始化Presenter
if (m_presenter) {
m_presenter->Init();
}
}
// IStatusUpdate接口方法实现
void MainWindow::OnStatusUpdate(const QString &statusMessage)
{
statusBar()->showMessage(statusMessage);
LOG_DEBUG("Status update: %s \n", statusMessage.toStdString().c_str());
}
// 回调需要显示几个图像
void MainWindow::OnNeedShowImageCount(const QStringList &deviceAliases)
{
// Handle the case when count is 0 (no images to show)
if (deviceAliases.isEmpty()) {
// Display a message in the grid view when there are no images to show
m_gridView->initImages(0);
LOG_DEBUG("No images to display\n");
} else {
m_gridView->initImages(deviceAliases.size());
// 为每个tile设置别名
for (int i = 0; i < deviceAliases.size(); ++i) {
m_gridView->setTileAlias(i, deviceAliases.at(i));
}
// 初始化设备状态列表
if (m_deviceStatusWidget && m_presenter) {
QList<DeviceInfo> devices;
for (const QString& alias : deviceAliases) {
QString displayName = m_presenter->getServerDisplayName(alias);
QString ip = m_presenter->getServerIp(alias);
devices.append(DeviceInfo(displayName.isEmpty() ? alias : displayName, alias, ip, DeviceStatus::Offline, true));
}
m_deviceStatusWidget->setDevices(devices);
}
}
}
void MainWindow::OnTearingResult(const BeltTearingResult &result)
{
// 如果图像有效,显示在网格控件中
if (result.bImageValid && !result.image.isNull()) {
// 使用服务器名称作为别名
m_gridView->setImages(result.aliasName, result.image);
} else if (result.bResultVaild) {
// 直接处理std::vector<TearingData>
m_tearingDataTableWidget->addDataBatch(result.serverName, result.result);
}
}
void MainWindow::OnServerConnected(const QString &serverName)
{
QString message = QString("已连接到服务器: %1").arg(serverName);
statusBar()->showMessage(message);
LOG_DEBUG("%s \n", message.toStdString().c_str());
}
void MainWindow::OnServerDisconnected(const QString &serverName)
{
QString message = QString("与服务器断开连接: %1").arg(serverName);
statusBar()->showMessage(message);
LOG_DEBUG("%s \n", message.toStdString().c_str());
}
void MainWindow::OnWorkStatusChanged(BeltTearingWorkStatus status)
{
QString statusStr;
switch (status) {
case BeltTearingWorkStatus::InitIng:
statusStr = "初始化中";
break;
case BeltTearingWorkStatus::Ready:
statusStr = "准备就绪";
break;
case BeltTearingWorkStatus::Working:
statusStr = "正在检测";
break;
case BeltTearingWorkStatus::Completed:
statusStr = "检测完成";
break;
case BeltTearingWorkStatus::Error:
statusStr = "设备异常";
break;
case BeltTearingWorkStatus::Disconnected:
statusStr = "连接断开";
break;
default:
statusStr = "未知状态";
break;
}
QString message = QString("工作状态: %1").arg(statusStr);
statusBar()->showMessage(message);
LOG_DEBUG("%s \n", message.toStdString().c_str());
}
void MainWindow::OnErrorOccurred(const QString &errorMessage)
{
statusBar()->showMessage("错误: " + errorMessage);
LOG_ERROR("Error occurred: %s \n", errorMessage.toStdString().c_str());
}
void MainWindow::OnDeviceStatusChanged(const QString &deviceName, int deviceStatus)
{
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateDeviceStatus(deviceName, static_cast<DeviceStatus>(deviceStatus));
}
}
void MainWindow::OnClearTearingData()
{
if (m_tearingDataTableWidget) {
m_tearingDataTableWidget->clearData();
}
}
void MainWindow::setupVersionDisplay()
{
// 创建版本信息标签
m_versionLabel = new QLabel(this);
// 设置版本信息文本:版本号 + 编译时间
QString versionText = QString("%1_%2_%3%4%5%6%7%8")
.arg(BELT_TEARING_APP_VERSION_STRING)
.arg(BELT_TEARING_APP_VERSION_BUILD)
.arg(YEAR)
.arg(MONTH, 2, 10, QChar('0'))
.arg(DAY, 2, 10, QChar('0'))
.arg(HOUR, 2, 10, QChar('0'))
.arg(MINUTE, 2, 10, QChar('0'))
.arg(SECOND, 2, 10, QChar('0'));
m_versionLabel->setText(versionText);
m_versionLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
// 设置样式使其看起来更美观
m_versionLabel->setStyleSheet("QLabel { color: rgb(239, 241, 245); font-size: 12px; margin-right: 10px; }");
// 将版本标签添加到状态栏的右侧
statusBar()->addPermanentWidget(m_versionLabel);
LOG_INFO("Version display initialized: %s\n", versionText.toStdString().c_str());
}