MFC项目开发方法和技巧总结(适合初级编程人员)

来源:互联网 发布:office 2013 优化版 编辑:程序博客网 时间:2024/06/06 01:54

在过去的两个月中,我和老师一起开发了一个编辑编译器,主要是参加省“挑战杯”比赛,当时我只有两个星期的MFC经验,很多地方都不会做,到处找代码,看文章,十分辛苦。好在网上资源还比较丰富,非常感谢  csdn pudn 两个网站。在此我把我学习和总结的MFC经验分享给大家,以供参考学习。

首先还是谈一下看技巧和方法这类文章的感受:

1.学习MFC一定要有点基础,要入门。你这少要到图书馆去看过、浏览过一两本书籍,我学习是看的孙鑫的视频,到图书馆看了本《Windows编程》很基础的书籍。

2.看别人的例子,然后自己动手做,想明白,是初学者很好的方式。

2.在没有掌握MFC平台的特性时,技巧和方法很重要,这个时候算法根本帮不上忙,多积累点经验也很好;但是编程序越到后来越是对一些理论的理解,像类、消息、继承等等概念的理解尤为重要,千万不能光学技巧,而不懂理论,不去学习像C++这些基础语言.

以上是我的一点感受,如果跟你的意见相反,那么仅作参考。

下面列举我积累的一些MFC开发技巧和方法,供大家学习参考.这些代码基本上都是我亲自做过的,已经验证了无误的,如有错误,请您更正。图片由于涉及的程序太多,我一时也无法上传齐,仅上传了3张。

 内容列表:

1.热键的使用:

2.将时间添加到状态栏

3.实现MFC中的鼠标事件,使其进入某个区域后显示一个浮动窗口,移出鼠标后再隐藏

4  模态和非模态对话框

5.对话框控件的着色

6.CEdit控件使用

7.如何禁用窗口关闭按钮

8.菜单操作

9.树形控件操作

10 使用字体颜色对话框获取字体和颜色信息

11.多文档的一些操作

12.ScrollView 滚动设置问题

13. POSITION变量

14. 字符串的拆分

15. 利用CTabCtrl 实现切换对话框的属性页效果

16.利用CPropertySheet 实现属性页效果

详细内容:

