Browse Source

优化部分代码,在编辑区拖拽时能够限制在QGraphicsView范围内

master
付春阳 1 day ago
parent
commit
aee3f9a292
5 changed files with 519 additions and 29 deletions
  1. +207
    -9
      customgraphics.cpp
  2. +25
    -9
      customgraphics.h
  3. +263
    -9
      hmimodule.cpp
  4. +4
    -1
      hmimodule.h
  5. +20
    -1
      mainwindow.cpp

+ 207
- 9
customgraphics.cpp View File

@@ -4,6 +4,14 @@
#include <QMenu>
#include <QGraphicsScene>
#include <QColorDialog>
#include <QInputDialog>
#include <QDialog>
#include <QLabel>
#include <QSpinBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QGraphicsView>

// HmiComponent 基类实现
HmiComponent::HmiComponent(QGraphicsItem *parent) : QGraphicsObject(parent)
@@ -47,6 +55,19 @@ void HmiComponent::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
}
}

void HmiComponent::setAddress(int address)
{
if (m_address != address) {
m_address = address;
update();
}
}

int HmiComponent::address() const
{
return m_address;
}

void HmiComponent::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// 右键不触发选中信号,留给 contextMenuEvent 处理
@@ -58,38 +79,212 @@ void HmiComponent::mousePressEvent(QGraphicsSceneMouseEvent *event)

void HmiComponent::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
// 右键点击时,先清空场景中的其他选中项,然后选中当前项
scene()->clearSelection();
setSelected(true);
emit selected(this); // 同样可以发出选中信号,以便更新属性面板等
emit selected(this);

QMenu menu;

QAction *propertyAction = menu.addAction("属性");
QAction *copyAction = menu.addAction("复制");
QAction *deleteAction = menu.addAction("删除");
QAction *appearanceAction = menu.addAction("改变外观");

