@@ -101,6 +101,21 @@ void Button::setCustomImage(const QString &imagePath) | |||||
update(); | update(); | ||||
} | } | ||||
void Button::setCurrentSize(QSizeF size) | |||||
{ | |||||
currentSize_ = size; | |||||
} | |||||
QSizeF Button::currentSize() | |||||
{ | |||||
return currentSize_; | |||||
} | |||||
QString Button::imagePath() | |||||
{ | |||||
return imagePath_; | |||||
} | |||||
void Button::loadImage() | void Button::loadImage() | ||||
{ | { | ||||
if(!imagePath_.isEmpty()){ | if(!imagePath_.isEmpty()){ | ||||
@@ -116,9 +131,7 @@ void Button::mousePressEvent(QGraphicsSceneMouseEvent *event) | |||||
// 检查是否点击了调整手柄 | // 检查是否点击了调整手柄 | ||||
QRectF resizeHandle = QRectF(currentSize_.width() - resizeHandleSize_, | QRectF resizeHandle = QRectF(currentSize_.width() - resizeHandleSize_, | ||||
currentSize_.height() - resizeHandleSize_, | currentSize_.height() - resizeHandleSize_, | ||||
resizeHandleSize_, | |||||
resizeHandleSize_); | |||||
resizeHandleSize_, resizeHandleSize_); | |||||
if (resizeHandle.contains(event->pos())) { | if (resizeHandle.contains(event->pos())) { | ||||
resizing_ = true; | resizing_ = true; | ||||
resizeStartPos_ = event->scenePos(); | resizeStartPos_ = event->scenePos(); | ||||
@@ -13,6 +13,9 @@ public: | |||||
void addMenuActions(QMenu *menu) override; | void addMenuActions(QMenu *menu) override; | ||||
void handleMenuAction(QAction *action) override; | void handleMenuAction(QAction *action) override; | ||||
void setCustomImage(const QString& imagePath); | void setCustomImage(const QString& imagePath); | ||||
void setCurrentSize(QSizeF size); | |||||
QSizeF currentSize(); | |||||
QString imagePath(); | |||||
void loadImage(); | void loadImage(); | ||||
// 鼠标事件处理 | // 鼠标事件处理 | ||||
@@ -35,13 +35,25 @@ void Comparator::paint(QPainter *painter, const QStyleOptionGraphicsItem *option | |||||
painter->setFont(QFont("Arial", 8)); | painter->setFont(QFont("Arial", 8)); | ||||
painter->setPen(Qt::black); | painter->setPen(Qt::black); | ||||
if (!registerId_.isEmpty()) { | if (!registerId_.isEmpty()) { | ||||
QString text = QString("%1: %2").arg(registerId_).arg(registerValue_); | |||||
QString text; | |||||
if (registerId_.left(1) == "K") | |||||
{ | |||||
text = QString("%1").arg(registerId_); | |||||
} else { | |||||
text = QString("%1: %2").arg(registerId_).arg(registerValue_); | |||||
} | |||||
painter->drawText(QRectF(-20, -25, 40, 20), Qt::AlignCenter, text); | painter->drawText(QRectF(-20, -25, 40, 20), Qt::AlignCenter, text); | ||||
} | } | ||||
// 在右上角显示第二个寄存器 | |||||
// 显示第二个寄存器 | |||||
if (!registerId2_.isEmpty()) { | if (!registerId2_.isEmpty()) { | ||||
QString text = QString("%1: %2").arg(registerId2_).arg(registerValue2_); | |||||
QString text; | |||||
if (registerId2_.left(1) == "K") | |||||
{ | |||||
text = QString("%1").arg(registerId2_); | |||||
} else { | |||||
text = QString("%1: %2").arg(registerId2_).arg(registerValue2_); | |||||
} | |||||
painter->drawText(QRectF(-20, 5, 40, 20), Qt::AlignCenter, text); | painter->drawText(QRectF(-20, 5, 40, 20), Qt::AlignCenter, text); | ||||
} | } | ||||
painter->restore(); | painter->restore(); | ||||
@@ -12,6 +12,8 @@ public: | |||||
QWidget *) override; | QWidget *) override; | ||||
bool setRegisterId(const QString &id) override; | bool setRegisterId(const QString &id) override; | ||||
void setRegisterValue(const QString ®isterId, quint16 value) override; | void setRegisterValue(const QString ®isterId, quint16 value) override; | ||||
QString registerId2() const { return registerId2_; } | |||||
QString compare() const { return compare_; } | |||||
void addMenuActions(QMenu *menu) override; | void addMenuActions(QMenu *menu) override; | ||||
void handleMenuAction(QAction *action) override; | void handleMenuAction(QAction *action) override; | ||||
void setCompare(QString) override; | void setCompare(QString) override; | ||||
@@ -1,6 +1,6 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
<!DOCTYPE QtCreatorProject> | <!DOCTYPE QtCreatorProject> | ||||
<!-- Written by QtCreator 4.11.1, 2025-08-12T08:51:43. --> | |||||
<!-- Written by QtCreator 4.11.1, 2025-08-12T14:54:10. --> | |||||
<qtcreator> | <qtcreator> | ||||
<data> | <data> | ||||
<variable>EnvironmentId</variable> | <variable>EnvironmentId</variable> | ||||
@@ -113,6 +113,26 @@ void Light::setOffImage(const QString &imagePath) | |||||
update(); | update(); | ||||
} | } | ||||
void Light::setCurrentSize(QSizeF size) | |||||
{ | |||||
currentSize_ = size; | |||||
} | |||||
QSizeF Light::currentSize() | |||||
{ | |||||
return currentSize_; | |||||
} | |||||
QString Light::onImagePath() | |||||
{ | |||||
return onImagePath_; | |||||
} | |||||
QString Light::offImagePath() | |||||
{ | |||||
return offImagePath_; | |||||
} | |||||
void Light::loadImage() | void Light::loadImage() | ||||
{ | { | ||||
if (!onImagePath_.isEmpty()) { | if (!onImagePath_.isEmpty()) { | ||||
@@ -16,6 +16,10 @@ public: | |||||
void setCustomImage(const QString& imagePath); | void setCustomImage(const QString& imagePath); | ||||
void setOnImage(const QString& imagePath); | void setOnImage(const QString& imagePath); | ||||
void setOffImage(const QString& imagePath); | void setOffImage(const QString& imagePath); | ||||
void setCurrentSize(QSizeF size); | |||||
QSizeF currentSize(); | |||||
QString onImagePath(); | |||||
QString offImagePath(); | |||||
void loadImage(); | void loadImage(); | ||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override; | void mousePressEvent(QGraphicsSceneMouseEvent *event) override; | ||||
@@ -203,6 +203,25 @@ void MainWindow::applyProjectToScene(const Project &proj, int pageIndex) | |||||
if (!item) continue; | if (!item) continue; | ||||
item->setPos(d.x, d.y); | item->setPos(d.x, d.y); | ||||
item->setRegisterId(d.registerId); | item->setRegisterId(d.registerId); | ||||
if (d.type == "比较") { | |||||
Comparator* compare = dynamic_cast<Comparator*>(item); | |||||
if (compare) { | |||||
compare->setRegisterId(d.registerId2); | |||||
compare->setCompare(d.compare); | |||||
if (d.registerId.left(1) == "K") | |||||
{ | |||||
compare->setRegisterValue(d.registerId, d.registerId.mid(1).toInt()); | |||||
} else { | |||||
registerManager->bindItem(compare, d.registerId); | |||||
} | |||||
if (d.registerId2.left(1) == "K") | |||||
{ | |||||
compare->setRegisterValue(d.registerId2, d.registerId2.mid(1).toInt()); | |||||
} else { | |||||
registerManager->bindItem(compare, d.registerId2); | |||||
} | |||||
} | |||||
} | |||||
connect(item, &Item::requestCopy, plcViews[pageIndex], &MyGraphicsView::onItemRequestCopy); | connect(item, &Item::requestCopy, plcViews[pageIndex], &MyGraphicsView::onItemRequestCopy); | ||||
connect(item, &Item::requestDelete, plcViews[pageIndex], &MyGraphicsView::onItemRequestDelete); | connect(item, &Item::requestDelete, plcViews[pageIndex], &MyGraphicsView::onItemRequestDelete); | ||||
connect(item, &Item::requestBindRegister, plcViews[pageIndex], &MyGraphicsView::onItemRequestBindRegister); | connect(item, &Item::requestBindRegister, plcViews[pageIndex], &MyGraphicsView::onItemRequestBindRegister); | ||||
@@ -210,7 +229,10 @@ void MainWindow::applyProjectToScene(const Project &proj, int pageIndex) | |||||
connect(item, &Item::requestReset, plcViews[pageIndex], &MyGraphicsView::onItemRequestReset); | connect(item, &Item::requestReset, plcViews[pageIndex], &MyGraphicsView::onItemRequestReset); | ||||
connect(item, &Item::requestSetON,plcViews[pageIndex], &MyGraphicsView::onItemRequestSetON); | connect(item, &Item::requestSetON,plcViews[pageIndex], &MyGraphicsView::onItemRequestSetON); | ||||
plcScenes[pageIndex]->addItem(item); | plcScenes[pageIndex]->addItem(item); | ||||
registerManager->bindItem(item,d.registerId); | |||||
if (d.type != "比较") | |||||
{ | |||||
registerManager->bindItem(item,d.registerId); | |||||
} | |||||
itemObjs.append(item); | itemObjs.append(item); | ||||
} | } | ||||
for (const auto& c : proj.connections_) { | for (const auto& c : proj.connections_) { | ||||
@@ -234,6 +256,20 @@ void MainWindow::applyProjectToScene(const Project &proj, int pageIndex) | |||||
if (!item) continue; | if (!item) continue; | ||||
item->setPos(d.x, d.y); | item->setPos(d.x, d.y); | ||||
item->setRegisterId(d.registerId); | item->setRegisterId(d.registerId); | ||||
if (d.type == "按钮") { | |||||
Button* button = dynamic_cast<Button*>(item); | |||||
if (button) { | |||||
button->setCustomImage(d.imagePath); | |||||
button->setCurrentSize(d.size); | |||||
} | |||||
} else if (d.type == "指示灯") { | |||||
Light* light = dynamic_cast<Light*>(item); | |||||
if (light) { | |||||
light->setOnImage(d.onImagePath); | |||||
light->setOffImage(d.offImagePath); | |||||
light->setCurrentSize(d.size); | |||||
} | |||||
} | |||||
connect(item, &Item::requestCopy, hmiViews[pageIndex], &MyGraphicsView::onItemRequestCopy); | connect(item, &Item::requestCopy, hmiViews[pageIndex], &MyGraphicsView::onItemRequestCopy); | ||||
connect(item, &Item::requestDelete, hmiViews[pageIndex], &MyGraphicsView::onItemRequestDelete); | connect(item, &Item::requestDelete, hmiViews[pageIndex], &MyGraphicsView::onItemRequestDelete); | ||||
connect(item, &Item::requestBindRegister, hmiViews[pageIndex], &MyGraphicsView::onItemRequestBindRegister); | connect(item, &Item::requestBindRegister, hmiViews[pageIndex], &MyGraphicsView::onItemRequestBindRegister); | ||||
@@ -265,6 +301,13 @@ void MainWindow::extractSceneToProject(Project &proj, int pageIndex) | |||||
d.x = it->pos().x(); | d.x = it->pos().x(); | ||||
d.y = it->pos().y(); | d.y = it->pos().y(); | ||||
d.registerId = it->registerId(); | d.registerId = it->registerId(); | ||||
if (d.type == "比较") { | |||||
Comparator* compare = dynamic_cast<Comparator*>(it); | |||||
if (compare) { | |||||
d.registerId2 = compare->registerId2(); | |||||
d.compare = compare->compare(); | |||||
} | |||||
} | |||||
proj.items_.append(d); | proj.items_.append(d); | ||||
} | } | ||||
for (QGraphicsItem* gi : plcScenes[pageIndex]->items()) { | for (QGraphicsItem* gi : plcScenes[pageIndex]->items()) { | ||||
@@ -298,6 +341,20 @@ void MainWindow::extractSceneToProject(Project &proj, int pageIndex) | |||||
d.x = it->pos().x(); | d.x = it->pos().x(); | ||||
d.y = it->pos().y(); | d.y = it->pos().y(); | ||||
d.registerId = it->registerId(); | d.registerId = it->registerId(); | ||||
if (d.type == "按钮") { | |||||
Button* button = dynamic_cast<Button*>(it); | |||||
if (button) { | |||||
d.imagePath = button->imagePath(); | |||||
d.size = button->currentSize(); | |||||
} | |||||
} else if (d.type == "指示灯") { | |||||
Light* light = dynamic_cast<Light*>(it); | |||||
if (light) { | |||||
d.onImagePath = light->onImagePath(); | |||||
d.offImagePath = light->offImagePath(); | |||||
d.size = light->currentSize(); | |||||
} | |||||
} | |||||
proj.items_.append(d); | proj.items_.append(d); | ||||
} | } | ||||
} | } | ||||
@@ -448,7 +505,7 @@ void MainWindow::saveProject() | |||||
void MainWindow::connection() | void MainWindow::connection() | ||||
{ | { | ||||
modbusManager->connectToDevice("COM6",QSerialPort::BaudRate(19200),QSerialPort::DataBits(8),QSerialPort::EvenParity,QSerialPort::StopBits(1)); | |||||
modbusManager->connectToDevice("COM1",QSerialPort::BaudRate(9600),QSerialPort::DataBits(8),QSerialPort::EvenParity,QSerialPort::StopBits(1)); | |||||
modbusManager->startSimulation(1000); | modbusManager->startSimulation(1000); | ||||
} | } | ||||
@@ -174,54 +174,6 @@ void MyGraphicsView::onItemRequestDelete(Item *item) | |||||
delete item; | delete item; | ||||
} | } | ||||
//void MyGraphicsView::onItemRequestBindRegister(Item *item) | |||||
//{ | |||||
// if (!item) return; | |||||
// bool ok = false; | |||||
// QString reg = QInputDialog::getText( | |||||
// this, | |||||
// "绑定寄存器", | |||||
// "格式: <类型><地址>\n" | |||||
// "类型: D(保持寄存器), M(线圈寄存器)\n" | |||||
// "示例: D100, M200\n" | |||||
// "地址范围: 0-4000", | |||||
// QLineEdit::Normal, | |||||
// item->registerId(), | |||||
// &ok | |||||
// ); | |||||
// if (ok && !reg.isEmpty()) { | |||||
// // 验证寄存器格式 | |||||
// QRegularExpression regex("^[DMdm]\\d{1,4}$"); | |||||
// QRegularExpressionMatch match = regex.match(reg); | |||||
// if (!match.hasMatch()) { | |||||
// QMessageBox::warning(this, "格式错误", "请输入有效的寄存器格式\n示例: D100, M200"); | |||||
// return; | |||||
// } | |||||
// int address = reg.mid(1).toInt(); | |||||
// if (address > 4000) { | |||||
// QMessageBox::warning(this, "范围错误", "寄存器地址必须在0-4000范围内"); | |||||
// return; | |||||
// } | |||||
// // 标准化格式 (D100) | |||||
// QString newReg = QString("%1%2").arg(reg[0].toUpper()).arg(address); | |||||
// if (item->setRegisterId(newReg)) | |||||
// { | |||||
// item->update(); | |||||
// // 发出绑定信号 | |||||
// emit itemBoundToRegister(item, newReg); | |||||
// } | |||||
// else | |||||
// { | |||||
// QMessageBox::warning(this, "提示", "请先重置再绑定新的寄存器"); | |||||
// } | |||||
// } | |||||
//} | |||||
void MyGraphicsView::onItemRequestBindRegister(Item *item) | void MyGraphicsView::onItemRequestBindRegister(Item *item) | ||||
{ | { | ||||
if (!item) return; | if (!item) return; | ||||
@@ -273,8 +225,8 @@ void MyGraphicsView::onItemRequestBindRegister(Item *item) | |||||
// 对于比较元件,直接设置值 | // 对于比较元件,直接设置值 | ||||
if (item->itemType() == "比较" && type == "K") { | if (item->itemType() == "比较" && type == "K") { | ||||
// 常数直接设置值 | // 常数直接设置值 | ||||
item->setRegisterId(type); | |||||
item->setRegisterValue(type, value); | |||||
item->setRegisterId(newReg); | |||||
item->setRegisterValue(newReg, value); | |||||
item->update(); | item->update(); | ||||
}else { | }else { | ||||
// 寄存器绑定 | // 寄存器绑定 | ||||
@@ -13,6 +13,15 @@ bool Project::saveToFile(const QString& filePath) const { | |||||
obj["x"] = item.x; | obj["x"] = item.x; | ||||
obj["y"] = item.y; | obj["y"] = item.y; | ||||
obj["registerId"] = item.registerId; | obj["registerId"] = item.registerId; | ||||
obj["registerId2"] = item.registerId2; | |||||
obj["compare"] = item.compare; | |||||
obj["imagePath"] = item.imagePath; | |||||
obj["onImagePath"] = item.onImagePath; | |||||
obj["offImagePath"] = item.offImagePath; | |||||
obj["width"] = item.size.width(); | |||||
obj["height"] = item.size.height(); | |||||
itemsArray.append(obj); | itemsArray.append(obj); | ||||
} | } | ||||
root["items"] = itemsArray; | root["items"] = itemsArray; | ||||
@@ -54,6 +63,18 @@ bool Project::loadFromFile(const QString& filePath) { | |||||
d.x = obj["x"].toDouble(); | d.x = obj["x"].toDouble(); | ||||
d.y = obj["y"].toDouble(); | d.y = obj["y"].toDouble(); | ||||
d.registerId = obj.contains("registerId") ? obj["registerId"].toString() : ""; | d.registerId = obj.contains("registerId") ? obj["registerId"].toString() : ""; | ||||
d.registerId2 = obj.contains("registerId2") ? obj["registerId2"].toString() : ""; | |||||
d.compare = obj.contains("compare") ? obj["compare"].toString() : "CP"; | |||||
d.imagePath = obj.contains("imagePath") ? obj["imagePath"].toString() : ""; | |||||
d.onImagePath = obj.contains("onImagePath") ? obj["onImagePath"].toString() : ""; | |||||
d.offImagePath = obj.contains("offImagePath") ? obj["offImagePath"].toString() : ""; | |||||
// 加载尺寸信息 | |||||
double width = obj.contains("width") ? obj["width"].toDouble() : 50.0; | |||||
double height = obj.contains("height") ? obj["height"].toDouble() : 50.0; | |||||
d.size = QSizeF(width, height); | |||||
items_.append(d); | items_.append(d); | ||||
} | } | ||||
QJsonArray connArray = root["connections"].toArray(); | QJsonArray connArray = root["connections"].toArray(); | ||||
@@ -3,6 +3,7 @@ | |||||
#include <QString> | #include <QString> | ||||
#include <QList> | #include <QList> | ||||
#include <QSizeF> | |||||
// PLC工程数据模型 | // PLC工程数据模型 | ||||
class Project | class Project | ||||
@@ -12,6 +13,13 @@ public: | |||||
QString type; | QString type; | ||||
double x, y; | double x, y; | ||||
QString registerId = ""; | QString registerId = ""; | ||||
QString registerId2 = ""; | |||||
QString compare = ""; | |||||
QString imagePath; // 按钮的图片路径 | |||||
QString onImagePath; // 指示灯的ON状态图片路径 | |||||
QString offImagePath; // 指示灯的OFF状态图片路径 | |||||
QSizeF size = QSizeF(50, 50); // 当前尺寸 | |||||
}; | }; | ||||
struct ConnectionData { | struct ConnectionData { | ||||
int from, to; | int from, to; | ||||