Qt多文档程序的一种实现

news2024/9/21 16:46:07

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

实现思路说明

  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/1680127.html

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

相关文章

【RAG 论文】IRCoT:基于 CoT 的交叉检索解决多步骤问题

论文&#xff1a;Interleaving Retrieval with Chain-of-Thought Reasoning for Knowledge-Intensive Multi-Step Questions ⭐⭐⭐⭐ ACL 2023, arXiv:2212.10509 Code: github.com/stonybrooknlp/ircot 论文速读 大多数 RAG 都是一次检索来辅助 LLM 生成&#xff0c;但是面对…

fastjson1.2.68对于文件操作的分析最全

fastjson1.2.68对于文件操作的分析 前言分析复制文件写入文件清空文件读取文件分析poc拓宽场景极限环境poc优化修改再次优化poc的分析 前言 这次分析也是分析了很久&#xff0c;因为每个链子都是自己去跟着分析了的&#xff0c;然后主要是去学习了一下怎么去挖链子 分析 前面…

洛谷P1364 医院设置

P1364 医院设置 题目描述 设有一棵二叉树&#xff0c;如图&#xff1a; 其中&#xff0c;圈中的数字表示结点中居民的人口。圈边上数字表示结点编号&#xff0c;现在要求在某个结点上建立一个医院&#xff0c;使所有居民所走的路程之和为最小&#xff0c;同时约定&#xff0c…

四、基于Stage模型的应用架构设计

前面我们了解了如何构建鸿蒙应用以及开发了第一个页面&#xff0c;这只是简单的demo&#xff1b;那么如何去设计&#xff0c;从0到1搭建一个真正的应用呢 一、基本概念 1、Stage模型基本概念 Stage模型概念图 AbilityStage&#xff1a;是一个Module级别的组件容器&#xff0…

红蓝对抗 网络安全 网络安全红蓝对抗演练

什么是红蓝对抗 在军事领域&#xff0c;演习是专指军队进行大规模的实兵演习&#xff0c;演习中通常分为红军、蓝军&#xff0c;演习多以红军守、蓝军进攻为主。类似于军事领域的红蓝军对抗&#xff0c;网络安全中&#xff0c;红蓝军对抗则是一方扮演黑客&#xff08;蓝军&…

BUUCTF靶场[MISC]wireshark、被嗅探的流量、神秘龙卷风、另一个世界

[misc]wireshark 考点&#xff1a;流量、追踪流 工具&#xff1a;wireshark 先看题目&#xff0c;管理员密码 将下载的文件用wireshark打开&#xff0c;查找flag 点击追踪tcp流&#xff0c;开始挨个查看flag [misc]被嗅探的流量 考点&#xff1a;流量、追踪流 工具&#xf…

类和对象、包等知识总结Java

类 类的概念&#xff1a;类是用来对一个实体&#xff08;对象&#xff09;进行描述的&#xff0c;主要描述该对象的属性&#xff0c;功能等。 类的定义和实例化 定义 定义类需要用到class关键字 &#xff08;大驼峰定义&#xff09;for example:class Dog... 初步了解一下…

2024年5月16日 十二生肖 今日运势

小运播报&#xff1a;2024年5月16日&#xff0c;星期四&#xff0c;农历四月初九 &#xff08;甲辰年己巳月庚辰日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;猴、鼠、鸡 需要注意&#xff1a;牛、兔、狗 喜神方位&#xff1a;西北方 财神方位&#xff1a;…

【2024年电工杯数学建模竞赛】选题分析+A题B题完整思路+代码分享

.2024年电工杯数学建模AB题选题思路 比赛开始第一时间在下面的资料裙分享&#xff1a; 点击链接加入群聊【2024数维杯数学建模ABC题资料汇总】&#xff1a;http://qm.qq.com/cgi-bin/qm/qr?_wv1027&kBwulH5tSN2X7iLXzZHAJqRk9sYnegd0y&authKey2TSsuOgqXZQ%2FvTX4R59…

ADS使用记录之使用RFPro进行版图联合仿真-加入集总元器件