// 使用 connect 将菜单动作的触发连接到信号的发射,复制和删除
connect(propertyAction, &QAction::triggered, this, [this]() {
// 弹出属性对话框
QDialog dialog;
dialog.setWindowTitle("属性");

QLabel* addressLabel = new QLabel("地址: ");
QSpinBox* addressSpin = new QSpinBox();
addressSpin->setRange(0, 4000);
addressSpin->setValue(m_address); // 使用当前组件地址初始化

// ON状态颜色设置
QLabel* onColorLabel = new QLabel("ON状态外观: ");
// 颜色显示,用QLabel设置背景色简单示范
QLabel* onColorDisplay = new QLabel;
onColorDisplay->setFixedSize(40, 20);
onColorDisplay->setAutoFillBackground(true);
QPalette onPal = onColorDisplay->palette();
onPal.setColor(QPalette::Window, m_onColor);
onColorDisplay->setPalette(onPal);
onColorDisplay->setFrameShape(QFrame::Box);

QPushButton* onColorBtn = new QPushButton("选择颜色");

// OFF状态颜色设置
QLabel* offColorLabel = new QLabel("OFF状态外观: ");
QLabel* offColorDisplay = new QLabel;
offColorDisplay->setFixedSize(40, 20);
offColorDisplay->setAutoFillBackground(true);
QPalette offPal = offColorDisplay->palette();
offPal.setColor(QPalette::Window, m_offColor);
offColorDisplay->setPalette(offPal);
offColorDisplay->setFrameShape(QFrame::Box);

QPushButton* offColorBtn = new QPushButton("选择颜色");

QObject::connect(offColorBtn, &QPushButton::clicked, [&]() {
QColor color = QColorDialog::getColor(m_offColor, nullptr, "选择 OFF 状态颜色");
if (color.isValid()) {
m_offColor = color;
QPalette pal = offColorDisplay->palette();
pal.setColor(QPalette::Window, color);
offColorDisplay->setPalette(pal);
offColorDisplay->update();
setColor(color); // 默认显示OFF状态颜色
}
});

// 地址布局
QHBoxLayout* addressLayout = new QHBoxLayout();
addressLayout->addWidget(addressLabel);
addressLayout->addWidget(addressSpin);

// ON颜色布局
QHBoxLayout* onColorLayout = new QHBoxLayout();
onColorLayout->addWidget(onColorLabel);
onColorLayout->addWidget(onColorDisplay);
onColorLayout->addWidget(onColorBtn);

// OFF颜色布局
QHBoxLayout* offColorLayout = new QHBoxLayout();
offColorLayout->addWidget(offColorLabel);
offColorLayout->addWidget(offColorDisplay);
offColorLayout->addWidget(offColorBtn);

// 确定/取消按钮
QPushButton* okBtn = new QPushButton("确定");
QPushButton* cancelBtn = new QPushButton("取消");
QHBoxLayout* btnLayout = new QHBoxLayout();
btnLayout->addStretch();
btnLayout->addWidget(okBtn);
btnLayout->addWidget(cancelBtn);

// 颜色选择按钮点击槽
QObject::connect(onColorBtn, &QPushButton::clicked, [&]() {
QColor color = QColorDialog::getColor(m_onColor, nullptr, "选择 ON 状态颜色");
if (color.isValid()) {
m_onColor = color;
QPalette pal = onColorDisplay->palette();
pal.setColor(QPalette::Window, color);
onColorDisplay->setPalette(pal);
onColorDisplay->update();
}
});

QVBoxLayout* mainLayout = new QVBoxLayout();
mainLayout->addLayout(addressLayout);
mainLayout->addLayout(onColorLayout);
mainLayout->addLayout(offColorLayout);
mainLayout->addLayout(btnLayout);

dialog.setLayout(mainLayout);

// 关闭逻辑
QObject::connect(okBtn, &QPushButton::clicked, [&]() {
// 保存地址
int newAddress = addressSpin->value();
setAddress(newAddress);

// 已经在onColorBtn / offColorBtn中修改了m_onColor / m_offColor,需要触发界面更新
update();
dialog.accept();
});
QObject::connect(cancelBtn, &QPushButton::clicked, &dialog, &QDialog::reject);

dialog.exec();
});

connect(copyAction, &QAction::triggered, this, [this]() {
emit copyRequested(this);
});

connect(deleteAction, &QAction::triggered, this, [this]() {
emit deleteRequested(this);
});
connect(appearanceAction, &QAction::triggered, this, &HmiComponent::changeAppearance);

// 在鼠标光标位置显示菜单
menu.exec(event->screenPos());
}

void HmiComponent::changeAppearance()
void HmiComponent::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
emit appearanceChangedRequested(this);
if (!(flags() & QGraphicsItem::ItemIsMovable)) {
// 如果项不可移动,直接调用基类处理
QGraphicsObject::mouseMoveEvent(event);
return;
}

// 计算拖动后的位置
QPointF delta = event->scenePos() - event->lastScenePos();
QPointF newPos = pos() + delta;

// 获取视图(假设只有1个视图)
QList<QGraphicsView*> views = scene()->views();
if (views.isEmpty()) {
// 没有视图则默认处理
QGraphicsObject::mouseMoveEvent(event);
return;
}
QGraphicsView* view = views.first();

// 获取视口矩形(像素坐标)
QRect viewportRect = view->viewport()->rect();

// 将视口矩形映射到场景坐标
QPointF topLeftScene = view->mapToScene(viewportRect.topLeft());
QPointF bottomRightScene = view->mapToScene(viewportRect.bottomRight());
QRectF visibleSceneRect(topLeftScene, bottomRightScene);

// 组件的边界矩形(局部坐标)
QRectF bounds = boundingRect();

// 计算移动后组件边界矩形(在场景坐标)
QRectF newBounds = bounds.translated(newPos);

// 限制组件边界必须完全在视图可见区域内
qreal limitedX = newPos.x();
qreal limitedY = newPos.y();

