简易CAD程序:Qt多文档程序的一种实现

news2024/11/17 4:58:54

注:文中所列代码质量不高,但不影响演示我的思路

实现思路说明

  1. 实现DemoApplication
    相当于MFC中CWinAppEx的派生类,暂时没加什么功能。
    DemoApplication.h

    #pragma once
    
    #include <QtWidgets/QApplication>
    
    
    //相当于MFC中CWinAppEx的派生类,
    class DemoApplication : public QApplication
    {
    	Q_OBJECT
    
    public:
    	DemoApplication(int &argc, char **argv);
    	~DemoApplication();
    
    };
    

    DemoApplication.cpp

    #include "DemoApplication.h"
    
    
    DemoApplication::DemoApplication(int &argc, char **argv)
    	: QApplication(argc, argv)
    {
    }
    
    DemoApplication::~DemoApplication()
    {
    }
    
    
  2. 实现DemoDocument
    相当与MFC的CDocument。DemoDocument保存了当前所有视图的指针(此处实际是DeomChildWindow*,因为DeomChildWindow与DeomView时1对1关系,根据DeomChildWindow可以获得DemoView指针,简化设计,就这样处理了),实现了增加视图addView、移除视图removeView、获取视图数量getViewCount等函数。
    DemoDocument.h

    #pragma once
    
    #include <QObject>
    #include <list>
    
    class DemoChildWindow;
    
    //相当与MFC的CDocument
    class DemoDocument : public QObject
    {
    	Q_OBJECT
    
    public:
    	DemoDocument(QObject *parent = 0);
    	~DemoDocument();
    
    	void addView(DemoChildWindow* pChildWindow);
    	void removeView(DemoChildWindow* pChildWindow);
    	int getViewCount() const;
    
    	unsigned int getId() { return m_nId; }
    
    signals:
    	void closedDocument(DemoDocument* pDocument);
    
    private:
    	static unsigned int allocId();
    
    private:
    	static unsigned int s_NextId;
    	unsigned int m_nId = 0;
    
    	std::list<DemoChildWindow*> m_viewList; //视图列表
    };
    
    

    DemoDocument.cpp

    #include "DemoDocument.h"
    
    
    unsigned int DemoDocument::s_NextId = 0;
    
    DemoDocument::DemoDocument(QObject *parent)
    	: QObject(parent)
    {
    	m_nId = allocId();
    }
    
    DemoDocument::~DemoDocument()
    {
    }
    
    unsigned int DemoDocument::allocId()
    {
    	if (DemoDocument::s_NextId == std::numeric_limits<unsigned int>::max())
    	{
    		DemoDocument::s_NextId = 0;
    	}
    
    	return ++DemoDocument::s_NextId;
    }
    
    
    void DemoDocument::addView(DemoChildWindow* pChildWindow)
    {
    	m_viewList.push_back(pChildWindow);
    }
    
    void DemoDocument::removeView(DemoChildWindow* pChildWindow)
    {
    	auto it = std::find(m_viewList.begin(), m_viewList.end(), pChildWindow);
    	if (it != m_viewList.end() )
    	{
    		m_viewList.erase(it);
    	}
    
    	if (m_viewList.size() == 0)
    	{
    		emit closedDocument(this);
    	}
    }
    
    int DemoDocument::getViewCount() const
    {
    	return int(m_viewList.size());
    }
    
    
  3. 实现DemoMainWindow
    相当于MFC中的CMainFrame,派生自CMDIFrameWndEx。此类new了一个QMdiArea对象,通过此对象实现多文档程序的通用功能,如切换窗口、层叠窗口、平铺窗口等。类DemoMainWindow直接管理了所有打开的文档,这点同MFC不一样,MFC是通过文档管理器、文档模版处理的,此处简化下,直接在DemoMainWindow中管理。此处我让DemoMainWindow负责新建、打开、关闭文档。
    DemoMainWindow.h

    #pragma once
    
    #include <QtWidgets/QMainWindow>
    #include <QMdiArea>
    #include <list>
    #include <memory>
    
    
    class DemoDocument;
    
    //相当于MFC中的CMainFrame,派生自CMDIFrameWndEx
    class DemoMainWindow : public QMainWindow
    {
    	Q_OBJECT
    
    public:
    	DemoMainWindow(QWidget *parent = Q_NULLPTR);
    	virtual ~DemoMainWindow();
    
    	DemoDocument* getActiveDocument() const;
    
    protected slots:
    	void onSlotNewDocument();
    	void onSlotClosedDocument(DemoDocument* pDocument );
    	void onSlotNewWindow();
    
    private:
    	//创建文档的一个视图(DemoChildWindow-DeomView)
    	void createNewWindow(DemoDocument* pDocument );
    
    private:
    	QMdiArea* m_pMDIArea = nullptr;
    	std::list<DemoDocument*> m_DocList; //文档列表
    };
    
    

    DemoMainWindow.cpp

    #include "DemoMainWindow.h"
    #include "DemoDocument.h"
    #include "DemoChildWindow.h"
    
    #include <QMdiSubWindow>
    #include <QMenuBar>
    
    
    DemoMainWindow::DemoMainWindow(QWidget *parent)
    	: QMainWindow(parent)
    {
    	m_pMDIArea = new QMdiArea();
    	this->setCentralWidget(m_pMDIArea);
    
    	//void subWindowActivated(QMdiSubWindow * window)
    
    	//菜单
    	QMenu* pFileMenu = menuBar()->addMenu(QStringLiteral("文件"));
    	QAction* pNewDocAction = new QAction(QStringLiteral("新建"), this);
    	connect(pNewDocAction, SIGNAL(triggered()), this, SLOT(onSlotNewDocument()));
    	pFileMenu->addAction(pNewDocAction);
    	
    	//窗口(实际需要动态添加到菜单栏中,即有视图窗口打开,就加入,否则就移除,此处暂未实现)
    	QMenu* pWinMenu = menuBar()->addMenu(QStringLiteral("窗口"));
    	QAction* pNewWinAction = new QAction(QStringLiteral("新建"), this);
    	connect(pNewWinAction, SIGNAL(triggered()), this, SLOT(onSlotNewWindow()));
    	pWinMenu->addAction(pNewWinAction);
    
    }
    
    DemoMainWindow::~DemoMainWindow()
    {
    	for (auto pDoc : m_DocList)
    	{
    		delete pDoc;
    	}
    	m_DocList.clear();
    }
    
    void DemoMainWindow::onSlotNewDocument()
    {
    	auto pNewDoc = new DemoDocument();
    	m_DocList.push_back(pNewDoc);
    	createNewWindow(pNewDoc);
    
    	connect(pNewDoc, SIGNAL(closedDocument(DemoDocument*)), 
    		this, SLOT(onSlotClosedDocument(DemoDocument*)));
    }
    
    void DemoMainWindow::onSlotClosedDocument(DemoDocument* pDocument)
    {
    	auto it = std::find(m_DocList.begin(), m_DocList.end(), pDocument);
    	if (it != m_DocList.end())
    	{
    		auto pDoc = *it;
    		delete pDoc;
    		m_DocList.erase(it);
    	}
    }
    
    void DemoMainWindow::onSlotNewWindow()
    {
    	auto pDocument = getActiveDocument();
    	createNewWindow(pDocument);
    }
    
    //创建文档的一个视图(DemoChildWindow-DeomView)
    void DemoMainWindow::createNewWindow(DemoDocument* pDocument)
    {
    	if (!pDocument)
    	{
    		Q_ASSERT(false);
    		return;
    	}
    
    	auto pChildWnd = new DemoChildWindow(pDocument);
    
    	//自己new QMdiSubWindow时,必须设置Qt::WA_DeleteOnClose,参看文档
    	//When you create your own subwindow, you must set the Qt::WA_DeleteOnClose widget 
    	//attribute if you want the window to be deleted when closed in the MDI area. 
    	//If not, the window will be hidden and the MDI area will not activate the next subwindow.
    	//添加方式如下:
    //	QMdiSubWindow *pMdiSubWindow = new QMdiSubWindow;
    //	pMdiSubWindow->setWidget(pChildWnd);
    //	pMdiSubWindow->setAttribute(Qt::WA_DeleteOnClose);
    //	m_pMDIArea->addSubWindow(pMdiSubWindow);
    //	pMdiSubWindow->show();
    
    	//这中方法更简单
    	auto pMdiSubWindow = m_pMDIArea->addSubWindow(pChildWnd);
    	pMdiSubWindow->setWindowTitle(QStringLiteral("文档%1:%2").arg(pDocument->getId()).arg(
    		pDocument->getViewCount()));
    	pMdiSubWindow->show();
    }
    
    DemoDocument* DemoMainWindow::getActiveDocument() const
    {
    	auto pCurMdiSubWindow = m_pMDIArea->currentSubWindow();
    	if (!pCurMdiSubWindow)
    	{
    		return nullptr;
    	}
    
    	auto pChildWnd = dynamic_cast<DemoChildWindow*>(pCurMdiSubWindow->widget());
    	if (!pChildWnd)
    	{
    		Q_ASSERT(false);
    		return nullptr;
    	}
    
    	return pChildWnd->GetDocument();
    }
    
    
    
    
  4. 实现DemoChildWindow
    相当于MFC中的ChildFrm,派生自CMDIChildWndEx, 与文档是n-1关系, 与DemoView时1-1关系。此类负责创建DemoView,并且包含了文档对象的指针。MFC中创建ChildFrm以及CView没那么直接,通过消息触发创建了CView,具体参看MFC即可,我此处就简化处理创建的过程。
    DemoChildWindow.h

    #pragma once
    
    #include <QWidget>
    
    class DemoDocument;
    class DemoView;
    
    //相当于MFC中的ChildFrm,派生自CMDIChildWndEx, 与文档是n-1关系, 与DemoView时1-1关系,
    class DemoChildWindow : public QWidget
    {
    	Q_OBJECT
    
    public:
    	DemoChildWindow(DemoDocument* pDoc, QWidget* parent = 0, Qt::WindowFlags f = 0);
    	~DemoChildWindow();
    
    	DemoDocument* GetDocument() const;
    
    protected:
    	virtual void closeEvent(QCloseEvent * event) override;
    
    private:
    	DemoDocument* m_pDoc;
    	DemoView* m_pView;
    };
    
    

    DemoChildWindow.cpp

    #include "DemoChildWindow.h"
    #include "DemoView.h"
    #include "DemoDocument.h"
    #include <QVBoxLayout>
    
    DemoChildWindow::DemoChildWindow(DemoDocument* pDoc, QWidget *parent, Qt::WindowFlags flags)
    	: QWidget(parent, flags)
    {
    	m_pDoc = pDoc;
    	m_pView = new DemoView();
    	m_pDoc->addView(this);
    
    	auto pVBoxLayout = new QVBoxLayout();
    	pVBoxLayout->addWidget(m_pView);
    	this->setLayout(pVBoxLayout);
    }
    
    DemoChildWindow::~DemoChildWindow()
    {
    }
    
    DemoDocument* DemoChildWindow::GetDocument() const
    {
    	return m_pDoc;
    }
    
    void DemoChildWindow::closeEvent(QCloseEvent * event)
    {
    	m_pDoc->removeView(this);
    	return QWidget::closeEvent(event);
    }
    
  5. 实现DemoView
    相当与MFC中的CView,在DemoView中仅显示了硬编码的文本字符串。
    DemoView.h

    #pragma once
    
    #include <QWidget>
    
    //相当与MFC中的CView
    class DemoView : public QWidget
    {
    	Q_OBJECT
    
    public:
    	DemoView(QWidget *parent = Q_NULLPTR);
    	~DemoView();
    
    private:
    	//Ui::DemoView ui;
    };
    
    

    DemoView.cpp

    #include "DemoView.h"
    #include <QVBoxLayout>
    #include <QLabel>
    
    DemoView::DemoView(QWidget *parent)
    	: QWidget(parent)
    {
    	auto pVBoxLayout = new QVBoxLayout();
    	pVBoxLayout->addWidget(new QLabel(QStringLiteral("视图测试")));
    	this->setLayout(pVBoxLayout);
    	this->setMinimumSize(300, 200);
    }
    
    DemoView::~DemoView()
    {
    }
    
    
  6. main函数

    #include "DemoApplication.h"
    #include "DemoMainWindow.h"
    
    int main(int argc, char *argv[])
    {
    	DemoApplication a(argc, argv);
    	DemoMainWindow w;
    	w.show();
    	return a.exec();
    }
    
    

