|
@@ -20,11 +20,30 @@ MainWindow::MainWindow(QWidget *parent) |
|
|
{ |
|
|
{ |
|
|
ui->setupUi(this); |
|
|
ui->setupUi(this); |
|
|
registerManager = new RegisterManager(this); |
|
|
registerManager = new RegisterManager(this); |
|
|
plc_ = new PLC(registerManager, ui->widget); |
|
|
|
|
|
hmi_ = new HMI(ui->widget); |
|
|
|
|
|
modbusManager = new ModbusManager(registerManager, this); |
|
|
modbusManager = new ModbusManager(registerManager, this); |
|
|
plc_->show(); |
|
|
|
|
|
hmi_->hide(); |
|
|
|
|
|
|
|
|
// 初始化PLC标签页 |
|
|
|
|
|
ui->plc_tab_widget->setTabsClosable(true); |
|
|
|
|
|
ui->plc_tab_widget->setMovable(true); |
|
|
|
|
|
|
|
|
|
|
|
// 初始化HMI标签页 |
|
|
|
|
|
ui->hmi_tab_widget->setTabsClosable(true); |
|
|
|
|
|
ui->hmi_tab_widget->setMovable(true); |
|
|
|
|
|
|
|
|
|
|
|
/* 2. 列表 */ |
|
|
|
|
|
ui->listWidget->setViewMode(QListView::IconMode); |
|
|
|
|
|
ui->listWidget->setIconSize(QSize(60, 30)); |
|
|
|
|
|
ui->listWidget->setDragEnabled(false); |
|
|
|
|
|
ui->listWidget->viewport()->installEventFilter(this); |
|
|
|
|
|
|
|
|
|
|
|
newPage(true); |
|
|
|
|
|
newPage(false); |
|
|
|
|
|
|
|
|
|
|
|
createComponents(); |
|
|
|
|
|
|
|
|
|
|
|
connect(ui->plc_tab_widget, &QTabWidget::tabCloseRequested,this,&MainWindow::onTabCloseRequested); |
|
|
|
|
|
connect(ui->hmi_tab_widget, &QTabWidget::tabCloseRequested,this,&MainWindow::onTabCloseRequested); |
|
|
|
|
|
connect(ui->listWidget,&QListWidget::currentTextChanged,this,&MainWindow::onListwidgetCurrenttextchanged); |
|
|
|
|
|
|
|
|
connect(ui->action_plc,&QAction::triggered,this,&MainWindow::plcChange); |
|
|
connect(ui->action_plc,&QAction::triggered,this,&MainWindow::plcChange); |
|
|
connect(ui->action_hmi,&QAction::triggered,this,&MainWindow::hmiChange); |
|
|
connect(ui->action_hmi,&QAction::triggered,this,&MainWindow::hmiChange); |
|
|
|
|
|
|
|
@@ -33,122 +52,390 @@ MainWindow::MainWindow(QWidget *parent) |
|
|
connect(ui->action_open, &QAction::triggered, this, &MainWindow::openProject); |
|
|
connect(ui->action_open, &QAction::triggered, this, &MainWindow::openProject); |
|
|
connect(ui->action_connect, &QAction::triggered, this, &MainWindow::connection); |
|
|
connect(ui->action_connect, &QAction::triggered, this, &MainWindow::connection); |
|
|
connect(ui->action_disconnect, &QAction::triggered, this, &MainWindow::disconnection); |
|
|
connect(ui->action_disconnect, &QAction::triggered, this, &MainWindow::disconnection); |
|
|
|
|
|
connect(ui->btn_insert, &QPushButton::clicked, this, &MainWindow::btnInsertClicked); |
|
|
|
|
|
|
|
|
connect(modbusManager, &ModbusManager::connectionStatusChanged, |
|
|
connect(modbusManager, &ModbusManager::connectionStatusChanged, |
|
|
this, &MainWindow::updateConnectionStatus); |
|
|
this, &MainWindow::updateConnectionStatus); |
|
|
|
|
|
// connect(modbusManager, &ModbusManager::connectionStatusChanged, |
|
|
|
|
|
// this, &PLC::updateConnectionStatus); |
|
|
|
|
|
// connect(modbusManager, &ModbusManager::errorOccurred, |
|
|
|
|
|
// this, &PLC::handleModbusError); |
|
|
|
|
|
// connect(this, &PLC::requestWriteRegister, |
|
|
|
|
|
// modbusManager, &ModbusManager::writeRegister); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
plc_->applyProjectToScene(plcProject_); // 初始空 |
|
|
|
|
|
hmi_->applyProjectToScene(hmiProject_); |
|
|
|
|
|
|
|
|
ui->stackedWidget->setCurrentIndex(0); |
|
|
|
|
|
setWindowTitle("未命名项目 - PLC编辑器"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
MainWindow::~MainWindow() |
|
|
MainWindow::~MainWindow() |
|
|
{ |
|
|
{ |
|
|
|
|
|
qDeleteAll(plcScenes); |
|
|
|
|
|
qDeleteAll(plcViews); |
|
|
|
|
|
qDeleteAll(hmiScenes); |
|
|
|
|
|
qDeleteAll(hmiViews); |
|
|
delete ui; |
|
|
delete ui; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::newPage(bool isPlc) |
|
|
|
|
|
{ |
|
|
|
|
|
// 创建新场景 |
|
|
|
|
|
QGraphicsScene* newScene = new QGraphicsScene(this); |
|
|
|
|
|
|
|
|
|
|
|
// 创建新视图 |
|
|
|
|
|
MyGraphicsView* newView = new MyGraphicsView(this); |
|
|
|
|
|
newView->setScene(newScene); |
|
|
|
|
|
newView->setSceneRect(0, 0, 800, 600); |
|
|
|
|
|
newView->setDragMode(QGraphicsView::RubberBandDrag); |
|
|
|
|
|
|
|
|
|
|
|
if (isPlc) { |
|
|
|
|
|
// 添加到PLC标签页 |
|
|
|
|
|
int newIndex = ui->plc_tab_widget->addTab(newView, QString("页面 %1").arg(plcScenes.size() + 1)); |
|
|
|
|
|
ui->plc_tab_widget->setCurrentIndex(newIndex); |
|
|
|
|
|
|
|
|
|
|
|
// 保存场景和视图 |
|
|
|
|
|
plcScenes.append(newScene); |
|
|
|
|
|
plcViews.append(newView); |
|
|
|
|
|
connect(newView, &MyGraphicsView::itemBoundToRegister, |
|
|
|
|
|
registerManager, &RegisterManager::bindItem); |
|
|
|
|
|
connect(newView, &MyGraphicsView::itemResetRegister, |
|
|
|
|
|
registerManager, &RegisterManager::unbindItem); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 添加到HMI标签页 |
|
|
|
|
|
int newIndex = ui->hmi_tab_widget->addTab(newView, QString("页面 %1").arg(hmiScenes.size() + 1)); |
|
|
|
|
|
ui->hmi_tab_widget->setCurrentIndex(newIndex); |
|
|
|
|
|
|
|
|
|
|
|
// 保存场景和视图 |
|
|
|
|
|
hmiScenes.append(newScene); |
|
|
|
|
|
hmiViews.append(newView); |
|
|
|
|
|
connect(newView, &MyGraphicsView::itemBoundToRegister, |
|
|
|
|
|
registerManager, &RegisterManager::bindItem); |
|
|
|
|
|
connect(newView, &MyGraphicsView::itemResetRegister, |
|
|
|
|
|
registerManager, &RegisterManager::unbindItem); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::createComponents() |
|
|
|
|
|
{ |
|
|
|
|
|
ui->listWidget->clear(); |
|
|
|
|
|
if (currentIsPLC_) |
|
|
|
|
|
{ |
|
|
|
|
|
struct Comp { QString name; QColor color; }; |
|
|
|
|
|
const QVector<Comp> comps = { |
|
|
|
|
|
{"常开", Qt::blue}, |
|
|
|
|
|
{"常闭", Qt::red}, |
|
|
|
|
|
{"比较", Qt::green}, |
|
|
|
|
|
{"线圈", Qt::darkYellow} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
for (const Comp &c : comps) { |
|
|
|
|
|
QListWidgetItem *it = new QListWidgetItem(c.name, ui->listWidget); |
|
|
|
|
|
|
|
|
|
|
|
QPixmap pix(60, 30); |
|
|
|
|
|
pix.fill(Qt::white); |
|
|
|
|
|
QPainter p(&pix); |
|
|
|
|
|
p.setRenderHint(QPainter::Antialiasing); |
|
|
|
|
|
p.setBrush(c.color.lighter(150)); |
|
|
|
|
|
p.setPen(QPen(c.color, 2)); |
|
|
|
|
|
p.drawRoundedRect(QRect(5, 5, 50, 20), 3, 3); |
|
|
|
|
|
p.setPen(Qt::black); |
|
|
|
|
|
p.drawText(QRect(5, 5, 50, 20), Qt::AlignCenter, c.name); |
|
|
|
|
|
|
|
|
|
|
|
it->setIcon(QIcon(pix)); |
|
|
|
|
|
it->setData(Qt::UserRole, c.name); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
struct Comp { QString name; QColor color; }; |
|
|
|
|
|
const QVector<Comp> comps = { |
|
|
|
|
|
{"按钮", Qt::blue}, |
|
|
|
|
|
{"指示灯", Qt::red} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
for (const Comp &c : comps) { |
|
|
|
|
|
QListWidgetItem *it = new QListWidgetItem(c.name, ui->listWidget); |
|
|
|
|
|
|
|
|
|
|
|
QPixmap pix(60, 30); |
|
|
|
|
|
pix.fill(Qt::white); |
|
|
|
|
|
QPainter p(&pix); |
|
|
|
|
|
p.setRenderHint(QPainter::Antialiasing); |
|
|
|
|
|
p.setBrush(c.color.lighter(150)); |
|
|
|
|
|
p.setPen(QPen(c.color, 2)); |
|
|
|
|
|
p.drawRoundedRect(QRect(5, 5, 50, 20), 3, 3); |
|
|
|
|
|
p.setPen(Qt::black); |
|
|
|
|
|
p.drawText(QRect(5, 5, 50, 20), Qt::AlignCenter, c.name); |
|
|
|
|
|
|
|
|
|
|
|
it->setIcon(QIcon(pix)); |
|
|
|
|
|
it->setData(Qt::UserRole, c.name); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::clearScene() |
|
|
|
|
|
{ |
|
|
|
|
|
if(currentIsPLC_) |
|
|
|
|
|
{ |
|
|
|
|
|
if (currentPageIndex() >= 0 && currentPageIndex() < plcScenes.size()) { |
|
|
|
|
|
plcScenes[currentPageIndex()]->clear(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
if (currentPageIndex() >= 0 && currentPageIndex() < hmiScenes.size()) { |
|
|
|
|
|
hmiScenes[currentPageIndex()]->clear(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::applyProjectToScene(const Project &proj, int pageIndex) |
|
|
|
|
|
{ |
|
|
|
|
|
if (currentIsPLC_) |
|
|
|
|
|
{ |
|
|
|
|
|
if (pageIndex < 0 || pageIndex >= plcScenes.size()) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
plcScenes[pageIndex]->clear(); |
|
|
|
|
|
QVector<Item*> itemObjs; |
|
|
|
|
|
for (const auto& d : proj.items_) { |
|
|
|
|
|
Item* item = creatItem(d.type); |
|
|
|
|
|
if (!item) continue; |
|
|
|
|
|
item->setPos(d.x, d.y); |
|
|
|
|
|
item->setRegisterId(d.registerId); |
|
|
|
|
|
connect(item, &Item::requestCopy, plcViews[pageIndex], &MyGraphicsView::onItemRequestCopy); |
|
|
|
|
|
connect(item, &Item::requestDelete, plcViews[pageIndex], &MyGraphicsView::onItemRequestDelete); |
|
|
|
|
|
connect(item, &Item::requestBindRegister, plcViews[pageIndex], &MyGraphicsView::onItemRequestBindRegister); |
|
|
|
|
|
plcScenes[pageIndex]->addItem(item); |
|
|
|
|
|
registerManager->bindItem(item,d.registerId); |
|
|
|
|
|
itemObjs.append(item); |
|
|
|
|
|
} |
|
|
|
|
|
for (const auto& c : proj.connections_) { |
|
|
|
|
|
if (c.from >= 0 && c.from < itemObjs.size() && c.to >= 0 && c.to < itemObjs.size()) { |
|
|
|
|
|
Connection* conn = new Connection( |
|
|
|
|
|
itemObjs[c.from], static_cast<Item::AnchorType>(c.fromType), |
|
|
|
|
|
itemObjs[c.to], static_cast<Item::AnchorType>(c.toType)); |
|
|
|
|
|
plcScenes[pageIndex]->addItem(conn); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
if (pageIndex < 0 || pageIndex >= hmiScenes.size()) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
hmiScenes[pageIndex]->clear(); |
|
|
|
|
|
QVector<Item*> itemObjs; |
|
|
|
|
|
for (const auto& d : proj.items_) { |
|
|
|
|
|
Item* item = creatItem(d.type); |
|
|
|
|
|
if (!item) continue; |
|
|
|
|
|
item->setPos(d.x, d.y); |
|
|
|
|
|
item->setRegisterId(d.registerId); |
|
|
|
|
|
connect(item, &Item::requestCopy, hmiViews[pageIndex], &MyGraphicsView::onItemRequestCopy); |
|
|
|
|
|
connect(item, &Item::requestDelete, hmiViews[pageIndex], &MyGraphicsView::onItemRequestDelete); |
|
|
|
|
|
connect(item, &Item::requestBindRegister, hmiViews[pageIndex], &MyGraphicsView::onItemRequestBindRegister); |
|
|
|
|
|
hmiScenes[pageIndex]->addItem(item); |
|
|
|
|
|
registerManager->bindItem(item,d.registerId); |
|
|
|
|
|
itemObjs.append(item); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::extractSceneToProject(Project &proj, int pageIndex) |
|
|
|
|
|
{ |
|
|
|
|
|
if (currentIsPLC_) |
|
|
|
|
|
{ |
|
|
|
|
|
if (pageIndex < 0 || pageIndex >= plcScenes.size()) return; |
|
|
|
|
|
proj.clear(); |
|
|
|
|
|
QList<Item*> items; |
|
|
|
|
|
for (QGraphicsItem* gi : plcScenes[pageIndex]->items()){ |
|
|
|
|
|
if (Item* it = dynamic_cast<Item*>(gi)){ |
|
|
|
|
|
items.append(it); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
for (Item* it : items) { |
|
|
|
|
|
Project::ItemData d; |
|
|
|
|
|
d.type = it->itemType(); |
|
|
|
|
|
d.x = it->pos().x(); |
|
|
|
|
|
d.y = it->pos().y(); |
|
|
|
|
|
d.registerId = it->registerId(); |
|
|
|
|
|
proj.items_.append(d); |
|
|
|
|
|
} |
|
|
|
|
|
for (QGraphicsItem* gi : plcScenes[pageIndex]->items()) { |
|
|
|
|
|
if (Connection* conn = dynamic_cast<Connection*>(gi)) { |
|
|
|
|
|
int fromIdx = items.indexOf(conn->from_); |
|
|
|
|
|
int toIdx = items.indexOf(conn->to_); |
|
|
|
|
|
if (fromIdx >= 0 && toIdx >= 0) { |
|
|
|
|
|
Project::ConnectionData c; |
|
|
|
|
|
c.from = fromIdx; |
|
|
|
|
|
c.to = toIdx; |
|
|
|
|
|
c.fromType = static_cast<int>(conn->fromType_); |
|
|
|
|
|
c.toType = static_cast<int>(conn->toType_); |
|
|
|
|
|
proj.connections_.append(c); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
if (pageIndex < 0 || pageIndex >= hmiScenes.size()) return; |
|
|
|
|
|
proj.clear(); |
|
|
|
|
|
QList<Item*> items; |
|
|
|
|
|
for (QGraphicsItem* gi : hmiScenes[pageIndex]->items()){ |
|
|
|
|
|
if (Item* it = dynamic_cast<Item*>(gi)){ |
|
|
|
|
|
items.append(it); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
for (Item* it : items) { |
|
|
|
|
|
Project::ItemData d; |
|
|
|
|
|
d.type = it->itemType(); |
|
|
|
|
|
d.x = it->pos().x(); |
|
|
|
|
|
d.y = it->pos().y(); |
|
|
|
|
|
d.registerId = it->registerId(); |
|
|
|
|
|
proj.items_.append(d); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int MainWindow::currentPageIndex() const |
|
|
|
|
|
{ |
|
|
|
|
|
if (currentIsPLC_) { |
|
|
|
|
|
return ui->plc_tab_widget->currentIndex(); |
|
|
|
|
|
} else { |
|
|
|
|
|
return ui->hmi_tab_widget->currentIndex(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool MainWindow::eventFilter(QObject *obj, QEvent *event) |
|
|
|
|
|
{ |
|
|
|
|
|
if (obj == ui->listWidget->viewport()) { |
|
|
|
|
|
static QListWidgetItem *dragItem = nullptr; |
|
|
|
|
|
static QPoint startPos; |
|
|
|
|
|
|
|
|
|
|
|
if (event->type() == QEvent::MouseButtonPress) { |
|
|
|
|
|
auto *me = static_cast<QMouseEvent*>(event); |
|
|
|
|
|
if (me->button() == Qt::LeftButton) { |
|
|
|
|
|
dragItem = ui->listWidget->itemAt(me->pos()); |
|
|
|
|
|
startPos = me->pos(); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (event->type() == QEvent::MouseMove && dragItem) { |
|
|
|
|
|
auto *me = static_cast<QMouseEvent*>(event); |
|
|
|
|
|
if ((me->pos() - startPos).manhattanLength() |
|
|
|
|
|
>= QApplication::startDragDistance()) { |
|
|
|
|
|
|
|
|
|
|
|
QString type = dragItem->data(Qt::UserRole).toString(); |
|
|
|
|
|
|
|
|
|
|
|
QMimeData *mime = new QMimeData; |
|
|
|
|
|
mime->setData("application/x-component", type.toUtf8()); |
|
|
|
|
|
|
|
|
|
|
|
QDrag *drag = new QDrag(this); |
|
|
|
|
|
drag->setMimeData(mime); |
|
|
|
|
|
drag->setPixmap(dragItem->icon().pixmap(ui->listWidget->iconSize())); |
|
|
|
|
|
drag->setHotSpot(drag->pixmap().rect().center()); |
|
|
|
|
|
drag->exec(Qt::CopyAction); |
|
|
|
|
|
|
|
|
|
|
|
dragItem = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (event->type() == QEvent::MouseButtonRelease) { |
|
|
|
|
|
dragItem = nullptr; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return QWidget::eventFilter(obj, event); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void MainWindow::plcChange() |
|
|
void MainWindow::plcChange() |
|
|
{ |
|
|
{ |
|
|
plc_->show(); |
|
|
|
|
|
hmi_->hide(); |
|
|
|
|
|
currentIsPLC_ = true; |
|
|
currentIsPLC_ = true; |
|
|
setWindowTitle((plcFilePath_.isEmpty() ? "未命名项目" : QFileInfo(plcFilePath_).fileName()) + " - PLC编辑器"); |
|
|
|
|
|
|
|
|
createComponents(); |
|
|
|
|
|
ui->stackedWidget->setCurrentIndex(0); // 显示PLC页面 |
|
|
|
|
|
// setWindowTitle((plcFilePath_.isEmpty() ? "未命名项目" : QFileInfo(plcFilePath_).fileName()) + " - PLC编辑器"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::hmiChange() |
|
|
void MainWindow::hmiChange() |
|
|
{ |
|
|
{ |
|
|
hmi_->show(); |
|
|
|
|
|
plc_->hide(); |
|
|
|
|
|
currentIsPLC_ = false; |
|
|
currentIsPLC_ = false; |
|
|
setWindowTitle((hmiFilePath_.isEmpty() ? "未命名项目" : QFileInfo(hmiFilePath_).fileName()) + " - HMI编辑器"); |
|
|
|
|
|
|
|
|
createComponents(); |
|
|
|
|
|
ui->stackedWidget->setCurrentIndex(1); // 显示HMI页面 |
|
|
|
|
|
// setWindowTitle((hmiFilePath_.isEmpty() ? "未命名项目" : QFileInfo(hmiFilePath_).fileName()) + " - HMI编辑器"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void MainWindow::newProject() |
|
|
void MainWindow::newProject() |
|
|
{ |
|
|
{ |
|
|
|
|
|
newPage(currentIsPLC_); |
|
|
|
|
|
|
|
|
|
|
|
// 更新窗口标题 |
|
|
if (currentIsPLC_) { |
|
|
if (currentIsPLC_) { |
|
|
plcProject_.clear(); |
|
|
|
|
|
plcFilePath_.clear(); |
|
|
|
|
|
plc_->clearScene(); |
|
|
|
|
|
setWindowTitle("未命名项目 - PLC编辑器"); |
|
|
setWindowTitle("未命名项目 - PLC编辑器"); |
|
|
} else { |
|
|
} else { |
|
|
hmi_->newPage(); |
|
|
|
|
|
hmiProject_.clear(); // 清除项目数据 |
|
|
|
|
|
hmiFilePath_.clear(); |
|
|
|
|
|
|
|
|
|
|
|
// 更新窗口标题 |
|
|
|
|
|
setWindowTitle("未命名项目 - HMI编辑器"); |
|
|
setWindowTitle("未命名项目 - HMI编辑器"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void MainWindow::openProject() |
|
|
void MainWindow::openProject() |
|
|
{ |
|
|
{ |
|
|
if (currentIsPLC_) |
|
|
|
|
|
{ |
|
|
|
|
|
QString filePath = QFileDialog::getOpenFileName(this, "打开项目", "", "项目文件 (*.plcproj)"); |
|
|
|
|
|
if (filePath.isEmpty()) return; |
|
|
|
|
|
if (plcProject_.loadFromFile(filePath)) |
|
|
|
|
|
{ |
|
|
|
|
|
plcFilePath_ = filePath; |
|
|
|
|
|
plc_->applyProjectToScene(plcProject_); |
|
|
|
|
|
setWindowTitle(QFileInfo(plcFilePath_).fileName() + " - PLC编辑器"); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
QMessageBox::critical(this, "错误", "无法打开PLC项目文件"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
QString filePath; |
|
|
|
|
|
QString filter; |
|
|
|
|
|
|
|
|
|
|
|
if (currentIsPLC_) { |
|
|
|
|
|
filter = "PLC项目文件 (*.plcproj)"; |
|
|
|
|
|
filePath = QFileDialog::getOpenFileName(this, "打开PLC项目", "", filter); |
|
|
|
|
|
} else { |
|
|
|
|
|
filter = "HMI项目文件 (*.hmiproj)"; |
|
|
|
|
|
filePath = QFileDialog::getOpenFileName(this, "打开HMI项目", "", filter); |
|
|
} |
|
|
} |
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
QString filePath = QFileDialog::getOpenFileName(this, "打开项目", "", "项目文件 (*.hmiproj)"); |
|
|
|
|
|
if (filePath.isEmpty()) return; |
|
|
|
|
|
|
|
|
|
|
|
Project newProject; |
|
|
|
|
|
if (newProject.loadFromFile(filePath)) { |
|
|
|
|
|
// 创建新页面 |
|
|
|
|
|
hmi_->newPage(); |
|
|
|
|
|
|
|
|
if (filePath.isEmpty()) return; |
|
|
|
|
|
|
|
|
// 应用项目到新页面 |
|
|
|
|
|
int newPageIndex = hmi_->currentPageIndex(); |
|
|
|
|
|
hmi_->applyProjectToScene(newProject, newPageIndex); |
|
|
|
|
|
|
|
|
Project project; |
|
|
|
|
|
if (project.loadFromFile(filePath)) { |
|
|
|
|
|
// 在当前模块新建一个页面 |
|
|
|
|
|
newPage(currentIsPLC_); |
|
|
|
|
|
int newPageIndex = currentPageIndex(); |
|
|
|
|
|
|
|
|
// 保存文件路径 |
|
|
|
|
|
hmiFilePath_ = filePath; |
|
|
|
|
|
setWindowTitle(QFileInfo(hmiFilePath_).fileName() + " - HMI编辑器"); |
|
|
|
|
|
} else { |
|
|
|
|
|
QMessageBox::critical(this, "错误", "无法打开HMI项目文件"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 将项目应用到新页面 |
|
|
|
|
|
applyProjectToScene(project, newPageIndex); |
|
|
|
|
|
|
|
|
|
|
|
// 更新窗口标题 |
|
|
|
|
|
setWindowTitle(QFileInfo(filePath).fileName() + |
|
|
|
|
|
(currentIsPLC_ ? " - PLC编辑器" : " - HMI编辑器")); |
|
|
|
|
|
} else { |
|
|
|
|
|
QMessageBox::critical(this, "错误", "无法打开项目文件"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void MainWindow::saveProject() |
|
|
void MainWindow::saveProject() |
|
|
{ |
|
|
{ |
|
|
|
|
|
QString filePath; |
|
|
|
|
|
QString filter; |
|
|
|
|
|
QString defaultSuffix; |
|
|
|
|
|
|
|
|
if (currentIsPLC_) { |
|
|
if (currentIsPLC_) { |
|
|
if (plcFilePath_.isEmpty()) { |
|
|
|
|
|
QString filePath = QFileDialog::getSaveFileName(this, "保存项目", "", "PLC项目文件 (*.plcproj)"); |
|
|
|
|
|
if (filePath.isEmpty()) return; |
|
|
|
|
|
if (!filePath.endsWith(".plcproj", Qt::CaseInsensitive)) |
|
|
|
|
|
filePath += ".plcproj"; |
|
|
|
|
|
plcFilePath_ = filePath; |
|
|
|
|
|
} |
|
|
|
|
|
plc_->extractSceneToProject(plcProject_); |
|
|
|
|
|
if (!plcProject_.saveToFile(plcFilePath_)) { |
|
|
|
|
|
QMessageBox::critical(this, "错误", "保存项目失败"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
filter = "PLC项目文件 (*.plcproj)"; |
|
|
|
|
|
defaultSuffix = "plcproj"; |
|
|
|
|
|
filePath = QFileDialog::getSaveFileName(this, "保存PLC项目", "", filter); |
|
|
} else { |
|
|
} else { |
|
|
if (hmiFilePath_.isEmpty()) { |
|
|
|
|
|
QString filePath = QFileDialog::getSaveFileName(this, "保存项目", "", "HMI项目文件 (*.hmiproj)"); |
|
|
|
|
|
if (filePath.isEmpty()) return; |
|
|
|
|
|
if (!filePath.endsWith(".hmiproj", Qt::CaseInsensitive)) |
|
|
|
|
|
filePath += ".hmiproj"; |
|
|
|
|
|
hmiFilePath_ = filePath; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
filter = "HMI项目文件 (*.hmiproj)"; |
|
|
|
|
|
defaultSuffix = "hmiproj"; |
|
|
|
|
|
filePath = QFileDialog::getSaveFileName(this, "保存HMI项目", "", filter); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 从当前页面提取项目 |
|
|
|
|
|
hmi_->extractSceneToProject(hmiProject_, hmi_->currentPageIndex()); |
|
|
|
|
|
|
|
|
if (filePath.isEmpty()) return; |
|
|
|
|
|
|
|
|
if (!hmiProject_.saveToFile(hmiFilePath_)) { |
|
|
|
|
|
QMessageBox::critical(this, "错误", "保存项目失败"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 确保文件有正确的扩展名 |
|
|
|
|
|
if (!filePath.endsWith("." + defaultSuffix, Qt::CaseInsensitive)) { |
|
|
|
|
|
filePath += "." + defaultSuffix; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Project project; |
|
|
|
|
|
// 从当前页面提取项目 |
|
|
|
|
|
extractSceneToProject(project, currentPageIndex()); |
|
|
|
|
|
|
|
|
|
|
|
if (project.saveToFile(filePath)) { |
|
|
|
|
|
// 更新窗口标题 |
|
|
|
|
|
setWindowTitle(QFileInfo(filePath).fileName() + |
|
|
|
|
|
(currentIsPLC_ ? " - PLC编辑器" : " - HMI编辑器")); |
|
|
|
|
|
} else { |
|
|
|
|
|
QMessageBox::critical(this, "错误", "保存项目失败"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -175,3 +462,79 @@ void MainWindow::updateConnectionStatus(bool connection) |
|
|
ui->textEdit->append("断开"); |
|
|
ui->textEdit->append("断开"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::onListwidgetCurrenttextchanged(const QString ¤tText) |
|
|
|
|
|
{ |
|
|
|
|
|
selectedComponentType = currentText; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::onTabCloseRequested(int index) |
|
|
|
|
|
{ |
|
|
|
|
|
if (currentIsPLC_) { |
|
|
|
|
|
if (plcScenes.size() > 1) { |
|
|
|
|
|
delete plcScenes.takeAt(index); |
|
|
|
|
|
delete plcViews.takeAt(index); |
|
|
|
|
|
ui->plc_tab_widget->removeTab(index); |
|
|
|
|
|
} else { |
|
|
|
|
|
QMessageBox::information(this, "提示", "至少保留一个PLC页面"); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
if (hmiScenes.size() > 1) { |
|
|
|
|
|
delete hmiScenes.takeAt(index); |
|
|
|
|
|
delete hmiViews.takeAt(index); |
|
|
|
|
|
ui->hmi_tab_widget->removeTab(index); |
|
|
|
|
|
} else { |
|
|
|
|
|
QMessageBox::information(this, "提示", "至少保留一个HMI页面"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::btnInsertClicked() |
|
|
|
|
|
{ |
|
|
|
|
|
// 1. 找场景中被选中的连线 |
|
|
|
|
|
QList<QGraphicsItem*> selectedItems = plcScenes[currentPageIndex()]->selectedItems(); |
|
|
|
|
|
Connection* selectedConn = nullptr; |
|
|
|
|
|
for (QGraphicsItem* item : selectedItems) { |
|
|
|
|
|
selectedConn = dynamic_cast<Connection*>(item); |
|
|
|
|
|
if (selectedConn) break; |
|
|
|
|
|
} |
|
|
|
|
|
if (!selectedConn) { |
|
|
|
|
|
QMessageBox::warning(this, "提示", "请先选中一条连线"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (selectedComponentType.isEmpty()) { |
|
|
|
|
|
QMessageBox::warning(this, "提示", "请先在列表中选择要插入的组件"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 2. 计算插入点(中点) |
|
|
|
|
|
QLineF lf = selectedConn->line(); |
|
|
|
|
|
QPointF insertPos = (lf.p1() + lf.p2()) / 2; |
|
|
|
|
|
|
|
|
|
|
|
// 3. 删除原连线 |
|
|
|
|
|
Item* from = selectedConn->from_; |
|
|
|
|
|
Item* to = selectedConn->to_; |
|
|
|
|
|
Item::AnchorType fromType = selectedConn->fromType_; |
|
|
|
|
|
Item::AnchorType toType = selectedConn->toType_; |
|
|
|
|
|
|
|
|
|
|
|
from->removeConnection(selectedConn); |
|
|
|
|
|
to->removeConnection(selectedConn); |
|
|
|
|
|
plcScenes[currentPageIndex()]->removeItem(selectedConn); |
|
|
|
|
|
delete selectedConn; |
|
|
|
|
|
|
|
|
|
|
|
// 4. 插入新元件 |
|
|
|
|
|
Item* newItem = creatItem(selectedComponentType); |
|
|
|
|
|
newItem->setPos(insertPos); |
|
|
|
|
|
connect(newItem, &Item::requestCopy, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestCopy); |
|
|
|
|
|
connect(newItem, &Item::requestDelete, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestDelete); |
|
|
|
|
|
connect(newItem, &Item::requestBindRegister, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestBindRegister); |
|
|
|
|
|
connect(newItem, &Item::requestCompare, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestCompare); |
|
|
|
|
|
connect(newItem, &Item::requestReset, plcViews[currentPageIndex()], &MyGraphicsView::onItemRequestReset); |
|
|
|
|
|
plcScenes[currentPageIndex()]->addItem(newItem); |
|
|
|
|
|
|
|
|
|
|
|
// 5. 新建两条连线 |
|
|
|
|
|
Connection* c1 = new Connection(from, fromType, newItem, Item::Left); |
|
|
|
|
|
plcScenes[currentPageIndex()]->addItem(c1); |
|
|
|
|
|
Connection* c2 = new Connection(newItem, Item::Right, to, toType); |
|
|
|
|
|
plcScenes[currentPageIndex()]->addItem(c2); |
|
|
|
|
|
} |