#include "WindowAppUiFrame.h" #include "selectwidget.h" #include "UiManager.h" #include "WindowMain.h" #include "DialogUiOption.h" #include "WindowAppUiScene.h" #include "VPCommand.h" #include "Preferences.h" #include "VControlObject.h" WindowAppUiFrame::WindowAppUiFrame(const QString& strTitle, QWidget *parent) : QMainWindow(parent) , m_nUiViewHeight(DEFAULT_UIVIEW_HEIGHT) , m_nUiViewWidth(DEFAULT_UIVIEW_WIDTH) , actionUndo(nullptr) , actionRedo(nullptr) { ui.setupUi(this); m_nScrollValueH = 0; m_nScrollValueV = 0; // UI元素初始化 this->initUI(); // 初始化布局工具栏 this->initLayoutToolbar(); //// 初始化控件工具栏 //this->initControlToolbar(); this->addToolBar(m_layoutToolbar); m_layoutToolbar->setMovable(false); //this->addToolBarBreak(); //this->addToolBar(m_controlToolbar); //m_controlToolbar->setMovable(false); // 初始化UiView ui.widgetUiView->init(strTitle, ui.uiNavView, this, ui.objectController); // 绑定鸟瞰图缩放时的同步刷新动作 connect(ui.widgetUiView, &WindowAppUiView::navigatorViewRequired, this, [=](bool required, const QTransform& tf) { Q_UNUSED(required); Q_UNUSED(tf); //ui.uiNavView->setTransform(WindowAppPouView::resetScale(tf)); ui.uiNavView->fitInView(ui.uiNavView->sceneRect(), Qt::KeepAspectRatio); ui.uiNavView->setVisible(required); ui.uiNavView->updateMainViewportRegion(); } ); //// 矩形区域变动时的响应动作 //connect(ui.widgetUiView, &WindowAppUiView::viewportRectChanged, ui.uiNavView, &WindowAppUiNavView::updateMainViewportRegion); // 统一转换为初始化函数 //ui.widgetUiView->uiScene()->m_pPropertyController = ui.objectController; //ui.widgetUiView->m_strPageName = strTitle; // g_pUiManager->registerNewUi(ui.widgetUiView); //// 将当前Scene绑定到鸟瞰图中进行同步 //ui.uiNavView->setScene((QGraphicsScene*)ui.widgetUiView->scene()); //// 绑定同步的鸟瞰图 //ui.uiNavView->setMainView(ui.widgetUiView); //// 调整View //ui.uiNavView->fitInView(ui.uiNavView->sceneRect(), Qt::KeepAspectRatio); WindowAppUiScene* pScene = ui.widgetUiView->uiScene(); WindowAppUiView* pView = ui.widgetUiView; WindowAppUiFrame* pFrame = this; vDebug() << pScene << " " << pView << " " << pFrame; } WindowAppUiFrame::~WindowAppUiFrame() { } /// /// 获取本Frame下的View指针 /// /// WindowAppUiView* WindowAppUiFrame::getUiView() { return ui.widgetUiView; } /// /// UI元素初始化 /// void WindowAppUiFrame::initUI() { //QWidget* mainWidget = new QWidget(); //QVBoxLayout* mainLayout = new QVBoxLayout(); //mainLayout->addWidget(ui.toolbarLayoutFrame, 0, Qt::AlignTop); //mainLayout->addWidget(ui.toolbarControlFrame, 1, Qt::AlignTop); //mainLayout->addWidget(ui.widgetUiView); //mainLayout->setContentsMargins(0, 0, 0, 0); //mainLayout->setSpacing(0); //mainWidget->setLayout(mainLayout); //this->setCentralWidget(mainWidget); // 2021-8-30 在QMainWindow作为QMdiSubView时,需要将QMainWindow设置为 Widget风格,否则窗体不显示 this->setWindowFlags(Qt::Widget); ui.widgetUiView->uiScene()->m_pUiFrame = this; QScrollArea* ScrollArea = new QScrollArea(ui.widget_1); ScrollArea->setWidget(ui.widgetUiView);//设置滚动条 ui.gridLayout->addWidget(ScrollArea); connect(ScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(horizontalValueChanged(int))); connect(ScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(verticalValueChanged(int))); //connect(ScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int))); ui.widgetUiView->resize(this->m_nUiViewWidth, this->m_nUiViewHeight); // 初始化界面分隔区域 //for (int i = 0; i < thePrefs.listUiStretchFactors.size(); i++) //{ // ui.splitter->setStretchFactor(i, 4); //} //// 更新界面分隔区域 //this->updateSplitterFromPref(); // 先按照默认尺寸进行拆分 ui.splitter->setStretchFactor(0, 4); ui.splitter->setStretchFactor(1, 2); //QList list = ui.splitter->sizes(); } /// /// 初始化布局工具栏 /// void WindowAppUiFrame::initLayoutToolbar() { m_layoutToolbar = new QToolBar(); m_layoutToolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); QAction* actionZorderTop = new QAction(QIcon(":/image/ZorderTop.png"), ("ZorderTop")); QAction* actionZorderBottom = new QAction(QIcon(":/image/ZorderBottom.png"), ("ZorderBottom")); QAction* actionZorderUp = new QAction(QIcon(":/image/ZorderUp.png"), ("ZorderUp")); QAction* actionZorderDown = new QAction(QIcon(":/image/ZorderDown.png"), ("ZorderDown")); // QAction* actionAlignLeft = new QAction(QIcon(":/image/AlignLeft.png"), ("Align Left")); // QAction* actionAlignTop = new QAction(QIcon(":/image/AlignTop.png"), ("Align Top")); // QAction* actionAlignRight = new QAction(QIcon(":/image/AlignRight.png"), ("Align Right")); // QAction* actionAlignBottom = new QAction(QIcon(":/image/AlignBottom.png"), ("Align Bottom")); // QAction* actionSamesize = new QAction(QIcon("./image/Samesize.png"), ("Make same size")); // QAction* actionZoomIn = new QAction(QIcon(":/image/ZoomOut.png"), ("Zoom In")); // QAction* actionZoomOut = new QAction(QIcon(":/image/ZoomIn.png"), ("Zoom Out")); // QAction* actionZoomZero = new QAction(QIcon(":/image/Zoom.png"), ("Zoom Zero")); QAction* actionOption = new QAction(QIcon(":/image/Option.png"), ("Options")); // QAction* actionSnap = new QAction(QIcon(":/image/Snap.png"), ("Snap to Grid")); // 2022-9-29,增加了Undo和Redo操作 actionUndo = new QAction(QIcon(":/image/Undo.png"), ("Undo")); actionRedo = new QAction(QIcon(":/image/Redo.png"), ("Redo")); // QAction* actionUpdate = new QAction(QIcon(":/image/Update.png"), ("Update ro Runtime")); QAction* actionDelete = new QAction(QIcon(":/image/Delete.png"), ("Delete")); QAction* actionPublish = new QAction(QIcon(":/image/ui_run.png"), ("Publish UI in Runtime")); m_layoutToolbar->addAction(actionZorderTop); m_layoutToolbar->addAction(actionZorderBottom); m_layoutToolbar->addAction(actionZorderUp); m_layoutToolbar->addAction(actionZorderDown); m_layoutToolbar->addSeparator(); // m_layoutToolbar->addAction(actionAlignLeft); // m_layoutToolbar->addAction(actionAlignTop); // m_layoutToolbar->addAction(actionAlignRight); // m_layoutToolbar->addAction(actionAlignBottom); // m_layoutToolbar->addAction(actionSamesize); // m_layoutToolbar->addSeparator(); // m_layoutToolbar->addAction(actionZoomIn); // m_layoutToolbar->addAction(actionZoomOut); // m_layoutToolbar->addAction(actionZoomZero); m_layoutToolbar->addAction(actionOption); // m_layoutToolbar->addAction(actionSnap); m_layoutToolbar->addSeparator(); m_layoutToolbar->addAction(actionUndo); m_layoutToolbar->addAction(actionRedo); m_layoutToolbar->addSeparator(); // m_layoutToolbar->addAction(actionUpdate); m_layoutToolbar->addAction(actionDelete); m_layoutToolbar->addSeparator(); m_layoutToolbar->addAction(actionPublish); m_layoutToolbar->setIconSize(QSize(14, 14)); // 工具栏Signal connect(actionZorderTop, &QAction::triggered, this, &WindowAppUiFrame::onToolZorderTop); connect(actionZorderBottom, &QAction::triggered, this, &WindowAppUiFrame::onToolZorderBottom); connect(actionZorderUp, &QAction::triggered, this, &WindowAppUiFrame::onToolZorderUp); connect(actionZorderDown, &QAction::triggered, this, &WindowAppUiFrame::onToolZorderDown); connect(actionUndo, &QAction::triggered, this, &WindowAppUiFrame::onToolUndo); connect(actionRedo, &QAction::triggered, this, &WindowAppUiFrame::onToolRedo); connect(actionPublish, &QAction::triggered, this, &WindowAppUiFrame::onToolPublish); connect(actionDelete, &QAction::triggered, this, &WindowAppUiFrame::onToolDelete); connect(actionOption, &QAction::triggered, this, &WindowAppUiFrame::onToolOption); // 拆分栏Signal connect(ui.splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(slotSplitterMoved(int, int))); } /// /// 拆分条移动时(暂未使用) /// /// /// void WindowAppUiFrame::slotSplitterMoved(int pos, int index) { Q_UNUSED(pos); Q_UNUSED(index); QList list = ui.splitter->sizes(); // qDebug() << list; } //======================================================================== // // 刻度尺绘制相关 // //======================================================================== /// /// 绘制水平刻度尺 /// /// /// void WindowAppUiFrame::DrawHorizontalScale(QPainter* painter, QPen* pen) { int Y = 51; int X = 4; //绘制一条水平坐标线 QPoint ptBegin(X, Y); QPoint ptEnd(this->rect().width(), Y); painter->drawLine(ptBegin, ptEnd); float m_fInterval = 4; float fDrawLeft = 10; int nIndex = 0; int nScaleHeight = 8; //刻度线高度 while (fDrawLeft < this->rect().width()) { if ((nIndex % 2 == 0) && (nIndex % 5 == 0)) { nScaleHeight = 8; QString sText = QString::number(nIndex / 10); painter->drawText(QPoint(fDrawLeft + X + 2, Y - nScaleHeight + 2), sText); } else { pen->setWidth(1); painter->setPen(*pen); //当是中间节点时,长度要比一般的长 nScaleHeight = (nIndex % 4) == 0 ? 4 : 2; } //绘制刻度值 painter->drawRect(QRectF((double)fDrawLeft + (double)X, (double)Y - (double)nScaleHeight, 0.1, (double)nScaleHeight)); fDrawLeft += m_fInterval; nIndex = nIndex + 1; } } /// /// 绘制垂直刻度尺 /// /// /// void WindowAppUiFrame::DrawVerticalScale(QPainter* painter, QPen* pen) { //绘制一条垂直坐标线 int X = 15 - 1; int Y = 51; QPoint ptBegin(X, Y); QPoint ptEnd(X, ui.widgetUiView->rect().height() - Y); painter->drawLine(ptBegin, ptEnd); float m_fInterval = 4; float fDrawTop = 0; int nIndex = 0; int nScaleWidth = 20; //刻度线宽度 while (fDrawTop < this->rect().height()) { if ((nIndex % 2 == 0) && (nIndex % 5 == 0)) { nScaleWidth = 8; QString sText = QString::number(nIndex / 10); int fontWidth = fontMetrics().width(sText); int nleft = (((X - nScaleWidth) - fontWidth) / 2) + 4; painter->drawText(QPoint(nleft, fDrawTop + Y + 10), sText); } else { pen->setWidth(1); painter->setPen(*pen); //当是中间节点时,长度要比一般的长 nScaleWidth = (nIndex % 4) == 0 ? 4 : 2; } //绘制刻度值 painter->drawRect(QRectF((double)X - (double)nScaleWidth, (double)fDrawTop + (double)Y, nScaleWidth, 0.1)); fDrawTop += m_fInterval; nIndex++; } } /// /// 绘制界面 /// /// void WindowAppUiFrame::paintEvent(QPaintEvent*) { QPainter painter(this); //设置画刷 QPen pen(Qt::black, 1); pen.setWidth(1); painter.setPen(pen); painter.translate(0, 0); //抗锯齿绘制 painter.setRenderHint(QPainter::Antialiasing); //绘制水平刻度尺 this->DrawHorizontalScale(&painter, &pen); //绘制垂直刻度尺 this->DrawVerticalScale(&painter, &pen); // 刷新Undo菜单启用禁用 this->refreshUndoMenu(); } /// /// 水平滚动条数值改变时,保存数值 /// /// void WindowAppUiFrame::horizontalValueChanged(int value) { m_nScrollValueH = value; } /// /// 垂直滚动条数值改变时,保存数值 /// /// void WindowAppUiFrame::verticalValueChanged(int value) { m_nScrollValueV = value; } void WindowAppUiFrame::onToolZorderTop() { ui.widgetUiView->uiScene()->zorderTopCurrentControl(); } void WindowAppUiFrame::onToolZorderBottom() { ui.widgetUiView->uiScene()->zorderBottomCurrentControl(); } void WindowAppUiFrame::onToolZorderUp() { ui.widgetUiView->uiScene()->zorderUpCurrentControl(); } void WindowAppUiFrame::onToolZorderDown() { ui.widgetUiView->uiScene()->zorderDownCurrentControl(); } /// /// Undo /// void WindowAppUiFrame::onToolUndo() { // vDebug() << "WindowAppUiFrame::onToolUndo()"; ui.widgetUiView->uiScene()->m_CommandManager.undo(); } /// /// Redo /// void WindowAppUiFrame::onToolRedo() { // vDebug() << "WindowAppUiFrame::onToolRedo()"; ui.widgetUiView->uiScene()->m_CommandManager.redo(); } //======================================================================== // // Toolbar 消息处理 // //======================================================================== /// /// UI界面设置 /// void WindowAppUiFrame::onToolOption() { DialogUiOption dialogUiOption( this->m_nUiViewWidth, this->m_nUiViewHeight, this ); // 进行UI界面设置 if (dialogUiOption.exec() == QDialog::Accepted) { // 保存用户设置的UI宽度和高度 this->m_nUiViewWidth = dialogUiOption.m_nWidth; this->m_nUiViewHeight = dialogUiOption.m_nHeight; // 同步修改UiView和UiScene的界面尺寸 ui.widgetUiView->resize(this->m_nUiViewWidth, this->m_nUiViewHeight); // 调整鸟瞰图View ui.uiNavView->fitInView(ui.uiNavView->sceneRect(), Qt::KeepAspectRatio); } } /// /// Ui控件删除 /// void WindowAppUiFrame::onToolDelete() { // ui.widgetUiView->uiScene()->deleteCurrentControl(); // 2022-10-19,统一替换成了Undo框架进行删除,但是步骤要复杂一些 WindowAppUiScene* uiScene = ui.widgetUiView->uiScene(); // 获取当前删除的控件 VControlObject* pDelControl = uiScene->getCurrentControl(); if (pDelControl == nullptr) { vDebug() << "Ignore, current control is nullptr."; return; } // 求出控件的中心点坐标 // 由于控件并非是QGraphicObject,所以位置需要换算一下 QPoint ptControlPos = pDelControl->m_pWidget->pos(); ptControlPos.setX(ptControlPos.x() + pDelControl->m_pWidget->geometry().width() / 2); ptControlPos.setY(ptControlPos.y() + pDelControl->m_pWidget->geometry().height() / 2); //QPoint ptPos = pDelControl->m_pProxyWidget->scenePos().toPoint(); // QPoint ptPos2 = pDelControl->m_pWidget->pos(); // 生成删除指令,调用Undo体系进行删除 UiControlDelCommand* controlDelCommand = new UiControlDelCommand( uiScene, pDelControl->m_Type, pDelControl->m_strID, ptControlPos, pDelControl->m_pWidget->size() ); uiScene->m_CommandManager.executeCommand(controlDelCommand); } /// /// UI界面发布至Runtime /// void WindowAppUiFrame::onToolPublish() { qDebug() << "WindowAppUiFrame::onActionRun."; // 通过Manager发布所有UI bool bRet = g_pUiManager->publishAll(); if (bRet) { INFORMATION_MESSAGE("Publish to runtime success!"); // 成功发布后,通知主框架把页面切换到Runtime页面 g_pMainWindow->onViewRunTime(); } else { // CRITICAL_MESSAGE("Publish to runtime failed!"); } } /// /// 序列化支持 /// /// /// /// bool WindowAppUiFrame::serialized(QDataStream& ar, bool in /*= true*/) { int paranum;//参数数量 // 保存 if (!in) { paranum = 3; ar << paranum;//先保存参数数量 // 宽和高 ar << (int)1 << m_nUiViewWidth; ar << (int)2 << m_nUiViewHeight; ar << (int)3 << ui.splitter->sizes(); } // 读取 else { QList splitters; int para; ar >> paranum;//读取参数数量 for (int i = 0; i < paranum; i++) { ar >> para; switch (para) { case 1: ar >> m_nUiViewWidth; break; case 2: ar >> m_nUiViewHeight; break; case 3: ar >> splitters; break; default: { vWarning() << "Serialized(In) Error"; return false; } break; } } // 设置Splitter 在 UI 上无数据的时候的(应该是属性表无数据)Splitter 的 sizes 是无效的 if (splitters.size()==2 && splitters[0] > 0 && splitters[1] > 0) { ui.splitter->setSizes(splitters); } } return true; } /// /// 刷新Undo/Redo按钮 /// void WindowAppUiFrame::refreshUndoMenu() { if (actionUndo != nullptr) { actionUndo->setEnabled( ui.widgetUiView->uiScene()->m_CommandManager.canUndo()); actionRedo->setEnabled( ui.widgetUiView->uiScene()->m_CommandManager.canRedo()); } }