@@ -0,0 +1,30 @@ | |||
#include "button.h" | |||
#include <QPainter> | |||
#include <QStyleOptionGraphicsItem> | |||
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()); | |||
} | |||
} |
@@ -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 |
@@ -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; | |||
} |
@@ -4,6 +4,8 @@ | |||
#include "coil.h" | |||
#include "contact.h" | |||
#include "comparator.h" | |||
#include "button.h" | |||
#include "light.h" | |||
Item* creatItem(const QString& type); | |||
@@ -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 | |||
@@ -1,6 +1,6 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE QtCreatorProject> | |||
<!-- Written by QtCreator 4.11.1, 2025-08-06T20:12:05. --> | |||
<!-- Written by QtCreator 4.11.1, 2025-08-07T09:52:05. --> | |||
<qtcreator> | |||
<data> | |||
<variable>EnvironmentId</variable> | |||
@@ -0,0 +1,106 @@ | |||
#include "hmi.h" | |||
#include "ui_hmi.h" | |||
#include <QListWidgetItem> | |||
#include <QMimeData> | |||
#include <QDrag> | |||
#include <QPainter> | |||
#include <QMouseEvent> | |||
#include <QDropEvent> | |||
#include <QGraphicsView> | |||
#include <QMessageBox> | |||
#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<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 HMI::createComponents() | |||
{ | |||
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 HMI::onListwidgetCurrenttextchanged(const QString &text) | |||
{ | |||
selectedComponentType = text; | |||
} |
@@ -0,0 +1,32 @@ | |||
#ifndef HMI_H | |||
#define HMI_H | |||
#include <QGraphicsScene> | |||
#include <QWidget> | |||
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 |
@@ -0,0 +1,49 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<ui version="4.0"> | |||
<class>HMI</class> | |||
<widget class="QWidget" name="HMI"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>0</x> | |||
<y>0</y> | |||
<width>964</width> | |||
<height>550</height> | |||
</rect> | |||
</property> | |||
<property name="windowTitle"> | |||
<string>Form</string> | |||
</property> | |||
<widget class="MyGraphicsView" name="graphicsView"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>200</x> | |||
<y>30</y> | |||
<width>761</width> | |||
<height>451</height> | |||
</rect> | |||
</property> | |||
<property name="dragMode"> | |||
<enum>QGraphicsView::NoDrag</enum> | |||
</property> | |||
</widget> | |||
<widget class="QListWidget" name="listWidget"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>10</x> | |||
<y>30</y> | |||
<width>171</width> | |||
<height>451</height> | |||
</rect> | |||
</property> | |||
</widget> | |||
</widget> | |||
<customwidgets> | |||
<customwidget> | |||
<class>MyGraphicsView</class> | |||
<extends>QGraphicsView</extends> | |||
<header>mygraphicsview.h</header> | |||
</customwidget> | |||
</customwidgets> | |||
<resources/> | |||
<connections/> | |||
</ui> |
@@ -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<qreal>::quiet_NaN(), | |||
std::numeric_limits<qreal>::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); | |||
} | |||
} |
@@ -4,6 +4,7 @@ | |||
#include <QGraphicsObject> | |||
#include <QColor> | |||
#include <QList> | |||
#include <QAction> | |||
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<Connection*> connections(); | |||
QString itemType(); | |||
virtual void MenuActions(QMenu *menu); // 添加基本菜单项 | |||
virtual void addMenuActions(QMenu *menu); // 添加额外菜单项 | |||
virtual void handleMenuAction(QAction *action); // 处理菜单动作 | |||
signals: | |||
void requestCopy(Item*); | |||
@@ -0,0 +1,30 @@ | |||
#include "light.h" | |||
#include <QPainter> | |||
#include <QStyleOptionGraphicsItem> | |||
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()); | |||
} | |||
} |
@@ -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 |
@@ -10,6 +10,7 @@ | |||
#include <QDropEvent> | |||
#include <QGraphicsView> | |||
#include <QMessageBox> | |||
#include <QAction> | |||
#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<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 QMainWindow::eventFilter(obj, event); | |||
plc_->show(); | |||
hmi_->hide(); | |||
} | |||
/* ---------- 填充列表 ---------- */ | |||
void MainWindow::createComponents() | |||
void MainWindow::hmiChange() | |||
{ | |||
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); | |||
} | |||
hmi_->show(); | |||
plc_->hide(); | |||
} | |||
void MainWindow::on_listWidget_currentTextChanged(const QString &text) | |||
{ | |||
selectedComponentType = text; | |||
} | |||
void MainWindow::on_pushButton_clicked() | |||
{ | |||
// 1. 找场景中被选中的连线 | |||
QList<QGraphicsItem*> selectedItems = ui->graphicsView->scene()->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); | |||
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); | |||
} |
@@ -2,6 +2,8 @@ | |||
#define MAINWINDOW_H | |||
#include <QMainWindow> | |||
#include <plc.h> | |||
#include <hmi.h> | |||
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 |
@@ -7,49 +7,23 @@ | |||
<x>0</x> | |||
<y>0</y> | |||
<width>1012</width> | |||
<height>656</height> | |||
<height>678</height> | |||
</rect> | |||
</property> | |||
<property name="windowTitle"> | |||
<string>MainWindow</string> | |||
</property> | |||
<widget class="QWidget" name="centralwidget"> | |||
<widget class="QListWidget" name="listWidget"> | |||
<widget class="QWidget" name="widget" native="true"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>20</x> | |||
<y>10</y> | |||
<width>171</width> | |||
<height>491</height> | |||
<x>10</x> | |||
<y>0</y> | |||
<width>981</width> | |||
<height>561</height> | |||
</rect> | |||
</property> | |||
</widget> | |||
<widget class="MyGraphicsView" name="graphicsView"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>210</x> | |||
<y>10</y> | |||
<width>761</width> | |||
<height>491</height> | |||
</rect> | |||
</property> | |||
<property name="dragMode"> | |||
<enum>QGraphicsView::NoDrag</enum> | |||
</property> | |||
</widget> | |||
<widget class="QPushButton" name="pushButton"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>30</x> | |||
<y>510</y> | |||
<width>93</width> | |||
<height>28</height> | |||
</rect> | |||
</property> | |||
<property name="text"> | |||
<string>插入</string> | |||
</property> | |||
</widget> | |||
</widget> | |||
<widget class="QMenuBar" name="menubar"> | |||
<property name="geometry"> | |||
@@ -64,36 +38,47 @@ | |||
<property name="title"> | |||
<string>文件</string> | |||
</property> | |||
<addaction name="actionnew"/> | |||
<addaction name="actionOpen"/> | |||
<addaction name="actionSave"/> | |||
<addaction name="action_new"/> | |||
<addaction name="action_open"/> | |||
<addaction name="action_save"/> | |||
</widget> | |||
<widget class="QMenu" name="menu_2"> | |||
<property name="title"> | |||
<string>页面切换</string> | |||
</property> | |||
<addaction name="action_plc"/> | |||
<addaction name="action_hmi"/> | |||
</widget> | |||
<addaction name="menu"/> | |||
<addaction name="menu_2"/> | |||
</widget> | |||
<widget class="QStatusBar" name="statusbar"/> | |||
<action name="actionnew"> | |||
<action name="action_new"> | |||
<property name="text"> | |||
<string>New</string> | |||
</property> | |||
</action> | |||
<action name="actionOpen"> | |||
<action name="action_open"> | |||
<property name="text"> | |||
<string>Open</string> | |||
</property> | |||
</action> | |||
<action name="actionSave"> | |||
<action name="action_save"> | |||
<property name="text"> | |||
<string>Save</string> | |||
</property> | |||
</action> | |||
<action name="action_plc"> | |||
<property name="text"> | |||
<string>PLC</string> | |||
</property> | |||
</action> | |||
<action name="action_hmi"> | |||
<property name="text"> | |||
<string>HMI</string> | |||
</property> | |||
</action> | |||
</widget> | |||
<customwidgets> | |||
<customwidget> | |||
<class>MyGraphicsView</class> | |||
<extends>QGraphicsView</extends> | |||
<header>mygraphicsview.h</header> | |||
</customwidget> | |||
</customwidgets> | |||
<resources/> | |||
<connections/> | |||
</ui> |
@@ -0,0 +1,158 @@ | |||
#include "plc.h" | |||
#include "ui_plc.h" | |||
#include "item.h" | |||
#include <QListWidgetItem> | |||
#include <QMimeData> | |||
#include <QDrag> | |||
#include <QPainter> | |||
#include <QMouseEvent> | |||
#include <QDropEvent> | |||
#include <QGraphicsView> | |||
#include <QMessageBox> | |||
#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<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 PLC::createComponents() | |||
{ | |||
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); | |||
} | |||
} | |||
void PLC::onListwidgetCurrenttextchanged(const QString &text) | |||
{ | |||
selectedComponentType = text; | |||
} | |||
void PLC::btnInsertClicked() | |||
{ | |||
// 1. 找场景中被选中的连线 | |||
QList<QGraphicsItem*> selectedItems = ui->graphicsView->scene()->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); | |||
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); | |||
} |
@@ -0,0 +1,33 @@ | |||
#ifndef PLC_H | |||
#define PLC_H | |||
#include <QGraphicsScene> | |||
#include <QWidget> | |||
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 |
@@ -0,0 +1,62 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<ui version="4.0"> | |||
<class>PLC</class> | |||
<widget class="QWidget" name="PLC"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>0</x> | |||
<y>0</y> | |||
<width>974</width> | |||
<height>536</height> | |||
</rect> | |||
</property> | |||
<property name="windowTitle"> | |||
<string>Form</string> | |||
</property> | |||
<widget class="QListWidget" name="listWidget"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>10</x> | |||
<y>30</y> | |||
<width>171</width> | |||
<height>451</height> | |||
</rect> | |||
</property> | |||
</widget> | |||
<widget class="MyGraphicsView" name="graphicsView"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>200</x> | |||
<y>30</y> | |||
<width>761</width> | |||
<height>451</height> | |||
</rect> | |||
</property> | |||
<property name="dragMode"> | |||
<enum>QGraphicsView::NoDrag</enum> | |||
</property> | |||
</widget> | |||
<widget class="QPushButton" name="btn_insert"> | |||
<property name="geometry"> | |||
<rect> | |||
<x>10</x> | |||
<y>0</y> | |||
<width>93</width> | |||
<height>28</height> | |||
</rect> | |||
</property> | |||
<property name="text"> | |||
<string>插入</string> | |||
</property> | |||
</widget> | |||
</widget> | |||
<customwidgets> | |||
<customwidget> | |||
<class>MyGraphicsView</class> | |||
<extends>QGraphicsView</extends> | |||
<header>mygraphicsview.h</header> | |||
</customwidget> | |||
</customwidgets> | |||
<resources/> | |||
<connections/> | |||
</ui> |