if (newBounds.left() < visibleSceneRect.left())
limitedX += visibleSceneRect.left() - newBounds.left();
if (newBounds.top() < visibleSceneRect.top())
limitedY += visibleSceneRect.top() - newBounds.top();
if (newBounds.right() > visibleSceneRect.right())
limitedX -= newBounds.right() - visibleSceneRect.right();
if (newBounds.bottom() > visibleSceneRect.bottom())
limitedY -= newBounds.bottom() - visibleSceneRect.bottom();

setPos(QPointF(limitedX, limitedY));
event->accept();
}


void HmiComponent::setOnColor(const QColor& color) {
m_onColor = color;
}

void HmiComponent::setOffColor(const QColor& color) {
m_offColor = color;
setColor(color); // 默认展示 OFF 状态颜色
}

QColor HmiComponent::onColor() const {
return m_onColor;
}

QColor HmiComponent::offColor() const {
return m_offColor;
}


HmiButton::HmiButton(QGraphicsItem *parent) : HmiComponent(parent)
{
m_color = Qt::gray;
m_offColor = m_color; // OFF状态颜色设为默认颜色
m_onColor = Qt::green; // ON状态颜色为绿色
m_componentName = "Button";
setColor(m_offColor); // 当前显示OFF颜色
}

QRectF HmiButton::boundingRect() const
@@ -106,8 +301,11 @@ void HmiButton::paintShape(QPainter *painter)

HmiIndicator::HmiIndicator(QGraphicsItem *parent) : HmiComponent(parent)
{
m_color = Qt::green;
m_color = Qt::red;
m_offColor = m_color; // OFF状态颜色设为默认颜色
m_onColor = Qt::green; // ON状态颜色为绿色
m_componentName = "Indicator";
setColor(m_offColor); // 当前显示OFF颜色
}

QRectF HmiIndicator::boundingRect() const


+ 25
- 9
customgraphics.h View File

@@ -2,6 +2,7 @@
#define CUSTOMGRAPHICS_H

#include <QGraphicsObject>
#include <QColor>
// 只需要前向声明,因为头文件中只用到了指针
class QPainter;
class QGraphicsSceneMouseEvent;
@@ -16,41 +17,56 @@ enum class ComponentType {
class HmiComponent : public QGraphicsObject
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(QColor color READ color WRITE setColor) // 当前颜色(默认使用 OFF 状态)
Q_PROPERTY(QString componentName READ componentName WRITE setComponentName)
// 新增address属性
Q_PROPERTY(int address READ address WRITE setAddress)

signals:
void selected(HmiComponent* item);
// 为复制和删除请求添加信号
void copyRequested(HmiComponent* item);
void deleteRequested(HmiComponent* item);
void appearanceChangedRequested(HmiComponent* item);

// 添加信号用于改变状态颜色
void changeOnColorRequested(HmiComponent* item);
void changeOffColorRequested(HmiComponent* item);

public:
explicit HmiComponent(QGraphicsItem *parent = nullptr);

void setColor(const QColor& color);
void setColor(const QColor& color); // 当前显示颜色
QColor color() const;

void setComponentName(const QString& name);
QString componentName() const;

void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
// 设置 ON / OFF 状态颜色
void setOnColor(const QColor& color);
void setOffColor(const QColor& color);
QColor onColor() const;
QColor offColor() const;

public slots:
void changeAppearance();
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
// 地址相关
void setAddress(int address);
int address() const;

protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
// 重写上下文菜单事件
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
virtual void paintShape(QPainter* painter) = 0;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;

protected:
QColor m_color;
QColor m_color; // 当前显示颜色(编辑器中为 OFF)
QColor m_onColor = Qt::green;
QColor m_offColor;
QString m_componentName;
int m_address = 0;
};