1.热键的使用:
方法一: (推荐使用此方法)
在MFC 中实现快捷键或者热键 需要将已经定义了命令相应的菜单ID 填入定义的热键 
即首先为工具栏或者菜单栏中中相应的ID添加命令响应函数 然后在资源中引入accelerator 并添加热键定义和填入相应的菜单ID号     这样热键的响应即和菜单的响应产生同样的效果
方法二:
//使用判断Ctrl键按下的宏:
#define IsCTRLPressed()  ((GetKeyState(VK_CONTROL) & (1<<(sizeof(SHORT)*8-1))) != 0)
//在PreTranslateMessage函数中作如下处理:
BOOL CAccelerator1Dlg::PreTranslateMessage(MSG* pMsg) 
{
 // TODO: Add your specialized code here and/or call the base class
 //用PreTranslateMessage的方法,判断Ctrl+Q是否按下,按下就执行快捷键对应的操作
 if(pMsg->message == WM_KEYDOWN && pMsg->wParam == 'Q' && IsCTRLPressed())
 {
  AfxMessageBox("Ctrl + Q 被按下");
  return TRUE;
 }
 
 return CDialog::PreTranslateMessage(pMsg);
}
方法三: (这个有点麻烦 不建议使用 仅做参考)
添加变量:HACCEL hAcc;
CAccelerator2Dlg::CAccelerator2Dlg(CWnd* pParent /*=NULL*/)
 : CDialog(CAccelerator2Dlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CAccelerator2Dlg)
  // NOTE: the ClassWizard will add member initialization here
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 hAcc = LoadAccelerators(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
}
添加消息响应:
afx_msg void OnCtrlQ();
ON_BN_CLICKED(IDC_CTRLQ, OnCtrlQ)
BOOL CAccelerator2Dlg::PreTranslateMessage(MSG* pMsg) 
{
 // TODO: Add your specialized code here and/or call the base class
 int iResult;
 //针对WM_KEYDOWN消息和WM_SYSKEYDOWN消息,翻译快捷键
 switch(pMsg->message)
 {
 case WM_KEYDOWN:
 case WM_SYSKEYDOWN:
  iResult = TranslateAccelerator(m_hWnd,hAcc,pMsg);
  //翻译快捷键成功,返回TRUE
  if(iResult)
   return TRUE;
 }
 return CDialog::PreTranslateMessage(pMsg);
}
添加响应函数:
void CAccelerator2Dlg::OnCtrlQ() 
{
 // TODO: Add your control notification handler code here
 AfxMessageBox("你按下了定义的快捷键"); 
}
2.将时间添加到状态栏
1)在字符串列表中添加 ID_INDICATOR_TIME 时间
2)在indicators指示器的将添加的ID_INDICATOR_TIME加入到指示器数组中
static UINT indicators[] =
{
ID_SEPARATOR,           // 状态行指示器
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
ID_INDICATOR_TIME
};
3)添加时间
添加SetTimer(1,1000,0)和OnTimer函数,Ontimer函数代码如下:

        void CMainFrame::OnTimer(UINT nIDEvent) 
{
    int nIndex=m_wndStatusBar.CommandToIndex(ID_INDICATOR_TIME);
 CTime time = CTime::GetCurrentTime();
     CString strText;
     strText=time.Format("%H:%M:%S");
 CWindowDC dc(&m_wndStatusBar);
 m_wndStatusBar.SetPaneText(nIndex,strText);
 CSize sizeText=dc.GetTextExtent(strText);//根据当前字体 获取显示内容的宽度和高度
 m_wndStatusBar.SetPaneInfo(nIndex,ID_INDICATOR_TIME,SBPS_POPOUT,sizeText.cx); //根据显示内容的宽度来显示时钟
 CMDIFrameWnd::OnTimer(nIDEvent);
}
3.实现MFC中的鼠标事件,使其进入某个区域后显示一个浮动窗口,移出鼠标后再隐藏
1)MainFrame 中添加
void CMainFrame::OnShowLeftBar() 
{
 ShowControlBar(&m_wndMyBar1, !m_wndMyBar1.IsVisible(), FALSE);
}
void CMainFrame::OnHideLeftBar() 
{
 ShowControlBar(&m_wndMyBar1, FALSE, TRUE);
}
2)CBarDemoView视图类中添加
BOOL CBarDemoView::PreTranslateMessage(MSG* pMsg) 
{
 // TODO: Add your specialized code here and/or call the base class
 CMainFrame *pMain=(CMainFrame *)AfxGetApp()->m_pMainWnd;
 if (pMsg->message == WM_MOUSEMOVE)
 {
  if (pMsg->pt.x>1000)//1000时鼠标横坐标的范围 你可以自己定
   pMain->OnShowLeftBar();
  else
   pMain->OnHideLeftBar();
 }
 return CView::PreTranslateMessage(pMsg);
}
或者当成员变量m_wndMyBar1为公有时, 也可以
if (pMsg->message == WM_MOUSEMOVE)
 {
  if (pMsg->pt.x>1000)
   
   pMain->ShowControlBar(&pMain->m_wndMyBar1, TRUE, FALSE);
  else
   pMain->ShowControlBar(&pMain->m_wndMyBar1, FALSE, FALSE);
 }
4  模态和非模态对话框
void CCreateDialogDlg::OnModel() 
{
 // TODO: Add your control notification handler code here
 //Add code
 CString str = "模式对话框";
 //新建CBuildDialog类的对象
 CBuildDialog pNewDialog;
 //在对话框中输出文本"模式对话框"
 pNewDialog.pType.Format("%s", str);
 //生成模式对话框
 pNewDialog.DoModal();
}

void CCreateDialogDlg::OnModeless() 
{
 // TODO: Add your control notification handler code here
 //Add code
 CString str = "非模式对话框";
 //定义指针变量
 CBuildDialog* pNewDialog;
 //为指针分配内存
 pNewDialog=new CBuildDialog();
 //在对话框中输出文本"模式对话框"
 pNewDialog->pType.Format("%s", str);
 //生成非模式对话框
 pNewDialog->Create(IDD_NEWDIALOG);
 //显示非模式对话框
 pNewDialog->ShowWindow(SW_RESTORE);
}
5.对话框控件的着色
ON_WM_CTLCOLOR()
  APPWizard添加的WM_CTLCOLOR消息响应
 afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
