荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: cooler (星光璀璨心依然), 信区: Program
标  题: [转载] [转寄] VC 和 MFC 的一些常见问题               pqf
发信站: BBS 荔园晨风站 (Thu Mar 23 15:51:59 2000), 转信

【 以下文字转载自 cooler 的信箱 】
【 原文由 cooler.bbs@melon.gznet.edu.cn 所发表 】
发信人: Javascript (Java), 信区: VisualC
标  题: VC 和 MFC 的一些常见问题
发信站: 华南网木棉站 (Sat Feb 12 20:43:50 2000), 转信


      VC 和 MFC 的一些常见问题
       Microsoft Corporation
    版本5.0,97年5月15日
    如何抛出(throw)由CUserException派生的异常?
    当我试图捕获(catch)一个派生类异常时,我得到以下错误"error
    C2039:'classCMyException': is not a member of 'CMyException'
    'classCMyException': undeclared identifier 'IsKindOf': cannot
    convert parameter 1 from 'int*' to 'const struct CRuntimeClass*"
    你必需通过使用DECLARE_DYNAMIC()和IMPLEMENT_DYNAMIC()宏来使你的
    CMyException类可以动态地创建。CATCH宏希望能够得到关于被抛出类的运行
    时刻信息。
    异常类一定要从CUserException中派生出来吗?
    不,CUserException中的"User"仅仅指用户产生的异常。而把它当作你所能
    派生的唯一异常是种常见的误解。
    如何从HDC建立一个CDC类?
    有时Windows API将会给你一个DC句柄,你可以通过它建立一个CDC类。例
    如:下拉式列表、组合框和按钮。通过hDC你将接收到绘制消息。下面是将
    HDC转换成你更熟悉的CDC的程序段。你也可以将该技巧用在其他任何MFC类和
    Windows句柄的转换中。
    void MyODList::DrawItem(LPDRAWITEMSTRUCT lpDrawItem)
    {
        CDC myDC;
        myDC.Attach(lpDrawItem->hDC);
        //在此插入其他需要的代码。
        //如果你不将句柄分离,它将被删除,从而导致问题。
        myDC.Detach();
    }
    另一个方法是调用CDC类的FromHandle方法:
                CDC * pDC = CDC:FromHandle(lpDrawItem->hDC);
    目前还不清楚哪种方法更优越?使用FromHandle()的错误也许会更少些,因
    为它不要求你分离(detach)句柄。
    如何从磁盘上读取256色位图文件?
    当前,MFC并不支持直接读取和显示DIB文件和BMP文件。然而,有很多样例应
    用程序能够说明如何完成该项任务。 第一个例子是MFC样例程序DIBLOOK。样
    例MULTDOCS用DIBLOOK提供的相同源代码来读取并显示DIB文件和BMP文件。其
    他两个VC++中附带的例子是SDK软件包中的DIBVIEW程序和SHOWDIB程序。
    如何改变一个视图的大小?
    通常,你可以调用函数MoveWindow()来改变窗口的大小。在用MFC库开发的
    应用程序中, 视图是被框架窗口所围绕的一个子窗口。为了改变一个视图的
    大小,你可以通过调用函数GetParentFrame()来得到框架窗口的指针,然后
    调用函数MoveWindow()来改变父窗口的大小。当父框架窗口改变大小时,视
    图也会自动地改变大小来适应父窗口。
    如何改变一个CFormView的大小?
    要想详细了解的话,你可以看有关Visual C++基础知识的文章Q98598
     《Using CFormView in SDI and MDI Applications》。基本上,在从
    CFormView类派生出来的类中,你必须覆盖函数OnInitialUpdate()。其他有
    关建立CFormView的细节问题,可以从该文章中获得。
    在类ClikethisView中声明如下函数:
      virtual void OnInitialUpdate();
    在ClikethisView的代码中,函数如下:
      void ClikethisView::OnInitialUpdate()
      {
          //使窗口与主对话框同样大小
          CFormView::OnInitialUpdate();
          GetParentFrame()->RecalcLayout();
          ResizeParentToFit( /*FALSE*/ );
      }
    如何使用一个文档模板的新视图?
    在用AppWizard创建的应用程序中,你有两种选择:改变当前视图的派生关系
    或者建立一个新视图并且在你的MDI程序中同时利用新视图和原先的视图。
    为了创建一个新视图,你可以用ClassWizard由CView派生一个新的类。当新
    类创建以后,利用新视图或修改由AppWizard提供的视图,两者的步骤是相同
    的。
    修改视类的头文件,从而将所有对CView类的引用改名为你所想要的名称。本
    例中的类由CScrollView派生而来。通常,这个步骤包括对类的改变,视类将
    由如下方式派生而来:
        class CMyView : public CScrollView
    修改视类的实现文件,从而将所有对CView的引用改名为你所想要的名称。这
    包括将IMPLEMENT_DYNCREATE那一行的语句改为:
        IMPLEMENT_DYNCREATE(CMyView, CScrollView)
    将BEGIN_MESSAGE_MAP那一行的语句改为:
        BEGIN_MESSAGE_MAP(CMyView, CScrollView)
    并且将其他所有的CView改成CScrollView.
    假如你修改的视图是由AppWizard生成的,那么就不需要作更多的修改了。而
    如果你在创建一个新视图,先在CWinApp::InitInstance()函数中找到对
    AddDocTemplate()函数的调用。AddDocTemplate()函数的第三个参数是
    RUNTIME_CLASS(CSomeView),用CMyView来代替CSomeView,就可以将当前视
    图改为新视图。在MDI应用程序中,你可以增加第二个AddDocTemplate()函数
    调用来使用多视图类型,将RUNTIME_CLASS(CSomeView)改为RUNTIME_CLASS
    (CMyView)。
    要想获得更多的信息请参阅Q99562中相关文章《Switching Views in a
    Single Document Interface Program》 。
    如何改变视图的背景色?
    你可以通过处理WM_ERASEBKGND消息来改变CView、CFrameWnd或CWnd对象的背
    景色。请看如下的程序段:
      BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
      {
          // 设置所要求背景色的刷子
          CBrush backBrush(RGB(255, 128, 128));
          // 保存旧刷子
          CBrush* pOldBrush = pDC->SelectObject(&backBrush);
          CRect rect;
          pDC->GetClipBox(&rect);     // 擦除所需的区域
          pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATC
OPY);
          pDC->SelectObject(pOldBrush);
          return TRUE;
      }
    而我则用如下方法解决这个问题:
      HBRUSH dlgtest::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
      {
          switch (nCtlColor)
          {
              case CTLCOLOR_BTN:
              case CTLCOLOR_STATIC:
              {
                  pDC->SetBkMode(TRANSPARENT);
              }
              case CTLCOLOR_DLG:
              {
                  CBrush*     back_brush;
                  COLORREF    color;
                  color = (COLORREF) GetSysColor(COLOR_BTNFACE);
                  back_brush = new CBrush(color);
                  return (HBRUSH) (back_brush->m_hObject);
              }
          }
          return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
      }
    如何得到当前视图?
    最佳方法是将视图当作一个参数来传递。如果不能这样做,但你确信它是当
    前激活文档和当前激活视图的话,你也可以得到该视图。具体细节见Visual
    C++文章Q108587《Get Current CDocument or CView from Anywhere》。
    简单说来,用:
          ((CFrameWnd*) AfxGetApp()->m_pMainWnd))->GetActiveDocument()
    和:
          ((CFrameWnd*)(AfxGetApp()->m_pMainWnd))->GetActiveView()
    来得到文档和视图。一个好的方法是将它们封装在你的CMyDoc和CMyView类的
    静态函数中,并且核对它们是否属于正确的RUNTIME_CLASS。然而,假如这个
    视图不是当前激活视图或者你在运行OLE本地激活,这样将不成功。
    如何在一个文档中建立多个视图?
    CDocTemplate::CreateNewFrame()函数创建MFC MDI应用程序中的文档的附加
    视图。为了调用该函数,要指定一个指向CDocument对象(指将为之建立视图
    的文档)的指针和一个指向可从中复制属性的框架窗口的指针。一般情形
    下,该函数的第二个参数为NULL。
    当应用程序调用函数CreateNewFrame()时,该函数就创建一个框架窗口和在
    该窗口内的视图。框架窗口和它的视图的类型由与CreateNewFrame()函数调
    用指定的文档相关的文档摸板(CDocTemplate)决定。
    Visual C++中的CHKBOOK MFC样例程序也演示了如何为文档建立附加的框架和
    视图。检查CHKBOOK.CPP文件中的CChkBookApp::OpenDocumentfile()函数。
    另一个用函数CreateNewFrame()的例子是MULTVIEW样本程序。
    CreateNewFrame()函数建立了一个框架和一个视图,而不仅仅是一个视图。
    假如CreateNewFrame()函数不能完全符合你的需要,可参考
    CreateNewFrame()函数的源程序来了解对建立结构和视图所必须的步骤。
    如何在MDI程序中得到所有的视图?
    你必须用一些文档中没有记载的函数:
      CDocument::GetFirstViewPosition(); // DOCCORE.CPP
      CDocument::GetNextView(); // DOCCORE.CPP
      CMultiDocTemplate::GetFirstDocPosition(); // DOCMULTI.CPP
      CMultiDocTemplate::GetNextDoc(); // DOCMULTI.CPP
    你还需要与CWinApp的成员m_templateList打交道。
    注意:在MFC 版本4.0中已改变。现在已经有一个叫CDocManager的类可以帮
    助你显示所有的视图和文档。请参考《MFC Internals》获得更详细的信息。
    如何建立一个可用鼠标拉动的CScrollView类
    在CIS上从MSMFC库下载AUTOSV.LZH。这个程序告诉你如何实现一个辅助消息
    循环来管理鼠标的活动,并提供了钩挂来对代码进行定制。这是一个免费软
    件。
    一定要用视图/文档结构吗?
    MFC并不一定要求你使用文档/视图结构。查看HELLO、 MDI和HELLOAPP例子?
    它们就没有用那种结构。大多数MFC特性都可以在非文档/视图应用程序中得
    到运用。但是当你不用文档 / 视图结构时,你确实会失去一些特性,例如打
    印预览和许多OLE特性。
    如何得到当前文档?
    请详细参阅"如何得到当前视图?"章节。
    文档何时被析构?
    在SDI程序中,程序退出后文档就被删除。在MDI程序中,与该文档相关的最
    后一个视图关闭时文档就被删除。为了在SDI和MDI中同时用这个文档,你应
    该在虚函数DeleteContents()函数中删除该文档的数据,而不是在析构器
    中。
    如何建立多文档?
    为了加入对附加文档类型的支持,你可以在CWinApp派生类中创建和注册附加
    CmultiDocTemplate对象。这种方法已经在MULTDOCS样例程序中得以说明。将
    一个附加文档类型加入到MFC程序的一般步骤如下:
    用AppWizard来创建一个新的文档类和视图类。
    用资源编辑器增加新的资源字串来支持新的文档类。要想知道关于文档样板
    字符串格式的更多内容,请参阅"如何理解文档样板字符串"。
    用资源编辑器增加附加的应用程序图标和菜单资源。注意,这些资源中每一
    个的ID都必须与在步骤2中创建的文档模板字符串的ID是相同的。这个ID被
    CmultiDocTemplate类用来识别与附加文档类型相关的资源。
    在应用程序的InitInstance()函数中,创建了另一个CMultiDocTemplate对
    象并且用CWinApp::AddDocTemplate()函数来注册。例如:
    CMultiDocTemplate* pDocTemplate2 = new CMultiDocTemplate(
      IDR_DOC2TYPE, RUNTIME_CLASS(CDoc2),
      RUNTIME_CLASS(CMDIChildWnd),RUNTIME_CLASS(CView2));
      AddDocTemplate(pDocTemplate2);
    最后,将定制的序列化和绘图代码加入到你的新文档和视图类中。
    如何得到一个打开文档的列表?
    下面的程序段指明如何得到用CDocTemplate对象建立的所有文档的指针列
    表。
    下面的程序段中,CMyApp由CWinApp派生而来。变量m_templateList是一个
    CPtrList对象,它是CwinApp的成员变量,包含一个所有文档模板指针的列
    表。文档模板函数GetFirstDocPosition()和GetNextDoc()被用来在文档模板
    列表中进行迭代来得到每一个文档模板。
      void CMyApp::GetDocumentList(CObList * pDocList)
      {
          ASSERT(pDocList->IsEmpty());
          POSITION pos = m_templateList.GetHeadPosition();
          while (pos)
          {
              CDocTemplate* pTemplate =
                  (CDocTemplate*)m_templateList.GetNext(pos);
              POSITION pos2 = pTemplate->GetFirstDocPosition();
              while (pos2)
              {
                  CDocument * pDocument;
                  if ((pDocument=pTemplate->GetNextDoc(pos2)) != NULL)
                      pDocList->AddHead(pDocument);
              }
          }
      }
    在参考手册或在线帮助中,有两个CdocTemplate类的公共成员函数没有被说
    明。然而, 这些公共成员函数在CDocTemplate类中被定义,并且为在打开文
    档的列表中前后搜索提供了简单的支持。
    这些函数如下:
    Function virtual POSITION GetFirstDocPosition() const;
    调用该函数得到在打开的文档列表中与模板相关联的第一个文档的位置。返
    回的POSITION的值能够被GetNextDoc成员函数反复使用。
    Function Virtual CDocument* GetNextDoc(POSITION& rPosition) const;
    rPostion是前面调用GetNextDoc 或GetFirstDocPosition成员函数返回的
    POSITION值。这个值不能是NULL。调用该函数来在所有打开的文档中进行迭
    代。该函数返回被rPosition所标识的文档并将rPosition设置为列表中的下
    一个文档的POSITION值。假如所检索的是列表中的最后一个文档,rPosition
    将被设为空值。
    注意,这仅对MFC3.2版本或更低版本有效,对MFC4.0版本请参考下面:
      void CMyApp::DoSomethingToAllDocs()
      {
          CObList  pDocList;
          POSITION pos = GetFirstDocTemplatePosition();
          while(pos)
          {
              CDocTemplate* pTemplate = GetNextDocTemplate(pos);
              POSITION pos2 = pTemplate->GetFirstDocPosition();
              while(pos2)
              {
                  CDocument* pDocument;
                  if(pDocument = pTemplate->GetNextDoc(pos2))
                      pDocList.AddHead(pDocument);
              }
          }
          if(!pDocList.IsEmpty()){
              pos = pDocList.GetHeadPosition();
          while(pos)
          {
              //为每一个文档调用CDocument函数
              ( (CDocument*)pDocList.GetNext(pos) )
                  ->UpdateAllViews(NULL);
          }
      }
    如何使我的程序在启动时不创建一个新文档?
    在程序的InitInstance中的ProcessShellCommand函数之前加入:
    cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing
    (C)1999 Microsoft Corporation 版权所有。保留所有权利。使用规定。

--
※ 来源:.华南网木棉站 bbs.gznet.edu.cn.[FROM: 202.38.248.177]
--
※ 转寄:.华南网木棉站 bbs.gznet.edu.cn.[FROM: 深大荔园晨风转站]
--
※ 转载:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.28.248]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店