深入浅出MFC文档/视图架构之文档模板

在"文档/视图"架构的MFC程序中,提供了文档模板管理者类CDocManager,由它管理应用程序所包含的文档模板。我们先看看这个类的声明:

/
// CDocTemplate manager object 
class CDocManager : public CObject
{DECLARE_DYNAMIC(CDocManager)public:// ConstructorCDocManager();//Document functionsvirtual void AddDocTemplate(CDocTemplate* pTemplate);virtual POSITION GetFirstDocTemplatePosition() const;virtual CDocTemplate* GetNextDocTemplate(POSITION& pos) const;virtual void RegisterShellFileTypes(BOOL bCompat);void UnregisterShellFileTypes();virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName); // open named filevirtual BOOL SaveAllModified(); // save before exitvirtual void CloseAllDocuments(BOOL bEndSession); // close documents before exitingvirtual int GetOpenDocumentCount();// helper for standard commdlg dialogsvirtual BOOL DoPromptFileName(CString& fileName, UINT nIDSTitle,DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate);//Commands// Advanced: process async DDE requestvirtual BOOL OnDDECommand(LPTSTR lpszCommand);virtual void OnFileNew();virtual void OnFileOpen();// Implementationprotected:CPtrList m_templateList;int GetDocumentCount(); // helper to count number of total documentspublic:static CPtrList* pStaticList; // for static CDocTemplate objectsstatic BOOL bStaticInit; // TRUE during static initializationstatic CDocManager* pStaticDocManager; // for static CDocTemplate objectspublic:virtual ~CDocManager();#ifdef _DEBUGvirtual void AssertValid() const;virtual void Dump(CDumpContext& dc) const;#endif
};

从上述代码可以看出,CDocManager类维护一个CPtrList类型的链表m_templateList(即文档模板链表,实际上,MFC的设计者在MFC的实现中大量使用了链表这种数据结构),CPtrList类型定义为:

class CPtrList : public CObject
{DECLARE_DYNAMIC(CPtrList)protected:struct CNode{CNode* pNext; CNode* pPrev;void* data;};public:// ConstructionCPtrList(int nBlockSize = 10);// Attributes (head and tail)// count of elementsint GetCount() const;BOOL IsEmpty() const;// peek at head or tailvoid*& GetHead();void* GetHead() const;void*& GetTail();void* GetTail() const;// Operations// get head or tail (and remove it) - don't call on empty list!void* RemoveHead();void* RemoveTail();// add before head or after tailPOSITION AddHead(void* newElement);POSITION AddTail(void* newElement);// add another list of elements before head or after tailvoid AddHead(CPtrList* pNewList);void AddTail(CPtrList* pNewList);// remove all elementsvoid RemoveAll();// iterationPOSITION GetHeadPosition() const;POSITION GetTailPosition() const;void*& GetNext(POSITION& rPosition); // return *Position++void* GetNext(POSITION& rPosition) const; // return *Position++void*& GetPrev(POSITION& rPosition); // return *Position--void* GetPrev(POSITION& rPosition) const; // return *Position--// getting/modifying an element at a given positionvoid*& GetAt(POSITION position);void* GetAt(POSITION position) const;void SetAt(POSITION pos, void* newElement);void RemoveAt(POSITION position);// inserting before or after a given positionPOSITION InsertBefore(POSITION position, void* newElement);POSITION InsertAfter(POSITION position, void* newElement);// helper functions (note: O(n) speed)POSITION Find(void* searchValue, POSITION startAfter = NULL) const;// defaults to starting at the HEAD// return NULL if not foundPOSITION FindIndex(int nIndex) const;// get the 'nIndex'th element (may return NULL)// Implementationprotected:CNode* m_pNodeHead;CNode* m_pNodeTail;int m_nCount;CNode* m_pNodeFree;struct CPlex* m_pBlocks;int m_nBlockSize;CNode* NewNode(CNode*, CNode*);void FreeNode(CNode*);public:~CPtrList();#ifdef _DEBUGvoid Dump(CDumpContext&) const;void AssertValid() const;#endif// local typedefs for class templatestypedef void* BASE_TYPE;typedef void* BASE_ARG_TYPE;
};
很显然,CPtrList是对链表结构体
struct CNode
{
 CNode* pNext; 
 CNode* pPrev;
 void* data;
};
  本身及其GetNext、GetPrev、GetAt、SetAt、RemoveAt、InsertBefore、InsertAfter、Find、FindIndex等各种操作的封装。
  作为一个抽象的链表类型,CPtrList并未定义其中节点的具体类型,而以一个void指针(struct CNode 中的void* data)巧妙地实现了链表节点成员具体类型的"模板"化。很显然,在Visual C++6.0开发的年代,C++语言所具有的语法特征"模板"仍然没有得到广泛的应用。