在函数中添加代码:
HBRUSH CNoRegularDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
 HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
 
 // TODO: Change any attributes of the DC here 
 pDC->SetBkMode(TRANSPARENT);
 pDC->SetTextColor(RGB(0, 0, 255)); 
 // TODO: Return a different brush if the default is not desired
 return hbr;
}
6.CEdit控件使用
1)CEdit 控件的追加字符
void CEditView_ReadView::ShowInfo(CString info)
{  
   CString AppendInfo;
   CEdit& theEdit = GetEditCtrl();
   int   nLength=theEdit.SendMessage(WM_GETTEXTLENGTH);     
   theEdit.SetSel(nLength,nLength); 
   AppendInfo="/r/n";
   AppendInfo+=info;
   theEdit.ReplaceSel(AppendInfo); 
   theEdit.LineScroll(theEdit.GetLineCount());//滚动到尾行

}
随输入自动滚动到最后一行(richedit同样适用)

    方法一:(摘自msdn)
        // The pointer to my edit.
        extern CEdit* pmyEdit;
        int nFirstVisible = pmyEdit->GetFirstVisibleLine();

        // Scroll the edit control so that the first visible line
        // is the first line of text.
        if (nFirstVisible > 0)
        {
            pmyEdit->LineScroll(-nFirstVisible, 0);
        }
    方法二:
        m_richedit.PostMessage(WM_VSCROLL, SB_BOTTOM, 0);
2)CEdit 清空字符
Delete all of the text.
pmyEdit->SetSel(0, -1);
pmyEdit->Clear();
7.如何禁用窗口关闭按钮(也可参照下面的菜单操作中的相同主题)
在一个 MFC 多文档界面 (MDI) 应用程序 在某些情况下可以防止用户单击关闭按钮以关闭 MFC 应用程序中的框架窗口的窗口的标题栏中。 关闭按钮可以删除删除在 WS_SYSMENU 样式从帧窗

口。 但是,此的 Minimize 最大化,和还原按钮也删除,并且无法添加。 这是 Windows 的设计的依据。

要解决此限制,可以通过禁用关闭按钮来模拟没有关闭按钮在窗口的功能。 在 WM_CREATE 消息处理程序中的 MDI 子框架窗口 (CMDIChildWnd 派生类) 禁用在关闭按钮使用下面的代码:

CMenu *pSysMenu = GetSystemMenu(FALSE);
ASSERT(pSysMenu != NULL);
VERIFY(pSysMenu->RemoveMenu(SC_CLOSE, MF_BYCOMMAND));
子框架窗口未处于最大化时, 以上代码禁止用户通过单击关闭按钮关闭子框架窗口。 当子框架窗口最大化时以上代码将使显示禁用关闭按钮。 但是,用户仍然可以通过单击此窗口关闭按钮

关闭子框架窗口。 可以通过它发送到子框架窗口时捕获 SC_CLOSE 命令并阻止此命令的进一步处理阻止这。 为此这一点,请使用 WM_SYSCOMMAND 消息处理程序为下面的示例中的子框架的类

// CChildFrame is a CMDIChildWnd-derived class.
void CChildFrame::OnSysCommand(UINT nID, LPARAM lParam)
{
    if(nID == SC_CLOSE)
        return;
    CMDIChildWnd::OnSysCommand(nID, lParam);
}
注意这里添加WM_SYSCOMMAND 时要把ChildFrame切换到Windows选项中才能看到该消息.
8.菜单操作
1)动态加载菜单
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point) 
{
 // TODO: Add your message handler code here and/or call default
 CMenu menu;
 menu.LoadMenu(IDR_MENUPOP);
 CMenu *PopMenu=menu.GetSubMenu(0);//弹出菜单只有一个子菜单,并且顶级菜单不弹出
 ClientToScreen(&point);
 PopMenu->TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON,point.x+20,point.y+20,GetParent());
 CView::OnRButtonDown(nFlags, point);
}
2)动态插入 创建菜单
CMenu Menu;
 Menu.CreatePopupMenu();//注意添加子菜单与添加菜单 添加菜单和插入菜单的的区别
 GetMenu()->AppendMenu(MF_POPUP,UINT(Menu.m_hMenu),"Juber(J)");//UINT 无符号整型(unsigned int)
 //GetMenu()->InsertMenu(1,MF_BYPOSITION|MF_POPUP,UINT(Menu.m_hMenu),"动态添加(T)");
 //GetMenu()->InsertMenu(1,MF_BYPOSITION|MF_POPUP,0,"InsertTest(T)");这条指令有区别
 Menu.AppendMenu(MF_STRING,IDM_WELCOME,"欢迎");//在resource中利用宏定义标识号,并添加响应函数
 Menu.AppendMenu(MF_STRING,111,"你好");
 Menu.AppendMenu(MF_STRING,112,"吗?");//定义的Menu子菜单整体先添加到了菜单上上可以添加菜单项,不用再用指针了
    GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,"新增菜单");
 GetMenu()->GetSubMenu(0)->InsertMenu(1,MF_BYPOSITION|MF_STRING,115,"插入菜单");
 GetMenu()->DeleteMenu(2,MF_BYPOSITION);
    GetMenu()->GetSubMenu(3)->DeleteMenu(0,MF_BYPOSITION);
 GetMenu()->GetSubMenu(1)->DeleteMenu(2,MF_BYPOSITION);
 Menu.Detach( );