// 按钮类
class HmiButton : public HmiComponent
{


+ 263
- 9
hmimodule.cpp View File

@@ -7,6 +7,11 @@
#include <QVBoxLayout>
#include <algorithm>
#include <QColorDialog>
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QDebug>

HMIModule::HMIModule(Ui::MainWindow* ui, QObject *parent)
: QObject{parent}, ui_(ui), m_scene(nullptr)
@@ -56,6 +61,236 @@ void HMIModule::init() {
connect(this, &HMIModule::pageRemoved, this, &HMIModule::onPageRemoved);
}

bool HMIModule::saveToFile(const QString& filePath)
{
QTabWidget* tabWidget = ui_->tabWidget_2;

QJsonArray pagesArray;

for (int i = 0; i < tabWidget->count(); ++i) {
QWidget* page = tabWidget->widget(i);
QString pageName = tabWidget->tabText(i);

QGraphicsView* graphicsView = page->findChild<QGraphicsView*>();
if (!graphicsView) continue;

QGraphicsScene* scene = graphicsView->scene();
if (!scene) continue;

QJsonObject pageObject;
pageObject["pageName"] = pageName;

QJsonArray componentsArray;

for (QGraphicsItem* item : scene->items()) {
HmiComponent* component = dynamic_cast<HmiComponent*>(item);
if (!component)
continue;

QJsonObject compObj;
// 组件类型
if (dynamic_cast<HmiButton*>(component)) {
compObj["type"] = "Button";
} else if (dynamic_cast<HmiIndicator*>(component)) {
compObj["type"] = "Indicator";
} else {
continue; // 忽略未知类型
}

// 位置
QPointF pos = component->pos();
compObj["x"] = pos.x();
compObj["y"] = pos.y();

// 颜色 (保存在HEX)
compObj["color"] = component->color().name();
// On / Off颜色
compObj["onColor"] = component->onColor().name();
compObj["offColor"] = component->offColor().name();
// 组件名称
compObj["componentName"] = component->componentName();
// 新增地址属性
compObj["address"] = component->address();

componentsArray.append(compObj);
}

pageObject["components"] = componentsArray;
pagesArray.append(pageObject);
}

QJsonObject rootObject;
rootObject["pages"] = pagesArray;

QJsonDocument doc(rootObject);

QFile file(filePath);
if (!file.open(QIODevice::WriteOnly)) {
emit logMessageGenerated(QString("无法打开文件进行保存: %1").arg(filePath));
return false;
}

file.write(doc.toJson(QJsonDocument::Indented));
file.close();

emit logMessageGenerated(QString("[%1] 保存成功: %2")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(filePath));
return true;
}

// 清空所有页面,重建页面并加载组件
bool HMIModule::openFromFile(const QString& filePath)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
emit logMessageGenerated(QString("无法打开文件进行加载: %1").arg(filePath));
return false;
}

QByteArray data = file.readAll();
file.close();

QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError) {
emit logMessageGenerated(QString("JSON解析错误: %1").arg(parseError.errorString()));
return false;
}

if (!doc.isObject()) {
emit logMessageGenerated("JSON格式错误,不是对象");
return false;
}

QJsonObject rootObj = doc.object();
if (!rootObj.contains("pages") || !rootObj["pages"].isArray()) {
emit logMessageGenerated("JSON缺少pages数组");
return false;
}

QJsonArray pagesArray = rootObj["pages"].toArray();

QTabWidget* tabWidget = ui_->tabWidget_2;

// 清空所有现有页面
while (tabWidget->count() > 0) {
QWidget* page = tabWidget->widget(0);
tabWidget->removeTab(0);
delete page;
}

m_availablePageNumbers.clear();
m_pageOrder.clear();

