@@ -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 Contact(type); | ||||
if (type == "线圈") return new Coil(type); | if (type == "线圈") return new Coil(type); | ||||
if (type == "比较") return new Comparator(type); | if (type == "比较") return new Comparator(type); | ||||
if (type == "按钮") return new Button(type); | |||||
if (type == "指示灯") return new Light(type); | |||||
return nullptr; | return nullptr; | ||||
} | } |
@@ -4,6 +4,8 @@ | |||||
#include "coil.h" | #include "coil.h" | ||||
#include "contact.h" | #include "contact.h" | ||||
#include "comparator.h" | #include "comparator.h" | ||||
#include "button.h" | |||||
#include "light.h" | |||||
Item* creatItem(const QString& type); | 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 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 | ||||
SOURCES += \ | SOURCES += \ | ||||
button.cpp \ | |||||
coil.cpp \ | coil.cpp \ | ||||
comparator.cpp \ | comparator.cpp \ | ||||
connection.cpp \ | connection.cpp \ | ||||
contact.cpp \ | contact.cpp \ | ||||
creatitem.cpp \ | creatitem.cpp \ | ||||
hmi.cpp \ | |||||
item.cpp \ | item.cpp \ | ||||
light.cpp \ | |||||
main.cpp \ | main.cpp \ | ||||
mainwindow.cpp \ | mainwindow.cpp \ | ||||
mygraphicsview.cpp | |||||
mygraphicsview.cpp \ | |||||
plc.cpp | |||||
HEADERS += \ | HEADERS += \ | ||||
button.h \ | |||||
coil.h \ | coil.h \ | ||||
comparator.h \ | comparator.h \ | ||||
connection.h \ | connection.h \ | ||||
contact.h \ | contact.h \ | ||||
creatitem.h \ | creatitem.h \ | ||||
hmi.h \ | |||||
item.h \ | item.h \ | ||||
light.h \ | |||||
mainwindow.h \ | mainwindow.h \ | ||||
mygraphicsview.h | |||||
mygraphicsview.h \ | |||||
plc.h | |||||
FORMS += \ | FORMS += \ | ||||
mainwindow.ui | |||||
hmi.ui \ | |||||
mainwindow.ui \ | |||||
plc.ui | |||||
# Default rules for deployment. | # Default rules for deployment. | ||||
qnx: target.path = /tmp/$${TARGET}/bin | qnx: target.path = /tmp/$${TARGET}/bin | ||||
@@ -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-06T20:12:05. --> | |||||
<!-- Written by QtCreator 4.11.1, 2025-08-07T09:52:05. --> | |||||
<qtcreator> | <qtcreator> | ||||
<data> | <data> | ||||
<variable>EnvironmentId</variable> | <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); | 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 | 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)); | return mapToScene(type == Left ? QPointF(-18, 0) : QPointF(18, 0)); | ||||
} | } | ||||
void Item::addConnection(Connection* conn) | void Item::addConnection(Connection* conn) | ||||
{ | { | ||||
// 对于"按钮"和"指示灯"类型,不允许添加连接 | |||||
if (type_ == "按钮" || type_ == "指示灯") | |||||
{ | |||||
return; | |||||
} | |||||
if (!connections_.contains(conn)) | if (!connections_.contains(conn)) | ||||
{ | |||||
connections_.append(conn); | connections_.append(conn); | ||||
} | |||||
} | } | ||||
void Item::removeConnection(Connection* conn) | void Item::removeConnection(Connection* conn) | ||||
@@ -108,6 +58,27 @@ QString Item::itemType() | |||||
return type_; | 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) | QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value) | ||||
{ | { | ||||
if (change == QGraphicsItem::ItemPositionChange) { | if (change == QGraphicsItem::ItemPositionChange) { | ||||
@@ -119,14 +90,27 @@ QVariant Item::itemChange(GraphicsItemChange change, const QVariant &value) | |||||
void Item::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) | 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; | 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 <QGraphicsObject> | ||||
#include <QColor> | #include <QColor> | ||||
#include <QList> | #include <QList> | ||||
#include <QAction> | |||||
class Connection; | class Connection; | ||||
@@ -15,15 +16,14 @@ public: | |||||
explicit Item(const QString &type, QGraphicsItem *parent = nullptr); | explicit Item(const QString &type, QGraphicsItem *parent = nullptr); | ||||
QRectF boundingRect() const override; | QRectF boundingRect() const override; | ||||
// void paint(QPainter *painter, | |||||
// const QStyleOptionGraphicsItem *option, | |||||
// QWidget *widget) override; | |||||
QPointF anchorPos(AnchorType type) const; | QPointF anchorPos(AnchorType type) const; | ||||
void addConnection(Connection* conn); | void addConnection(Connection* conn); | ||||
void removeConnection(Connection* conn); | void removeConnection(Connection* conn); | ||||
QList<Connection*> connections(); | QList<Connection*> connections(); | ||||
QString itemType(); | QString itemType(); | ||||
virtual void MenuActions(QMenu *menu); // 添加基本菜单项 | |||||
virtual void addMenuActions(QMenu *menu); // 添加额外菜单项 | |||||
virtual void handleMenuAction(QAction *action); // 处理菜单动作 | |||||
signals: | signals: | ||||
void requestCopy(Item*); | 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 <QDropEvent> | ||||
#include <QGraphicsView> | #include <QGraphicsView> | ||||
#include <QMessageBox> | #include <QMessageBox> | ||||
#include <QAction> | |||||
#include "creatitem.h" | #include "creatitem.h" | ||||
MainWindow::MainWindow(QWidget *parent) | MainWindow::MainWindow(QWidget *parent) | ||||
@@ -17,21 +18,12 @@ MainWindow::MainWindow(QWidget *parent) | |||||
, ui(new Ui::MainWindow) | , ui(new Ui::MainWindow) | ||||
{ | { | ||||
ui->setupUi(this); | 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() | MainWindow::~MainWindow() | ||||
@@ -39,121 +31,15 @@ MainWindow::~MainWindow() | |||||
delete ui; | 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 | #define MAINWINDOW_H | ||||
#include <QMainWindow> | #include <QMainWindow> | ||||
#include <plc.h> | |||||
#include <hmi.h> | |||||
QT_BEGIN_NAMESPACE | QT_BEGIN_NAMESPACE | ||||
namespace Ui { class MainWindow; } | namespace Ui { class MainWindow; } | ||||
@@ -16,20 +18,14 @@ public: | |||||
explicit MainWindow(QWidget *parent = nullptr); | explicit MainWindow(QWidget *parent = nullptr); | ||||
~MainWindow(); | ~MainWindow(); | ||||
protected: | |||||
bool eventFilter(QObject *obj, QEvent *event) override; | |||||
private slots: | private slots: | ||||
void on_listWidget_currentTextChanged(const QString ¤tText); | |||||
void on_pushButton_clicked(); | |||||
void plcChange(); | |||||
void hmiChange(); | |||||
private: | private: | ||||
void createComponents(); | |||||
Ui::MainWindow *ui; | Ui::MainWindow *ui; | ||||
QGraphicsScene *m_scene; | |||||
QString selectedComponentType; | |||||
PLC *plc_; | |||||
HMI *hmi_; | |||||
}; | }; | ||||
#endif // MAINWINDOW_H | #endif // MAINWINDOW_H |
@@ -7,49 +7,23 @@ | |||||
<x>0</x> | <x>0</x> | ||||
<y>0</y> | <y>0</y> | ||||
<width>1012</width> | <width>1012</width> | ||||
<height>656</height> | |||||
<height>678</height> | |||||
</rect> | </rect> | ||||
</property> | </property> | ||||
<property name="windowTitle"> | <property name="windowTitle"> | ||||
<string>MainWindow</string> | <string>MainWindow</string> | ||||
</property> | </property> | ||||
<widget class="QWidget" name="centralwidget"> | <widget class="QWidget" name="centralwidget"> | ||||
<widget class="QListWidget" name="listWidget"> | |||||
<widget class="QWidget" name="widget" native="true"> | |||||
<property name="geometry"> | <property name="geometry"> | ||||
<rect> | <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> | </rect> | ||||
</property> | </property> | ||||
</widget> | </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> | ||||
<widget class="QMenuBar" name="menubar"> | <widget class="QMenuBar" name="menubar"> | ||||
<property name="geometry"> | <property name="geometry"> | ||||
@@ -64,36 +38,47 @@ | |||||
<property name="title"> | <property name="title"> | ||||
<string>文件</string> | <string>文件</string> | ||||
</property> | </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> | </widget> | ||||
<addaction name="menu"/> | <addaction name="menu"/> | ||||
<addaction name="menu_2"/> | |||||
</widget> | </widget> | ||||
<widget class="QStatusBar" name="statusbar"/> | <widget class="QStatusBar" name="statusbar"/> | ||||
<action name="actionnew"> | |||||
<action name="action_new"> | |||||
<property name="text"> | <property name="text"> | ||||
<string>New</string> | <string>New</string> | ||||
</property> | </property> | ||||
</action> | </action> | ||||
<action name="actionOpen"> | |||||
<action name="action_open"> | |||||
<property name="text"> | <property name="text"> | ||||
<string>Open</string> | <string>Open</string> | ||||
</property> | </property> | ||||
</action> | </action> | ||||
<action name="actionSave"> | |||||
<action name="action_save"> | |||||
<property name="text"> | <property name="text"> | ||||
<string>Save</string> | <string>Save</string> | ||||
</property> | </property> | ||||
</action> | </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> | </widget> | ||||
<customwidgets> | |||||
<customwidget> | |||||
<class>MyGraphicsView</class> | |||||
<extends>QGraphicsView</extends> | |||||
<header>mygraphicsview.h</header> | |||||
</customwidget> | |||||
</customwidgets> | |||||
<resources/> | <resources/> | ||||
<connections/> | <connections/> | ||||
</ui> | </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> |