3)使菜单无效
有ON_UPDATE_COMMAND_UI or ON_COMMAND 时用pCui->Enable;
没有时需要MainFrame构造函数中加上 m_bAutoMenuEnable  = FALSE
CMenu* mmenu = GetMenu();
CMenu* submenu = mmenu->GetSubMenu(0);
submenu->EnableMenuItem(ID_FILE_NEW, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
4)禁止对话框中的关闭按钮有二种方法。
第一种方法,用ModiftMenu()涵数来实现:

CMenu* pMenu = this->GetSystemMenu(FALSE);
pMenu->ModifyMenu(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED );

第二种方法,用EnableMenuItem()涵数来实现:

CMenu* pMenu = this->GetSystemMenu(FALSE);
pMenu->EnableMenuItem( SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
恢复关闭按钮
CMenu* pMenu = this->GetSystemMenu(FALSE);
pMenu->EnableMenuItem( SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
9.树形控件操作
1)生成结点与加载图标
BOOL CTreeCtrl2Dlg::OnInitDialog()
{
 CDialog::OnInitDialog();

 // Add "About..." menu item to system menu.

 // IDM_ABOUTBOX must be in the system command range.
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);

 CMenu* pSysMenu = GetSystemMenu(FALSE);
 if (pSysMenu != NULL)
 {
  CString strAboutMenu;
  strAboutMenu.LoadString(IDS_ABOUTBOX);
  if (!strAboutMenu.IsEmpty())
  {
   pSysMenu->AppendMenu(MF_SEPARATOR);
   pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  }
 }

 // Set the icon for this dialog.  The framework does this automatically
 //  when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE);   // Set big icon
 SetIcon(m_hIcon, FALSE);  // Set small icon
 
 // TODO: Add extra initialization here
 //以上代码均为自动生成的代码 只是为了方便阅读二列出
 //节点的图标  
 int i=0;
 int i_count=2;
 //载入图标
 HICON icon[4];
 icon[0]=AfxGetApp()->LoadIcon (IDI_ICON1); 
 icon[1]=AfxGetApp()->LoadIcon (IDI_ICON2);
 //创建图像列表控件
 CImageList *m_imagelist=new CImageList; 
 m_imagelist->Create(16,16,0,7,7); 
 m_imagelist->SetBkColor (RGB(255,255,255));
 for(int n=0;n<i_count;n++)
 {
  m_imagelist->Add(icon[n]);  //把图标载入图像列表控件
 }
 m_ctrlTree.SetImageList(m_imagelist,TVSIL_NORMAL);  //为m_mytree设置一个图像列表,使m_ctrlTree的节点显示不同的图标
 m_ctrlTree.SetTextColor(RGB(0,0,255));
 m_ctrlTree.SetBkColor(RGB(236,233,216));
 //添加项目
 HTREEITEM  Specifics;
 CString str[2]={"年级查询","性别查询"};
     for(i=0;i<2;i++)
  hRootItem[i]=m_ctrlTree.InsertItem(str[i],TVI_ROOT);
 Specifics=m_ctrlTree.InsertItem("大一",0,1,hRootItem[0]);//在根结点上添加大一,选中时显示图标1,未选中时显示图标0
 m_ctrlTree.SetItemData(Specifics,DWORD(0));
 Specifics=m_ctrlTree.InsertItem("大二",0,1,hRootItem[0]);
 m_ctrlTree.SetItemData(Specifics,DWORD(1));
 Specifics=m_ctrlTree.InsertItem("大三",0,1,hRootItem[0]);
 m_ctrlTree.SetItemData(Specifics,DWORD(2));
 Specifics=m_ctrlTree.InsertItem("大四",0,1,hRootItem[0]);
 m_ctrlTree.SetItemData(Specifics,DWORD(3));
 Specifics=m_ctrlTree.InsertItem("男生",0,1,hRootItem[1]);
 m_ctrlTree.SetItemData(Specifics,DWORD(4));
 Specifics=m_ctrlTree.InsertItem("女生",0,1,hRootItem[1]);
 m_ctrlTree.SetItemData(Specifics,DWORD(5));
 //展开结点
 m_ctrlTree.Expand(hRootItem[0],TVE_EXPAND);
 m_ctrlTree.Expand(hRootItem[1],TVE_EXPAND);
 return TRUE;  // return TRUE  unless you set the focus to a control
}
2)为树形控件添加右键菜单
选中树形控件,点击右键,选择为树形控件添加右键单击的事件处理程序,在其中添加菜单代码。
.cpp文件中如下所示:

