|
- #include "hmieditorwidget.h"
- #include "hmibutton.h"
- #include "hmiled.h"
- #include "hmicontrolitem.h"
-
- #include <QVBoxLayout>
- #include <QContextMenuEvent>
- #include <QMenu>
- #include <QMetaObject>
- #include <QGraphicsView>
- #include <QApplication>
- #include <QClipboard>
-
- HmiEditorWidget::HmiEditorWidget(QWidget* parent)
- : EditorWidget(parent)
- {
- // 左侧:在父类 EditorWidget 的左侧工具栏区域追加页面按钮与标签
- QLayoutItem* item = layout()->itemAt(0)->widget()->layout()->itemAt(0);
- auto* leftLayout = dynamic_cast<QVBoxLayout*>(item->layout());
-
- m_newPageButton = new QPushButton("新建页面", this);
- m_deletePageButton = new QPushButton("删除页面", this);
- m_prevPageButton = new QPushButton("上一页", this);
- m_nextPageButton = new QPushButton("下一页", this);
- m_pageLabel = new QLabel("无页面", this);
-
- leftLayout->addWidget(m_newPageButton);
- leftLayout->addWidget(m_deletePageButton);
- leftLayout->addWidget(m_prevPageButton);
- leftLayout->addWidget(m_nextPageButton);
- leftLayout->addWidget(m_pageLabel);
- leftLayout->addStretch();
-
- connect(m_newPageButton, &QPushButton::clicked, this, &HmiEditorWidget::onNewPageClicked);
- connect(m_deletePageButton, &QPushButton::clicked, this, &HmiEditorWidget::onDeletePageClicked);
- connect(m_prevPageButton, &QPushButton::clicked, this, &HmiEditorWidget::onPreviousPageClicked);
- connect(m_nextPageButton, &QPushButton::clicked, this, &HmiEditorWidget::onNextPageClicked);
-
- // 工具栏项
- initToolbar();
-
- // 确保视图已创建(父类提供)
- ensureViewReady();
-
- // 捕获编辑区鼠标:既监听 QGraphicsView 自身,也监听其 viewport
- if (editArea) {
- editArea->installEventFilter(this);
- if (editArea->viewport())
- editArea->viewport()->installEventFilter(this);
- }
- }
-
- HmiEditorWidget::~HmiEditorWidget() {
- clearPages();
- }
-
- void HmiEditorWidget::refreshView()
- {
- if (m_currentPageIndex >= 0 && !m_pages.isEmpty()) {
- editArea->setScene(nullptr);
- editArea->setScene(m_pages[m_currentPageIndex]);
- initViewScale();
- editArea->viewport()->update();
- }
- }
-
- void HmiEditorWidget::initToolbar() {
- // “按钮”
- auto* buttonItem = new QListWidgetItem();
- buttonItem->setIcon(QIcon(":resource/image/button.png"));
- buttonItem->setData(Qt::UserRole, QString("按钮"));
- buttonItem->setToolTip("按钮");
- toolbar->addItem(buttonItem);
-
- // “指示灯”
- auto* ledItem = new QListWidgetItem();
- ledItem->setIcon(QIcon(":resource/image/light.png"));
- ledItem->setData(Qt::UserRole, QString("指示灯"));
- ledItem->setToolTip("指示灯");
- toolbar->addItem(ledItem);
- }
-
- void HmiEditorWidget::onToolbarItemClicked(QListWidgetItem* item) {
- if (!item) return;
-
- // —— 关键改动 ——:
- // 不再“立即创建到场景中心”,而是进入“放置模式”
- m_pendingType = item->data(Qt::UserRole).toString();
- setPlacingCursor(true);
-
- appendOutput(QString("已选择控件:%1。请在编辑区点击以放置。").arg(m_pendingType));
- }
-
- QGraphicsScene* HmiEditorWidget::getCurrentScene() const {
- if (m_currentPageIndex >= 0 && m_currentPageIndex < m_pages.size())
- return m_pages[m_currentPageIndex];
- return nullptr;
- }
-
- void HmiEditorWidget::clearPages() {
- for (QGraphicsScene* scene : m_pages) delete scene;
- m_pages.clear();
- m_currentPageIndex = -1;
- if (editArea) editArea->setScene(nullptr);
- updatePageLabel();
- }
-
- void HmiEditorWidget::createNewPage()
- {
- auto* newScene = new QGraphicsScene(this);
- QRect viewRect = editArea->viewport()->rect();
- if (viewRect.isEmpty()) {
- viewRect = QRect(0,0,800,600);
- editArea->setSceneRect(viewRect);
- }
-
- newScene->setSceneRect(viewRect);
- m_pages.append(newScene);
- m_currentPageIndex = m_pages.size() - 1;
-
- QMetaObject::invokeMethod(this, [this, newScene](){
- editArea->setScene(newScene);
- initViewScale();
- updatePageLabel();
- editArea->viewport()->update();
- }, Qt::QueuedConnection);
- }
-
- void HmiEditorWidget::switchToPage(int index) {
- if (index >= 0 && index < m_pages.size()) {
- m_currentPageIndex = index;
- editArea->resetTransform();
- editArea->setScene(m_pages[index]);
- updatePageLabel();
- QMetaObject::invokeMethod(this, [this](){
- initViewScale();
- editArea->viewport()->update();
- }, Qt::QueuedConnection);
- }
- }
-
- void HmiEditorWidget::initViewScale()
- {
- if (!editArea || m_currentPageIndex < 0 || m_pages.isEmpty()) return;
-
- QRect viewRect = editArea->viewport()->rect();
- if (viewRect.isEmpty()) viewRect = QRect(0,0,800,600);
-
- auto* currentScene = m_pages[m_currentPageIndex];
- QRectF currentRect = currentScene->sceneRect();
- const qreal newW = qMax(currentRect.width(), qreal(viewRect.width()));
- const qreal newH = qMax(currentRect.height(), qreal(viewRect.height()));
- currentScene->setSceneRect(0,0,newW,newH);
-
- editArea->viewport()->update();
- }
-
- void HmiEditorWidget::updatePageLabel()
- {
- if (m_pages.isEmpty()) {
- m_pageLabel->setText("无页面");
- m_deletePageButton->setEnabled(false);
- m_prevPageButton->setEnabled(false);
- m_nextPageButton->setEnabled(false);
- } else {
- m_pageLabel->setText(QString("第 %1/%2 页").arg(m_currentPageIndex+1).arg(m_pages.size()));
- m_deletePageButton->setEnabled(m_pages.size()>1);
- m_prevPageButton->setEnabled(m_currentPageIndex>0);
- m_nextPageButton->setEnabled(m_currentPageIndex<m_pages.size()-1);
- }
- }
-
- bool HmiEditorWidget::eventFilter(QObject* obj, QEvent* event)
- {
- // —— 右键空白处:弹出“粘贴”菜单(保留原逻辑) —— //
- if (obj == editArea && event->type() == QEvent::ContextMenu) {
- auto* contextEvent = static_cast<QContextMenuEvent*>(event);
- if (m_currentPageIndex >= 0 && m_pages[m_currentPageIndex]) {
- QGraphicsItem* hit = editArea->itemAt(contextEvent->pos());
- if (!hit) {
- QMenu menu;
- QAction* pasteAction = new QAction("粘贴", &menu);
- pasteAction->setEnabled(HmiControlItem::hasClipboardData());
- connect(pasteAction, &QAction::triggered, [this, contextEvent](){
- if (m_currentPageIndex >= 0 && m_pages[m_currentPageIndex] &&
- HmiControlItem::hasClipboardData()) {
-
- const QPointF scenePos = editArea->mapToScene(contextEvent->pos());
- HmiControlItem* newItem =
- HmiControlItem::createFromClipboard(HmiControlItem::getClipboardData(), scenePos);
- if (newItem) {
- m_pages[m_currentPageIndex]->addItem(newItem);
- m_pages[m_currentPageIndex]->clearSelection();
- newItem->setSelected(true);
- editArea->viewport()->update();
- }
- }
- });
- menu.addAction(pasteAction);
- menu.exec(contextEvent->globalPos());
- }
- }
- return true;
- }
-
- // —— 关键改动:放置模式下,点击编辑区创建 —— //
- // 捕获 QGraphicsView 的 viewport 左键按下
- if (obj == (editArea ? editArea->viewport() : nullptr)
- && event->type() == QEvent::MouseButtonPress && !m_pendingType.isEmpty()) {
-
- auto* me = static_cast<QMouseEvent*>(event);
- if (me->button() == Qt::LeftButton
- && m_currentPageIndex >= 0
- && m_pages[m_currentPageIndex]) {
-
- const QPointF scenePos = editArea->mapToScene(me->pos());
- HmiControlItem* item = createItemByType(m_pendingType, scenePos);
- if (item) {
- m_pages[m_currentPageIndex]->addItem(item);
- m_pages[m_currentPageIndex]->clearSelection();
- item->setSelected(true);
- editArea->viewport()->update();
- }
- // 一次放一个:退出放置模式(如需连续放置,注释掉两行)
- m_pendingType.clear();
- setPlacingCursor(false);
-
- return true; // 已处理
- }
- }
-
- return EditorWidget::eventFilter(obj, event);
- }
-
- void HmiEditorWidget::resizeEvent(QResizeEvent* e) {
- EditorWidget::resizeEvent(e);
- if (m_currentPageIndex >= 0 && !m_pages.isEmpty()) initViewScale();
- }
-
- void HmiEditorWidget::showEvent(QShowEvent* e) {
- EditorWidget::showEvent(e);
- if (m_pages.isEmpty()) createNewPage();
- }
-
- void HmiEditorWidget::keyPressEvent(QKeyEvent* event)
- {
- // Ctrl+C:复制(保留原逻辑——复制首个选中项至静态剪贴板)
- if (event->matches(QKeySequence::Copy)) {
- if (m_currentPageIndex >= 0 && m_pages[m_currentPageIndex]) {
- auto selectedItems = m_pages[m_currentPageIndex]->selectedItems();
- if (!selectedItems.isEmpty()) {
- if (auto* item = dynamic_cast<HmiControlItem*>(selectedItems.first())) {
- HmiControlItem::copyToClipboard(item->saveToClipboard());
- }
- }
- }
- return;
- }
-
- // Ctrl+V:粘贴(关键改动:若有选中源控件 → 旁边粘贴;否则 → 场景中心)
- if (event->matches(QKeySequence::Paste)) {
- if (m_currentPageIndex >= 0 &&
- m_pages[m_currentPageIndex] &&
- HmiControlItem::hasClipboardData()) {
-
- QPointF pastePos;
- auto selectedItems = m_pages[m_currentPageIndex]->selectedItems();
- static int s_pasteIndex = 0; // 连续多次粘贴时,用来轻微错行
-
- if (!selectedItems.isEmpty()) {
- if (auto* src = dynamic_cast<HmiControlItem*>(selectedItems.first())) {
- pastePos = calcPasteBesidePos(src, s_pasteIndex++);
- }
- } else {
- // 无选中项:仍按原逻辑 → 场景中心
- QRectF rect = m_pages[m_currentPageIndex]->sceneRect();
- pastePos = QPointF(rect.width()/2, rect.height()/2);
- s_pasteIndex = 0;
- }
-
- HmiControlItem* newItem =
- HmiControlItem::createFromClipboard(HmiControlItem::getClipboardData(), pastePos);
- if (newItem) {
- m_pages[m_currentPageIndex]->addItem(newItem);
- m_pages[m_currentPageIndex]->clearSelection();
- newItem->setSelected(true);
- editArea->viewport()->update();
- }
- }
- return;
- }
-
- // Delete:删除(保留原逻辑)
- if (event->matches(QKeySequence::Delete)) {
- if (m_currentPageIndex >= 0 && m_pages[m_currentPageIndex]) {
- auto selectedItems = m_pages[m_currentPageIndex]->selectedItems();
- for (QGraphicsItem* gi : selectedItems) {
- if (auto* ci = dynamic_cast<HmiControlItem*>(gi)) ci->deleteItem();
- }
- editArea->viewport()->update();
- }
- return;
- }
-
- EditorWidget::keyPressEvent(event);
- }
-
- void HmiEditorWidget::onNewPageClicked() { createNewPage(); }
-
- void HmiEditorWidget::onDeletePageClicked() {
- if (m_currentPageIndex >= 0 && m_pages.size() > 1) {
- QGraphicsScene* scene = m_pages[m_currentPageIndex];
- m_pages.removeAt(m_currentPageIndex);
- delete scene;
-
- m_currentPageIndex = qMin(m_currentPageIndex, m_pages.size()-1);
- editArea->setScene(m_pages[m_currentPageIndex]);
- initViewScale();
- updatePageLabel();
- editArea->viewport()->update();
- appendOutput(QString("删除页面,剩余页面数: %1").arg(m_pages.size()));
- }
- }
-
- void HmiEditorWidget::onPreviousPageClicked() { switchToPage(m_currentPageIndex - 1); }
- void HmiEditorWidget::onNextPageClicked() { switchToPage(m_currentPageIndex + 1); }
-
- // —— 私有辅助 —— //
-
- HmiControlItem* HmiEditorWidget::createItemByType(const QString& type, const QPointF& scenePos)
- {
- HmiControlItem* item = nullptr;
- if (type == "按钮") {
- item = new HmiButton();
- appendOutput("添加按钮控件");
- } else if (type == "指示灯") {
- item = new HmiLed();
- appendOutput("添加指示灯控件");
- }
- if (item) item->setPos(scenePos);
- return item;
- }
-
- void HmiEditorWidget::setPlacingCursor(bool on)
- {
- if (!editArea) return;
- if (on) {
- editArea->setCursor(Qt::CrossCursor);
- if (editArea->viewport()) editArea->viewport()->setCursor(Qt::CrossCursor);
- } else {
- editArea->unsetCursor();
- if (editArea->viewport()) editArea->viewport()->unsetCursor();
- }
- }
-
- QPointF HmiEditorWidget::calcPasteBesidePos(HmiControlItem* src, int pasteIndex) const
- {
- if (!src) return QPointF();
-
- // 使用“映射到场景后的边界框”来获取可视宽度,避免缩放带来的误差
- QRectF sceneRect = src->mapToScene(src->boundingRect()).boundingRect();
- const qreal w = qMax<qreal>(sceneRect.width(), 24.0); // 保底宽度
- const qreal gap = 12.0; // 与原件的水平间隔
- const qreal stepY = 8.0; // 连续粘贴时的竖向微调
-
- QPointF base = src->pos();
- return QPointF(base.x() + w + gap, base.y() + pasteIndex * stepY);
- }
|