Qt多文档程序的一种实现

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

实现思路说明

  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();
    }
    
    

运行演示

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

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

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

外卖系统拦截器实现(Interceptor)

SpringMVC的拦截器主要是用于拦截控制器方法的执行&#xff1b; 概念&#xff1a;是一种动态拦截方法调用的机制&#xff0c;类似于过滤器。在Spring中动态拦截控制器中方法的执行。 作用&#xff1a;在指定的控制器中调用前后执行预先设定的代码&#xff0c;完成功能增强。 应…

day08|字符串题目part01

相关题目&#xff1a; ● 344.反转字符串 ● 541. 反转字符串II ● 卡码网&#xff1a;54.替换数字 ● 151.翻转字符串里的单词 ● 卡码网&#xff1a;55.右旋转字符串 344.反转字符串—双指针的应用 力扣链接 思路&#xff1a;创建两个指针分别指向头部和尾部&#xff0c;首…

【JavaEE进阶】 Bean的作用域与生命周期

文章目录 &#x1f343;Bean的作用域&#x1f6a9;作用域的使用&#x1f6a9;观察Bean的作用域&#x1f388;单例作用域&#x1f388;多例作用域&#x1f388;请求作用域&#x1f388;会话作⽤域&#x1f388;Application作⽤域 &#x1f384;Bean的⽣命周期⭕总结 &#x1f34…

Linux 第三十三章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

rocketmq的存储和检索

messageId是rocketmq自动生成的。

JSP+SQL学生成绩管理系统

Java版本&#xff1a;1.8 数据库&#xff1a;MySQL 框架&#xff1a;Spring Spring MVC MyBatis 服务器&#xff1a;Tomcat 前端解析框架&#xff1a;Thymeleaf 开发工具&#xff1a;Idea 2017 版本管理工具&#xff1a;Maven 版本控制工具&#xff1a;GitHub 经过对系统的需…

国际化日期(inti)

我们可以使用国际化API自动的格式化数字或者日期&#xff0c;并且格式化日期或数字的时候是按照各个国家的习惯来进行格式化的&#xff0c;非常的简单&#xff1b; const now new Date(); labelDate.textContent new Intl.DateTimeFormat(zh-CN).format(now);比如说这是按照…

link.click()时浏览器报错The file at ‘data:image/png;base64,iVBORw

代码如下&#xff1a; const dataURL canvas.toDataURL({format: "png",width: 400,height: 400, });const link document.createElement("a"); link.download new Date().getTime();link.href dataURL; document.body.appendChild(link); link.click…

【考研数学】准备开强化,更「张宇」还是「武忠祥」?

数一125学长前来回答&#xff0c;选择哪位老师的课程&#xff0c;这通常取决于你的个人偏好和学习风格&#xff01; 张宇老师和武忠祥老师都是非常有经验的数学老师&#xff0c;他们的教学方法各有特点。 张宇老师的教学风格通常被认为是通俗易懂&#xff0c;善于将复杂的概念…

x264 帧类型代价计算原理:slicetype_mb_cost 函数分析

slicetype_mb_cost 函数 函数功能 计算每个宏块 MB 的代价 cost。函数参数分析 x264_t *h:全局编码结构体x264_mb_analysis_t *a:宏块分析结构体x264_frame_t **frames:系列帧数据结构体int p0:帧序号之一,一般指向靠前帧int p1:帧序号之一,一般指向靠后帧int b:帧标志…

《系统架构设计师教程(第2版)》第4章-信息安全技术基础知识-02-信息加密技术

文章目录 1. 信息加密技术1.1 数据加密1.2 对称密钥加密算法1&#xff09;数据加密标准&#xff08;DES)2&#xff09;三重DES&#xff08;Triple-DES&#xff09;3&#xff09;国际数据加密算法&#xff08;IDEA&#xff09;4&#xff09;高级加密标准&#xff08;AES&#xf…

【C -> Cpp】由C迈向Cpp (6):静态、友元和内部类

标题&#xff1a;【C -&#xff1e; Cpp】由C迈向Cpp &#xff08;6&#xff09;&#xff1a;静态、友元和内部类 水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 &#xff08;一&#xff09;静态成员 &#xff08;二&#xff09;友元 &#xff08;三&#xff09…

Zynq UltraScale+ RFSoC 配置存储器器件

Zynq UltraScale RFSoC 配置存储器器件 下表所示闪存器件支持通过 Vivado 软件对 Zynq UltraScale RFSoC 器件执行擦除、空白检查、编程和验证等配置操 作。 本附录中的表格所列赛灵思系列非易失性存储器将不断保持更新 &#xff0c; 并支持通过 Vivado 软件对其中所列…

扭亏为盈的赛力斯,真正进入稳态了吗?

“72小时内大定破1万台”。5月15日&#xff0c;问界新M5开启全国大规模交付&#xff0c;从当前取得的成绩来看&#xff0c;赛力斯的“富贵”似乎还将延续。 其实&#xff0c;此前基于问界新M7等车型的爆火&#xff0c;赛力斯已经找到了创收轨道。财报显示&#xff0c;2024年一…

无代码无国界:我们正在走向软件安全的狂野西部吗?

我们使用的几乎所有东西都是基于代码构建的&#xff0c;从汽车到智能冰箱再到门铃。在企业中&#xff0c;无数的应用程序保持设备、工作流程和操作的运行。因此&#xff0c;当早期的无代码开发平台于 2010 年推出时&#xff0c;承诺为公民开发人员提供更易于访问的应用程序开发…

用友GRP-U8 bx_dj_check.jsp SQL注入漏洞复现(XVE-2024-10537)

0x01 免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测&#xff0c;如有侵权请联系删…

【2024华为HCIP831 | 高级网络工程师之路】刷题日记(18)

个人名片&#xff1a;&#x1faaa; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&a…

动态手势识别(VGG11)

学校的大作业要做一个视频图像处理相关的&#xff0c;就做了动态手势识别 VGG代码 import torch import torch.nn as nnclass VGG_11_3D(nn.Module):def __init__(self, num_classes, pretrainedFalse):super(VGG_11_3D, self).__init__()self.conv1 nn.Conv3d(3, 64, kernel…

labelimg删除用不到的标签(yolo格式)以及 下载使用

问题&#xff1a;当我们标注完成新的类别后后直接删除classes.txt中不需要的类别之后再次打开labelimg会闪退&#xff0c;如何删除不需要的标签并且能够正确运行呢&#xff1f;&#xff08;yolo格式&#xff09; 原因&#xff1a;当我们打开labelimg进行标注的时候&#xff0c…