void CTreeCtrl2Dlg::OnRclickTree(NMHDR* pNMHDR, LRESULT* pResult)
{
 // TODO: Add your control notification handler code here
 CPoint cp;
    GetCursorPos(&cp);
    m_ctrlTree.ScreenToClient(&cp);
    HTREEITEM titem = m_ctrlTree.HitTest(cp, NULL);
 // 以上很关键,保证右键点击的位置是树叶或树枝
 if(titem!=hRootItem[0] && titem!=hRootItem[1])
    {   
  m_ctrlTree.SelectItem(titem);
        m_ctrlTree.ClientToScreen(&cp);
  // 动态创建自定义菜单
        CMenu *pMenu = new CMenu();
        VERIFY(pMenu->CreatePopupMenu());
        pMenu->AppendMenu(MF_STRING,IDR_MENU_VIEWDOC,"查看数据");
  pMenu->TrackPopupMenu(TPM_LEFTALIGN,cp.x,cp.y,this);
        pMenu->DestroyMenu();
        // 可以在此过滤点击树叶或树枝才弹出菜单,我没有限制
 /*****************************也可以加载预定义菜单 二种方法任选一种 
        m_ctrlTree.SelectItem(titem);
        m_ctrlTree.ClientToScreen(&cp);
        CMenu menu;
  menu.LoadMenu(IDR_MENU_TREECTRL);
  CMenu *pContexMenu=menu.GetSubMenu(0);
  pContexMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,cp.x+8,cp.y,this);
  *******************************************************************************/
    }
 *pResult = 0;
}
3)想像资源管理器左边的树一样,鼠标移动到节点上时文字自动加下划线
  Track   Select属性设置为true即可。 即跟踪属性设置为TRUE.
10 使用字体颜色对话框获取字体和颜色信息
1)字体信息
定义变量:CFont m_myfont;
添加菜单响应函数
void CGraphicView::OnFont() 
{
 // TODO: Add your command handler code here
 CFontDialog Dlg;
 if(IDOK==Dlg.DoModal())
 {   
  if(m_myfont.m_hObject )
   m_myfont.DeleteObject();//切断原先的资源联系
  m_myfont.CreateFontIndirect(Dlg.m_cf.lpLogFont );
     m_fontname=Dlg.m_cf.lpLogFont->lfFaceName;
  m_fontwth=Dlg.m_cf.lpLogFont->lfWidth;
  m_fontclr=Dlg.m_cf.rgbColors;
 }
}
保存先前字体的字体对话框
void CSimpleEditView::OnFormatFont()
{
  LOGFONT lf;
 CFont *font=GetEditCtrl().GetFont();
 if(font==NULL)
  { 
    font= new CFont;
    font->CreatePointFont(120,"Fixedsys");
    font->GetLogFont(&lf);
    delete font;
 } 
 else
  font->GetLogFont(&lf);
 CFontDialog cf(&lf);
 if(cf.DoModal()==IDOK)
 {
    m_font.DeleteObject();
    m_font.CreateFontIndirect(&lf);
    SetFont(&m_font);
 }
}
2)颜色信息
定义变量:COLORREF m_clr;
添加菜单响应函数
void CGraphicView::OnColor() 
{
 // TODO: Add your command handler code here
 CColorDialog Dlg;
 Dlg. m_cc.rgbResult=m_clr;
 Dlg.m_cc.Flags|=CC_RGBINIT|CC_FULLOPEN;//完全打开颜色对话框 视需要而定
 if(IDOK==Dlg.DoModal())
  m_clr=Dlg. m_cc.rgbResult;
}
11.多文档的一些操作
1)多文档的一打开只显示一个视图,要求一打开就显示两个视图       
最佳答案 在APP类的Inistance中的return TRUE之前加如下一句就可以了:
pMainFrame->SendMessage(WM_COMMAND, ID_FILE_NEW, 0);
这条命令 也能实现在其他视类或对话框中打开文档。
2)重载打开 、保存、另存为操作
void CSimpleEditView::OnFileOpen()
{
  CDocument *pDoc=GetDocument();
  char szFilters[]="Text Files(*.txt)|*.txt|All Files(*.*)|*.*||";
  CFileDialog fileDlg (TRUE,"txt",NULL,OFN_FILEMUSTEXTIST |OFN_HIDEREADONLY,szFilters,this);
  if(fileDlg.DoMadal()==IDOK)
  {
    pDoc->setPathName(fileDlg.GetFileName());
    pDoc->OnOpenDocument(fileDlg.GetFileName);
  }
}