ADS使用记录之使用RFPro进行版图联合仿真-加入集总元器件 ADS使用记录之使用RFPro进行版图联合仿真中已经简单介绍了使用RFPro对版图就行仿真的方法。但是&#xff0c;如果版图中含有一些非微带的结构&#xff0c;比如说电感、电容、晶体管呢&#xff0c;在此举例解释一下。 …

什么可以替代iframe?

网页嵌套中&#xff0c;iframe曾几何时不可一世&#xff0c;没有其他更好的选择&#xff01; iframe即内联框架&#xff0c;作为网页设计中的一种技术&#xff0c;允许在一个网页内部嵌套另一个独立的HTML文档。尽管它在某些场景下提供了便利&#xff0c;但也存在多方面的缺陷…

【Python报错】Python安装模块时报错Fatal error in launcher

【Python报错】Python安装模块时报错Fatal error in launcher 最近需要用到python下载一个小工具&#xff0c;自信敲下回车键本想看到黑乎乎的终端上会出现快速跳跃的命令代码&#xff0c;没想到&#xff0c;报错了...... Fatal error in launcher: Unable to create process …

全网最全的基于电机控制的38类simulink仿真全家桶----新手大礼包

整理了基于电机的38种simulink仿真全家桶&#xff0c;包含多种资料&#xff0c;类型齐全十分适合新手学习使用。包括但是不局限于以下&#xff1a; 1、基于多电平逆变器的无刷直流电机驱动simulink仿真 2、基于负载转矩的感应电机速度控制simulink仿真 3、基于滑膜观测器的永…

Unity与Andriod的交互

Unity与安卓的信息交互 这次分享的不同于传统的方式AndroidJavaClass("com.unity3d.player.UnityPlayer") 如果是新手的话&#xff0c;请看 交互新手教程 这里讲的是在Unity中调用java代码&#xff0c;或者在unity中传参到java中&#xff0c;在Java代码中运行。 以下…

二叉树遍历的实现

递归实现 先序遍历 代码实现 存储状态 中序遍历 后序遍历 算法分析 实质 复杂度 非递归算法实现 中序遍历 层次遍历 原理 实现

InfiniGate自研网关实现五

17.核心通信组件管理和处理服务映射 引入模块api-gateway-core 到 api-gateway-assist 中进行创建和使用&#xff0c;并拉取自注册中心的映射信息注册到本地的网关通信组件中。 第17节是在第15节的基础上继续完善服务发现的相关功能&#xff0c;把从注册中心拉取的网关映射信…

基于单片机的智能安防系统设计(32+4G+WIFI版)-设计说明书

设计摘要&#xff1a; 本设计基于STM32单片机&#xff0c;旨在实现一个智能安防系统&#xff0c;主要包括烟雾和温度传感器、人体红外传感器、显示屏、按键、4G模块和WiFi模块等组件。通过这些组件的协作&#xff0c;实现了火灾检测、入侵监测、状态显示、用户交互和远程通信等…

vscode对一些软件的调试插件。

vscode对一些软件的调试插件。 1、ae &#xff0c;f1然后选择运行 after effect 脚本 2、maya,右键send code to maya 3、max&#xff0c;ctrle运行脚本到max 4、unity 从在Visual Studio代码使用.NET的核心&#xff1a; 1、安装.NET Core SDK&#xff0c;链接: https://dotn…

QT客户端开发的注意事项

QT客户端开发是一个涉及图形用户界面&#xff08;GUI&#xff09;设计、网络编程、数据库交互等多个方面的复杂过程。以下是在进行QT客户端开发时应注意的一些关键事项&#xff0c;通过关注这些事项&#xff0c;可以提高QT客户端应用的质量和开发效率。北京木奇移动技术有限公司…

内网安全-隧道搭建穿透上线FRPNPSSPPNgrokEW项目

旨在代理连接肉鸡后实现本地渗透肉鸡网络架构 Linux&#xff1a;Proxychains Windows&#xff1a;Sockscap Proxifier 穿透项目&#xff1a;Ngrok Frp Spp Nps EW(停更) 优点&#xff1a;穿透加密数据&#xff0c;中间平台&#xff0c;防追踪&#xff0c;解决网络问题 https://…