简易CAD程序: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();
    }
    
    

运行演示

在这里插入图片描述

  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Module developer’s guide to FreeCAD source code by Qingfeng Xia http://www.iesensor.com • 2015-09-18 version 0.1 for FreeCAD version 0.16-dev • 2016-09-18 version 0.2 for FreeCAD version 0.17-dev License of this book This ebook is licensed the same as FreeCAD document license CC-BY 3.0 http://creativecommons.org/licenses/by/3.0/Contents 1 FreeCAD overview and architecture 7 1.1 Introduction to FreeCAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.2 Key features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.3 Software architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.3.1 Key software libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.3.2 Mixed python and c++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.3.3 GPL code will not be included into installer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.4 How 3D model are renderred . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.4.1 Selection of 3D visualization libarary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.4.2 Discussion of 3D rendering library selection on FreeCAD Forum . . . . . . . . . . . . . . . . . . . . . 8 1.5 Roadmap of FreeCAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.5.1 Keep updated with main components: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.5.2 C++11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.5.3 Pyside 2 project for Qt 5.x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2 Organisation of FreeCAD source code 11 2.1 Build system for FreeCAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.1.1 Analysis of src/cMake/SMesh.cMake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.2 List of files and folders in FreeCAD source folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.3 List of modules in FreeCAD Mod folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.4 Learning path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.5 Learning OpenInventor/Coin3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.5.1 OpenInventor in FreeCAD’s ViewProvider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.5.2 Important classes in OpenInventor/Coin3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.5.3 Window System integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 2.5.4 Pivy: Coin3D ’s Python wrapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3 Base, App and Main module 19 3.1 List of header files in Base folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.1.1 Frequently included headers files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.1.2 Correct way of using Sequencer in try-catch block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.1.3 String enconding utf8 and conversion into wchar_t QString . . . . . . . . . . . . . . . . . . . . . . . . 22 3.2 Type, BaseClass, PyObjectBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.2.1 Type system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.2.2 src/Base/BaseClass.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.2.3 src/Base/PyObjectBase.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.2.4 src/Base/Persistence.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.2.5 GeoFeature: Base class of all geometric document objects . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.3 Unit scheme for physial quantity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.3.1 src/Base/Unit.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.3.2 src/Base/Quantity.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.4 List of header files in App folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.5 Property framewrok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.5.1 Naming of property and PropertyEditor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.5.2 src/App/PropertyStandard.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.5.3 PropertyEnumeration, see src/App/Enumeration.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.5.4 Geometry related property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.5.5 File related property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值