void CSimpleEditView::OnFileSave()
{
  CDocument *pDoc=GetDocument();
  if(pDoc->GetPathName=="")
  {
 char szFilters[]="Text Files(*.txt)|*.txt|All Files(*.*)|*.*||";
   CFileDialog fileDlg (TRUE,"txt",NULL,OFN_FILEMUSTEXTIST |OFN_HIDEREADONLY,szFilters,this);
   if(fileDlg.DoMadal()==IDOK)
   {
      pDoc->setPathName(fileDlg.GetFileName());
      pDoc->OnSaveDocument(fileDlg.GetFileName);
   }
 }
else
 pDoc->OnSaveDocument(pDoc->getPathName());
}

oid CSimpleEditView::OnFileSave()
{
  CDocument *pDoc=GetDocument();
  if(pDoc->GetPathName=="")
  {
 char szFilters[]="Text Files(*.txt)|*.txt|All Files(*.*)|*.*||";
   CFileDialog fileDlg (TRUE,"txt",NULL,OFN_FILEMUSTEXTIST |OFN_HIDEREADONLY,szFilters,this);
   if(fileDlg.DoMadal()==IDOK)
   {
      pDoc->setPathName(fileDlg.GetFileName());
      pDoc->OnSaveDocument(fileDlg.GetFileName);
   }
 }
else
 pDoc->OnSaveDocument(pDoc->getPathName());
}
3)获得活动视类的操作 (待续)
获得活动视图 要严格区别 SDI程序与MDI程序
否则可能产生奇怪的错误
 诸如First-chance   exception   in   ***.exe:   0xC0000005:   Access   Violation. 的错误.