for (const QJsonValue& pageVal : pagesArray) {
if (!pageVal.isObject())
continue;

QJsonObject pageObj = pageVal.toObject();

QString pageName = pageObj["pageName"].toString("Unnamed");
int pageNumber = 0;
if (pageName.startsWith("Page ")) {
pageNumber = pageName.mid(5).toInt();
}

// 新建页面
QWidget* newPage = new QWidget(tabWidget);
newPage->setObjectName(pageName);

QGraphicsView* newGraphicsView = new QGraphicsView(newPage);
CustomGraphicsScene* newScene = new CustomGraphicsScene(newGraphicsView, this);

// 设置大小,与默认页面相同
QSize defaultSize(691, 381);
newGraphicsView->resize(defaultSize);
newScene->setSceneRect(0, 0, 800, 600);

newGraphicsView->setScene(newScene);

QVBoxLayout* layout = new QVBoxLayout(newPage);
layout->addWidget(newGraphicsView);
newPage->setLayout(layout);

int tabIndex = tabWidget->addTab(newPage, pageName);

// 连接信号
connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated);
connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested);
connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested);
connect(newScene, &CustomGraphicsScene::deleteRequestFromScene, this, &HMIModule::onDeleteRequested);

m_pageOrder.append(pageNumber);

QJsonArray compArray = pageObj["components"].toArray();
for (const QJsonValue& compVal : compArray) {
if (!compVal.isObject())
continue;

QJsonObject compObj = compVal.toObject();

QString typeStr = compObj["type"].toString();
double x = compObj["x"].toDouble();
double y = compObj["y"].toDouble();
QString colorName = compObj["color"].toString();
QString onColorName = compObj["onColor"].toString();
QString offColorName = compObj["offColor"].toString();
QString componentName = compObj["componentName"].toString();
int address = compObj["address"].toInt(0);

HmiComponent* newItem = nullptr;
if (typeStr == "Button") {
newItem = new HmiButton();
} else if (typeStr == "Indicator") {
newItem = new HmiIndicator();
} else {
continue;
}

if (newItem) {
newItem->setPos(QPointF(x, y));
QColor color(colorName);
if (color.isValid()) {
newItem->setColor(color);
}
QColor onColor(onColorName);
if (onColor.isValid())
newItem->setOnColor(onColor);
QColor offColor(offColorName);
if (offColor.isValid())
newItem->setOffColor(offColor);

QColor currentColor(colorName);
if (currentColor.isValid()) {
// 可以根据实际业务逻辑判断,是否恢复为onColor或offColor
// 这里直接恢复当前颜色
newItem->setColor(currentColor);
} else {
// 如果当前颜色无效,则使用 offColor 作为默认颜色
newItem->setColor(newItem->offColor());
}

newItem->setComponentName(componentName);
// 设置地址
newItem->setAddress(address);
newScene->addItem(newItem);
setupNewComponent(newItem);
}
}
}

// 自动切换到第一页
if (tabWidget->count() > 0) {
tabWidget->setCurrentIndex(0);
}

emit logMessageGenerated(QString("[%1] 打开文件成功: %2")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(filePath));
return true;
}

void HMIModule::setupNewComponent(HmiComponent* item)
{
if (!item) return;
@@ -63,7 +298,9 @@ void HMIModule::setupNewComponent(HmiComponent* item)
connect(item, &HmiComponent::selected, this, &HMIModule::onComponentSelected);
connect(item, &HmiComponent::copyRequested, this, &HMIModule::onCopyRequested);
connect(item, &HmiComponent::deleteRequested, this, &HMIModule::onDeleteRequested);
connect(item, &HmiComponent::appearanceChangedRequested, this, &HMIModule::onChangeAppearanceRequested); // 连接信号
connect(item, &HmiComponent::changeOnColorRequested, this, &HMIModule::onChangeOnColorRequested);
connect(item, &HmiComponent::changeOffColorRequested, this, &HMIModule::onChangeOffColorRequested);


QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
QString log = QString("[%1] 创建 %2 组件").arg(currentTime).arg(item->componentName());
@@ -177,13 +414,6 @@ void HMIModule::onDeleteRequested()
}
}

void HMIModule::onChangeAppearanceRequested(HmiComponent* item)
{
QColor color = QColorDialog::getColor(item->color(), nullptr, "选择颜色");
if (color.isValid()) {
item->setColor(color);
}
}