运行演示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1684322.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI语音识别技术-ASR

一、首先什么是ASR技术&#xff1f; 语音识别技术是一种将人的语音转换为文本的技术。其目标是将人类的语音中的词汇内容转换为计算机可读的输入&#xff0c;ASR技术就是将人的语言转化为计算机能够识别的文字的过程。 二、ASR技术应用中遇到的难点 在自动语音识别应用场景中&…

快速搭建流媒体服务

1、安装流媒体服务 源码地址&#xff1a;https://gitee.com/ossrs/srs 本次采用docker安装 docker run --rm -it -p 1935:1935 -p 1985:1985 -p 8080:8080 -p 8000:8000/udp -p 10080:10080/udp registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5 查看运行效果&#xff…

2024年5月19日优雅草蜻蜓K知识付费系统旗舰版v1.0.9进度更新

v1.1.0更新 v1.1.0更新 2024年5月19日优雅草蜻蜓K知识付费系统旗舰版v1.0.9进度更新&#xff0c;首页体育栏目完善新增用户发布页面 开发进度 首页体育栏目完善 新增用户发布页面 新增用户登录完善 新增学习课程页面完善-过往课程数据完成 去掉其他三方登录&#xff0c;新增…

linux安装KubeSphere

linux安装KubeSphere 介绍 KubeSphere 是在目前主流容器调度平台 Kubernetes 之上构建的企业级分布式多租户容器平台&#xff0c;提供简单易用的操作界面以及向导式操作方式&#xff0c;在降低用户使用容器调度平台学习成本的同时&#xff0c;极大减轻开发、测试、运维的日常…

