|
- #include "mygraphicsview.h"
- #include <QMimeData>
- #include <QCursor>
- #include <QGraphicsScene>
- #include <QDebug>
- #include <QMenu>
- #include <QInputDialog>
- #include <QMessageBox>
- #include <QRegularExpression>
-
- MyGraphicsView::ClipInfo MyGraphicsView::clipboard_ = {};
-
- MyGraphicsView::MyGraphicsView(QWidget *parent)
- : QGraphicsView(parent)
- {
- setAcceptDrops(true);
- setRenderHint(QPainter::Antialiasing);
- setFocusPolicy(Qt::StrongFocus);
- setDragMode(QGraphicsView::RubberBandDrag);
- }
-
- void MyGraphicsView::dragEnterEvent(QDragEnterEvent *event)
- {
- if (event->mimeData()->hasFormat("application/x-component"))
- event->acceptProposedAction();
- else
- event->ignore();
- }
-
- void MyGraphicsView::dragMoveEvent(QDragMoveEvent *event)
- {
- if (event->mimeData()->hasFormat("application/x-component"))
- event->acceptProposedAction();
- else
- event->ignore();
- }
-
- void MyGraphicsView::dropEvent(QDropEvent *event)
- {
- if (!event->mimeData()->hasFormat("application/x-component")) {
- event->ignore();
- return;
- }
-
- QString type = QString::fromUtf8(event->mimeData()->data("application/x-component"));
-
- QPointF scenePos = mapToScene(event->pos());
- Item *item = creatItem(type);
- item->setPos(scenePos);
- connect(item, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
- connect(item, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
- connect(item, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister);
- connect(item, &Item::requestCompare, this, &MyGraphicsView::onItemRequestCompare);
- connect(item, &Item::requestReset, this, &MyGraphicsView::onItemRequestReset);
- scene()->addItem(item);
-
- event->acceptProposedAction();
- }
-
- void MyGraphicsView::keyPressEvent(QKeyEvent *event)
- {
- if (event->key() == Qt::Key_Delete && scene()) {
- QList<QGraphicsItem*> selectedItems = scene()->selectedItems();
- for (QGraphicsItem* item : selectedItems) {
- if (auto conn = dynamic_cast<Connection*>(item)) {
- // 先通知两端节点断开
- conn->from_->removeConnection(conn);
- conn->to_->removeConnection(conn);
- scene()->removeItem(conn);
- delete conn;
- } else if (auto node = dynamic_cast<Item*>(item)) {
- // 删除节点的所有连线
- QList<Connection*> conns = node->connections();
- for (Connection* conn : conns) {
- conn->from_->removeConnection(conn);
- conn->to_->removeConnection(conn);
- scene()->removeItem(conn);
- delete conn;
- }
- scene()->removeItem(node);
- delete node;
- }
- }
- }else if (event->matches(QKeySequence::Copy)) {
- // Ctrl+C
- QList<QGraphicsItem*> selectedItems = scene()->selectedItems();
- for (QGraphicsItem* item : selectedItems) {
- if (auto node = dynamic_cast<Item*>(item)) {
- clipboard_.input = node->itemType();
- break;
- }
- }
- } else if (event->matches(QKeySequence::Paste)) {
- // Ctrl+V
- if (!clipboard_.input.isEmpty()) {
- QPointF center = mapToScene(viewport()->rect().center());
- Item* newItem = creatItem(clipboard_.input);
- newItem->setPos(center);
- connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
- connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
- connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister);
- connect(newItem, &Item::requestCompare, this, &MyGraphicsView::onItemRequestCompare);
- connect(newItem, &Item::requestReset, this, &MyGraphicsView::onItemRequestReset);
- scene()->addItem(newItem);
- }
- } else {
- QGraphicsView::keyPressEvent(event);
- }
- }
-
- void MyGraphicsView::contextMenuEvent(QContextMenuEvent *event)
- {
- QPointF scenePos = mapToScene(event->pos());
- QList<QGraphicsItem*> itemsAt = scene()->items(scenePos);
- if (itemsAt.isEmpty() && !clipboard_.input.isEmpty()) {
- QMenu menu;
- QAction* pasteAct = menu.addAction("粘贴");
- QAction* sel = menu.exec(event->globalPos());
- if (sel == pasteAct) {
- Item* newItem = creatItem(clipboard_.input);
- newItem->setPos(scenePos);
- connect(newItem, &Item::requestCopy, this, &MyGraphicsView::onItemRequestCopy);
- connect(newItem, &Item::requestDelete, this, &MyGraphicsView::onItemRequestDelete);
- connect(newItem, &Item::requestBindRegister, this, &MyGraphicsView::onItemRequestBindRegister);
- connect(newItem, &Item::requestCompare, this, &MyGraphicsView::onItemRequestCompare);
- connect(newItem, &Item::requestReset, this, &MyGraphicsView::onItemRequestReset);
- scene()->addItem(newItem);
- }
- } else {
- QGraphicsView::contextMenuEvent(event); // 让Item自己弹出菜单
- }
- }
-
- // ----------- 连线交互 ------------
-
- Item* MyGraphicsView::anchorItemAt(const QPoint& viewPos, Item::AnchorType& anchorType)
- {
- QPointF scenePos = mapToScene(viewPos);
- for (QGraphicsItem* item : scene()->items(scenePos)) {
- if (Item* node = dynamic_cast<Item*>(item)) {
- QRectF r = node->boundingRect();
- QPointF local = node->mapFromScene(scenePos);
- if (QLineF(local, QPointF(r.left(), r.center().y())).length() < 10) {
- anchorType = Item::Left;
- return node;
- }
- if (QLineF(local, QPointF(r.right(), r.center().y())).length() < 10) {
- anchorType = Item::Right;
- return node;
- }
- }
- }
- return nullptr;
- }
-
- void MyGraphicsView::onItemRequestCopy(Item *item)
- {
- clipboard_.input = item->itemType();
- }
-
- void MyGraphicsView::onItemRequestDelete(Item *item)
- {
- QList<Connection*> conns = item->connections();
- for (Connection* conn : conns) {
- conn->from_->removeConnection(conn);
- conn->to_->removeConnection(conn);
- scene()->removeItem(conn);
- delete conn;
- }
- scene()->removeItem(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::onItemRequestCompare(Item *item)
- {
- if (!item) return;
-
- QString compare = QInputDialog::getText(
- this,
- "绑定寄存器",
- "格式:>、<、=、<=、>=",
- QLineEdit::Normal
- );
- item->setCompare(compare);
- }
-
- void MyGraphicsView::onItemRequestReset(Item *item)
- {
- QStringList unboundRegs = item->resetRegister();
- for (const QString& reg : unboundRegs) {
- emit itemResetRegister(item, reg); // 解绑每个寄存器
- }
- }
-
- void MyGraphicsView::mousePressEvent(QMouseEvent *event)
- {
- if (event->button() == Qt::LeftButton) {
- Item::AnchorType anchor;
- Item* node = anchorItemAt(event->pos(), anchor);
- if (node) {
- drawingConnection_ = true;
- startItem_ = node;
- startAnchor_ = anchor;
- tempLine_ = scene()->addLine(QLineF(node->anchorPos(anchor), mapToScene(event->pos())),
- QPen(Qt::darkGray, 2, Qt::DashLine));
- return;
- }
- }
- QGraphicsView::mousePressEvent(event);
- }
-
- void MyGraphicsView::mouseMoveEvent(QMouseEvent *event)
- {
- if (drawingConnection_ && tempLine_) {
- QLineF l = tempLine_->line();
- l.setP2(mapToScene(event->pos()));
- tempLine_->setLine(l);
- return;
- }
- QGraphicsView::mouseMoveEvent(event);
- }
-
- void MyGraphicsView::mouseReleaseEvent(QMouseEvent *event)
- {
- if (drawingConnection_ && tempLine_) {
- // 检查鼠标释放点是否在某个Item boundingRect内
- QPointF scenePos = mapToScene(event->pos());
- for (QGraphicsItem* item : scene()->items(scenePos)) {
- if (Item* node = dynamic_cast<Item*>(item)) {
- QRectF r = node->boundingRect();
- QPointF local = node->mapFromScene(scenePos);
- // 计算落点距离左右端点
- double distLeft = QLineF(local, QPointF(r.left(), r.center().y())).length();
- double distRight = QLineF(local, QPointF(r.right(), r.center().y())).length();
- Item::AnchorType anchor = (distLeft < distRight) ? Item::Left : Item::Right;
- // 生成连线
- Connection* conn = new Connection(startItem_, startAnchor_, node, anchor);
- scene()->addItem(conn);
- break;
- }
- }
- // 清除临时线
- scene()->removeItem(tempLine_);
- delete tempLine_;
- tempLine_ = nullptr;
- drawingConnection_ = false;
- startItem_ = nullptr;
- return;
- }
- QGraphicsView::mouseReleaseEvent(event);
- }
|