// 添加页面后的槽函数
void HMIModule::onPageAdded(int pageNumber, int index)
@@ -203,6 +433,30 @@ void HMIModule::onPageRemoved(int pageNumber, int index)
}
}

void HMIModule::onChangeOnColorRequested(HmiComponent* item)
{
QColor color = QColorDialog::getColor(item->onColor(), nullptr, "选择 ON 状态颜色");
if (color.isValid()) {
item->setOnColor(color);
emit logMessageGenerated(QString("[%1] 设置 %2 的 ON 状态颜色为 %3")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(item->componentName())
.arg(color.name()));
}
}

void HMIModule::onChangeOffColorRequested(HmiComponent* item)
{
QColor color = QColorDialog::getColor(item->offColor(), nullptr, "选择 OFF 状态颜色");
if (color.isValid()) {
item->setOffColor(color); // 同时更新当前显示颜色
emit logMessageGenerated(QString("[%1] 设置 %2 的 OFF 状态颜色为 %3")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(item->componentName())
.arg(color.name()));
}
}

void HMIModule::onComponentSelected(HmiComponent* item)
{
// 不需要任何操作,可以留空
@@ -266,7 +520,7 @@ void HMIModule::addPage()
tabIndex = tabWidget->addTab(newPage, pageName);
}

// 连接信号和槽 *******************************************************************
// 连接信号和槽
connect(newScene, &CustomGraphicsScene::componentCreated, this, &HMIModule::onComponentCreated);
connect(newScene, &CustomGraphicsScene::copyRequestFromScene, this, &HMIModule::onCopyRequested);
connect(newScene, &CustomGraphicsScene::pasteRequestFromScene, this, &HMIModule::onPasteRequested);


+ 4
- 1
hmimodule.h View File

@@ -15,6 +15,8 @@ public:
explicit HMIModule(Ui::MainWindow* ui, QObject *parent = nullptr);
void setButtonIcon(QAbstractButton* button, const QString& iconPath);
void init();
bool saveToFile(const QString& filePath);
bool openFromFile(const QString& filePath);

signals:
void pageAdded(int pageNumber, int index);
@@ -29,13 +31,14 @@ private slots:
void onCopyRequested();
void onPasteRequested(const QPointF& scenePos);
void onDeleteRequested();
void onChangeAppearanceRequested(HmiComponent* item);
void addPage();
void deletePage();
void prePage();
void nextPage();
void onPageAdded(int pageNumber, int index);
void onPageRemoved(int pageNumber, int index);
void onChangeOnColorRequested(HmiComponent* item);
void onChangeOffColorRequested(HmiComponent* item);

private:
void setupNewComponent(HmiComponent* item);


+ 20
- 1
mainwindow.cpp View File

@@ -3,7 +3,8 @@
#include <QToolButton>
#include <QVBoxLayout>
#include <QButtonGroup>

#include <QFileDialog>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@@ -16,6 +17,24 @@ MainWindow::MainWindow(QWidget *parent)
initMainWindow();
// 连接 HMIModule 的信号到 MainWindow 的槽
connect(hmi_, &HMIModule::logMessageGenerated, this, &MainWindow::appendLog);

connect(ui_->action_3, &QAction::triggered, this, [this]() {
QString fileName = QFileDialog::getSaveFileName(this, "保存HMI设计", "", "JSON文件 (*.json)");
if (!fileName.isEmpty()) {
if (!hmi_->saveToFile(fileName)) {
QMessageBox::warning(this, "保存失败", "文件保存失败!");
}
}
});

connect(ui_->action_2, &QAction::triggered, this, [this]() {
QString fileName = QFileDialog::getOpenFileName(this, "打开HMI设计", "", "JSON文件 (*.json)");
if (!fileName.isEmpty()) {
if (!hmi_->openFromFile(fileName)) {
QMessageBox::warning(this, "打开失败", "文件打开失败或格式不正确!");
}
}
});
}

MainWindow::~MainWindow()


Loading…
Cancel
Save