而CDocManager类的成员函数
virtual void AddDocTemplate(CDocTemplate* pTemplate);
virtual POSITION GetFirstDocTemplatePosition() const;
virtual CDocTemplate* GetNextDocTemplate(POSITION& pos) const;

则完成对m_TemplateList链表的添加及遍历操作的封装,我们来看看这三个函数的源代码:

void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)
{if (pTemplate == NULL){if (pStaticList != NULL){POSITION pos = pStaticList->GetHeadPosition();while (pos != NULL){CDocTemplate* pTemplate = (CDocTemplate*)pStaticList->GetNext(pos);AddDocTemplate(pTemplate);}delete pStaticList;pStaticList = NULL;}bStaticInit = FALSE;}else{ASSERT_VALID(pTemplate);ASSERT(m_templateList.Find(pTemplate, NULL) == NULL);// must not be in listpTemplate->LoadTemplate();m_templateList.AddTail(pTemplate);}
}
POSITION CDocManager::GetFirstDocTemplatePosition() const
{return m_templateList.GetHeadPosition();
}
CDocTemplate* CDocManager::GetNextDocTemplate(POSITION& pos) const
{return (CDocTemplate*)m_templateList.GetNext(pos);
}
2.文档模板类CDocTemplate

  文档模板类CDocTemplate是一个抽象基类(这意味着不能直接用它来定义对象而必须用它的派生类),它定义了文档模板的基本处理函数接口。对一个单文档界面程序,需使用单文档模板类CSingleDocTemplate,而对于一个多文档界面程序,需使用多文档模板类CMultipleDocTemplate。我们首先来看看CDocTemplate类的声明: 

class CDocTemplate : public CCmdTarget
{DECLARE_DYNAMIC(CDocTemplate)// Constructorsprotected:CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);public:virtual void LoadTemplate();// Attributespublic:// setup for OLE containersvoid SetContainerInfo(UINT nIDOleInPlaceContainer);// setup for OLE serversvoid SetServerInfo(UINT nIDOleEmbedding, UINT nIDOleInPlaceServer = 0,
CRuntimeClass* pOleFrameClass = NULL, CRuntimeClass* pOleViewClass = NULL);// iterating over open documentsvirtual POSITION GetFirstDocPosition() const = 0;virtual CDocument* GetNextDoc(POSITION& rPos) const = 0;// Operationspublic:virtual void AddDocument(CDocument* pDoc); // must overridevirtual void RemoveDocument(CDocument* pDoc); // must overrideenum DocStringIndex{windowTitle, // default window titledocName, // user visible name for default documentfileNewName, // user visible name for FileNew// for file based documents:filterName, // user visible name for FileOpenfilterExt, // user visible extension for FileOpen// for file based documents with Shell open support:regFileTypeId, // REGEDIT visible registered file type identifierregFileTypeName, // Shell visible registered file type name};virtual BOOL GetDocString(CString& rString,
enum DocStringIndex index) const; // get one of the info stringsCFrameWnd* CreateOleFrame(CWnd* pParentWnd, CDocument* pDoc,BOOL bCreateView);// Overridablespublic:enum Confidence{noAttempt,maybeAttemptForeign,maybeAttemptNative,yesAttemptForeign,yesAttemptNative,yesAlreadyOpen};virtual Confidence MatchDocType(LPCTSTR lpszPathName,CDocument*& rpDocMatch);virtual CDocument* CreateNewDocument();virtual CFrameWnd* CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther);virtual void InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc,BOOL bMakeVisible = TRUE);virtual BOOL SaveAllModified(); // for all documentsvirtual void CloseAllDocuments(BOOL bEndSession);virtual CDocument* OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible = TRUE) = 0;// open named file// if lpszPathName == NULL => create new file with this typevirtual void SetDefaultTitle(CDocument* pDocument) = 0;// Implementationpublic:BOOL m_bAutoDelete;virtual ~CDocTemplate();// back pointer to OLE or other server (NULL if none or disabled)CObject* m_pAttachedFactory;// menu & accelerator resources for in-place containerHMENU m_hMenuInPlace;HACCEL m_hAccelInPlace;// menu & accelerator resource for server editing embeddingHMENU m_hMenuEmbedding;HACCEL m_hAccelEmbedding;// menu & accelerator resource for server editing in-placeHMENU m_hMenuInPlaceServer;HACCEL m_hAccelInPlaceServer;#ifdef _DEBUGvirtual void Dump(CDumpContext&) const;virtual void AssertValid() const;#endifvirtual void OnIdle(); // for all documentsvirtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo);protected:UINT m_nIDResource; // IDR_ for frame/menu/accel as wellUINT m_nIDServerResource; // IDR_ for OLE inplace frame/menu/accelUINT m_nIDEmbeddingResource; // IDR_ for OLE open frame/menu/accelUINT m_nIDContainerResource; // IDR_ for container frame/menu/accelCRuntimeClass* m_pDocClass; // class for creating new documentsCRuntimeClass* m_pFrameClass; // class for creating new framesCRuntimeClass* m_pViewClass; // class for creating new viewsCRuntimeClass* m_pOleFrameClass; // class for creating in-place frameCRuntimeClass* m_pOleViewClass; // class for creating in-place viewCString m_strDocStrings; // '\n' separated names// The document names sub-strings are represented as _one_ string:// windowTitle\ndocName\n ... (see DocStringIndex enum)
};