多文档的情况:
对于MDI程序,由于子窗口才是文档框窗,因此首先要用GetActiveFrame()取得活动子框架窗口,然后通过该子窗口获取活动视图和文档.
方法一:
CMDIChildWnd* pChild=(CMDIChildWnd*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveFrame();
取得活动视图:
CMyView *pView=(CMyView*)pChild->GetActiveView();
取得活动文档:
CMyDocument* pDoc=pChild->GetActiveDocument();
单文档情况:
对于SDI程序,主框架窗口就是文档框窗.
得到视图类的指针.
可以 先得到框架指针,然后调用 GetActiveView 函数指向当前活动视. 
 CMyView *pView;
 pView=(CMyView*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveView(); 

12.ScrollView 滚动设置问题
void CInstrView::OnInitialUpdate() 
{
 CScrollView::OnInitialUpdate();
 
 // TODO: Add your specialized code here and/or call the base class
 GetParent()->SetWindowText(GetDocument()->GetTitle()+" 指令表");//添加标题
 // TODO: calculate the total size of this view
        //方法一:
 CSize sizeTotal;
 sizeTotal.cx = sizeTotal.cy = 800;
 SetScrollSizes(MM_TEXT, sizeTotal);
 /* 方法二:
     //滚动视的总尺寸。cx成员包含了水平分量。cy成员包含了垂直分量。
    //这些尺寸是以逻辑单位表示的。cx和cy都必须大于或等于0。   
    //就是说:当客户窗口小于1200,600的时候滚动条就会出现。
    CSize sizeTotal(1200,600);
    //当鼠标在滚动条的条体上单击时,要在水平和垂直方向上滚动的量。
    //cx中存放水平滚动量,cy成员中存放垂直滚动量。   
    CSize sizePage(300,300);
    //当响应鼠标单击滚动条的滚动箭头时要在水平或垂直方向上滚动的量。
    //cx中存放水平滚动量,cy成员中存放垂直滚动量
    CSize sizeLine(1,1);
    //设置映射模式为MM_TEXT
    SetScrollSizes(MM_TEXT, sizeTotal,sizePage,sizeLine);*/

}
13. POSITION变量
在MFC4.0以前的版本中,POSITION实际上就是一个void指针。在5.0中的定义大概是: 
struct   __POSITION   {   int   unused;   }   ; 
typedef   __POSITION   *   POSITION   ; 
6.0中才变为: 
struct   __POSITION   {     }   ; 
typedef   __POSITION   *   POSITION   ; 
VC在使用CList时,一些函数往往用POSITION参数,
或者返回POSITION类型,其实查看CList的原代码就知道,
原来CList返回的POSITION就是它的链表的一个结点指针,也就是说,在CList里有一个CNode的类定义了结点,而POSITION就是CNode* .
所以说,虽然__POSITION结构体没有任何字段,但用POSITION结构体指针,
仅仅用来表达CNode*指针,并且是强制转换过来的。于是POSITION被VC用为一种常见的数据类型---32位指针。

14. 字符串的拆分
用AfxExtractSubString()解析复合串(hangwire发表于2002-1-4 10:24:46)
    MFC有几个未公开的函数很有用,AfxExtractSubString()就是其中之一。你在MSDN文档里是找不到关于这个函数的说明的,但是你如果研究过MSDN里的例子程序的话,就会发现很多代码

中都使用了这个函数。它的功能简单说来就是从某个用NULL或者换行符"/n"分割的字符串中吸取子串。
这个函数非常很有用,用它可以从串表资源中的子串,还可以从Windows控件(如标准的"File Open"对话框)中解析出特定的字符串,如多选文件名等。
在MFC的AppWizard工程中一般都要创建一个名为IDR_MAINFRAME的串资源,它包含很多有用的信息,如应用程序名、文档类型的名字,或者默认文档类型的文件扩展名--专门用于"File

Open/Save"对话框。下面是一个用AfxExtractSubString()解析信息串的例子:

   CString Fullstring, Appname, Fileext;
   Fullstring.LoadString(IDR_MAINFRAME); 
    //获取完整的分割串
   AfxExtractSubString(Appname, Fullstring, 0, '/n');    
    //析出第一个子串
   AfxExtractSubString(Fileext, Fullstring, 4, '/n');    
    //析出第四个子串

使用这个函数可以避免因为自己写的解析代码而可能出现的错误。
 CString str = "123,456,789";
CString output = "";
for (int i=0; i<3; i++)
{
AfxExtractSubString(output, str, i, ',');
AfxMessageBox(output);
}
参数1:用来存放你取出的子串
参数2:要拆分的整个字符串
参数3:你要取的子字符串位置,从0开始
参数4:特定字符 ( dylan_ding 发表于 2005-2-19 10:58:00)
//实例代码
void CSplitStringDlg::OnBtnSplit() 
{
 // TODO: Add your control notification handler code here
 int i,cnt;
 UpdateData();
 //方法一
 if(m_Sourcestr.IsEmpty())
 {
  MessageBox("原串为空");
     return;
 }
 AfxMessageBox("方法一结果");
 CString output = "";
 //方法一需要指定取出子串的个数
 for (i=0; i<3; i++)
 {
    AfxExtractSubString(output, m_Sourcestr, i, ' ');
    m_Splitstr.AddString(output);
    AfxMessageBox(output);
 }
 //方法二
 AfxMessageBox("方法二结果");
 CStringArray strArr;
 cnt=StrSplit(m_Sourcestr, ' ', strArr);
    for (i=0; i<cnt;i++)
    AfxMessageBox(strArr[i]);
}
//方法二更好 不用指定取出子串的个数
//按指定的分隔符拆分字符串(strin split)2007年08月15日 星期三 下午 08:43//功能: 按指定的分隔符拆分字符串
//参数: const CString& strSourse [in] 要拆分的字符串
//参数: TCHAR    splitChar [in] 分隔符 
//参数: CStringArray& strArr   [out] 拆分结果
//返回: 拆分结果中的元素个数
int CSplitStringDlg::StrSplit(const CString& strSourse, TCHAR splitChar, CStringArray& strArr)
{
 strArr.RemoveAll();
 int nOldPos = 0;
 int nNewPos = 0;
 int nCount   = 0;
 while(0 <= (nNewPos = strSourse.Find(' ', nOldPos)))
 {
    strArr.Add(strSourse.Mid(nOldPos, nNewPos - nOldPos));
    nCount++;
    nOldPos = nNewPos + 1;
 }
 if(strSourse.GetLength()>nOldPos)
 {
    strArr.Add(strSourse.Mid(nOldPos,strSourse.GetLength() - nOldPos));//这是后来添加的功能  能够返回最后一个字符串
    nCount++;
 }
 return nCount;
}
15. 利用CTabCtrl 实现切换对话框的属性页效果
对话框中使用Tab控件的步骤是
1.在对话框中添加Tab控件
2.为各选项卡建立对话框模板资源
3.响应Tab控件的TCN_SELCHANGE消息,在OnSelChange()函数中,用ShowWindow()函数显示欲显示的选项卡,隐藏其他。非模式对话框的生存期问题这里仍然存在,不可忽视
4.初始化Tab控件。可在对话框初始化时手工调用OnSelChange()函数的方法来实现.
1)在主对话框的OnInitDialog()内初始化 :
//初始化m_tab控件   成员变量m_tab 为CTabCtrl类型
    m_tab.InsertItem(0," 兴趣爱好"); 
    m_tab.InsertItem(1," 职业"); 
    //动态创建对话框 并添加到tab控件
 pDialog[0]= new CTest1;
    pDialog[1] = new CTest2;
 pDialog[0]->Create(IDD_DIALOGHOB,GetDlgItem(IDC_TAB));  
    pDialog[1]->Create(IDD_DIALOGJOB,GetDlgItem(IDC_TAB)); 
 pDialog[0]->ShowWindow(SW_SHOW);
 pDialog[1]->ShowWindow(SW_HIDE);
 //设置页面的位置在m_tab控件范围内 并显示对话框  否则tab控件将不可见
 //方法一
 CRect rect;
 m_tab.GetClientRect(&rect);
 rect.top+=20;
 rect.bottom-=4;
 rect.left+=4;
 rect.right-=4;
 pDialog[0]->MoveWindow(&rect);
 pDialog[1]->MoveWindow(&rect);
 //方法二
 /*
 CRect tabRect, itemRect;
 int nX, nY, nXc, nYc;
 m_tab.GetWindowRect(&itemRect);
 ScreenToClient(&itemRect);
 nX  = itemRect.left+1;
 nY  = itemRect.top+20;
 nXc = itemRect.Width()-1;
 nYc = itemRect.Height()-21;
 if(pDialog[0]->SetWindowPos(&wndTop,nX,nY,nXc,nYc, SWP_SHOWWINDOW) == 0)
 {
  DWORD err = GetLastError();
 }
 if(pDialog[1]->SetWindowPos(&wndTop,nX,nY,nXc,nYc, SWP_HIDEWINDOW) == 0)
 {
  DWORD err = GetLastError();
 }
 */
 // TODO: Add extra initialization here
 m_tab.SetCurSel(1);  
2)m_tab控件属性页选择时显示各页:
void CMy3Dlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
int CurSel;  
    CurSel=m_tab.GetCurSel();  
