@@ -32,4 +32,7 @@ qnx: target.path = /tmp/$${TARGET}/bin | |||||
else: unix:!android: target.path = /opt/$${TARGET}/bin | else: unix:!android: target.path = /opt/$${TARGET}/bin | ||||
!isEmpty(target.path): INSTALLS += target | !isEmpty(target.path): INSTALLS += target | ||||
DISTFILES += | |||||
DISTFILES += \ | |||||
images/T-常开触点-01.png \ | |||||
images/按钮.png \ | |||||
images/灯泡.png |
@@ -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-05T21:07:14. --> | |||||
<!-- Written by QtCreator 4.11.1, 2025-08-06T20:14:02. --> | |||||
<qtcreator> | <qtcreator> | ||||
<data> | <data> | ||||
<variable>EnvironmentId</variable> | <variable>EnvironmentId</variable> | ||||
@@ -1,90 +1,86 @@ | |||||
#include "hmiwidget.h" | #include "hmiwidget.h" | ||||
#include <QGraphicsSceneMouseEvent> | |||||
#include <QCursor> | |||||
#include <QDebug> | |||||
#include<QMenu> | |||||
#include<QGraphicsScene> | |||||
// ResizableShape 模板类的实现 | |||||
template <typename BaseShape> | |||||
ResizableShape<BaseShape>::ResizableShape(qreal x, qreal y, qreal w, qreal h) | |||||
: BaseShape(x, y, w, h), resizing(false) | |||||
{ | |||||
this->setFlag(QGraphicsItem::ItemIsMovable, true); | |||||
this->setFlag(QGraphicsItem::ItemIsSelectable, true); | |||||
this->setAcceptHoverEvents(true); | |||||
} | |||||
ResizableRectangle::ResizableRectangle(qreal x, qreal y, qreal w, qreal h) | |||||
: QGraphicsRectItem(x, y, w, h), resizing(false) | |||||
template <typename BaseShape> | |||||
void ResizableShape<BaseShape>::hoverMoveEvent(QGraphicsSceneHoverEvent *event) | |||||
{ | |||||
if (isInResizeArea(event->pos())) { | |||||
this->setCursor(Qt::SizeFDiagCursor); | |||||
} else { | |||||
this->setCursor(Qt::SizeAllCursor); | |||||
} | |||||
BaseShape::hoverMoveEvent(event); | |||||
} | |||||
template <typename BaseShape> | |||||
bool ResizableShape<BaseShape>::isInResizeArea(const QPointF &pos) const | |||||
{ | { | ||||
setFlag(QGraphicsItem::ItemIsMovable, true); | |||||
setFlag(QGraphicsItem::ItemIsSelectable, true); | |||||
setCursor(Qt::ArrowCursor); | |||||
QRectF r = this->rect(); | |||||
QRectF resizeArea(r.bottomRight() - QPointF(20, 20), r.bottomRight()); | |||||
return resizeArea.contains(pos); | |||||
} | } | ||||
void ResizableRectangle::mousePressEvent(QGraphicsSceneMouseEvent *event) | |||||
template <typename BaseShape> | |||||
void ResizableShape<BaseShape>::mousePressEvent(QGraphicsSceneMouseEvent *event) | |||||
{ | { | ||||
// 检查是否在调整区域 | |||||
if (rect().bottomRight().x() - 10 <= event->pos().x() && | |||||
rect().bottomRight().y() - 10 <= event->pos().y()) { | |||||
if (isInResizeArea(event->pos())) { | |||||
resizing = true; | resizing = true; | ||||
setCursor(Qt::SizeFDiagCursor); | |||||
this->setCursor(Qt::SizeFDiagCursor); | |||||
} else { | } else { | ||||
// 传递事件给基类处理移动 | |||||
resizing = false; | resizing = false; | ||||
setCursor(Qt::SizeAllCursor); | |||||
QGraphicsRectItem::mousePressEvent(event); | |||||
this->setCursor(Qt::SizeAllCursor); | |||||
BaseShape::mousePressEvent(event); | |||||
} | } | ||||
} | } | ||||
void ResizableRectangle::mouseMoveEvent(QGraphicsSceneMouseEvent *event) | |||||
template <typename BaseShape> | |||||
void ResizableShape<BaseShape>::mouseMoveEvent(QGraphicsSceneMouseEvent *event) | |||||
{ | { | ||||
if (resizing) { | if (resizing) { | ||||
// 调整大小逻辑 | |||||
QRectF newRect = rect(); | |||||
QRectF newRect = this->rect(); | |||||
newRect.setBottomRight(event->pos()); | newRect.setBottomRight(event->pos()); | ||||
setRect(newRect); | |||||
this->setRect(newRect); | |||||
} else { | } else { | ||||
// 传递事件给基类处理移动 | |||||
QGraphicsRectItem::mouseMoveEvent(event); | |||||
BaseShape::mouseMoveEvent(event); | |||||
} | } | ||||
} | } | ||||
void ResizableRectangle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) | |||||
template <typename BaseShape> | |||||
void ResizableShape<BaseShape>::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) | |||||
{ | { | ||||
resizing = false; | resizing = false; | ||||
setCursor(Qt::ArrowCursor); | |||||
QGraphicsRectItem::mouseReleaseEvent(event); | |||||
this->setCursor(Qt::SizeAllCursor); | |||||
BaseShape::mouseReleaseEvent(event); | |||||
} | } | ||||
// -------------------- ResizableEllipse -------------------- | |||||
ResizableEllipse::ResizableEllipse(qreal x, qreal y, qreal w, qreal h) | |||||
: QGraphicsEllipseItem(x, y, w, h), resizing2(false) | |||||
template <typename BaseShape>//虚函数 | |||||
void ResizableShape<BaseShape>::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) | |||||
{ | { | ||||
setFlag(QGraphicsItem::ItemIsMovable, true); | |||||
setFlag(QGraphicsItem::ItemIsSelectable, true); | |||||
setCursor(Qt::ArrowCursor); | |||||
BaseShape::paint(painter, option, widget); | |||||
} | } | ||||
void ResizableEllipse::mousePressEvent(QGraphicsSceneMouseEvent *event) | |||||
// ResizableRectangle 实现 | |||||
ResizableRectangle::ResizableRectangle(qreal x, qreal y, qreal w, qreal h) | |||||
: ResizableShape<QGraphicsRectItem>(x, y, w, h) | |||||
{ | { | ||||
QRectF ellipseRect = rect(); | |||||
if (ellipseRect.bottomRight().x() - 10 <= event->pos().x() && | |||||
ellipseRect.bottomRight().y() - 10 <= event->pos().y()) { | |||||
resizing2 = true; | |||||
setCursor(Qt::SizeFDiagCursor); | |||||
} else { | |||||
// 传递事件给基类处理移动 | |||||
resizing2 = false; | |||||
setCursor(Qt::SizeAllCursor); | |||||
QGraphicsEllipseItem::mousePressEvent(event); | |||||
} | |||||
} | } | ||||
void ResizableEllipse::mouseMoveEvent(QGraphicsSceneMouseEvent *event) | |||||
// ResizableEllipse 实现 | |||||
ResizableEllipse::ResizableEllipse(qreal x, qreal y, qreal w, qreal h) | |||||
: ResizableShape<QGraphicsEllipseItem>(x, y, w, h) | |||||
{ | { | ||||
if (resizing2) { | |||||
QRectF newRect = rect(); | |||||
newRect.setBottomRight(event->pos()); | |||||
setRect(newRect); | |||||
} else { | |||||
// 传递事件给基类处理移动 | |||||
QGraphicsEllipseItem::mouseMoveEvent(event); | |||||
} | |||||
} | } | ||||
void ResizableEllipse::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) | |||||
{ | |||||
resizing2 = false; | |||||
setCursor(Qt::ArrowCursor); | |||||
QGraphicsEllipseItem::mouseReleaseEvent(event); | |||||
} | |||||
// 显式实例化模板类 | |||||
template class ResizableShape<QGraphicsRectItem>; | |||||
template class ResizableShape<QGraphicsEllipseItem>; |
@@ -1,50 +1,41 @@ | |||||
#ifndef HMIELEMENT_H | |||||
#define HMIELEMENT_H | |||||
#ifndef HMIWIDGET_H | |||||
#define HMIWIDGET_H | |||||
#include <QGraphicsRectItem> | #include <QGraphicsRectItem> | ||||
#include <QGraphicsEllipseItem> | #include <QGraphicsEllipseItem> | ||||
#include <QGraphicsSceneMouseEvent> | #include <QGraphicsSceneMouseEvent> | ||||
#include <QPen> | |||||
#include <QBrush> | |||||
#include <QCursor> | |||||
#include <QPainter> | |||||
// 可调整大小的形状模板基类 | |||||
template <typename BaseShape> | |||||
class ResizableShape : public BaseShape { | |||||
protected: | |||||
bool resizing; | |||||
// 自定义矩形类,支持大小调整 | |||||
class ResizableRectangle : public QGraphicsRectItem | |||||
{ | |||||
public: | public: | ||||
// 构造函数 | |||||
ResizableRectangle(qreal x, qreal y, qreal w, qreal h); | |||||
ResizableShape(qreal x, qreal y, qreal w, qreal h); | |||||
protected: | |||||
// 鼠标按下事件 | |||||
// 事件处理 | |||||
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override; | |||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override; | void mousePressEvent(QGraphicsSceneMouseEvent *event) override; | ||||
// 鼠标移动事件 | |||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; | void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; | ||||
// 鼠标释放事件 | |||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; | void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; | ||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; | |||||
protected: | |||||
bool isInResizeArea(const QPointF &pos) const; | |||||
}; | |||||
private: | |||||
bool resizing; //是否正在调整大小 | |||||
// 可调整大小的矩形 | |||||
class ResizableRectangle : public ResizableShape<QGraphicsRectItem> { | |||||
public: | |||||
ResizableRectangle(qreal x, qreal y, qreal w, qreal h); | |||||
}; | }; | ||||
// 自定义圆形类,支持大小调整 | |||||
class ResizableEllipse : public QGraphicsEllipseItem | |||||
{ | |||||
// 可调整大小的椭圆 | |||||
class ResizableEllipse : public ResizableShape<QGraphicsEllipseItem> { | |||||
public: | public: | ||||
// 构造函数 | |||||
ResizableEllipse(qreal x, qreal y, qreal w, qreal h); | ResizableEllipse(qreal x, qreal y, qreal w, qreal h); | ||||
protected: | |||||
// 鼠标按下事件 | |||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override; | |||||
// 鼠标移动事件 | |||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; | |||||
// 鼠标释放事件 | |||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; | |||||
private: | |||||
bool resizing2; // 是否正在调整大小 | |||||
}; | }; | ||||
#endif // HMIELEMENT_H | |||||
#endif // HMIWIDGET_H |
@@ -2,6 +2,7 @@ | |||||
#include <QApplication> | #include <QApplication> | ||||
#include<QStyleFactory> | #include<QStyleFactory> | ||||
#include<QDir> | |||||
int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||||
{ | { | ||||
QApplication::setStyle(QStyleFactory::create("Fusion")); | QApplication::setStyle(QStyleFactory::create("Fusion")); | ||||
@@ -9,4 +10,5 @@ int main(int argc, char *argv[]) | |||||
MainWindow w; | MainWindow w; | ||||
w.show(); | w.show(); | ||||
return a.exec(); | return a.exec(); | ||||
} | } |
@@ -1,23 +1,47 @@ | |||||
#include "mainwindow.h" | #include "mainwindow.h" | ||||
#include "ui_mainwindow.h" | #include "ui_mainwindow.h" | ||||
#include"hmiwidget.h" | #include"hmiwidget.h" | ||||
#include<QDebug> | |||||
#include<QDir> | |||||
#include <QGraphicsView> | |||||
#include <QGraphicsScene> | |||||
MainWindow::MainWindow(QWidget *parent) | MainWindow::MainWindow(QWidget *parent) | ||||
: QMainWindow(parent) | : QMainWindow(parent) | ||||
, ui(new Ui::MainWindow) | , ui(new Ui::MainWindow) | ||||
,canDrawCircle(false) | |||||
,canDrawEllipse(false) | |||||
,canDrawRectangle(false) | ,canDrawRectangle(false) | ||||
{ | { | ||||
ui->setupUi(this); | ui->setupUi(this); | ||||
addDockWidget(Qt::BottomDockWidgetArea, ui->dockWidget_3);//将dockWidget_3添加到主窗口的下方 | |||||
scene = new QGraphicsScene(this); | scene = new QGraphicsScene(this); | ||||
scene->setSceneRect(0, 0, 800, 600);//因为场景初始无内容时,QGraphicsView 自动将场景中心与视图中心对齐 | |||||
scene->setBackgroundBrush(QBrush(Qt::lightGray)); | |||||
ui->graphicsView_2->setScene(scene); | ui->graphicsView_2->setScene(scene); | ||||
ui->graphicsView_2->setRenderHint(QPainter::Antialiasing); | |||||
ui->graphicsView_2->setDragMode(QGraphicsView::RubberBandDrag); | |||||
ui->graphicsView_2->setAcceptDrops(true);// 启用视图的拖放功能(接收拖拽) | |||||
ui->graphicsView_2->viewport()->installEventFilter(this); | |||||
ui->treeWidget_2->setDragEnabled(true);// 允许拖拽 | |||||
ui->treeWidget_2->setDragDropMode(QAbstractItemView::DragOnly);// 仅拖拽 | |||||
ui->actiondelete->setShortcut(QKeySequence::Delete);//设置快捷键 | |||||
ui->actioncopy->setShortcut(QKeySequence::Copy); | |||||
ui->actionpaste->setShortcut(QKeySequence::Paste); | |||||
ui->treeWidget->topLevelItem(0)->setIcon(0, QIcon("../two/IntegratedPlatform/images/T-常开触点-01.png")); | |||||
ui->treeWidget->topLevelItem(1)->setIcon(0, QIcon("../two/IntegratedPlatform/images/T-常闭触点-01-01.png")); | |||||
ui->treeWidget->topLevelItem(2)->setIcon(0, QIcon("../two/IntegratedPlatform/images/大于等于.png")); | |||||
ui->treeWidget->topLevelItem(3)->setIcon(0, QIcon("../two/IntegratedPlatform/images/线-圈-圈.png")); | |||||
ui->treeWidget_2->topLevelItem(0)->setIcon(0, QIcon("../two/IntegratedPlatform/images/灯泡.png")); | |||||
ui->treeWidget_2->topLevelItem(1)->setIcon(0, QIcon("../two/IntegratedPlatform/images/按钮.png")); | |||||
connect(ui->treeWidget_2, &QTreeWidget::itemClicked, this, &MainWindow::onHmiItemClicked); | connect(ui->treeWidget_2, &QTreeWidget::itemClicked, this, &MainWindow::onHmiItemClicked); | ||||
ui-> graphicsView_2->viewport()->installEventFilter(this); | |||||
connect(ui->actiondelete, &QAction::triggered, this, &MainWindow::onActionDeleteTriggered); | |||||
connect(ui->actioncopy, &QAction::triggered, this, &MainWindow::onActionCopyTriggered); | |||||
connect(ui->actionpaste, &QAction::triggered, this, &MainWindow::onActionPasteTriggered); | |||||
addDockWidget(Qt::BottomDockWidgetArea, ui->dockWidget_3);//将dockWidget_3添加到主窗口的下方 | |||||
ui->treeWidget_2->topLevelItem(0)->setIcon(0, QIcon("C:/Users/admin/Desktop/灯泡.png")); | |||||
ui->treeWidget_2->topLevelItem(1)->setIcon(0, QIcon("C:/Users/admin/Desktop/按钮.png")); | |||||
} | } | ||||
MainWindow::~MainWindow() | MainWindow::~MainWindow() | ||||
@@ -29,58 +53,261 @@ void MainWindow::onHmiItemClicked(QTreeWidgetItem *item) | |||||
{ | { | ||||
if (item->text(0) == "指示灯") | if (item->text(0) == "指示灯") | ||||
{ | { | ||||
canDrawCircle = true; | |||||
canDrawEllipse = true; | |||||
canDrawRectangle = false; | canDrawRectangle = false; | ||||
} | } | ||||
else if(item->text(0) == "按钮") | |||||
else if (item->text(0) == "按钮") | |||||
{ | { | ||||
canDrawCircle=false; | |||||
canDrawRectangle = true;//如果点击的是按钮,则不允许绘制灯 | |||||
canDrawEllipse = false; | |||||
canDrawRectangle = true; | |||||
} | } | ||||
else { | |||||
canDrawRectangle = false;//如果点击的是灯,则不允许绘制按钮 | |||||
canDrawCircle = false; | |||||
else | |||||
{ | |||||
canDrawEllipse = false; | |||||
canDrawRectangle = false; | |||||
} | } | ||||
} | } | ||||
bool MainWindow::eventFilter(QObject *obj, QEvent *event) | bool MainWindow::eventFilter(QObject *obj, QEvent *event) | ||||
{ | { | ||||
// 修正1:使用一致的视图对象名(graphicsView_2) | |||||
if (obj != ui->graphicsView_2->viewport()) { | |||||
return false; // 不是我们关心的对象,不处理 | |||||
if (obj != ui->graphicsView_2->viewport()) | |||||
{ | |||||
return QMainWindow::eventFilter(obj, event); | |||||
} | } | ||||
// 只处理鼠标按下事件 | |||||
if (event->type() == QEvent::MouseButtonPress) { | |||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); | |||||
if (mouseEvent->button() == Qt::LeftButton) { | |||||
// 获取点击的场景坐标 | |||||
if (event->type() == QEvent::MouseButtonPress)//点击生成 | |||||
{ | |||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); | |||||
if (mouseEvent->button() == Qt::RightButton)//打开右键菜单 | |||||
{ | |||||
QPointF scenePos = ui->graphicsView_2->mapToScene(mouseEvent->pos()); | QPointF scenePos = ui->graphicsView_2->mapToScene(mouseEvent->pos()); | ||||
// 根据标志绘制元素 | |||||
if (canDrawCircle) { | |||||
ResizableEllipse *circle = new ResizableEllipse( | |||||
scenePos.x(), scenePos.y(), 50, 50); | |||||
circle->setBrush(QBrush(Qt::red)); // 设置指示灯颜色 | |||||
scene->addItem(circle); | |||||
QGraphicsItem *item = scene->itemAt(scenePos, ui->graphicsView_2->transform()); | |||||
if (item && !item->isSelected())// 如果有项在点击位置,选中它并清除其他选择 | |||||
{ | |||||
scene->clearSelection(); // 清除所有当前选择 | |||||
item->setSelected(true); // 选中当前项 | |||||
} | } | ||||
else if (canDrawRectangle) { | |||||
ResizableRectangle *rectangle = new ResizableRectangle( | |||||
scenePos.x(), scenePos.y(), 100, 50); | |||||
rectangle->setBrush(QBrush(Qt::yellow)); // 设置按钮颜色 | |||||
scene->addItem(rectangle); | |||||
QPoint globalPos = mouseEvent->globalPos(); | |||||
showContextMenu(globalPos); | |||||
return true; | |||||
} | |||||
if (mouseEvent->button() == Qt::LeftButton) | |||||
{ | |||||
QPointF scenePos = ui->graphicsView_2->mapToScene(mouseEvent->pos()); | |||||
QGraphicsItem *item = scene->itemAt(scenePos, ui->graphicsView_2->transform()); | |||||
if (item) | |||||
{ | |||||
return QMainWindow::eventFilter(obj, event); | |||||
} | } | ||||
// 重置绘制标志 | |||||
canDrawCircle = false; | |||||
canDrawRectangle = false; | |||||
// 修正2:使用一致的树控件对象名(treeWidget_2) | |||||
if (ui->treeWidget_2->currentItem()) { | |||||
ui->treeWidget_2->currentItem()->setSelected(false); | |||||
if (canDrawEllipse) | |||||
{ | |||||
createEllipse(scenePos); // 封装为函数,避免重复代码 | |||||
resetDrawFlags(); | |||||
} | } | ||||
return true; // 事件已处理 | |||||
else if (canDrawRectangle) | |||||
{ | |||||
createRectangle(scenePos); // 封装为函数 | |||||
resetDrawFlags(); | |||||
} | |||||
if (!item) | |||||
{ | |||||
scene->clearSelection(); | |||||
if (ui->treeWidget_2->currentItem()) | |||||
{ | |||||
ui->treeWidget_2->currentItem()->setSelected(false); | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
} | |||||
//拖拽生成 | |||||
if (event->type() == QEvent::DragEnter) | |||||
{ | |||||
QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent*>(event); | |||||
if (dragEvent->source() == ui->treeWidget_2)//检查拖拽源是否为树控件,并接受拖拽 | |||||
{ | |||||
dragEvent->acceptProposedAction(); | |||||
return true; | |||||
} | |||||
} | |||||
// 拖拽移动(可选:显示拖拽反馈) | |||||
if (event->type() == QEvent::DragMove) | |||||
{ | |||||
QDragMoveEvent *dragEvent = static_cast<QDragMoveEvent*>(event); | |||||
dragEvent->acceptProposedAction(); | |||||
return true; | |||||
} | |||||
// 拖拽释放(生成图形) | |||||
if (event->type() == QEvent::Drop) | |||||
{ | |||||
QDropEvent *dropEvent = static_cast<QDropEvent*>(event); | |||||
QModelIndex index = ui->treeWidget_2->currentIndex();// 获取拖拽的树项 | |||||
if (!index.isValid()) return true; | |||||
QTreeWidgetItem *item = ui->treeWidget_2->currentItem(); | |||||
if (!item) return true; | |||||
QPointF scenePos = ui->graphicsView_2->mapToScene(dropEvent->pos());// 计算释放位置(转换为场景坐标) | |||||
if (item->text(0) == "指示灯") | |||||
{ | |||||
createEllipse(scenePos); | |||||
} | |||||
else if (item->text(0) == "按钮") | |||||
{ | |||||
createRectangle(scenePos); | |||||
} | } | ||||
dropEvent->acceptProposedAction(); | |||||
return true; | |||||
} | } | ||||
// 修正3:正确处理未过滤的事件 | |||||
return QMainWindow::eventFilter(obj, event); | return QMainWindow::eventFilter(obj, event); | ||||
} | } | ||||
//删除 | |||||
void MainWindow::onActionDeleteTriggered() | |||||
{ | |||||
QList<QGraphicsItem*> selectedItems = scene->selectedItems();//获取场景中所有选中的项 | |||||
foreach (QGraphicsItem *item, selectedItems)//遍历并删除所有选中的项 | |||||
{ | |||||
scene->removeItem(item); | |||||
delete item;//删除对象 | |||||
} | |||||
} | |||||
// 复制功能 | |||||
void MainWindow::onActionCopyTriggered() | |||||
{ | |||||
copiedItemsData.clear(); | |||||
QList<QGraphicsItem*> selectedItems = scene->selectedItems(); | |||||
if (selectedItems.isEmpty()) return; | |||||
foreach (QGraphicsItem *item, selectedItems) | |||||
{ | |||||
QByteArray itemData; | |||||
QDataStream stream(&itemData, QIODevice::WriteOnly); | |||||
stream << item->type();// 基础属性 | |||||
stream << item->pos(); | |||||
stream << item->flags(); | |||||
stream << item->transform(); | |||||
stream << item->isVisible(); | |||||
if (auto shapeItem = dynamic_cast<QAbstractGraphicsShapeItem*>(item))//处理所有图形形状项 | |||||
{ | |||||
stream << shapeItem->pen(); | |||||
stream << shapeItem->brush(); | |||||
stream << shapeItem->boundingRect(); | |||||
} | |||||
if (auto resizableRect = dynamic_cast<ResizableRectangle*>(item))//处理矩形圆形两项,存储几何信息 | |||||
{ | |||||
stream << resizableRect->rect();//实际存储的矩形 | |||||
} | |||||
else if (auto resizableEllipse = dynamic_cast<ResizableEllipse*>(item)) | |||||
{ | |||||
stream << resizableEllipse->rect(); | |||||
} | |||||
copiedItemsData.append(itemData); | |||||
} | |||||
lastPastePos = selectedItems.first()->pos(); | |||||
} | |||||
// 粘贴功能 | |||||
void MainWindow::onActionPasteTriggered() | |||||
{ | |||||
if (copiedItemsData.isEmpty()) return; | |||||
QPointF offset(20,20); | |||||
lastPastePos+=offset; | |||||
scene->clearSelection(); | |||||
foreach (const QByteArray &itemData, copiedItemsData) | |||||
{ | |||||
QDataStream stream(itemData); | |||||
int itemType; | |||||
QPointF pos; | |||||
QGraphicsItem::GraphicsItemFlags flags; | |||||
QTransform transform; | |||||
bool visible; | |||||
stream >> itemType >> pos >> flags >> transform >> visible; | |||||
QGraphicsItem *newItem = nullptr; | |||||
switch (itemType) | |||||
{ | |||||
case QGraphicsRectItem::Type: | |||||
{ | |||||
QPen pen; | |||||
QBrush brush; | |||||
QRectF rect; | |||||
stream >> pen >> brush >> rect; | |||||
ResizableRectangle *rectItem = new ResizableRectangle(rect.x(), rect.y(), rect.width(), rect.height()); | |||||
rectItem->setPen(pen); | |||||
rectItem->setBrush(brush); | |||||
newItem = rectItem; | |||||
break; | |||||
} | |||||
case QGraphicsEllipseItem::Type: | |||||
{ | |||||
QPen pen; | |||||
QBrush brush; | |||||
QRectF rect; | |||||
stream >> pen >> brush >> rect; | |||||
ResizableEllipse *ellipseItem = new ResizableEllipse(rect.x(), rect.y(), rect.width(), rect.height()); | |||||
ellipseItem->setPen(pen); | |||||
ellipseItem->setBrush(brush); | |||||
newItem = ellipseItem; | |||||
break; | |||||
} | |||||
} | |||||
if (newItem) { | |||||
scene->addItem(newItem); | |||||
newItem->setPos(lastPastePos); | |||||
newItem->setFlags(flags); | |||||
newItem->setTransform(transform); | |||||
newItem->setVisible(visible); | |||||
newItem->setSelected(true); | |||||
} | |||||
} | |||||
} | |||||
void MainWindow::createEllipse(const QPointF &pos) | |||||
{ | |||||
ResizableEllipse *ellipse = new ResizableEllipse(pos.x(), pos.y(), 50, 50); | |||||
ellipse->setBrush(QBrush(Qt::red)); | |||||
ellipse->setPen(QPen(Qt::black, 1)); | |||||
scene->addItem(ellipse); | |||||
ellipse->setSelected(true); | |||||
} | |||||
void MainWindow::createRectangle(const QPointF &pos) | |||||
{ | |||||
ResizableRectangle *rectangle = new ResizableRectangle(pos.x(), pos.y(), 100, 50); | |||||
rectangle->setBrush(QBrush(Qt::yellow)); | |||||
rectangle->setPen(QPen(Qt::black, 1)); | |||||
scene->addItem(rectangle); | |||||
rectangle->setSelected(true); | |||||
} | |||||
void MainWindow::resetDrawFlags() | |||||
{ | |||||
canDrawEllipse = false; | |||||
canDrawRectangle = false; | |||||
if (ui->treeWidget_2->currentItem()) | |||||
{ | |||||
ui->treeWidget_2->currentItem()->setSelected(false); | |||||
} | |||||
} | |||||
void MainWindow::showContextMenu(QPoint pos) | |||||
{ | |||||
QPoint viewportPos = ui->graphicsView_2->mapFromGlobal(pos); | |||||
QPointF scenePos = ui->graphicsView_2->mapToScene(viewportPos); | |||||
QGraphicsItem* clickedItem = scene->itemAt(scenePos, ui->graphicsView_2->transform());//检查是否有图形项在点击位置 | |||||
QMenu contextMenu(this); | |||||
if (!clickedItem) | |||||
{ | |||||
QAction* pasteAction = contextMenu.addAction("粘贴");// 空白处右键:只添加粘贴选项 | |||||
pasteAction->setEnabled(!copiedItemsData.isEmpty()); | |||||
connect(pasteAction, &QAction::triggered, this, &MainWindow::onActionPasteTriggered); | |||||
contextMenu.exec(pos+QPoint(10, 10)); | |||||
return; | |||||
} | |||||
// 添加动作 | |||||
QAction* propertiesAction = contextMenu.addAction("属性"); | |||||
QAction* copyAction = contextMenu.addAction("复制"); | |||||
QAction* pasteAction = contextMenu.addAction("粘贴"); | |||||
QAction* deleteAction = contextMenu.addAction("删除"); | |||||
QAction* onAction = contextMenu.addAction("置为ON"); | |||||
QAction* offAction = contextMenu.addAction("置为OFF"); | |||||
// 连接动作到现有功能 | |||||
connect(deleteAction, &QAction::triggered, this, &MainWindow::onActionDeleteTriggered); | |||||
connect(copyAction, &QAction::triggered, this, &MainWindow::onActionCopyTriggered); | |||||
connect(pasteAction, &QAction::triggered, this, &MainWindow::onActionPasteTriggered); | |||||
contextMenu.exec(pos+QPoint(10, 10)); | |||||
} |
@@ -19,12 +19,21 @@ public: | |||||
~MainWindow(); | ~MainWindow(); | ||||
private slots: | private slots: | ||||
void onHmiItemClicked(QTreeWidgetItem *item); | void onHmiItemClicked(QTreeWidgetItem *item); | ||||
void onActionDeleteTriggered(); // 添加删除功能的槽函数 | |||||
void onActionCopyTriggered();//复制功能槽函数 | |||||
void onActionPasteTriggered();//粘贴功能槽函数 | |||||
void createEllipse(const QPointF &pos); // 创建指示灯(圆形) | |||||
void createRectangle(const QPointF &pos); // 创建按钮(矩形) | |||||
void resetDrawFlags(); // 重置绘制标志 | |||||
void showContextMenu(QPoint pos); | |||||
protected: | protected: | ||||
bool eventFilter(QObject *obj, QEvent *event) override; | bool eventFilter(QObject *obj, QEvent *event) override; | ||||
private: | private: | ||||
Ui::MainWindow *ui; | Ui::MainWindow *ui; | ||||
bool canDrawCircle; | |||||
bool canDrawEllipse; | |||||
bool canDrawRectangle; | bool canDrawRectangle; | ||||
QGraphicsScene *scene; // QGraphicsScene,用于容纳图形项 | QGraphicsScene *scene; // QGraphicsScene,用于容纳图形项 | ||||
QList<QByteArray> copiedItemsData; // 存储序列化的图形项数据 | |||||
QPointF lastPastePos; // 记录上次粘贴位置 | |||||
}; | }; | ||||
#endif // MAINWINDOW_H | #endif // MAINWINDOW_H |
@@ -52,7 +52,7 @@ | |||||
<property name="font"> | <property name="font"> | ||||
<font> | <font> | ||||
<family>宋体</family> | <family>宋体</family> | ||||
<pointsize>16</pointsize> | |||||
<pointsize>18</pointsize> | |||||
</font> | </font> | ||||
</property> | </property> | ||||
<column> | <column> | ||||
@@ -103,6 +103,9 @@ | |||||
<property name="mouseTracking"> | <property name="mouseTracking"> | ||||
<bool>false</bool> | <bool>false</bool> | ||||
</property> | </property> | ||||
<property name="layoutDirection"> | |||||
<enum>Qt::LeftToRight</enum> | |||||
</property> | |||||
</widget> | </widget> | ||||
</item> | </item> | ||||
<item row="0" column="0"> | <item row="0" column="0"> | ||||
@@ -110,12 +113,15 @@ | |||||
<property name="font"> | <property name="font"> | ||||
<font> | <font> | ||||
<family>宋体</family> | <family>宋体</family> | ||||
<pointsize>16</pointsize> | |||||
<pointsize>18</pointsize> | |||||
</font> | </font> | ||||
</property> | </property> | ||||
<property name="selectionMode"> | <property name="selectionMode"> | ||||
<enum>QAbstractItemView::SingleSelection</enum> | <enum>QAbstractItemView::SingleSelection</enum> | ||||
</property> | </property> | ||||
<property name="textElideMode"> | |||||
<enum>Qt::ElideMiddle</enum> | |||||
</property> | |||||
<column> | <column> | ||||
<property name="text"> | <property name="text"> | ||||
<string>控件栏</string> | <string>控件栏</string> | ||||
@@ -175,9 +181,9 @@ | |||||
<property name="title"> | <property name="title"> | ||||
<string>操作</string> | <string>操作</string> | ||||
</property> | </property> | ||||
<addaction name="actionxioam"/> | |||||
<addaction name="actionzhantuie"/> | |||||
<addaction name="actionshanchu"/> | |||||
<addaction name="actioncopy"/> | |||||
<addaction name="actionpaste"/> | |||||
<addaction name="actiondelete"/> | |||||
</widget> | </widget> | ||||
<widget class="QMenu" name="menu_3"> | <widget class="QMenu" name="menu_3"> | ||||
<property name="font"> | <property name="font"> | ||||
@@ -240,7 +246,7 @@ | |||||
</font> | </font> | ||||
</property> | </property> | ||||
</action> | </action> | ||||
<action name="actionxioam"> | |||||
<action name="actioncopy"> | |||||
<property name="text"> | <property name="text"> | ||||
<string>复制</string> | <string>复制</string> | ||||
</property> | </property> | ||||
@@ -284,7 +290,7 @@ | |||||
</font> | </font> | ||||
</property> | </property> | ||||
</action> | </action> | ||||
<action name="actionzhantuie"> | |||||
<action name="actionpaste"> | |||||
<property name="text"> | <property name="text"> | ||||
<string>粘贴</string> | <string>粘贴</string> | ||||
</property> | </property> | ||||
@@ -295,7 +301,7 @@ | |||||
</font> | </font> | ||||
</property> | </property> | ||||
</action> | </action> | ||||
<action name="actionshanchu"> | |||||
<action name="actiondelete"> | |||||
<property name="text"> | <property name="text"> | ||||
<string>删除</string> | <string>删除</string> | ||||
</property> | </property> | ||||