#include "document.h" #include "graphicsitems.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include HMIDocument::HMIDocument(QWidget *parent) : BaseDocument(HMI, parent), m_title("未命名HMI"), m_canDrawEllipse(false), m_canDrawRectangle(false), m_lastPastePos(0, 0) { // 创建绘图场景 m_scene = new QGraphicsScene(this); m_scene->setSceneRect(0, 0, 800, 600); m_scene->setBackgroundBrush(QBrush(Qt::lightGray)); // 创建视图 m_view = new QGraphicsView(m_scene, this); m_view->setRenderHint(QPainter::Antialiasing); m_view->setDragMode(QGraphicsView::RubberBandDrag); m_view->setAcceptDrops(true); m_view->viewport()->installEventFilter(this); // 布局(让视图占满文档区域) auto layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(m_view); setLayout(layout); } HMIDocument::~HMIDocument() { } // 事件过滤器(处理绘图、拖拽等事件) bool HMIDocument::eventFilter(QObject *obj, QEvent *event) { if (obj != m_view->viewport()) { return QWidget::eventFilter(obj, event); } // 鼠标按下事件(绘制图形) if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::RightButton) { // 右键菜单 showContextMenu(mouseEvent->globalPos()); return true; } if (mouseEvent->button() == Qt::LeftButton) { QPointF scenePos = m_view->mapToScene(mouseEvent->pos()); QGraphicsItem *item = m_scene->itemAt(scenePos, m_view->transform()); // 如果点击空白区域且有绘制标志,创建图形 if (!item) { if (m_canDrawEllipse) { createEllipse(scenePos); resetDrawFlags(); } else if (m_canDrawRectangle) { createRectangle(scenePos); resetDrawFlags(); } m_scene->clearSelection(); // 清除选择 return true; } } } // 拖拽事件(从工具栏拖拽绘制) if (event->type() == QEvent::DragEnter) { QDragEnterEvent *dragEvent = static_cast(event); dragEvent->acceptProposedAction(); return true; } if (event->type() == QEvent::DragMove) { static_cast(event)->acceptProposedAction(); return true; } if (event->type() == QEvent::Drop) { QDropEvent *dropEvent = static_cast(event); const QMimeData *mimeData = dropEvent->mimeData(); // 显式获取mimeData QPointF scenePos = m_view->mapToScene(dropEvent->pos()); // 使用QMimeData if (mimeData && mimeData->hasText()) { QString type = mimeData->text(); if (type == "指示灯") { createEllipse(scenePos); } else if (type == "按钮") { createRectangle(scenePos); } } dropEvent->acceptProposedAction(); return true; } return QWidget::eventFilter(obj, event); } // 创建椭圆(指示灯) void HMIDocument::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)); m_scene->addItem(ellipse); ellipse->setSelected(true); } // 创建矩形(按钮) void HMIDocument::createRectangle(const QPointF &pos) { ResizableRectangle *rect = new ResizableRectangle(pos.x(), pos.y(), 100, 50); rect->setBrush(QBrush(Qt::yellow)); rect->setPen(QPen(Qt::black, 1)); m_scene->addItem(rect); rect->setSelected(true); } // 重置绘制标志 void HMIDocument::resetDrawFlags() { m_canDrawEllipse = false; m_canDrawRectangle = false; } // 右键菜单 void HMIDocument::showContextMenu(QPoint globalPos) { QPoint viewportPos = m_view->mapFromGlobal(globalPos); QPointF scenePos = m_view->mapToScene(viewportPos); QGraphicsItem *clickedItem = m_scene->itemAt(scenePos, m_view->transform()); QMenu menu(this); if (!clickedItem) { // 空白区域:仅显示粘贴 QAction *pasteAction = menu.addAction("粘贴"); pasteAction->setEnabled(!m_copiedItemsData.isEmpty()); connect(pasteAction, &QAction::triggered, this, &HMIDocument::pasteItems); } else { // 选中图形:显示完整菜单 QAction *propAction = menu.addAction("属性"); QAction *copyAction = menu.addAction("复制"); QAction *pasteAction = menu.addAction("粘贴"); QAction *deleteAction = menu.addAction("删除"); QAction *onAction = menu.addAction("置为ON"); QAction *offAction = menu.addAction("置为OFF"); pasteAction->setEnabled(!m_copiedItemsData.isEmpty()); connect(propAction, &QAction::triggered, this, &HMIDocument::showItemProperties); connect(copyAction, &QAction::triggered, this, &HMIDocument::copySelectedItems); connect(pasteAction, &QAction::triggered, this, &HMIDocument::pasteItems); connect(deleteAction, &QAction::triggered, this, &HMIDocument::deleteSelectedItems); // ON/OFF动作(针对指示灯和按钮) connect(onAction, &QAction::triggered, [=]() { if (auto ellipse = dynamic_cast(clickedItem)) { ellipse->setBrush(ellipse->onColor()); } else if (auto rect = dynamic_cast(clickedItem)) { rect->setBrush(rect->pressedColor()); } }); connect(offAction, &QAction::triggered, [=]() { if (auto ellipse = dynamic_cast(clickedItem)) { ellipse->setBrush(ellipse->offColor()); } else if (auto rect = dynamic_cast(clickedItem)) { rect->setBrush(rect->releasedColor()); } }); } menu.exec(globalPos + QPoint(10, 10)); } // 复制选中项 void HMIDocument::copySelectedItems() { m_copiedItemsData.clear(); QList selectedItems = m_scene->selectedItems(); if (selectedItems.isEmpty()) return; foreach (QGraphicsItem *item, selectedItems) { m_copiedItemsData.append(serializeItem(item)); } m_lastPastePos = selectedItems.first()->pos(); } // 粘贴项 void HMIDocument::pasteItems() { if (m_copiedItemsData.isEmpty()) return; QPointF offset(20, 20); m_lastPastePos += offset; m_scene->clearSelection(); foreach (const QByteArray &itemData, m_copiedItemsData) { QGraphicsItem *newItem = deserializeItem(itemData); if (newItem) { m_scene->addItem(newItem); newItem->setPos(m_lastPastePos); newItem->setSelected(true); } } } // 删除选中项 void HMIDocument::deleteSelectedItems() { QList selectedItems = m_scene->selectedItems(); foreach (QGraphicsItem *item, selectedItems) { m_scene->removeItem(item); delete item; } } // 显示属性对话框 void HMIDocument::showItemProperties() { QList selectedItems = m_scene->selectedItems(); if (selectedItems.isEmpty()) return; QGraphicsItem *item = selectedItems.first(); // 将QGraphicsItem转换为NamedItem NamedItem *namedItem = dynamic_cast(item); if (!namedItem) return; QDialog dialog(this); dialog.setWindowTitle("属性设置"); QFormLayout *form = new QFormLayout(&dialog); // 名称输入 - 使用NamedItem接口 QLineEdit *nameEdit = new QLineEdit(namedItem->name()); // 颜色选择(根据图形类型) QColor tempColor1, tempColor2; QPushButton *colorBtn1 = new QPushButton; QPushButton *colorBtn2 = new QPushButton; if (auto ellipse = dynamic_cast(item)) { tempColor1 = ellipse->onColor(); tempColor2 = ellipse->offColor(); form->addRow("ON颜色:", colorBtn1); form->addRow("OFF颜色:", colorBtn2); } else if (auto rect = dynamic_cast(item)) { tempColor1 = rect->pressedColor(); tempColor2 = rect->releasedColor(); form->addRow("按下颜色:", colorBtn1); form->addRow("释放颜色:", colorBtn2); } // 初始化颜色按钮 colorBtn1->setStyleSheet("background-color:" + tempColor1.name()); colorBtn2->setStyleSheet("background-color:" + tempColor2.name()); // 颜色选择对话框 connect(colorBtn1, &QPushButton::clicked, [&]() { QColor c = QColorDialog::getColor(tempColor1, &dialog); if (c.isValid()) { tempColor1 = c; colorBtn1->setStyleSheet("background-color:" + c.name()); } }); connect(colorBtn2, &QPushButton::clicked, [&]() { QColor c = QColorDialog::getColor(tempColor2, &dialog); if (c.isValid()) { tempColor2 = c; colorBtn2->setStyleSheet("background-color:" + c.name()); } }); // 布局组装 form->addRow("名称:", nameEdit); QDialogButtonBox *btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); form->addRow(btnBox); connect(btnBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); connect(btnBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); // 应用属性 if (dialog.exec() == QDialog::Accepted) { // 使用NamedItem接口设置名称 namedItem->setName(nameEdit->text()); if (auto ellipse = dynamic_cast(item)) { ellipse->setOnColor(tempColor1); ellipse->setOffColor(tempColor2); } else if (auto rect = dynamic_cast(item)) { rect->setPressedColor(tempColor1); rect->setReleasedColor(tempColor2); } item->update(); } } // 序列化图形项(用于复制粘贴) QByteArray HMIDocument::serializeItem(QGraphicsItem *item) { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); // 基础信息 stream << item->type(); stream << item->pos(); stream << item->flags(); stream << item->transform(); stream << item->isVisible(); // 形状信息 if (auto shape = dynamic_cast(item)) { stream << shape->pen(); stream << shape->brush(); stream << shape->boundingRect(); } // 具体图形信息 if (auto rect = dynamic_cast(item)) { stream << rect->rect(); stream << rect->pressedColor(); stream << rect->releasedColor(); stream << rect->name(); } else if (auto ellipse = dynamic_cast(item)) { stream << ellipse->rect(); stream << ellipse->onColor(); stream << ellipse->offColor(); stream << ellipse->name(); } return data; } // 反序列化图形项(用于粘贴) QGraphicsItem *HMIDocument::deserializeItem(const QByteArray &data) { QDataStream stream(data); int type; QPointF pos; QGraphicsItem::GraphicsItemFlags flags; QTransform transform; bool visible; stream >> type >> pos >> flags >> transform >> visible; QGraphicsItem *item = nullptr; if (type == QGraphicsRectItem::Type) { QPen pen; QBrush brush; QRectF boundRect; QRectF rect; QColor pressedColor, releasedColor; QString name; stream >> pen >> brush >> boundRect >> rect >> pressedColor >> releasedColor >> name; ResizableRectangle *rectItem = new ResizableRectangle(0, 0, rect.width(), rect.height()); rectItem->setPen(pen); rectItem->setBrush(brush); rectItem->setPressedColor(pressedColor); rectItem->setReleasedColor(releasedColor); rectItem->setName(name); item = rectItem; } else if (type == QGraphicsEllipseItem::Type) { QPen pen; QBrush brush; QRectF boundRect; QRectF rect; QColor onColor, offColor; QString name; stream >> pen >> brush >> boundRect >> rect >> onColor >> offColor >> name; ResizableEllipse *ellipseItem = new ResizableEllipse(0, 0, rect.width(), rect.height()); ellipseItem->setPen(pen); ellipseItem->setBrush(brush); ellipseItem->setOnColor(onColor); ellipseItem->setOffColor(offColor); ellipseItem->setName(name); item = ellipseItem; } if (item) { item->setFlags(flags); item->setTransform(transform); item->setVisible(visible); } return item; }