文档模板挂接了后面要介绍的文档、视图和框架窗口,使得它们得以互相关联。通过文档模板,程序确定了创建或打开一个文档时,以什么样的视图和框架窗口来显示。文档模板依靠保存相互对应的文档、视图和框架窗口的CRuntimeClass对象指针来实现上述挂接,这就是文档模板类中的成员变量m_pDocClass、m_pFrameClass、m_pViewClass的由来。实际上,对m_pDocClass、m_pFrameClass、m_pViewClass的赋值在CDocTemplate类的构造函数中实施:

CDocTemplate::CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)
{ASSERT_VALID_IDR(nIDResource);ASSERT(pDocClass == NULL || pDocClass->IsDerivedFrom(RUNTIME_CLASS(CDocument)));ASSERT(pFrameClass == NULL ||pFrameClass->IsDerivedFrom(RUNTIME_CLASS(CFrameWnd)));ASSERT(pViewClass == NULL || pViewClass->IsDerivedFrom(RUNTIME_CLASS(CView)));m_nIDResource = nIDResource;m_nIDServerResource = NULL;m_nIDEmbeddingResource = NULL;m_nIDContainerResource = NULL;m_pDocClass = pDocClass;m_pFrameClass = pFrameClass;m_pViewClass = pViewClass;m_pOleFrameClass = NULL;m_pOleViewClass = NULL;m_pAttachedFactory = NULL;m_hMenuInPlace = NULL;m_hAccelInPlace = NULL;m_hMenuEmbedding = NULL;m_hAccelEmbedding = NULL;m_hMenuInPlaceServer = NULL;m_hAccelInPlaceServer = NULL;// add to pStaticList if constructed as static instead of on heapif (CDocManager::bStaticInit){m_bAutoDelete = FALSE;if (CDocManager::pStaticList == NULL)CDocManager::pStaticList = new CPtrList;if (CDocManager::pStaticDocManager == NULL)CDocManager::pStaticDocManager = new CDocManager;CDocManager::pStaticList->AddTail(this);}else{m_bAutoDelete = TRUE; // usually allocated on the heapLoadTemplate();}
}

文档模板类CDocTemplate还保存了它所支持的全部文档类的信息,包括所支持文档的文件扩展名、文档在框架窗口中的名字、图标等。CDocTemplate类的AddDocument、RemoveDocument成员函数使得CDocument* pDoc参数所指向的文档归属于本文档模板(通过将this指针赋值给pDoc所指向CDocument对象的m_pDocTemplate成员变量)或脱离与本文档模板的关系:

void CDocTemplate::AddDocument(CDocument* pDoc)
{ASSERT_VALID(pDoc);ASSERT(pDoc->m_pDocTemplate == NULL); // no template attached yetpDoc->m_pDocTemplate = this;
}
void CDocTemplate::RemoveDocument(CDocument* pDoc)
{ASSERT_VALID(pDoc);ASSERT(pDoc->m_pDocTemplate == this); // must be attached to uspDoc->m_pDocTemplate = NULL;
}