Centos7.9安装卸载Docker

文章目录 1、官网安装1.1、卸载旧版本Docker1.2、通过rpm仓库安装1.2.1、设置仓库1.2.2、安装Docker Engine1.2.3、启动Docker1.2.4、验证安装 1.3、通过rpm软件包安装1.4、通过便捷脚本安装 2、yum安装2.1、安装docker-ce以及客户端2.2、启动docker2.3、配置镜像加速 3、卸载D…

Shell编程之条件判断语句

目录 一、条件判断 1、test命令 2、文件测试 3、整数值比较 4、字符串判断 5、逻辑测试 二、if语句 1、if单分支语句 2、双分支语句 3、多分之语句 4、case 分支语句 一、条件判断 Shell环境根据命令执行后的返回状态值&#xff08;echo $?&#xff09;来判断是否执行成…

docker如何拉取nginx最新镜像并运行

要拉取Docker Hub上的最新Nginx镜像&#xff0c;您可以使用以下命令&#xff1a; docker pull nginx 这个命令会从Docker Hub下载最新版本的Nginx镜像。如果您想要拉取特定版本的Nginx镜像&#xff0c;可以指定版本号&#xff0c;例如&#xff1a; docker pull nginx:1.18.0 拉…

思科模拟器--06.单臂路由升级版--多端路由互连实验--24.5.20

