diff --git a/button.cpp b/button.cpp new file mode 100644 index 0000000..7f68bc0 --- /dev/null +++ b/button.cpp @@ -0,0 +1,30 @@ +#include "button.h" +#include +#include + +Button::Button(const QString &type) : Item(type) +{ + +} + +QRectF Button::boundingRect() const +{ + return QRectF(0, 0, 50, 50); +} + +void Button::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + painter->setRenderHint(QPainter::Antialiasing); + + if (type_ == "按钮") { + painter->drawRect(0,0,50,50); + } + if (option->state & QStyle::State_Selected) { + QPen pen(Qt::DashLine); + pen.setColor(Qt::blue); + pen.setWidth(2); + painter->setPen(pen); + painter->setBrush(Qt::NoBrush); + painter->drawRect(boundingRect()); + } +} diff --git a/button.h b/button.h new file mode 100644 index 0000000..083a98f --- /dev/null +++ b/button.h @@ -0,0 +1,15 @@ +#ifndef BUTTON_H +#define BUTTON_H +#include "item.h" + +class Button : public Item +{ +public: + Button(const QString &type); + QRectF boundingRect() const override; + void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *) override; +}; + +#endif // BUTTON_H diff --git a/creatitem.cpp b/creatitem.cpp index c9725ab..01eb617 100644 --- a/creatitem.cpp +++ b/creatitem.cpp @@ -6,5 +6,7 @@ Item *creatItem(const QString &type) if (type == "常闭") return new Contact(type); if (type == "线圈") return new Coil(type); if (type == "比较") return new Comparator(type); + if (type == "按钮") return new Button(type); + if (type == "指示灯") return new Light(type); return nullptr; } diff --git a/creatitem.h b/creatitem.h index d85eaea..990d8ac 100644 --- a/creatitem.h +++ b/creatitem.h @@ -4,6 +4,8 @@ #include "coil.h" #include "contact.h" #include "comparator.h" +#include "button.h" +#include "light.h" Item* creatItem(const QString& type); diff --git a/editor.pro b/editor.pro index 7793fcc..dcadb17 100644 --- a/editor.pro +++ b/editor.pro @@ -16,28 +16,38 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ + button.cpp \ coil.cpp \ comparator.cpp \ connection.cpp \ contact.cpp \ creatitem.cpp \ + hmi.cpp \ item.cpp \ + light.cpp \ main.cpp \ mainwindow.cpp \ - mygraphicsview.cpp + mygraphicsview.cpp \ + plc.cpp HEADERS += \ + button.h \ coil.h \ comparator.h \ connection.h \ contact.h \ creatitem.h \ + hmi.h \ item.h \ + light.h \ mainwindow.h \ - mygraphicsview.h + mygraphicsview.h \ + plc.h FORMS += \ - mainwindow.ui + hmi.ui \ + mainwindow.ui \ + plc.ui # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin diff --git a/editor.pro.user b/editor.pro.user index 0791f7a..6b8b30b 100644 --- a/editor.pro.user +++ b/editor.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/hmi.cpp b/hmi.cpp new file mode 100644 index 0000000..b48b907 --- /dev/null +++ b/hmi.cpp @@ -0,0 +1,106 @@ +#include "hmi.h" +#include "ui_hmi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "creatitem.h" + +HMI::HMI(QWidget *parent) : + QWidget(parent), + ui(new Ui::HMI) +{ + ui->setupUi(this); + /* 1. 场景 */ + m_scene = new QGraphicsScene(this); + ui->graphicsView->setScene(m_scene); + ui->graphicsView->setSceneRect(0, 0, 800, 600); + ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag); + + /* 2. 列表 */ + ui->listWidget->setViewMode(QListView::IconMode); + ui->listWidget->setIconSize(QSize(60, 30)); + ui->listWidget->setDragEnabled(false); + ui->listWidget->viewport()->installEventFilter(this); + + /* 3. 填充列表 */ + createComponents(); + connect(ui->listWidget,&QListWidget::currentTextChanged,this,&HMI::onListwidgetCurrenttextchanged); +} + +HMI::~HMI() +{ + delete ui; +} + +bool HMI::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(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(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 HMI::createComponents() +{ + struct Comp { QString name; QColor color; }; + const QVector 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 HMI::onListwidgetCurrenttextchanged(const QString &text) +{ + selectedComponentType = text; +} diff --git a/hmi.h b/hmi.h new file mode 100644 index 0000000..9f831ee --- /dev/null +++ b/hmi.h @@ -0,0 +1,32 @@ +#ifndef HMI_H +#define HMI_H + +#include +#include + +namespace Ui { +class HMI; +} + +class HMI : public QWidget +{ + Q_OBJECT + +public: + explicit HMI(QWidget *parent = nullptr); + ~HMI(); + void createComponents(); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private slots: + void onListwidgetCurrenttextchanged(const QString ¤tText); + +private: + Ui::HMI *ui; + QGraphicsScene *m_scene; + QString selectedComponentType; +}; + +#endif // HMI_H diff --git a/hmi.ui b/hmi.ui new file mode 100644 index 0000000..93b29ca --- /dev/null +++ b/hmi.ui @@ -0,0 +1,49 @@ + + + HMI + + + + 0 + 0 + 964 + 550 + + + + Form + + + + + 200 + 30 + 761 + 451 + + + + QGraphicsView::NoDrag + + + + + + 10 + 30 + 171 + 451 + + + + + + + MyGraphicsView + QGraphicsView +
mygraphicsview.h
+
+
+ + +
diff --git a/item.cpp b/item.cpp index 6c493e4..ffd4192 100644 --- a/item.cpp +++ b/item.cpp @@ -18,79 +18,29 @@ QRectF Item::boundingRect() const return QRectF(-22, -15, 44, 30); } -//void Item::paint(QPainter *painter, -// const QStyleOptionGraphicsItem * option, -// QWidget *) -//{ -// painter->setRenderHint(QPainter::Antialiasing); - -// if (type_ == "线圈") { -// // 绘制线圈样式: 两边线段+中间椭圆 -// painter->drawLine(-12, 0, -5, 0); -// painter->drawEllipse(QRectF(-5, -8, 10, 16)); -// painter->drawLine(5, 0, 12, 0); - -// // 画锚点 -// painter->setBrush(Qt::darkGray); -// painter->setPen(Qt::NoPen); -// painter->drawEllipse(QPointF(-12, 0), 4, 4); // 左锚点 -// painter->drawEllipse(QPointF(12, 0), 4, 4); // 右锚点 -// } -// else if (type_ == "常开") { -// painter->drawLine(-12, 0, -4, 0); -// painter->drawLine(-4, -8, -4, 8); -// painter->drawLine(4, -8, 4, 8); -// painter->drawLine(4, 0, 12, 0); - -// // 锚点 -// painter->setBrush(Qt::darkGray); -// painter->setPen(Qt::NoPen); -// painter->drawEllipse(QPointF(-18, 0), 4, 4); // 左 -// painter->drawEllipse(QPointF(18, 0), 4, 4); // 右 -// } -// else if (type_ == "常闭") { -// painter->drawLine(-15, -10, 15, 10); // 对角线 -// painter->drawLine(-12, 0, -4, 0); -// painter->drawLine(-4, -8, -4, 8); -// painter->drawLine(4, -8, 4, 8); -// painter->drawLine(4, 0, 12, 0); - -// // 锚点 -// painter->setBrush(Qt::darkGray); -// painter->setPen(Qt::NoPen); -// painter->drawEllipse(QPointF(-18, 0), 4, 4); // 左 -// painter->drawEllipse(QPointF(18, 0), 4, 4); // 右 -// } -// else if (type_ == "比较") { -// painter->drawRect(QRectF(-12, -8, 24, 16)); -// painter->setFont(QFont("Arial", 8)); -// painter->drawText(QRectF(-10, -8, 20, 16), Qt::AlignCenter, "CP"); - -// // 锚点 -// painter->setBrush(Qt::darkGray); -// painter->setPen(Qt::NoPen); -// painter->drawEllipse(QPointF(-18, 0), 4, 4); -// painter->drawEllipse(QPointF(18, 0), 4, 4); -// } -// if (option->state & QStyle::State_Selected) { -// QPen pen(Qt::DashLine); -// pen.setColor(Qt::blue); -// pen.setWidth(2); -// painter->setPen(pen); -// painter->setBrush(Qt::NoBrush); -// painter->drawRect(boundingRect()); -// } -//} - QPointF Item::anchorPos(AnchorType type) const { + // 对于"按钮"和"指示灯"类型,返回无效坐标 + if (type_ == "按钮" || type_ == "指示灯") { + return QPointF(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); + } + + // 其他类型正常返回连接点位置 return mapToScene(type == Left ? QPointF(-18, 0) : QPointF(18, 0)); } void Item::addConnection(Connection* conn) { + // 对于"按钮"和"指示灯"类型,不允许添加连接 + if (type_ == "按钮" || type_ == "指示灯") + { + return; + } if (!connections_.contains(conn)) + { connections_.append(conn); + } } void Item::removeConnection(Connection* conn) @@ -108,6 +58,27 @@ QString Item::itemType() return type_; } +void Item::MenuActions(QMenu *menu) +{ + menu->addAction("复制"); + menu->addAction("删除"); +} + +void Item::addMenuActions(QMenu *menu) +{ + Q_UNUSED(menu); +} + +void Item::handleMenuAction(QAction *action) +{ + if (action->text() == "复制") { + emit requestCopy(this); + } + else if (action->text() == "删除") { + emit requestDelete(this); + } +} + QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value) { if (change == QGraphicsItem::ItemPositionChange) { @@ -119,14 +90,27 @@ QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value) void Item::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { +// QMenu menu; +// QAction* copyAct = menu.addAction("复制"); +// QAction* deleteAct = menu.addAction("删除"); +// QAction* selected = menu.exec(event->screenPos()); +// if (selected == copyAct) { +// emit requestCopy(this); +// } +// if (selected == deleteAct) { +// emit requestDelete(this); +// } QMenu menu; - QAction* copyAct = menu.addAction("复制"); - QAction* deleteAct = menu.addAction("删除"); - QAction* selected = menu.exec(event->screenPos()); - if (selected == copyAct) { - emit requestCopy(this); - } - if (selected == deleteAct) { - emit requestDelete(this); + + // 创建菜单 + MenuActions(&menu); + addMenuActions(&menu); + + // 执行菜单 + QAction *selected = menu.exec(event->screenPos()); + + // 处理菜单动作 + if (selected) { + handleMenuAction(selected); } } diff --git a/item.h b/item.h index b33acae..34fdce8 100644 --- a/item.h +++ b/item.h @@ -4,6 +4,7 @@ #include #include #include +#include class Connection; @@ -15,15 +16,14 @@ public: explicit Item(const QString &type, QGraphicsItem *parent = nullptr); QRectF boundingRect() const override; -// void paint(QPainter *painter, -// const QStyleOptionGraphicsItem *option, -// QWidget *widget) override; - QPointF anchorPos(AnchorType type) const; void addConnection(Connection* conn); void removeConnection(Connection* conn); QList connections(); QString itemType(); + virtual void MenuActions(QMenu *menu); // 添加基本菜单项 + virtual void addMenuActions(QMenu *menu); // 添加额外菜单项 + virtual void handleMenuAction(QAction *action); // 处理菜单动作 signals: void requestCopy(Item*); diff --git a/light.cpp b/light.cpp new file mode 100644 index 0000000..633838e --- /dev/null +++ b/light.cpp @@ -0,0 +1,30 @@ +#include "light.h" +#include +#include + +Light::Light(const QString &type) : Item(type) +{ + +} + +QRectF Light::boundingRect() const +{ + return QRectF(0, 0, 50, 50); +} + +void Light::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + painter->setRenderHint(QPainter::Antialiasing); + + if (type_ == "指示灯") { + painter->drawEllipse(0,0,50,50); + } + if (option->state & QStyle::State_Selected) { + QPen pen(Qt::DashLine); + pen.setColor(Qt::blue); + pen.setWidth(2); + painter->setPen(pen); + painter->setBrush(Qt::NoBrush); + painter->drawRect(boundingRect()); + } +} diff --git a/light.h b/light.h new file mode 100644 index 0000000..110a5e0 --- /dev/null +++ b/light.h @@ -0,0 +1,15 @@ +#ifndef LIGHT_H +#define LIGHT_H +#include "item.h" + +class Light : public Item +{ +public: + Light(const QString &type); + QRectF boundingRect() const override; + void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *) override; +}; + +#endif // LIGHT_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 86f7f65..c102b1e 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "creatitem.h" MainWindow::MainWindow(QWidget *parent) @@ -17,21 +18,12 @@ MainWindow::MainWindow(QWidget *parent) , ui(new Ui::MainWindow) { ui->setupUi(this); - - /* 1. 场景 */ - m_scene = new QGraphicsScene(this); - ui->graphicsView->setScene(m_scene); - ui->graphicsView->setSceneRect(0, 0, 800, 600); - ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag); - - /* 2. 列表 */ - ui->listWidget->setViewMode(QListView::IconMode); - ui->listWidget->setIconSize(QSize(60, 30)); - ui->listWidget->setDragEnabled(false); - ui->listWidget->viewport()->installEventFilter(this); - - /* 3. 填充列表 */ - createComponents(); + plc_ = new PLC(ui->widget); + hmi_ = new HMI(ui->widget); + plc_->show(); + hmi_->hide(); + connect(ui->action_plc,&QAction::triggered,this,&MainWindow::plcChange); + connect(ui->action_hmi,&QAction::triggered,this,&MainWindow::hmiChange); } MainWindow::~MainWindow() @@ -39,121 +31,15 @@ MainWindow::~MainWindow() delete ui; } -/* ---------- 拖拽核心 ---------- */ -bool MainWindow::eventFilter(QObject *obj, QEvent *event) +void MainWindow::plcChange() { - if (obj == ui->listWidget->viewport()) { - static QListWidgetItem *dragItem = nullptr; - static QPoint startPos; - - if (event->type() == QEvent::MouseButtonPress) { - auto *me = static_cast(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(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 QMainWindow::eventFilter(obj, event); + plc_->show(); + hmi_->hide(); } -/* ---------- 填充列表 ---------- */ -void MainWindow::createComponents() +void MainWindow::hmiChange() { - struct Comp { QString name; QColor color; }; - const QVector 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); - } + hmi_->show(); + plc_->hide(); } -void MainWindow::on_listWidget_currentTextChanged(const QString &text) -{ - selectedComponentType = text; -} - -void MainWindow::on_pushButton_clicked() -{ - // 1. 找场景中被选中的连线 - QList selectedItems = ui->graphicsView->scene()->selectedItems(); - Connection* selectedConn = nullptr; - for (QGraphicsItem* item : selectedItems) { - selectedConn = dynamic_cast(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); - ui->graphicsView->scene()->removeItem(selectedConn); - delete selectedConn; - - // 4. 插入新元件 - Item* newItem = creatItem(selectedComponentType); - newItem->setPos(insertPos); - connect(newItem, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy); - connect(newItem, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete); - ui->graphicsView->scene()->addItem(newItem); - - // 5. 新建两条连线 - Connection* c1 = new Connection(from, fromType, newItem, Item::Left); - ui->graphicsView->scene()->addItem(c1); - Connection* c2 = new Connection(newItem, Item::Right, to, toType); - ui->graphicsView->scene()->addItem(c2); -} diff --git a/mainwindow.h b/mainwindow.h index e473d57..d357df0 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -2,6 +2,8 @@ #define MAINWINDOW_H #include +#include +#include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -16,20 +18,14 @@ public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); -protected: - bool eventFilter(QObject *obj, QEvent *event) override; - private slots: - void on_listWidget_currentTextChanged(const QString ¤tText); - - void on_pushButton_clicked(); + void plcChange(); + void hmiChange(); private: - void createComponents(); - Ui::MainWindow *ui; - QGraphicsScene *m_scene; - QString selectedComponentType; + PLC *plc_; + HMI *hmi_; }; #endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui index aef3cbb..73fda7d 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -7,49 +7,23 @@ 0 0 1012 - 656 + 678 MainWindow - + - 20 - 10 - 171 - 491 + 10 + 0 + 981 + 561 - - - - 210 - 10 - 761 - 491 - - - - QGraphicsView::NoDrag - - - - - - 30 - 510 - 93 - 28 - - - - 插入 - - @@ -64,36 +38,47 @@ 文件 - - - + + + + + + + 页面切换 + + + + - + New - + Open - + Save + + + PLC + + + + + HMI + + - - - MyGraphicsView - QGraphicsView -
mygraphicsview.h
-
-
diff --git a/plc.cpp b/plc.cpp new file mode 100644 index 0000000..0be8e03 --- /dev/null +++ b/plc.cpp @@ -0,0 +1,158 @@ +#include "plc.h" +#include "ui_plc.h" +#include "item.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "creatitem.h" + +PLC::PLC(QWidget *parent) : + QWidget(parent), + ui(new Ui::PLC) +{ + ui->setupUi(this); + /* 1. 场景 */ + m_scene = new QGraphicsScene(this); + ui->graphicsView->setScene(m_scene); + ui->graphicsView->setSceneRect(0, 0, 800, 600); + ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag); + + /* 2. 列表 */ + ui->listWidget->setViewMode(QListView::IconMode); + ui->listWidget->setIconSize(QSize(60, 30)); + ui->listWidget->setDragEnabled(false); + ui->listWidget->viewport()->installEventFilter(this); + + /* 3. 填充列表 */ + createComponents(); + connect(ui->listWidget,&QListWidget::currentTextChanged,this,&PLC::onListwidgetCurrenttextchanged); + connect(ui->btn_insert,&QPushButton::clicked,this,&PLC::btnInsertClicked); +} + +PLC::~PLC() +{ + delete ui; +} + +bool PLC::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(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(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 PLC::createComponents() +{ + struct Comp { QString name; QColor color; }; + const QVector 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); + } +} + +void PLC::onListwidgetCurrenttextchanged(const QString &text) +{ + selectedComponentType = text; +} + +void PLC::btnInsertClicked() +{ + // 1. 找场景中被选中的连线 + QList selectedItems = ui->graphicsView->scene()->selectedItems(); + Connection* selectedConn = nullptr; + for (QGraphicsItem* item : selectedItems) { + selectedConn = dynamic_cast(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); + ui->graphicsView->scene()->removeItem(selectedConn); + delete selectedConn; + + // 4. 插入新元件 + Item* newItem = creatItem(selectedComponentType); + newItem->setPos(insertPos); + connect(newItem, &Item::requestCopy, ui->graphicsView, &MyGraphicsView::onItemRequestCopy); + connect(newItem, &Item::requestDelete, ui->graphicsView, &MyGraphicsView::onItemRequestDelete); + ui->graphicsView->scene()->addItem(newItem); + + // 5. 新建两条连线 + Connection* c1 = new Connection(from, fromType, newItem, Item::Left); + ui->graphicsView->scene()->addItem(c1); + Connection* c2 = new Connection(newItem, Item::Right, to, toType); + ui->graphicsView->scene()->addItem(c2); +} diff --git a/plc.h b/plc.h new file mode 100644 index 0000000..c56b766 --- /dev/null +++ b/plc.h @@ -0,0 +1,33 @@ +#ifndef PLC_H +#define PLC_H + +#include +#include + +namespace Ui { +class PLC; +} + +class PLC : public QWidget +{ + Q_OBJECT + +public: + explicit PLC(QWidget *parent = nullptr); + ~PLC(); + void createComponents(); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private slots: + void onListwidgetCurrenttextchanged(const QString ¤tText); + void btnInsertClicked(); + +private: + Ui::PLC *ui; + QGraphicsScene *m_scene; + QString selectedComponentType; +}; + +#endif // PLC_H diff --git a/plc.ui b/plc.ui new file mode 100644 index 0000000..33a7d94 --- /dev/null +++ b/plc.ui @@ -0,0 +1,62 @@ + + + PLC + + + + 0 + 0 + 974 + 536 + + + + Form + + + + + 10 + 30 + 171 + 451 + + + + + + + 200 + 30 + 761 + 451 + + + + QGraphicsView::NoDrag + + + + + + 10 + 0 + 93 + 28 + + + + 插入 + + + + + + MyGraphicsView + QGraphicsView +
mygraphicsview.h
+
+
+ + +