而CDocTemplate类的CreateNewDocument成员函数则首先调用CDocument运行时类的CreateObject函数创建一个CDocument对象,再调用AddDocument成员函数将其归属于本文档模板类:

CDocument* CDocTemplate::CreateNewDocument()
{// default implementation constructs one from CRuntimeClassif (m_pDocClass == NULL){TRACE0("Error: you must override CDocTemplate::CreateNewDocument.\n");ASSERT(FALSE);return NULL;}CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();if (pDocument == NULL){TRACE1("Warning: Dynamic create of document type %hs failed.\n",m_pDocClass->m_lpszClassName);return NULL;}ASSERT_KINDOF(CDocument, pDocument);AddDocument(pDocument);return pDocument;
}
文档类对象由文档模板类构造生成,单文档模板类CSingleDocTemplate只能生成一个文档类对象,并用成员变量 m_pOnlyDoc 指向该对象;多文档模板类可以生成多个文档类对象,用成员变量 m_docList 指向文档对象组成的链表。

  CSingleDocTemplate的构造函数、AddDocument及RemoveDocument成员函数都在CDocTemplate类相应函数的基础上增加了对m_pOnlyDoc指针的处理:

CSingleDocTemplate::CSingleDocTemplate(UINT nIDResource,
CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass,
CRuntimeClass* pViewClass)
: CDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass)
{m_pOnlyDoc = NULL;
}
void CSingleDocTemplate::AddDocument(CDocument* pDoc)
{ASSERT(m_pOnlyDoc == NULL); // one at a time pleaseASSERT_VALID(pDoc);CDocTemplate::AddDocument(pDoc);m_pOnlyDoc = pDoc;
}
void CSingleDocTemplate::RemoveDocument(CDocument* pDoc)
{ASSERT(m_pOnlyDoc == pDoc); // must be this oneASSERT_VALID(pDoc);CDocTemplate::RemoveDocument(pDoc);m_pOnlyDoc = NULL;
}

同样,CMultiDocTemplate类的相关函数也需要对m_docList所指向的链表进行操作(实际上AddDocument和RemoveDocument成员函数是文档模板管理其所包含文档的函数):

// CMultiDocTemplate document management (a list of currently open documents)
void CMultiDocTemplate::AddDocument(CDocument* pDoc)
{ASSERT_VALID(pDoc);CDocTemplate::AddDocument(pDoc);ASSERT(m_docList.Find(pDoc, NULL) == NULL); // must not be in listm_docList.AddTail(pDoc);
}
void CMultiDocTemplate::RemoveDocument(CDocument* pDoc)
{ASSERT_VALID(pDoc);CDocTemplate::RemoveDocument(pDoc);m_docList.RemoveAt(m_docList.Find(pDoc));
}

由于CMultiDocTemplate类可包含多个文档,依靠其成员函数GetFirstDocPosition和GetNextDoc完成对文档链表m_docList的遍历:

POSITION CMultiDocTemplate::GetFirstDocPosition() const
{return m_docList.GetHeadPosition();
}
CDocument* CMultiDocTemplate::GetNextDoc(POSITION& rPos) const
{return (CDocument*)m_docList.GetNext(rPos);
}

而CSingleDocTemplate的这两个函数实际上并无太大的意义,仅仅是MFC要玩的某种"招数",这个"招数"高明吗?相信看完MFC的相关源代码后你或许不会这么认为,实际上CSingleDocTemplate的GetFirstDocPosition、GetNextDoc函数仅仅只能判断m_pOnlyDoc的是否为NULL:

POSITION CSingleDocTemplate::GetFirstDocPosition() const
{return (m_pOnlyDoc == NULL) ? NULL : BEFORE_START_POSITION;
}CDocument* CSingleDocTemplate::GetNextDoc(POSITION& rPos) const
{CDocument* pDoc = NULL;if (rPos == BEFORE_START_POSITION){// first time through, return a real documentASSERT(m_pOnlyDoc != NULL);pDoc = m_pOnlyDoc;}rPos = NULL; // no morereturn pDoc;
}

笔者认为,MFC的设计者们将GetFirstDocPosition、GetNextDoc作为基类CDocTemplate的成员函数是不合理的,一种更好的做法是将GetFirstDocPosition、GetNextDoc移至CMultiDocTemplate派生类。

CDocTemplate还需完成对其对应文档的关闭与保存操作:

BOOL CDocTemplate::SaveAllModified()
{POSITION pos = GetFirstDocPosition();while (pos != NULL){CDocument* pDoc = GetNextDoc(pos);if (!pDoc->SaveModified())return FALSE;}return TRUE;
}
void CDocTemplate::CloseAllDocuments(BOOL)
{POSITION pos = GetFirstDocPosition();while (pos != NULL){CDocument* pDoc = GetNextDoc(pos);pDoc->OnCloseDocument();}
}
前文我们提到,由于MFC的设计者将CSingleDocTemplate和CMultiDocTemplate的行为未进行规范的区分,它对仅仅对应一个文档的CSingleDocTemplate也提供了所谓的GetFirstDocPosition、GetNextDoc遍历操作,所以基类CDocTemplate的SaveAllModified和CloseAllDocuments函数(都是遍历)就可统一CSingleDocTemplate和CMultiDocTemplate两个本身并不相同类的SaveAllModified和CloseAllDocuments行为(实际上,对于CSingleDocTemplate而言,SaveAllModified和CloseAllDocuments中的"All"是没有太大意义的。教室里有1个老师和N个同学,老师可以对同学们说"所有同学",而学生对老师说"所有老师"相信会被当成神经病)。MFC的设计者们特意使用了"将错就错"的方法意图简化CSingleDocTemplate和CMultiDocTemplate类的设计,读者朋友可以不认同他们的做法。

  CDocTemplate还提供了框架窗口的创建和初始化函数:

/
// Default frame creation
CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)
{if (pDoc != NULL)ASSERT_VALID(pDoc);// create a frame wired to the specified documentASSERT(m_nIDResource != 0); // must have a resource ID to load fromCCreateContext context;context.m_pCurrentFrame = pOther;context.m_pCurrentDoc = pDoc;context.m_pNewViewClass = m_pViewClass;context.m_pNewDocTemplate = this;if (m_pFrameClass == NULL){TRACE0("Error: you must override CDocTemplate::CreateNewFrame.\n");ASSERT(FALSE);return NULL;}CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();if (pFrame == NULL){TRACE1("Warning: Dynamic create of frame %hs failed.\n",m_pFrameClass->m_lpszClassName);return NULL;}ASSERT_KINDOF(CFrameWnd, pFrame);if (context.m_pNewViewClass == NULL)TRACE0("Warning: creating frame with no default view.\n");// create new from resourceif (!pFrame->LoadFrame(m_nIDResource,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, // default frame styles
NULL, &context)){TRACE0("Warning: CDocTemplate couldn't create a frame.\n");// frame will be deleted in PostNcDestroy cleanupreturn NULL;}// it worked !return pFrame;
}
void CDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc,BOOL bMakeVisible)
{// just delagate to implementation in CFrameWndpFrame->InitialUpdateFrame(pDoc, bMakeVisible);
}
3. CWinApp与CDocManager/CDocTemplate类


  应用程序CWinApp类对象与CDocManager和CDocTemplate类的关系是:CWinApp对象中包含一个CDocManager指针类型的共有数据成员m_pDocManager,CWinApp::InitInstance函数调用CWinApp::AddDocTemplate函数向链表m_templateList添加模板指针(实际上是调用前文所述CDocManager的AddDocTemplate函数)。另外,CWinApp也提供了GetFirstDocTemplatePosition和GetNextDocTemplate函数实现来对m_templateList链表进行访问(实际上也是调用了前文所述CDocManager的GetFirstDocTemplatePosition、GetNextDocTemplate函数)。我们仅摘取CWinApp类声明的一小部分:

class CWinApp : public CWinThread
{…CDocManager* m_pDocManager;// Running Operations - to be done on a running application// Dealing with document templatesvoid AddDocTemplate(CDocTemplate* pTemplate);POSITION GetFirstDocTemplatePosition() const;CDocTemplate* GetNextDocTemplate(POSITION& pos) const;// Dealing with filesvirtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName); // open named filevoid CloseAllDocuments(BOOL bEndSession); // close documents before exiting// Command Handlers
protected:// map to the following for file new/openafx_msg void OnFileNew();afx_msg void OnFileOpen();int GetOpenDocumentCount();…
};