实验图纸如下: 第0步: 先放置六台个人电脑,一台交换机和一台2911路由器(千兆路由器(G0开头的)) 接着,用直通线将 PC0的F0,PC1的F0分别和交换机的F0/0, F0/1连接 交换机的F0/3和路由器的G0/0连接 PC2的F0,PC3的F0分别和交换机的F0/4, F0/5连接 交换机的F0/6和路由器的G0/1…

MySQL---函数与约束

目录 一、函数 1. 字符串函数 2. 数值函数 3. 日期函数 4. 流程函数 5. 总结 二、约束 1. 概述 2. 约束演示 3. 外键约束 3.1 添加外键 3.2 删除外键 3.3 外键删除更新行为 4. 总结 一、函数 1. 字符串函数 命令如下所示&#xff1a; -- concat select concat("Hel…

Qt | QGridLayout 类(网格布局)

01、上节回顾 Qt | QBoxLayout 及其子类(盒式布局)02、QGridLayout 简介 1、网格布局原理(见下图): 基本原理是把窗口划分为若干个单元格,每个子部件被放置于一个或多个单元格之中,各 单元格的大小可由拉伸因子和一行或列中单元格的数量来确定,若子部件的大小(由 sizeH…

园区网的基本了解

园区网使用的典型技术---IEEE802.3标准/IEEE802.11标准 封闭式园区网络 ---由内部人员使用&#xff0c;不能访问互联网。 ---制订各式各样的规章制度 ---NAC&#xff0c;网络接入控制 开放式园区网络 ---服务于公众的&#xff0c;认证 园区网的发展 第一代&#xff1a;…

开关电源重点可靠性测试项目与测试方法

为确保开关电源在复杂工作环境下的安全性与稳定性&#xff0c;各种安全性测试成为不可或缺的环节。本文将深入探讨几项关键的安全性测试项目&#xff0c;帮助用户全面了解如何评估开关电源的可靠性和安全性。 一、过压保护测试方法 目的是为了检测当输出电压过高时&#xff0c;…

express.js--token中间件验证及token解析(三)

主要作用 访问路由接口时&#xff0c;哪些需要校验token 通过token解析身份信息&#xff0c;就可以知道是哪个人 框架基本搭建express.js--基本用法及路由模块化(一)-CSDN博客 如何生成tokenexpress.js--生成token(二)-CSDN博客 middleware/index.js const jwt require(…

【linux】yumvim工具理解使用

目录 Linux 软件包管理器 yum 关于 rzsz 注意事项 查看软件包 Linux开发工具 Linux编辑器-vim使用 vim的基本概念 vim的基本操作 vim正常模式命令集 vim末行模式命令集 简单vim配置 配置文件的位置 sudo提权 Linux 软件包管理器 yum 1.yum是什么&#xff1…

Java基础22(JSON解析 注解)

目录 一、JSON解析 1. JSON语法 2. JSON的用途 3. Java解析JSON 4. 使用Fastjson 4.1 Fastjson 的优点 4.2 Fastjson 导包 4.3 Fastjson的主要对象 4.4 常用方法 将Java对象 "序列化"&#xff08;转换&#xff09; 为JSON字符串&#xff1a; 将JSON字符串…

薪资不公、晋升无望?动笔写一份申诉材料吧!

薪资不公、晋升无望&#xff1f;动笔写一份申诉材料吧&#xff01; 引言&#xff1a;每个努力工作的人都值得公平对待 在职场上&#xff0c;我们付出了汗水和智慧&#xff0c;期待着相应的回报——合理的工资和公正的晋升机会。然而&#xff0c;现实并不总是如此美好。当你感觉…

康谋分享 | aiSim5基于生成式AI扩大仿真测试范围(终)

在前面的几章节中探讨了aiSim仿真合成数据的置信度&#xff0c;此外在场景重建和测试流程闭环的过程中&#xff0c;难免会面临3D场景制作重建耗时长、成本高、扩展性低以及交通状况复杂程度难以满意等问题&#xff0c;当前的主要挑战在于如何自动化生成3D静态场景并添加动态实例…

深入理解C#中的IO操作 - FileStream流详解与示例

文章目录 一、FileStream类的介绍二、文件读取和写入2.1 文件读取&#xff08;FileStream.Read&#xff09;2.2 文件写入&#xff08;FileStream.Write&#xff09; 三、文件复制、移动和目录操作3.1 文件复制&#xff08;FileStream.Copy&#xff09;3.2 文件移动&#xff08;…

VMware ESXI 7.0安装部署

1、为什么要虚拟化&#xff1f; 目前&#xff0c;物理服务器存在以下几个问题&#xff1a; 1&#xff09;硬件资源利用率低&#xff1b; 2&#xff09;可靠性不足&#xff0c;物理服务器宕机即可造成整体业务停摆&#xff1b; 3&#xff09;维护量大&#xff0c;无法实现统…

H5228 6.5-75V60V48V36V24V12V 升降压芯片LED恒流驱动IC 支持无频闪数转模调光

H5228 是款调光特性良好的宽范围调光比且无频闪调光的 LED 恒流驱动器。支持降压、 升压和升降压拓扑的应用&#xff0c;具有 6.5~75V 宽输入工作电压范围&#xff0c;采用连续电流模式&#xff08;CCM&#xff09; 为高亮度 LED 供电。调光深度可调很低&#xff0c;在低亮负…