switch(CurSel)  
 {  
 case 0:  
  pDialog[0]->ShowWindow(TRUE); 
  pDialog[1]->ShowWindow(FALSE);   
  break;  
 case 1:  
  pDialog[0]->ShowWindow(FALSE); 
  pDialog[1]->ShowWindow(TRUE);  
  break;  
 default: ;  
 }  
*pResult = 0;
}
注意:
新建的用于选项卡中显示的对话框应设置为没有标题栏、Child风格、无边框的、非模式的。
别忘了在主对话框的头文件中要加 入对应对话框的头文件.
16.利用CPropertySheet 实现属性页效果
1)插入你需要的属性页资源:从菜单中选择插入资源->Dialog->CPropertyPage风格的Large对话框
生成属性页类  class CProp1 : public CPropertyPage  可以插入多个页
2)插入一个类 
class CPropSheet : public CPropertySheet

其头文件中包含 #include "Prop1.h"
#include "Prop2.h"
#include "Prop3.h"
3)在CPropSheet类的构造函数中添加属性页到CPropSheet中  
CPropSheet::CPropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
 :CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
 AddPage(&m_Prop1);
 AddPage(&m_Prop2);
 AddPage(&m_Prop3);
}

CPropSheet::CPropSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
 :CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
 AddPage(&m_Prop1);
 AddPage(&m_Prop2);
 AddPage(&m_Prop3);
}
这样基本实现了属性页功能.

 程序运行部分图片:

 

原创粉丝点击