来看CWinApp派生类CSDIExampleApp(单文档)、CMDIExampleApp(多文档)的InitInstance成员函数的例子(仅仅摘取与文档模板相关的部分):

BOOL CSDIExampleApp::InitInstance()
{…CSingleDocTemplate* pDocTemplate;pDocTemplate = new CSingleDocTemplate(IDR_MAINFRAME,RUNTIME_CLASS(CSDIExampleDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CSDIExampleView));AddDocTemplate(pDocTemplate);…return TRUE;
}
BOOL CMDIExampleApp::InitInstance()
{…CMultiDocTemplate* pDocTemplate;pDocTemplate = new CMultiDocTemplate(IDR_MDIEXATYPE,RUNTIME_CLASS(CMDIExampleDoc),RUNTIME_CLASS(CChildFrame), // custom MDI child frameRUNTIME_CLASS(CMDIExampleView));AddDocTemplate(pDocTemplate);…
}
读者朋友,看完本次连载,也许您有许多不明白的地方,这是正常的。因为其所讲解的内容与后续几次连载息息相关,我们愈往后看,就会愈加清晰。对于本次连载的内容,您只需要建立基本的印象。最初的浅尝辄止是为了最终的深入脊髓!


  我们试图对MFC的深层机理刨根究底,"拨开云雾见月明"的过程是艰辛的!

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

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

相关文章

深入浅出MFC文档/视图架构之文档

1、文档类CDocument在"文档/视图"架构的MFC程序中,文档是一个CDocument派生对象,它负责存储应用程序的数据,并把这些信息提供给应用程序的其余部分。CDocument类对文档的建立及归档提供支持并提供了应用程序用于控制其数据的接口&a…

centos 6 安装mysql,CentOS6.5安装MySQL教程(完整教程)

Step 1:检测系统是否安装MYSQL# yum list installed | grep mysql顺便提下如果yum有如下提示不能用的情况:yum在自动更新原因是yum在自动更新 只要关掉它就OK了解决方案:直接输入# rm -f /var/run/yum.pid或者:# /etc/init.d/y…

linux学习之一

忙啦几天,今天终于又有时间在这里打理本园子啦,今天写一下linux下磁盘如何自动挂载其实很简单,要让某些 partition 在开机的时候就自动挂载,写入 /etc/fstab 当中,或者是将指令完整的写到 /etc/rc.d/rc.local&#xff…

MFC 多文档源码分析1

添加模板在复写的CWinApp::InitInstance()函数中添加下面代码 CMultiDocTemplate* pDocTemplate; pDocTemplate new CMultiDocTemplate(IDR_SMARTTTYPE,RUNTIME_CLASS(CCosiWorksDoc),RUNTIME_CLASS(CChildFrame), // custom MDI child frameRUNTIME_CLASS(CCosiWorksView)); …

matlab求零空间,matlab求矩阵的零空间的一组整数基,该怎样操作?

匿名用户1级2015-09-18 回答第一部分:矩阵基本知识一、矩阵的创建直接输入法利用Matlab函数创建矩阵利用文件创建矩阵二、矩阵的拆分矩阵元素矩阵拆分特殊矩阵三、矩阵的运算算术运算关系运算逻辑运算四、矩阵分析对角阵三角阵矩阵的转置与旋转矩阵的翻转矩阵的逆与…

php通过条件来定义const,php用const出错是什么原因

大家都知道define是定义常量的,如果在类中定义常量呢&#xff1f;当然不能用define&#xff0c;而用const&#xff0c;如下例&#xff1a;<?php //在类外面通常这样定义常量define("PHP","phpernote.com");class MyClass{ //常量的值将始终保持不变。在…

UE4角色Location远距离时动画抖动问题(float精度不够)解决方案

正题&#xff1a;关于UE4引擎当角色Location超过9999.999后&#xff0c;角色动画更新抖动问题的解决思路。 前提&#xff1a; 1.UE4引擎中距离单位是厘米(cm)&#xff0c;也就说我们制作好1.8米的角色在UE4中为180个虚幻单位。这样做个人愚见是为了提高浮点值&#xff08;float…

android Handler的使用(一)

Handler的使用(一) Handler基本概念&#xff1a; Handler主要用于异步消息的处理&#xff1a;当发出一个消息之后&#xff0c;首先进入一个消息队列&#xff0c;发送消息的函数即刻返回&#xff0c;而另外一个部分逐个的在消息队列中将消息取出&#xff0c;然后对消息进行出来…

php和python的多线程,Python多线程以及线程锁简单理解(代码)

本篇文章给大家带来的内容是关于Python多线程以及线程锁简单理解(代码)&#xff0c;有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你有所帮助。多线程threading 模块创建线程创建自己的线程类线程通信线程同步互斥方法线程锁需要了解&#xff01;&a…

现实地形导入UE4全流程

制作地形方法很多&#xff0c;今天给大家分享一种原创野套路。此方法特点是将现实中的地形于UE4中呈现&#xff0c;而不是手动绘制地形。首先从地理空间数据云获得指定区域的地理数据&#xff0c;然后使用GlobalMapper更准确选出区域并把数据转换成WorldMachine可识别的格式&am…

php对象存储hadoop存储,三个理由告诉你对象存储替换HDFS还不错

Hadoop使企业能够对庞大的非结构化数据集进行大规模分析处理。这个数据集可以包含数以百万计&#xff0c;甚至数十亿个需要读取的文件。为了降低成本并提高数据处理性能&#xff0c;数据和应用程序应该存在于相同的物理硬件上。这样做使数据无需移动&#xff0c;就地处理&#…

Web请求中同步与异步的区别

普通的B/S模式就是同步&#xff0c;而AJAX技术就是异步&#xff0c;当然XMLHttpReques有同步的选项。 同步&#xff1a;提交请求->等待服务器处理->处理完毕返回。这个期间客户端浏览器不能干任何事。 异步: 请求通过事件触发->服务器处理&#xff08;这是浏览器仍然可…

大地形pawn抖动问题

在pawn的event tick里调用下面函数即可

php蓝牙连接不上,蓝牙音响连接不上手机怎么办 两种方法轻松解决连接问题

我们听歌一般用耳机和音响。现在蓝牙音频越来越普及&#xff0c;但毕竟是无线产品。信号不时中断或不连接是正常的。蓝牙音频连不上手机真的很头疼。出现这种情况的原因是什么&#xff0c;如何解决&#xff1f;为什么蓝牙音频不能连接到手机1.蓝牙音频没有进入匹配状态&#xf…

Bootstrap页面布局16 - BS导航菜单和其响应式布局以及导航中的下拉菜单

代码&#xff1a; <div classcontainer-fluid><h2 classpage-header>导航</h2><!--    .navrbar navbar-fixed-top:导航固定显示在顶部&#xff0c;对应的navbar-fixed-bottom:导航固定显示在页面底部    .brand:提示文字或者主题    .active…

HMI使用自定义控件流程

1.定义控件ID号&#xff0c;以FO_COMP_CUSTOM为基数#define SCENEENTITY_SIMULATOR_SHAPEFO_COMP_CUSTOM 2102.编写控件类&#xff0c;并继承于CFOBitmapShape 具体实现可以在程序中找例子&#xff0c;重新OnDraw3d这个虚函数来实现控件的绘制3. 在MainFrm.cpp中&#xff0c;在…

nginx 怎么重新编译安装mysql,centos 下 编译安装 nginx + mysql + php 服务

centos 下编译安装nginx mysql php 服务1、安装nginx1.1、安装依赖包yum install wget make gcc gcc-c pcre-devel openssl-devel -y yum install ncurses-devel libtool zilib-devel -y1.2、创建www用户useradd www -s /sbin/nologin -M1.3、创建目录mkdir -p /var/log/ngin…

hdu 1874(Dijkstra + Floyd)

链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1874 畅通工程续 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 27692 Accepted Submission(s): 10019 Problem Description某省自从实行了很多年…

php原生session,利用Memcached在php下实现session机制 替换PHP的原生session支持

方法文件session实现文件:memcachedsession.php实现原理(也是PHP内部session的实现原理)&#xff1a;1.先判断客户端有没有sessionid&#xff0c;a.没有就添加一个sessionid给客户端&#xff0c;通常是32位hash码&#xff0c;同时初始化一个数组做session容器b.如果客户端有ses…

Web 开发中很实用的10个效果【附源码下载】

在工作中&#xff0c;我们可能会用到各种交互效果。而这些效果在平常翻看文章的时候碰到很多&#xff0c;但是一时半会又想不起来在哪&#xff0c;所以养成知识整理的习惯是很有必要的。这篇文章给大家推荐10个在 Web 开发中很有用的效果&#xff0c;记得收藏&#xff01; 超炫…