MFC 窗体大小控制

xiaoxiao2021-02-28  82

窗口 让窗口一启动就最大化   把应用程序类(CxxxApp)的 InitInstance() 函数中的 m_pMainWnd->ShowWindow(SW_SHOW); 改为 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED); 则窗口一启动就最大化显示。  如何设置窗口的初始尺寸  在将应用程序类(CxxAPP)的 InitInstance() 函数中加入: m_pMainWnd->SetWindowPos(NULL,x,y,Width,Height,SWP_NOMOVE); Width为窗口宽度,Height为窗口高度 SWP_NOMOVE表示忽略位置(x,y)  如: 让窗口居中显示  以下两种方法可任选其一:  在应用程序类(CxxxApp)的 InitInstance() 函数中加入: 在主框架类(MainFrm.cpp)OnCreate()函数中加入: CenterWindow( GetDesktopWindow() ); 如:如何修改窗口标题  窗口标题一般形式为:文档标题 - 程序标题  1、设置文档标题:  在文档类(CxxxDoc)OnNewDocument()函数中加入语句:SetTitle("文档名"); 如:TextEditorDoc.cpp 可删除Debug文件夹和Release文件夹; 原则上还可删除主文件夹中所有图标为 的文件,包括.aps.ncb.opt.plg等文件,它们都能在编译时重建。但一般.clw不要删除,它可能导致ClassWizard不好用。 控件 如何隐藏和显示控件  CWnd类的函数BOOL ShowWindow(int nCmdShow)可以隐藏或显示一个控件。  1 CWnd *pWnd; pWnd = GetDlgItem( IDC_EDIT1 ); //获取控件指针,IDC_EDIT为控件ID pWnd->ShowWindow( SW_HIDE ); //隐藏控件 2 CWnd *pWnd; pWnd = GetDlgItem( IDC_EDIT1 ); //获取控件指针,IDC_EDIT为控件ID pWnd->ShowWindow( SW_SHOW ); //显示控件 按钮的使能与禁止  ClassWizardMember Variables为按钮定义变量,如:m_Button1 m_Button1.EnableWindow(true); 使按钮处于允许状态 m_Button1.EnableWindow(false); 使按钮被禁止,并变灰显示 改变控件的大小和位置  CWnd类的函数MoveWindow()SetWindowPos()可以改变控件的大小和位置。  void MoveWindow(int x,int y,int nWidth,int nHeight); void MoveWindow(LPCRECT lpRect); 第一种用法需给出控件新的坐标和宽度、高度; 第二种用法给出存放位置的CRect对象; 例: CWnd *pWnd; pWnd = GetDlgItem( IDC_EDIT1 ); //获取控件指针,IDC_EDIT1为控件ID pWnd->MoveWindow( CRect(0,0,100,100) ); //在窗口左上角显示一个宽100、高100的编辑控件 SetWindowPos()函数使用更灵活,多用于只修改控件位置而大小不变或只修改大小而位置不变的情况: BOOL SetWindowPos(const CWnd* pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags); 第一个参数一般设为NULL; xy控件位置;cxcy控件宽度和高度; nFlags常用取值: SWP_NOZORDER:忽略第一个参数; SWP_NOMOVE:忽略xy,维持位置不变; SWP_NOSIZE:忽略cxcy,维持大小不变; 例: CWnd *pWnd; pWnd = GetDlgItem( IDC_BUTTON1 ); //获取控件指针,IDC_BUTTON1为控件ID pWnd->SetWindowPos( NULL,50,80,0,0,SWP_NOZORDER | SWP_NOSIZE ); //把按钮移到窗口的(50,80) pWnd = GetDlgItem( IDC_EDIT1 ); pWnd->SetWindowPos( NULL,0,0,100,80,SWP_NOZORDER | SWP_NOMOVE ); //把编辑控件的大小设为(100,80),位置不变 pWnd = GetDlgItem( IDC_EDIT1 ); pWnd->SetWindowPos( NULL,0,0,100,80,SWP_NOZORDER ); //编辑控件的大小和位置都改变 以上方法也适用于各种窗口。 单选按钮控件(Radio Button)的使用  一、对单选按钮进行分组:  每组的第一个单选按钮设置属性:GroupTabstopAuto;其余按钮设置属性TabstopAuto 如: Radio1Radio2Radio3为一组,Radio4Radio5为一组 设定Radio1属性:GroupTabstopAuto 设定Radio2属性:TabstopAuto 设定Radio3属性:TabstopAuto 设定Radio4属性:GroupTabstopAuto 设定Radio5属性:TabstopAuto 二、用ClassWizard为单选控件定义变量,每组只能定义一个。如:m_Radio1m_Radio4 三、用ClassWizard生成各单选按钮的单击消息函数,并加入内容: void CWEditView::OnRadio1()  { m_Radio1 = 0; //第一个单选按钮被选中 } void CWEditView::OnRadio2()  { m_Radio1 = 1; //第二个单选按钮被选中 } void CWEditView::OnRadio3()  { m_Radio1 = 2; //第三个单选按钮被选中 } void CWEditView::OnRadio4()  { m_Radio4 = 0; //第四个单选按钮被选中 } void CWEditView::OnRadio5()  { m_Radio4 = 1; //第五个单选按钮被选中 } 当控件变量值为0时,它对应组的第一个单选按钮处于选中状态。 BOOL CDzyApp::InitInstance()  ... {  AfxEnableControlContainer();  ……  // The one and only window has been initialized, so show and update it.  m_pMainWnd->SetWindowPos(NULL,0,0,750,555,SWP_NOMOVE);//设置窗口的初始大小为750*555 m_pMainWnd->ShowWindow(SW_SHOW);  m_pMainWnd->UpdateWindow();  return TRUE;  } m_pMainWnd -> CenterWindow( GetDesktopWindow() ); int  CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)  if (CFrameWnd::OnCreate(lpCreateStruct) == -1return -1;  ……  // TODO: Delete these three lines if you don't want the toolbar to  // be dockable  m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);  EnableDocking(CBRS_ALIGN_ANY);  DockControlBar(&m_wndToolBar);  CenterWindow( GetDesktopWindow() ); //使窗口打开时处于屏幕正中 return 0;  } BOOL CTextEditorDoc::OnNewDocument()  if (!CDocument::OnNewDocument())  return FALSE;  // TODO: add reinitialization code here  // (SDI documents will reuse this document)  SetTitle("未命名.txt"); //设置文档标题  return TRUE;  } 2 、设置程序标题: 在框架类 (CMainFrame)PreCreateWindow()函数中加入语句: m_strTitle = _T("程序标题 "); 如: MainFrm.cppBOOL CMainFrame::PreCreateWindow(CREATESTRUCT &  cs)  if!CFrameWnd::PreCreateWindow(cs) )  return FALSE;  // TODO: Modify the Window class or styles here by modifying  // the CREATESTRUCT cs  cs.style&=~FWS_ADDTOTITLE;//去除标题栏文字前面的"无标题" m_strTitle = _T("文本整理器"); //设置程序标题  return TRUE;  } 以上两点比较适用于视图 -文档结构的程序,在新建文档时,系统会自动运行 OnNewDocument()函数,在其中可以设置合适的标题。对于未采用文档的程序可以用下面的方法修改标题: 3 、修改窗口标题: 修改窗口标题一般在打开文件函数 OnFileOpen()和另存为函数 OnFileSaveAs()中进行,可以使用下面的函数:其中文档标题和程序标题可使用定义过的串变量。 项目 如何干净的删除一个类?   1、先删除项目中对应的 .h.cpp文件,(选中后用 Delete键删除) 2、保存后退出项目,到文件夹中删除实际的 .h.cpp文件; 3、删除 .clw文件; 4、重新进入项目,进行全部重建( rebuild all)。 如何建立一个新类?      插入 ”(Insert)菜单中选择 新建类 ”(New Class),在弹出的对话框中选择基类 (Base class),在 Name中输入新类的名字(一般都以 C开头)即可。   如果想要建立一个没有基类的自定义类,则在 New Class对话框中把 Class type设置为 generic,再输入类名即可。 如何把外来文件添加到项目中?       先把外来文件复制到当前项目的目录下,从 项目 ”(Project)菜单下选择 添加项目 ”(Add to Project)下的 “Files”菜单项,从弹出的打开文件对话框中把外来文件打开即可。 如何在一个工作区中打开多个项目?      一般编程者都有这样的经历:做了一个项目,由于不满意,想从头重做,但又想把旧项目的一些可用内容拷到新项目中来,以免做重复工作,这时就需要在新项目中打开旧项目。       先打开新项目,从 项目 ”(Project)菜单下选择 插入项目到工作区 ”(Insert Project into Workspace),从弹出的打开文件对话框中打开旧项目的 .asp文件即可。     之后,可以利用 项目 ”(Project)菜单下的 设置活动项目 ”(Select Active Project)的选项中切换各打开的项目。 注意:在一个工作区中打开的各项目不能同名。 如何把项目中的文件分类存放?  当我们往项目中添加新类时,它会把源文件放在 Source Files下,头文件放在 Header Files下。当项目中文件很多时,管理不便,最好添加新节点,把文件分类放置。 右击项目节点树的根节点,选择 “New Folder...”,在弹出的对话框中填入新节点名,则新节点就建立了,用鼠标节点树中的文件拖入新节点,就可以把文件分类了。 以上分类只是在项目的节点树中分类,它不影响文件在磁盘上的位置,所有 .cpp文件和 .h文件仍在项目的根目录下,最好文件本身也能分类存放在不同文件夹中。 Windows下,用 新建文件夹 在项目的根目录下建立子文件夹,如 DialogClass,把所有对话框类的 .cpp文件和 .h文件拖入其中。 回到 VC下,右键单击项目树中更改了路径的节点,选择 “Properties”,在弹出的对话框中修改文件路径,如:把原路径 “.\Dialog1.cpp”改为 “.\DialogClass\Dialog1.cpp” 打开 Dialog1.cpp文件,修改它包含的文件路径。如: #include "stdafx.h" #include "PluckBox.h" #include "Dialog1.h" 改为: #include "stdafx.h" #include "..\\PluckBox.h" #include "Dialog1.h"  打开 ClassWizard,它会提示你文件不存在,单击 确定 后,从对话框中用 “Browse...”选择文件所在路径,则 ClassWizard也可正常使用了。 编辑 编辑代码时,跟随提示消失了怎么办?  单 击 工具 ”(Tools)菜单中的 设置 ”(Options)菜单项,在弹出的 Options对话框中选择 Editor制表页,把它最下方的四个复选框都 选中( Auto list memberAuto type infoCode commentsAuto parameter info),这样,当用户输入 “->”“.”时,会自动显示跟随提示,减少了输入负担。 对话框 如何修改对话框的背景色  在对话框的 OnPaint()函数中加入下面语句: CRect rect; GetClientRect(&rect); //计算对话框的尺寸 dc.FillSolidRect(&rect,RGB(192,248,202)); //绘制对话框背景色 如何让弹出式对话框具有统一的背景色  在应用程序类 CxxxAppInitInstance()函数中加入下面的语句: SetDialogBkColor( RGB(192,248,202) ); 则所有用户定义的弹出式对话框都以 RGB(192,248,202)为背景色,就不需要逐个进行设置了。 如何让打开文件对话框能进行多项选择  在定制打开文件对话框时,增加 OFN_ALLOWMULTISELECT属性,就可以使打开文件对话框进行多选了。 如: CFileDialog m_Dlg( TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, NULL, NULL ); 之后,用 GetStartPosition()函数获取选择的起始文件位置,用 GetNextPathName()函数获取各位置上的文件名。 如: if( m_Dlg.DoModal() == IDOK ) { POSITION pos; pos = m_Dlg.GetStartPosition(); while( pos ) { m_Path = m_Dlg.GetNextPathName(pos); ………… } } 为什么用打开文件对话框选择多个文件到一定数目时,文件没有打开?   CFileDialog为文件列表设置有缓冲区,当选择文件过多时,会造成缓冲区溢出,造成一些文件没有被打开。可以采用自定义大缓冲区代替系统缓冲区的方法解决。 如: CFileDialog m_Dlg( TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, NULL, NULL );//定制打开文件对话框 char* pBuf = new char[20480]; //申请缓冲区 m_Dlg.m_ofn.nMaxFile = 20480; //pBuf代替 CFileDialog缓冲区 m_Dlg.m_ofn.lpstrFile = pBuf; m_Dlg.m_ofn.lpstrFile[0] = NULL; ………… delete []pBuf; //回收缓冲区 提示对话框(MessageBox  在视类和对话框类中可使用 MFC函数中用的 MessageBox()函数弹出提示对话框。这个函数原型为: int MessageBox(LPCTSTR lpszText,LPCTSTR lpsCaption=NULL,UINT nType=MB_OK);  参数: lpszText 显示的字符串 lpsCaption 对话框的标题 nType 风格,可为如下值的组合: 指定下列标志中的一个来显示消息框中的按钮,标志的含义如下。 MB_ABORTRETRYIGNORE:消息框含有三个按钮: AbortRetryIgnore MB_OK:消息框含有一个按钮: OK。这是缺省值。 MB_OKCANCEL:消息框含有两个按钮: OKCancel MB_RETRYCANCEL:消息框含有两个按钮: RetryCancel MB_YESNO:消息框含有两个按钮: YesNo MB_YESNOCANCEL:消息框含有三个按钮: YesNoCancel 指定下列标志中的一个来显示消息框中的图标:标志的含义如下。 MB_ICONEXCLAMATION: MB_ICONWARNING:一个惊叹号出现在消息框。 MB_ICONINFORMATION MB_ICONASTERISK:一个圆圈中小写字母 i组成的图标出现在消息框。 MB_ICONOUESTION:一个问题标记图标出现在消息框。 MB_ICONSTOP: MB_ICONERROR MB_ICONHAND:一个停止消息图标出现在消息框。 指定下列标志中的一个来指定缺省的按钮:标志的含义如下。 MB_DEFBUTTON1:第一个按钮为缺省按钮。如果 MB_DEFBUTTON2MB_DEFBUTTON3MB_DEFBUTTON4没有被指定,则 MB_DEFBUTTON1为缺省值。 MB_DEFBUTTON2;第二个按钮为缺省按钮。 MB_DEFBUTTON3:第三个按钮为缺省按钮。 MB_DEFBUTTON4:第四个按钮为缺省按钮。 例:提示文件是否存盘: int t; t=MessageBox(m_PathName+"的文字已经改变,要存盘吗? ", "警告 ",MB_YESNOCANCEL | MB_ICONWARNING); if(t==0 || t==IDCANCEL) return; if(t==IDYES) OnFileSave(); 在文档类等其它类中不能使用 MFC中的 MessageBox()函数,只能使用 API函数中的 MessageBox()函数: int MessageBox(HWND hWnd,LPCTSTR lpszText,LPCTSTR lpCaption,UINT UType); hWnd:标识将被创建的消息框的拥有窗口。如果此参数为 NULL,则消息框没有拥有窗口。 后三个参数与视类的 MessageBox相同,但没有缺省值,必须设置。 例: ::MessageBox(NULL,m_PathName+"的文字已经改变,要存盘吗? ", "警告 ",MB_YESNOCANCEL | MB_ICONWARNING); 调试 error C2146: syntax error : missing ';' before identifier ……  如果出现这个错误且错误数目很多,通常并不是缺失了分号引起的,而是忘记了添加某头文件引起的。   最常见的是新加入了对话框,然后用它的类定义了一个对象,再编译出现上面的错误。 解决方法是在引用新类的文件中加入 #include "类名 .h",再编译,错误消失。 fatal error C1010: unexpected end of file while looking for precompiled header directive  在一个项目中,如果用 “New”向工程中添加了一个 .cpp文件,编译,出错。   解决方法:                    1)   在新建的 .cpp文件的开头加入 #include "stdafx.h"                   2)   可以使用右键点击项目工程中的该cpp文件,选择setting,在c/c++栏,选择PreCompiled headers,然后设置第一选项,选择不使用预编译头,解决这个问题。发布 Debug 模式和Release模式  早就发现用 VC编译出来的 .exe文件比用 Turbo C编译出来的文件大了许多,于是就认为 VC编译时一定加了很多没用的东西,记得当时还做过把 VC自动生成的项目中自认为没用的函数都删掉的傻事。后来才从网上的文章中了解到还有编译模式一说。   Debug模式是用来调试用的,它生成的执行文件中含有大量调试信息,所以很大; Release模式生成的执行文件消除了这些调试信息,可用来作为成品发布。 默 认情况下是 Debug模式,切换方法是在 编译 ”(Build)菜单中选 设置项目配置 ”(Set Active Configure)。从弹出的对话框中选择 Win32 Release模式,然后再重新编译。这时在工作目录下会多出一个 Release目录,其中的 exe文件比 Debug目录下的那个要小得多。 动态链接库和静态链接库  VC 做好了一个程序,拿到别人那里却不能运行,这也是很多编程者都经历过的,这样的软件只能在安装有 VC的机器上运行,也不应拿出去发布。实际上如果你没有使 用 ActiveX控件和自定义的动态 DLL技术,只需把 MFC的动态链接库打包到你的程序里就可以了,也就是使用静态链接库。   设置方法:从 项目 ”(Project)菜单下选择 设置 ” (Settings),在弹出的对话框中的 General选项卡下,把 “User MFC in a Shared DLL”改为 “User MFC in a Static Library”,关闭对话框后重新编译即可。 在静态链接库下编译的文件比动态链接库的要大很多,不过,如果使用 Release模式编译,一般也就几百 K,它就可以在没有安装 VC的机器上运行了。 发布VC源代码时,哪些文件可以删除?  AfxGetMainWnd() -> SetWindowText( " 文档标题 " + "  -  " + " 程序标题 " ); 四、设置默认按钮: 在定义控件变量时,ClassWizard在构造函数中会把变量初值设为-1,只需把它改为其它值即可。 如: //{{AFX_DATA_INIT(CWEditView) m_Ridio1 = 0; //初始时第一个单选按钮被选中 m_Ridio4 = 0; //初始时第四个单选按钮被选中 //}}AFX_DATA_INIT 旋转控件(Spin)的使用  当单击旋转控件上的按钮时,相应的编辑控件值会增大或减小。其设置的一般步骤为:  一、在对话框中放入一个Spin控件和一个编辑控件作为Spin控件的伙伴窗口 设置Spin控件属性:Auto buddySet buddy integerArrow keys 设置文本控件属性:Number 二、用ClassWizardSpin控件定义变量m_Spin,为编辑控件定义变量m_Edit,定义时注意要把m_Edit设置为int型。 三、在对话框的OnInitDialog()函数中加入语句: BOOL CMyDlg::OnInitDialog()  { CDialog::OnInitDialog(); m_Spin.SetBuddy( GetDlgItem( IDC_EDIT1 ) ); //设置编辑控件为Spin控件的伙伴窗口 m_Spin.SetRange( 0, 10 ); //设置数据范围为0-10 return TRUE; } 四、用ClassWizard为编辑控件添加EN_CHANGE消息处理函数,再加入语句: void CMyDlg::OnChangeEdit1()  { m_Edit = m_Spin.GetPos(); //获取Spin控件当前值 } UpdateData()  对于可以接收数据的控件,如编辑控件来说,UpdateData()函数至关重要。当控件内容发生变化时,对应的控件变量的值并没有跟着变化,同样,当控件变量值变化时,控件内容也不会跟着变。  UpdateData()函数就是解决这个问题的。 UpdateData(true); 把控件内容装入控件变量 UpdateData(false); 用控件变量的值更新控件 如:有编辑控件IDC_EDIT1,对应的变量为字符串m_Edit1 1、修改变量值并显示在控件中: m_Edit1 = _T("结果为50"); UpdateData(false); 2、读取控件的值到变量中: ClassWizardIDC_EDIT1添加EN_CHANGE消息处理函数,这个函数在编辑控件内容发生变化时执行。 void CEditView::OnChangeEdit1() { UpdateData(true); //更新变量值 } 其它 如何获取程序所在的路径  也就是获取你这个程序本身所在的路径。  在应用程序类CxxApp的头文件中定义一个变量CString m_exePath;用来放置程序的路径名,在应用程序类CxxAppInitInstance()函数中加入如下语句: TCHAR m_Path[MAX_PATH]; GetModuleFileName( NULL, m_Path, MAX_PATH ); //获取程序路径(包括程序名) int i = 0, j; while( m_Path[i]!=0 ) { if( m_Path[i]=='\\' ) j = i; i++; } m_Path[j+1] = '\0'; m_exePath.Format( "%s", m_Path ); //分离路径名(去掉程序名) 这段程序执行后,字符串变量m_exePath中放置的就是程序所在路径,其中不包括程序名。 获取程序的位置有什么用呢? 1、打开与应用程序在一起放置的数据文件: 如果你运行程序过程中使用过打开文件对话框打开过其它路径下的文件,这时系统的默认路径就发生了改变,有可能使你原定的数据文件打不开了,如果采用以下方法就可以没问题了: CFile file; file.Open( m_exePath+"数据文件名", CFile::modeRead ); 2、放置程序运行中的临时文件: 同样,当系统的默认路径发生改变后,程序中生成的临时文件就会放得到处都是,成了一个个垃圾文件,采用以下方法可使临时文件只放在程序所在路径下: CFile file; file.Open( m_exePath+"临时文件名", CFile::modeCreate | CFile::modeWrite ); …… 程序结束时,用下面的方法删除临时文件: CFile::Remove( m_exePath+"临时文件名" ); 如何在你的程序中执行其它程序  在自己的程序中调用其它程序的方法有好几种,这里我介绍我用过的两种:  一、WinExec()函数: 一般用法:WinExec(m_PathName,SW_SHOWNORMAL); m_PathName为执行程序的路径名,必须为可执行文件。 如:WinExec("C:\\Program Files\\Internet Explorer\\iexplore.exe",SW_SHOWNORMAL);为打开IE浏览器 二、ShellExecute()函数: 一般用法:ShellExecute(NULL,NULL,m_PathName,NULL,_T("c:\\temp"),SW_SHOWNORMAL); m_PathName为打开的程序路径名; _T("c:\\temp")为工作目录; WinExec()不同的是ShellExecute()函数也可以打开非可执行文件,比如你指定的文件为.txt,结果会打开记事本装入该文件。我用这种方法调用自己制作的帮助文件(.chm)效果很好。 如果不使用串行化,如何在程序结束时保存文件?  在文档-视图结构中,用串行化自动保存文件在各种VC书上都有介绍。现在的问题是我不使用串行化,而是自己动手保存,当点击窗口的关闭按钮时,如何提示并保存文档。  ClassWizard在文档类(CxxDoc)中添加函数CanCloseFrame(),再在其中加入保存文件的语句就可以了。 例: //退出程序 BOOL CEditDoc::CanCloseFrame(CFrameWnd* pFrame)  { CFile file; if(b_Flag) //b_Flag为文档修改标志,在修改文档时将其置为True { int t; t=::MessageBox(NULL,"文字已经改变,要存盘吗?","警告", MB_YESNOCANCEL | MB_ICONWARNING); //弹出提示对话框 if(t==0 || t==IDCANCEL) return false; if(t==IDYES) { CString sFilter="Text File(*.txt)|*.txt||"; CFileDialog m_Dlg(FALSE,"txt",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,(LPCTSTR)sFilter,NULL); //定制文件对话框 int k=m_Dlg.DoModal(); //弹出文件对话框 if(k==IDCANCEL || k==0) return false; m_PathName=m_Dlg.GetPathName(); //获取选择的文件路径名 file.Open(m_PathName,CFile::modeCreate | CFile::modeWrite); file.Write(m_Text,m_TextLen); //数据写入文件 file.Close(); } } return CDocument::CanCloseFrame(pFrame); } 这样当你单击窗口上的关闭按钮时,如果数据已修改了,就会弹出一个提示保存数据的对话框,提示你保存数据。 程序中的b_Flag是数据修改标志,应该在修改数据时进行设置,m_Text是准备保存的数据,放在文档内。 POSITION怎么用?  POSITION类型数据用于表征各种列表中元素的位置,它类似于数组的下标,但又有所不同。主要区别是: 我们不能访问POSITION型数据的值,也不能对POSITION数据型数据进行加减、比较等运算。 POSITION型数据访问列表时,都是采用迭代法,一般格式为: POSITION pos; //定义pos型变量 pos = GetHeadPosition(); //获取列表起始元素位置 while( pos ) { x = GetNext(pos); //获取pos处的列表值,同时修改pos为下一个元素位置 } GetNext()就是一种迭代,其格式为: TYPE GetNext(POSITION& rPosition); 首先,它返回当前pos位置处的元素;再就是把pos值修改为下一个元素位置。这样循环时,可依次取得列表中各元素的值;当到达列表尾时,posNULL,循环结束。 所以使用POSITION型数据时,你不要试图用加减等操作去修改它,只能用GetNext()(向后迭代)或GetPrev()(向前迭代)反复迭代来修改它的值。 如果你想直接到达指定值,还可以用Find()函数或FindIndex()函数获得指定值的POSITION值。 POSITION Find(TYPE Value);用于在列表中查找值为Value的元素的POSITION值; POSITION FindIndex(int nIndex);用于获取列表中第nIndex个元素的POSITION值,nIndex0开始。 如: pos = FindIndex(5); //求列表中第5个元素的位置 x = GetNext(pos); //读取元素的值 总之,POSITION类型在多种涉及列表的类中提供,不同的类提供的函数有所不同,但用法都是类似的。 如何从完整的文件路径中分离文件名和路径名?  从路径中分离文件名: CString GetFileName(CString pathname)  {  for( int i=pathname.GetLength()-1; i>=0; i-- )  {  if( pathname[i]=='\\' )  break;  }  return pathname.Mid( i+1 );  } 从路径中分离路径名(去除文件名): CString GetPath(CString pathname)  {  int i = 0, j;  while( i<pathname.GetLength() )  {  if( pathname[i]=='\\' )  j = i;  i++;  }  return pathname.Left( j+1 );  }
VC 常见问题百问  

(1) 如何通过代码获得应用程序主窗口的 指针? 主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现。 AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED) //使程序最大化.

(2) 确定应用程序的路径 Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。 Example: TCHAR exeFullPath[MAX_PATH] // MAX_PATH在API中定义了吧,好象是 128 GetModuleFileName(NULL,exeFullPath,MAX_PATH) (3) 如何在程序中获得其他程序的 图标? 两种方法: (1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle, (2) SDK函数 SHGetFileInfo 获得有关文件的很多信息,如大小图标,属性, 类型等. Example(1): 在程序窗口左上角显示 NotePad图标. void CSampleView: OnDraw(CDC * pDC) { if( :: SHGetFileInfo(_T("c:\\pwin95\\notepad.exe"),0, &stFileInfo,sizeof(stFileInfo),SHGFI_ICON)) { pDC ->DrawIcon(10,10,stFileInfo.hIcon) } } Example(2):同样功能,Use ExtractIcon Function void CSampleView:: OnDraw(CDC *pDC) { HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T ("NotePad.exe"),0) if (hIcon &&hIcon!=(HICON)-1) pDC->DrawIcon(10,10,hIcon) }      说明: 获得notepad.exe的路径正规上来说用GetWindowsDirectory函数得到, 如果是调用 win95下的画笔,应该用访问注册表的方法获得其路径,要作成一个比较考究的程序,考虑应该全面点.

 

(4) 获得各种目录信息 Windows目录: Use "GetWindowsDirectory" Windows下的system目录: Use "GetSystemDirectory" temp目录: Use "GetTempPath" 当前目录: Use "GetCurrentDirectory" 请注意前两个函数的第一个参数为目录变量名,后一个为缓冲区后两个相反.

(5) 如何自定义消息 1) 手工定义消息,可以这么写 #define WM_MY_MESSAGE(WM_USER+100), MS 推荐的至少是 WM_USER+100 (2)写消息处理函数,用 WPARAM,LPARAM返回LRESULT. LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam) { temp目录: Use "GetTempPath" //加入你的处理函数 irectory" }

(6) 如何改变窗口的图标? 向窗口发送 WM_SECTION消息。 Example: HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON) ASSERT(hIcon) AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM)hIcon)

(7) 如何改变窗口的缺省风格? 重载 CWnd:: PreCreateWindow 并修改CREATESTRUCT结构来指定窗口风格和其他创建信息. Example: Delete "Max" Button and Set Original Window's Position and Size BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs) { cs.style &=~WS_MAXINIZEMOX cs.x=cs.y=0 cs.cx=GetSystemMetrics(SM_CXSCREEN/2) cs.cy=GetSystemMetrics(SM_CYSCREEN/2) return CMDIFramewnd ::PreCreateWindow(cs) }

(8)  如何将窗口居中显示? Call Function CWnd:: Center Windows Example(1): Center Window( ) //Relative to it's parent // Relative to Screen Example(2): Center Window(CWnd:: GetDesktopWindow( )) //Relative to Application's MainWindow AfxGetMainWnd( ) -> Center Window( )

(9) 如何让窗口和 MDI窗口一启动就最大化和最小化? 先说窗口。 在 InitStance 函数中设定 m_nCmdShow的取值. m_nCmdShow=SW_SHOWMAXMIZED //最大化 m_nCmdShow=SW_SHOWMINMIZED //最小化 m_nCmdShow=SW_SHOWNORMAL //正常方式 MDI窗口: 如果是创建新的应用程序,可以用MFC AppWizard 的Advanced 按钮并在MDI子窗口风格组中检测最大化或最小化还可以重载 MDI Window 的PreCreateWindow函数,设置WS_MAXMIZE or WS_MINMIZE 如果从 CMDIChildWnd派生,调用 OnInitialUpdate函数中的 CWnd::Show Window来指定 MDI Child Window的风格。

(10)  如何限制窗口的大小? 也就是 FixedDialog形式。 Windows发送 WM_GETMAXMININFO消息来跟踪, 响应它,在 OnGetMAXMININFO 中写代码:

(11) 如何使窗口不可见? 很简单,用SW_HIDE 隐藏窗口,可以结合 FindWindow,ShowWindow控制.

(12) 如何创建一个字回绕的CEditView 重载CWnd : : PreCreateWindow和修改CREATESTRUCT结构,关闭CEditView对象的ES_AUTOHSCROLL和WS_HSCROLL 风格位, 由于CEditView : : PreCreateWindow显示设置cs. style,调用基类函数后要修改cs . style。 BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs) { //First call basse class function . BOOL bResutl =CEditView : : PreCreateWindow (cs) // Now specify the new window style . cs.style &= ~ (ES_AUTOHSCROLL |WS_HSCROLL) return bResult }

(13) 如何使程序保持极小状态? 这么办: 在恢复程序窗体大小时,Windows会发送WM_QUERY-OPEN消息,用 ClassWizard设置成员函数 OnQueryOpen() ,add following code: Bool CMainFrame:: OnQueryOpen( ) { Return false }

(14) 移动窗口 调用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置与父窗口有关(顶层窗口与屏幕有关)。调用CWnd : : MoveWindow时必须要指定窗口的大小。 //Move window to positoin 100 , 100 of its parent window . SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER)

(15) 通用控件的显示窗口 MFC提供了几个CView派生的视窗类, 封装了通用控件的功能,但仍然使用工作框文档显示窗口体系结构:CEditView封装了编辑控件,CTreeView保持了树列表控件, CListView封装了列表显示窗口控件,CRichEditView可以处理多种编辑控件。

(16) 重置窗口的大小 调用CWnd: : SetWindowPos并指定SWP_NOMOVE标志, 也可调用CWnd : : MoveWindow 但必须指定窗口的位置。 // Get the size of the window . Crect reWindow GetWindowRect (reWindow ) //Make the window twice as wide and twice as tall . SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2, reWindow . Height () * 2, SWP_NOMOVE |SWP_NOZORDER )

(17) 如何单击除了窗口标题栏以外的区域使窗口移动 当窗口需要确定鼠标位置时Windows向窗口发送 WM_NCHITTEST信息,可以处理该信息使Windows认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可以使用ClassWizard 处理该信息并调用基类函数, 如果函数返回HTCLIENT 则表明鼠标在客房区域,返回HTCAPTION表明鼠标在Windows的标题栏中。 UINT CSampleDialog : : OnNcHitTest (Cpoint point ) { UINT nHitTest =Cdialog: : OnNcHitTest (point ) return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest } 上述技术有两点不利之处, 其一是在窗口的客户区域双击时,窗口将极大; 其二, 它不适合包含几个视窗的主框窗口。 还有一种方法,当用户按下鼠标左键使主框窗口认为鼠标在其窗口标题上,使用ClassWizard在视窗中处理WM_LBUTTODOWN信息并向主框窗口发送一个WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。 void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point ) { CView : : OnLButtonDow (nFlags , pont ) //Fool frame window into thinking somene clicked on its caption bar . GetParentFrame ( ) —> PostMessage ( WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn .x , point .y) ) } 该技术也适用于对话框和基于对的应用程序,只是不必调用 CWnd: :GetParentFrame 。 void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point ) { Cdialog : : OnLButtonDow (nFlags, goint ) //Fool dialog into thinking simeone clicked on its caption bar . PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) ) }

(18) 如何改变视窗的背景颜色 Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用ClassWizard重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE以防止Windows擦除窗口。 //Paint area that needs to be erased. BOOL CSampleView : : OnEraseBkgnd (CDC* pDC) { // Create a pruple brush. CBrush Brush (RGB (128 , 0 , 128) ) // Select the brush into the device context . CBrush* pOldBrush = pDC—>SelcetObject (&brush) // Get the area that needs to be erased . CRect reClip pDC—>GetCilpBox (&rcClip) //Paint the area. pDC—> PatBlt (rcClip.left , rcClip.top , rcClip.Width ( ) , rcClip.Height( ) , PATCOPY ) //Unselect brush out of device context . pDC—>SelectObject (pOldBrush ) // Return nonzero to half fruther processing . return TRUE }

(19) 如何改变窗口标题 调用CWnd : : SetWindowText可以改变任何窗口(包括控件)的标题。 //Set title for application's main frame window . AfxGetMainWnd ( ) —> SetWindowText (_T("Application title") ) //Set title for View's MDI child frame window . GetParentFrame ( ) —> SetWindowText ("_T ("MDI Child Frame new title") ) //Set title for dialog's push button control. GetDigitem (IDC_BUTTON) —> SetWindowText (_T ("Button new title ") ) 如 果需要经常修改窗口的标题(注:控件也是窗口),应该考虑使用半文档化的函数AfxSetWindowText。该函数在AFXPRIV.H中说明,在 WINUTIL.CPP中实现,在联机帮助中找不到它,它在AFXPRIV.H中半文档化, 在以后发行的MFC中将文档化。 AfxSetWindowText的实现如下: voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew ) { itn nNewLen= Istrlen (Ipaznew) TCHAR szOld [256] //fast check to see if text really changes (reduces flash in the controls ) if (nNewLen >_contof (szOld) || : : GetWindowText (hWndCrtl, szOld , _countof (szOld) !=nNewLen || Istrcmp (szOld , IpszNew)! = 0 { //change it : : SetWindowText(hWndCtrl , IpszNew ) } }

(20) 如何防止主框窗口在其说明中显示活动的文档名 创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位,如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置 CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。 BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs) { //Turn off FWS_ADDTOTITLE in main frame . cs.styel & = ~FWS_ADDTOTITLE   return CMDIFrameWnd : : PreCreateWindow (cs ) } 关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。

(21) 如何获取有关窗口正在处理的当前消息的信息 调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如,可以使用ClassWizard将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage来确定所选中的菜单项。 viod CMainFrame : : OnCommmonMenuHandler ( ) { //Display selected menu item in debug window . TRACE ("Menu item %u was selected . \n" ,

(22) 如何在代码中获取工具条和状态条的指针 缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个 AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针: //Get pointer to status bar . CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_STUTUS_BAR) //Get pointer to toolbar . CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_TOOLBAR)

(23) 如何使能和禁止工具条的工具提示 如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者 禁止工具提示,需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数: void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ) { ASSERT_VALID (m_wndToolBar) DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) if (bDisplayTips) dwStyle |=CBRS_TOOLTIPS else dwStyle & = ~CBRS_TOOLTIPS m_wndToolBar.SetBarStyle (dwStyle ) }

(24) 如何创建一个不规则形状的窗口 可以使用新的SDK函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一个指定的区域,实际上使窗口成为指定的不规则形状。 使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删除所在的缺省控件、标题以及边界。 给对话类增加一个CRgn数据成员,以后要使用该数据成员建立窗口区域。 Class CRoundDlg : public CDialog { … private : Crgn m_rgn : // window region … } 修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn将该区域分配给窗口: BOOL CRoundDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //Get size of dialog . CRect rcDialog GetClientRect (rcDialog ) // Create region and assign to window . m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width( ) , rcDialog.Height ( ) ) SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn ,TRUE ) return TRUE } 通过建立区域和调用SetWindowRgn,已经建立一个不规则形状的窗口,下面的例子程序是修改OnPaint函数使窗口形状看起来象一个球形体。 voik CRoundDlg : : OnPaint ( ) { CPaintDC de (this) // device context for painting . //draw ellipse with out any border dc. SelecStockObject (NULL_PEN) //get the RGB colour components of the sphere color COLORREF color= RGB( 0 , 0 , 255) BYTE byRed =GetRValue (color) BYTE byGreen = GetGValue (color) BYTE byBlue = GetBValue (color) // get the size of the view window Crect rect GetClientRect (rect) // get minimun number of units int nUnits =min (rect.right , rect.bottom ) //calculate he horiaontal and vertical step size float fltStepHorz = (float) rect.right /nUnits float fltStepVert = (float) rect.bottom /nUnits int nEllipse = nUnits/3 // calculate how many to draw int nIndex // current ellipse that is being draw CBrush brush // bursh used for ellipse fill color CBrush *pBrushOld // previous brush that was selected into dc //draw ellipse , gradually moving towards upper-right corner for (nIndex = 0 nIndes < + nEllipse nIndes++) { //creat solid brush brush . CreatSolidBrush (RGB ( ( (nIndex*byRed ) /nEllipse ). ( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse ) ) ) //select brush into dc pBrushOld= dc .SelectObject (&brhsh) //draw ellipse dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex , rect. right -( (int) fltStepHorz * nIndex )+ 1, rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1) //delete the brush brush.DelecteObject ( ) } } 最后,处理WM_NCHITTEST消息,使当击打窗口的任何位置时能移动窗口。 UINT CRoundDlg : : OnNchitTest (Cpoint point ) { //Let user move window by clickign anywhere on thewindow . UINT nHitTest = CDialog : : OnNcHitTest (point) rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest }

(25) 如何获取应用程序的 实例句柄? 应用程序的实例句柄保存在CWinApp m_hInstance 中,可以这么调用AfxGetInstancdHandle获得句柄. Example: HANDLE hInstance=AfxGetInstanceHandle()

(26) 如何编程结束应用程序? 这是个很简单又是编程中经常要遇到的问题. 向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示是否保存修改过的数据. Example: AfxGetMainWindow()->SendMessage(WM_CLOSE) 还可以创建一个自定义的函数 Terminate Window void Terminate Window(LPCSTR pCaption) { CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption) if (pWnd) pWnd ->SendMessage(WM_CLOSE) }      说明: FindWindow函数不是提倡的做法,因为它无法处理标题栏自动改变,比如我们要检测 Notepad是不是已运行而事先不知道Notepad的标题栏,这时FindWindow就无能为力了,可以通过枚举 windows任务列表的办法来实现。在机械出版社"Windows 95 API开发人员指南"一书有比较详细的介绍,这里就不再多说乐。

(27) 如何创建和使用无模式对话框 MFC将模式和无模式对话封装在同一个类中,但是使用无模式对话需要几个对话需要几个 额处的步骤。首先,使用资源编辑器建立对话资源并使用ClassWizard创建一个CDialog的派生类。模式和无模式对话的中止是不一样的:模式对 话通过调用CDialog : : EndDialog 来中止,无模式对话则是调用CWnd: : DestroyWindow来中止的,函数CDialog : : OnOK和CDialog : : OnCancel调用EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。 void CSampleDialog : : OnOK ( ) { // Retrieve and validate dialog data . if (! UpdateData (TRUE) ) { // the UpdateData rountine will set focus to correct item TRACEO (" UpdateData failed during dialog termination .\n") return } //Call DestroyWindow instead of EndDialog . DestroyWindow ( ) } void CSampleDialog : : OnCancel ( ) { //Call DestroyWindow instead of EndDialog . DestroyWindow ( ) } 其 次,需要正确删除表示对话的C++对象。对于模式对来说,这很容易,需要创建函数返回后即可删除C++对象;无模式对话不是同步的,创建函数调用后立即返 回,因而用户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy,可以重置该函数并执行清除操作,诸如删除this指针。 void CSampleDialog : : PostNcDestroy ( ) { // Declete the C++ object that represents this dialog. delete this 最后,要创建无模式对话。可以调用CDialog : : DoModal创建一个模式对放,要创建一个无模式对话则要调用CDialog: : Create。下面的例子说明 了应用程序是如何创建无模式对话的: 象;无模式对话不是同步的,创建函数调用后立即返回, void CMainFrame : : OnSampleDialog ( ) { //Allocate a modeless dialog object . CSampleDilog * pDialog =new CSampleDialog ASSERT_VALID (pDialog) Destroy ( ) //Create the modeless dialog . represents this dialog. BOOL bResult = pDialog —> Creste (IDD_IDALOG) ASSERT (bResult ) }

 

(28) 如何防止主框窗口在其说明中显示活动的文档名 创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位,如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置 CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。 BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs) { //Turn off FWS_ADDTOTITLE in main frame . cs.styel & = ~FWS_ADDTOTITLE   return CMDIFrameWnd : : PreCreateWindow (cs ) } 关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。

(29) 如何在代码中获取工具条和状态条的指针 缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个 AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针: //Get pointer to status bar . CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_STUTUS_BAR) //Get pointer to toolbar . CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_TOOLBAR)

(30)  怎样加载其他的应用程序? 三个SDK函数 winexec, shellexecute,createprocess可以使用。 WinExec最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数值得说一下,比如泥用 SW_SHOWMAXMIZED方式去加载一个无最大化按钮的程序,就是Neterm,calc等等,就不会出现正常的窗体,但是已经被加到任务列表里了。 ShellExecute 较 WinExex灵活一点,可以指定工作目录,下面的Example就是直接打开 c:\temp\1.txt,而不用加载与 txt文件关联的应用程序,很多安装程序完成后都会打开一个窗口,来显示Readme or Faq,我猜就是这么作的啦. ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c:\\temp"),SW_SHOWMAXMIZED) CreateProcess最复杂,一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等.来看个很简单的Example: STARTUPINFO stinfo //启动窗口的信息 PROCESSINFO procinfo //进程的信息 CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE, NORMAL_PRIORITY_ CLASS,NULL,NULL, &stinfo,&procinfo)

(31) 如何在代码中获取工具条和状态条的指针 缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个 AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针: //Get pointer to status bar . CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_STUTUS_BAR)

(32) 如何使能和禁止工具条的工具提示 如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者 禁止工具提示,需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数: void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ) { ASSERT_VALID (m_wndToolBar) DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) if (bDisplayTips) dwStyle |=CBRS_TOOLTIPS else dwStyle & = ~CBRS_TOOLTIPS m_wndToolBar.SetBarStyle (dwStyle ) } //Get pointer to toolbar . CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( ) —> GetDescendantWindow(AFX_IDW_TOOLBAR)

(33) 如何设置工具条标题 工具条是一个窗口,所以可以在调用CWnd : : SetWindowText来设置标题,例子如下: int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct ) { … // Set the caption of the toolbar . m_wndToolBar.SetWindowText (_T "Standdard")

(34) 如何使窗口始终在最前方? BringWindowToTop(Handle) SetWindowPos函数,指定窗口的 最顶风格,用WS_EX_TOPMOST扩展窗口的风格 Example: void ToggleTopMost( CWnd *pWnd) { ASSERT_VALID(pWnd) pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)? &wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE) }

(35) 如何在对话框中显示一个位图 这要归功于Win 32先进的静态控件和Microsoft的资源编辑器,在对话框中显示位图是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也可以显示图标、位图以及增强型元文件。

(36) 如何改变对话或窗体视窗的背景颜色 调用CWinApp : : SetDialogBkColor可以改变所有应用程序的背景颜色。第一个参数指定了背景颜色,第二个参数指定了文本颜色。下例将应用程序对话设置为蓝色背景和黄色文本。 BOOL CSampleApp : : InitInstance ( ) { … //use blue dialog with yellow text . SetDialogBkColor (RGB (0, 0, 255 ), RGB ( 255 ,255 , 0 ) ) … } 需要重画对话(或对话的子控件)时,Windows向对话发送消息WM_CTLCOLOR,通常用户可以让Windows选择绘画背景的刷子,也可重置该消息指定刷子。下例说明了创建一个红色背景对话的步骤。 首先,给对话基类增加一人成员变量 CBursh :class CMyFormView : public CFormView { … private : CBrush m_ brush // background brush … } 其次, 在类的构造函数中将刷子初始化为所需要的背景颜色。 CMyFormView : : CMyFormView ( ) { // Initialize background brush . m_brush .CreateSolidBrush (RGB ( 0, 0, 255) ) } 最后,使用ClassWizard处理WM_CTLCOLOR消息并返回一个用来绘画对话背景的刷子句柄。注意:由于当重画对话控件时也要调用该函数,所以要检测nCtlColor参量。 HBRUSH CMyFormView : : OnCtlColor (CDC* pDC , CWnd*pWnd , UINT nCtlColor ) { // Determine if drawing a dialog box . If we are, return +handle to //our own background brush . Otherwise let windows handle it . if (nCtlColor = = CTLCOLOR _ DLG ) return (HBRUSH) m_brush.GetSafeHandle ( ) return CFormView : : OnCtlColor (pDC, pWnd , nCtlColor ) }

(37) 如何获取一个对话控件的指针 有两种方法。其一,调用CWnd: : GetDlgItem,获取一个CWnd*指针调用成员函数。下例调用GetDlgItem,将返回值传给一个CSpinButtonCtrl*以便调用CSpinButtonCtrl : : SetPos 函数: BOOL CSampleDialog : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //Get pointer to spin button . CSpinButtonCtrl * pSpin - ( CSpinButtonCtrl *) GetDlgItem(IDC_SPIN) ASSERT _ VALID (pSpin) //Set spin button's default position . pSpin —> SetPos (10) return TRUE } 其 二, 可以使用ClassWizard将控件和成员变量联系起来。在ClassWizard中简单地选择Member Variables标签,然后选择Add Variable …按钮。如果在对话资源编辑器中,按下Ctrl键并双击控件即可转到Add Member Variable对话。

 

(38) 如何禁止和使能控件 控件也是窗口,所以可以调用CWnd : : EnableWindow使能和禁止控件。 //Disable button controls . m_wndOK.EnableWindow (FALSE ) m_wndApply.EnableWindow (FALSE )

 

(39) 如何改变控件的字体 由于控件是也是窗口,用户可以调用CWnd: : SetFont指定新字体。该函数用一个Cfont指针,要保证在控件撤消之前不能撤消字体对象。下例将下压按钮的字体改为8点Arial字体: //Declare font object in class declaration (.H file ). private : Cfont m_font // Set font in class implementation (.Cpp file ). Note m_wndButton is a //member variable added by ClassWizard.DDX routines hook the member //variable to a dialog button contrlo. BOOL CSampleDialog : : OnInitDialog ( ) { … //Create an 8-point Arial font m_font . CreateFont (MulDiv (8 , -pDC —> GetDeviceCaps(LOGPIXELSY) ,72). 0 , 0 , 0 , FW_NORMAL , 0 , 0,0, ANSI_CHARSER, OUT_STROKE_PRECIS , CLIP_STROKE _PRECIS , DRAFT _QUALITY VARIABLE_PITCH |FF_SWISS, _T("Arial") ) //Set font for push button . m_wndButton . SetFont (&m _font ) … }

(40) 如何在OLE控件中使用OLE_COLOR数据类型 诸如COleControl : : GetFortColor和COleControl : : GetBackColor等函数返回OLE _COLOR数据类型的颜色,而GDI对象诸如笔和刷子使用的是COLORREF数据类型,调用COleControl : : TranslateColor可以很容易地将OLE_COLOR类型改为COLORREF类型。下例创建了一个当前背景颜色的刷子: void CSampleControl : : OnDraw (CDC* pdc const Crect& rcBounds , const Crect& rcInvalid ) { //Create a brush of the cuttent background color. CBrush brushBack (TranslateColor (GetBackColor () ) ) //Paint the background using the current backgroundcolor . pdc—> FilllRect (rcBounds , &brushBack) //other drawign commands … }

 

 

(41) 在不使用通用文件打开对话的情况下如何显示一个文件列表 调用CWnd: : DlgDirList或者CWnd: : DlgDirListComboBox,Windows 将自动地向列表框或组合框填充可用的驱动器名或者指定目录中的文件,下例将Windows目录中的文件填充在组合框中: BOOL CSampleDig : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) TCHAR szPath [MAX_PATH] = {"c:\\windows"} int nReslt = DlgDirListComboBox (szPath, IDC_COMBO , IDC_CURIDIR, DDL_READWRITE |DDL_READONLY|DDL_HIDDEN| DDL_SYSTEM|DDL_ARCHIVE) return TRUE }

(42) 为什么旋转按钮控件看起来倒转 需要调用CSpinCtrl : : SetRange 设置旋转按钮控件的范围,旋转按钮控件的缺省上限为0,缺省下限为100,这意味着增加时旋转按控件的值由100变为0。下例将旋转按钮控件的范围设置为0到100: BOOL CAboutDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //set the lower and upper limit of the spin button m_wndSpin . SetRange ( 0 ,100 ) return TRUE } Visual C++ 4.0 Print对话中的Copise旋转按钮控件也有同样的问题:按下Up按钮时拷贝的数目减少,而按下Down 按钮时拷贝的数目增加。

(43) 为什么旋转按钮控件不能自动地更新它下面的编辑控件 如果使用旋转按钮的autu buddy特性, 则必须保证在对话的标记顺序中buddy窗口优先于旋转按钮控件。从Layout菜单中选择Tab Order菜单项(或者按下Crtl+D)可以设置对话的标签顺序。

(44) 如何用位图显示下压按钮 Windows 95按钮有几处新的创建风格,尤其是BS_BITMAP和BS_ICON,要想具有位图按钮,创建按钮和调用CButton : : SetBitmap或CButton : : SetIcon时要指定BS_BITMAP或BS_ICON风格。 首先,设置按钮的图标属性。然后,当对话初始化时调用CButton: : SetIcon。注意:下例用图标代替位图,使用位图时要小心,因为不知道背景所有的颜色——并非每个人都使用浅灰色。 BOOL CSampleDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //set the images for the push buttons . BOOL CSampleDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //set the images for the push buttons . m_wndButton1.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION1)) m_wndButton2.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION2)) m_wndButton3.SetIcon (AfxGetApp ( ) —> LoadIcon (IDI _ IPTION3)) return TRUE }

 

(45) 如何一个创建三态下压按钮 可以使用新的BS_PUSHBUTTON 风格位和检测框以及按钮来创建一个三态下压按钮。这很容易,只需将检测框和按钮拖拉到对话中并指定属性Push—like即可。不用任何附加程序就可以成为三态下压按钮。

(46) 如何动态创建控件 分配一个控件对象的实例并调用其Create成员函数。开发者最容易忽略两件事:忘记指定WS_VISBLE标签和在栈中分配控件对象。下例动态地创建一个下压按钮控件: //In class declaration (.H file ). private : CButton* m _pButton //In class implementation (.cpp file ) . m_pButton =new CButton ASSERT_VALID (m_pButton) m_pButton —>Create (_T ("Button Title ") , WS_CHILD |WS_VISIBLE |BS_PUSHBUTTON. Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON )

(47) 如何限制编辑框中的准许字符 如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指定新的创建标志 ES_NUMBERS,它是Windows 95新增加的标志,该标志限制 编辑控件只按收数字字符。如果用户需要复杂的编辑控件,可以使用Microsoft 的屏蔽编辑控件,它是一个很有用的OLE定制控件。 如果希望 不使用OLE 定制控件自己处理字符,可以派生一个CEdit类并处理WM_CHAR消息,然后从编辑控件中过滤出特定的字符。首先,使用ClassWizard建立一 个 CEdit的派生类,其次,在对话类中指定一个成员变量将编辑控件分类在OnInitdialog 中调用CWnd: : SubclassDlgItem . //In your dialog class declaration (.H file ) private : CMyEdit m_wndEdit // Instance of your new edit control . //In you dialog class implementation (.CPP file ) BOOL CSampleDialog : : OnInitDialog ( ) { … //Subclass the edit lontrod . m_wndEdit .SubclassDlgItem (IDC_EDIT,this) … } 使用ClassWizard处理WM_CHAR消息,计算nChar参量并决定所执行的操作,用户可以确定是否修改、传送字符。下例说明了如何显示字母字符,如果字符是字母字符,则调用CWnd OnChar,否则不调用OnChar. //Only display alphabetic dharacters . void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags ) { //Determine if nChar is an alphabetic character. if (: : IsCharAlpha ( ( TCHAR) nChar ) ) CEdit : : OnChar (nChar, nRepCnt , nFlags ) } 如果要修改字符,则不能仅仅简单地用修改过的nChar调用CEdit: : OnChar,然后CEdit: : OnChar调用CWnd: : Default获取原来的wParam 和lParam 的值,这样是不行的。要修改一个字符,需要首先修改nChar,然后用修改过的nChar调用CWnd: : DefWindowProc。下例说明了如何将字符转变为大写: //Make all characters uppercase void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags ) { //Make sure character is uppercase . if (: : IsCharAlpha ( .( TCHAR) nChar) nChar=: : CharUpper(nChar ) //Bypass default OnChar processing and directly call //default window proc. DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt, nFlags )) }

(48) 如何改变控件的颜色 有两种方法。其一,可以在父类中指定控件的颜色,或者利用MFC4.0新的消息反射在控件类中 指定颜色。 当控件需要重新着色时,工作框调用父窗口(通常是对话框)的CWnd: : OnCrtlColor,可以在父窗口类中重置该函数并指定控件的新的绘画属性。例如,下述代码将对话中的所有编辑控件文本颜色改为红色: HBRUSH CAboutDig : : OnCtlColor (CDC * pDCM , CWnd * pWnd , UINT nCtlColor) { HBRUSH hbr = CDialog : : OnCtlColor (pDC, pWnd , nCtlColor ) //Draw red text for all edit controls . if (nCtlColor= = CTLCOLOR_EDIT ) pDC —> SetTextColor (RGB (255, 0 , 0 , ) ) return hbr } 然 而,由于每个父窗口必须处理通知消息并指定每个控件的绘画属性,所以,这种方法不是完全的面向对象的方法。控件处理该消息并指定绘画属性更合情合理。消息 反射允许用户这样做。通知消息首先发送给父窗口,如果父窗口没有处理则发送给控件。创建一个定制彩色列表框控件必须遵循下述步骤。 首先,使用ClassWizard 创建一个CListBox 的派生类并为该类添加下述数据成员。 class CMyListBox publilc CListBox { … private COLORREF m_clrFor // foreground color COLORREF m_clrBack //background color Cbrush m_brush //background brush … } 其次,在类的构造函数中,初始化数据中。 CMyListBox : : CMyListBox () { //Initialize data members . m_clrFore =RGB (255 , 255 , 0) //yellow text m_clrBack=RGB (0 , 0 , 255) // blue background m_brush . CreateSolidBrush (m _clrBack ) } 最后,使用ClassWizard处理反射的WM_CTLCOLOR(=WM_CTLCOLOR)消息并指定新的绘画属性。 HBRUSH CMyListBox : : CtlColor (CDC* pDC, UINT nCtlColor ) { pDC—>SetTextColor (m_clrFore) pDC—>SetBkColor (m_clrBack) return (HBRUSH) m_brush.GetSafeHandle () } 现在,控件可以自己决定如何绘画,与父窗口无关。

(49) 当向列表框中添加多个项时如何防止闪烁 调用CWnd::SetRedraw 清除重画标志可以禁止CListBox(或者窗口)重画。当向列表框添加几个项时,用户可以清除重画标志,然后添加项,最后恢复重画标志。为确保重画列表 框的新项,调用SetRedraw (TRUE) 之后调用CWnd::Invalidate。 //Disable redrawing. pListBox->SetRedraw (FALSE) //Fill in the list box gere //Enable drwing and make sure list box is redrawn. pListBox->SetRedraw (TRUE) pListBox->Invalidate ()

(50) 如何向编辑控件中添加文本 由于没有CEdit:: AppendText函数,用户只好自己做此项工作。调用CEdit:: SetSel移动到编辑控件末尾,然后调用CEdit:: ReplaceSel添加文本。下例是AppendText 的一种实现方法: void CMyEdit:: AppendText (LPCSTR pText) { int nLen=GetWindowTextLength () SetFocus () SetSel (nLen, nLen) ReplaceSel (pText) }

(51) 如何访问预定义的GDI对象 可以通过调用CDC:: SlectStockObject使用Windows的几个预定义的对象,诸如刷子、笔以及字体。下例使用了Windows预定义的笔和刷子GDI对象在视窗中画一个椭圆。 //Draw ellipse using stock black pen and gray brush. void CSampleView:: OnDraw (CDC* pDC) { //Determine size of view. CRect rcView GetClientRect (rcView) //Use stock black pen and stock gray brush to draw ellipse. pDC->SelectStockObject (BLACK_PEN) pDC->SelectStockObject (GRAY_BRUSH) //Draw the ellipse. pDC->Ellipse (reView) } 也可以调用新的SDK函数GetSysColorBrush获取一个系统颜色刷子,下例用背景色在视窗中画一个椭圆: void CsampleView:: OnDraw (CDC* pDC) { //Determine size of view. CRect rcView GetClientRect (rcView) //Use background color for tooltips brush. CBrush * pOrgBrush=pDC->SelectObject ( CBrush ::FromHandle( ::GetSysColorBrush (COLOR_INFOBK))) //Draw the ellipse. pDC->Ellipse (rcView) //Restore original brush. pDC->SelectObject (pOrgBrush) }

(52) 如何获取GDI对象的属性信息 可以调用GDIObject:: GetObject。这个函数将指定图表设备的消息写入到缓冲区。下例创建了几个有用的辅助函数。 //Determine if font is bold. BOOL IsFontBold (const CFont&font) { LOGFONT stFont font.GetObject (sizeof (LOGFONT), &stFont) return (stFont.lfBold)? TRUE: FALSE } //Return the size of a bitmap. CSize GetBitmapSize (const CBitmap&bitmap) { BITMAP stBitmap bitmap.GetObject (sizeof (BITMAP), &stBitmap) return CSize (stBitmap.bmWidth, stBitmap.bmHeight) } //Create a pen with the same color as a brush. BOOL CreatePenFromBrush (Cpen&pen, cost Cbrush&brush) { LOGBRUSH stBrush brush.Getobject (sizeof (LOGBRUSH), &stBrush) return pen. Createpen (PS_SOLID, 0, stBrush.ibColor) }

(53) 如何实现一个橡皮区矩形 CRectTracker是一个很有用的类,可以通过调用CRectTracker::TrackRubberBand 响应WM_LBUTTONDOWN消息来创建一个橡皮区矩形。 下例表明使用CRectTracker移动和重置视窗中的蓝色椭圆的大小是很容易的事情。 首先,在文件档中声明一个CRectTracker数据成员: class CSampleView : Public CView { … public : CrectTracker m_tracker … } 其次,在文档类的构造函数中初始化CRectTracker 对象: CSampleDoc:: CSampleDOC () { //Initialize tracker position, size and style. m_tracker.m_rect.SetRect (0, 0, 10, 10) m_tracker.m_nStyle=CRectTracker:: resizeInside | CRectTracker ::dottedLine } 然后,在OnDraw函数中画椭圆和踪迹矩形: void CSampleView:: OnDraw (CDC* pDC) { CSampleDoc* pDoc=GetDocument () ASSERT_VALID (pDoc) //Select blue brush into device context. CBrush brush (RGB (0, 0, 255)) CBrush* pOldBrush=pDC->SelectObject (&brush) //draw ellipse in tracking rectangle. Crect rcEllipse pDoc->m_tracker.GetTrueRect (rcEllipse) pDC->Ellipse (rcEllipse) //Draw tracking rectangle. pDoc->m_tracker.Draw (pDC) //Select blue brush out of device context. pDC->Selectobject (pOldBrush) } 最后,使用ClassWizard处理WM_LBUTTONDOWN消息,并增加下述代码。该段代码根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。 void CSampleView::OnLButtonDown (UINT nFlags, CPoint point) { //Get pointer to document. CSampleDoc* pDoc=GetDocument () ASSERT_VALID (pDoc) //If clicked on ellipse, drag or resize it.Otherwise create a //rubber-band rectangle nd create a new ellipse. BOOL bResult=pDoc->m_tracker.HitTest (point)!= CRectTracker::hitNothing //Tracker rectangle changed so update views. if (bResult) { pDoc->m_tracker.Track (this,point,TRue) pDoc->SetModifiedFlag () pDoc->UpdateAllViews (NULL) } else pDoc->m-tracker.TrackRubberBand(this,point,TRUE) CView:: onLButtonDown (nFlags,point) }

(54) 如何更新翻转背景颜色的文本 调用CDC:: SetBkmode并传送OPAQUE用当前的背景颜色填充背景,或者调用CDC::SetBkMode并传送TRANSPAARENT使背景保持不变, 这两种方法都可以设置背景模式。下例设置背景模式为TRANSPARENT,可以两次更新串,用花色带黑阴影更新文本。黑色串在红色串之后,但由于设置了 背景模式仍然可见。 void CSampleView:: OnDraw (CDC* pDC) { //Determint size of view. CRect rcView GetClientRect (rcVieew) //Create sample string to display. CString str (_T ("Awesome Shadow Text...")) //Set the background mode to transparent. pDC->SetBKMode (TRANSPARENT) //Draw black shadow text. rcView.OffsetRect (1, 1) pDc->SetTextColor (RGB (0, 0, 0)) pDC->DrawText (str, str.GetLength (), rcView, DT_SINGLELINE | DT_CENTER | DT_VCENTER) //Draw red text. rcView.OffsetRect (-1,-1) pDc->SetTextColor (RGB (255, 0, 0)) pDC->DrawText (str, str.GetLength (), rcView, DT_SINGLELINE | DT_CENTER | DT_VCENTER) }

(55) 如何创建一个具有特定点大小的字体 可以指定字体逻辑单位的大小,但有时指定字体的点的大小可能会更方便一些。可以如下将字体的点转换为字体的高度: int nHeigth=mulDiv (nPointSize, -dc.GetDeviceCaps (LOGPIXELSY), 72) 下例创建了一个8点的Apial字体: … CClientDC dc (AqfxGetMainWnd ()) m_font. CreateFont (MulDiv (8, -dc.GetDeviceCaps (LOGPIXELSY), 72), 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS, DRAFT_QUALITY, VARIABLE_PITCH | FF-SWISS,_T("Arial"))

(56) 如何计算一个串的大小 函数CDC:: Det text Extent 根据当前选择的字体计算一个串的高度和宽度。如果使用的不是系统字体而是其他字体,则在调用GetTextExtent之前将字体选进设备上下文中是很重 要的,否则计算高度和宽度时将依据系统字体,由此得出的结果当然是不正确的。下述样板程序当改变下压按钮的标题时动态调整按钮的大小,按钮的大小由按钮的 字体和标题的大小而定。响应消息WM_SETTEXT时调用OnSetText,该消息使用ON_MESSAE宏指令定义的用户自定义消息。 LRESULT CMyButton:: OnSettext (WPARAM wParam, LPARAM lParam) { //Pass message to window procedure. LRESULT bResult=CallWindowProc (*GetSuperWndProcAddr(), m_hWnd, GetCurrentMessage() ->message,wParam,lParam) //Get title of push button. CString strTitle GetWindowText (strTitle) //Select current font into device context. CDC* pDC=GetDc () CFont*pFont=GetFont () CFont*pOldFont=pDC->SelectObject (pFont) //Calculate size of title. CSize size=pDC->GetTextExent (strTitle,strTitle.GetLength()) //Adjust the button's size based on its title. //Add a 5-pixel border around the button. SetWindowPos (NULL, 0, 0, size.cx+10, size.cy+10, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE) //Clean up. pDC->SelectFont (pOldFont) ReleaseDC (pDC) return bResult }

(57) 如何显示旋转文本 只要用户使用TrueType或者GDI笔或字体就可以显示旋转文本(有些硬件设备也支持旋转光 栅字体)。LOGFONT结构中的ifEscapement成员指定了文本行和x轴的角度,角度的单位是十分之一度而不是度,例如, ifEscapement为450表示字体旋转45度。为确保所有的字体沿坐标系统的同一方向旋转,一定要设置ifEscapement成员的 CLIP_LH_ANGLES位,否则,有些字体可能反向旋转。下例使用了14点Arial字体每间隔15度画一个串。 void CSampleView:: OnDraw (CDC* pDC) { //Determine the size of the window. CRect rcClient GetClientRect (rcClient) //Create sample string. CString str (_T ("Wheeee...I am rotating!")) //Draw transparent, red text. pDC->SetBkMode (TRANSPARENT) pDC->SetTextColor (RGB (255,0,0)) CFont font //font object LOGFONT stFont //font definition //Set font attributes that will not change. memset (&stFont, 0, sizeof (LOGFONT)) stFont.ifheight=MulDiv (14, -pDC->GetDeviceCaps(LOGPIXELSY), 72) stFont.ifWeight=FW_NORMAL stFont.ifClipPrecision=LCIP_LH_ANGLES strcpy (stFont.lfFaceName, "Arial") //Draw text at 15degree intervals. for (int nAngle=0 nAngle<3600 nAngle+=150) { //Specify new angle. stFont.lfEscapement=nAngle //Create and select font into dc. font.CreateFontIndirect(&stfont) CFont* pOldFont=pDC ->SelectObject(&font) //Draw the text. pDC->SelectObject(pOldFont) font.DelectObjext() } }

 

(58) 如何正确显示包含标签字符的串 调用GDI文本绘画函数时需要展开标签字符,这可以通过调用CDC:: TabbedTextOut或者CDC:: DrawText并指定DT_EXPANDTABS标志来完成。TabbedTextOut函数允许指定标签位的数组,下例指定每20设备单位展开一个标 签: void CSampleView:: OnDraw (CDC* pDC) { CTestDoc* pDoc=GetDocument () ASSERT_VALID (pDoC) CString str str.Format (_T ("Cathy\tNorman\tOliver")) int nTabStop=20 //tabs are every 20 pixels pDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10) }

(59) 如何快速地格式化一个CString对象 调用CString:: Format,该函数和printf函数具有相同的参数,下例说明了如何使用Format函数: //Get size of window. CRect rcWindow GetWindowRect (rcWindow) //Format message string. CString strMessage strMessage.Format (_T ("Window Size (%d, %d)"), rcWindow.Width (), rcWindow.Height ()) //Display the message. MessageBox (strmessage)

(60)  串太长时如何在其末尾显示一个省略号 调用CDC:: DrawText并指定DT_END_ELLIPSIS标志,这样就可以用小略号取代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息,指定DT_END_ELLIPSIS标志并省略号取代串中间的字符。 void CSampleView:: OnDraw (CDC* pDC) { CTestDoc* pDoc=GetDocument () ASSERT_VALID (pDoc) //Add ellpsis to end of string if it does not fit pDC->Drawtext (CString ("This is a long string"), CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS) //Add ellpsis to middle of string if it does not fit pDC->DrawText (AfxgetApp () ->m_pszhelpfilePath, CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS) }

(61) 为什么即使调用EnableMenuItem菜单项后,菜单项还处于禁止状态 需要将CFrameWnd:: m_bAutomenuEnable设置为FALSE,如果该数据成员为TRUE(缺省值),工作框将自动地禁止没有ON_UPDATE_COMMAND_UI或者ON_COMMAND的菜单项。 //Disable MFC from automatically disabling menu items. m_bAuoMenuEnable=FALSE //Now enable the menu item. CMenu* pMenu=GetMenu () ASSERT_VALID (pMenu) pMenu->EnableMenuItem (ID_MENU_ITEM,MF_BYCOMMAND | MF_ENABLED)

 

(62) 如何给系统菜单添加一个菜单项 给系统菜单添加一个菜单项需要进行下述三个步骤: 首先,使用Resource Symbols对话(在View菜单中选择Resource Symbols...可以显示该对话)定义菜单项ID,该ID应大于0x0F而小于0xF000; 其次,调用CWnd::GetSystemMenu获取系统菜单的指针并调用CWnd:: Appendmenu将菜单项添加到菜单中。下例给系统菜单添加两个新的 int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct) { … //Make sure system menu item is in the right range. ASSERT (IDM_MYSYSITEM &0xFFF0)==IDM_MYSYSITEM) ASSERT (IDM-MYSYSITEM<0xF000) //Get pointer to system menu. CMenu* pSysmenu=GetSystemmenu (FALSE) ASSERT_VALID (pSysMenu) //Add a separator and our menu item to system menu. CString StrMenuItem (_T ("New menu item")) pSysMenu->Appendmenu (MF_SEPARATOR) pSysMenu->AppendMenu (MF_STRING, IDM_MYSYSITEM, strMenuitem) … } 现在,选择系统菜单项时用户应进行检测。使用ClassWizard处理WM_SYSCOMMAND消息并检测用户菜单的nID参数: void CMainFrame:: OnSysCommand (UINT nID,LPARAM lParam) { //Determine if our system menu item was selected. if ( (nID & 0xFFF0)==IDM_MYSYSITEM) { //TODO-process system menu item } else CMDIFrameWnd ::OnSysCommand (nID, lParam) } 最后,一个设计良好的UI应用程序应当在系统菜单项加亮时在状态条显示一个帮助信息,这可以通过增加一个包含系统菜单基ID的串表的入口来实现。

(63) 如何确定顶层菜单所占据的菜单行数 这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度;最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代码实现。 int CMainFrame:: GetMenuRows () { CRect rcFrame,rcClient GetWindowRect (rcFrame) GetClientRect (rcClient) return (rcFrame.Height () -rcClient.Height () - :: GetSystemMetrics(SM_CYCAPTION) - (:: getSystemMetrics(SM_CYFRAME) *2)) / :: GetSystemMetrics(SM_CYMENU) }

(64) 在用户环境中如何确定系统显示元素的颜色 调用SDK函数GetSysColor可以获取一个特定显示元素的颜色。下例说明了如何在MFC函数CMainFrameWnd:: OnNcPaint中调用该函数设置窗口标题颜色。 void CMiniFrameWnd:: OnNcPaint () { … dc.SetTextColor (:: GetSysColor (m_bActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT)) …

 

(65) 如何查询和设置系统参数 在Windows 3.1 SDK中介绍过SDK函数SystemParametersInfo,调用该函数可以查询和设置系统参数,诸如按键的重复速率设置、鼠标双击延迟时间、图标字体以及桌面覆盖位图等等。 //Create a font that is used for icon titles. LOGFONT stFont ∶: SystemParametersInfo (SPIF_GETICONTITLELOGFONT, sizeof (LOGFONT), &stFont, SPIF_SENDWININICHANGE) m_font.CreateFontIndirect (&stFont) //Change the wallpaper to leaves.bmp. ∶ : SystemParametersInfo (SPI_SETDESKWALLPAPER, 0, _T (" forest.bmp"), SPIF_UPDATEINIFILE)

 

(66) 如何确定当前屏幕分辨率 调用SDK函数GetSystemMetrics,该函数可以检索有关windows显示信息,诸如标题大小、边界大小以及滚动条大小等等。 //Initialize CSize object with screen size. CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN))

 

(67) 如何使用一个预定义的Windows光标 调用CWinApp:: LoadStandardCursor并传送光标标识符。 BOOL CSampleDialog:: OnSetCursor (CWnd* pWnd, UINT nHitTest, UINT message) { //Display wait cursor if busy. if (m_bBusy) { SetCursor (AfxGetApp () ->LoadStandardCursor (IDC_WAIT)) return TRUE } return CDialog:: OnSetCursor (pWnd. nHitTest,message) }

(68) 如何检索原先的Task Manager应用程序使用的任务列表 原先的Task Manager应用程序显示顶层窗口的列表。为了显示该列表,窗口必须可见、包含一个标题以及不能被其他窗口拥有。调用CWnd:: GetWindow可以检索顶层窗口的列表,调用IsWindowVisible、GetWindowTextLength以及GetOwner可以确定 窗口是否应该在列表中。下例将把TaskManager窗口的标题填充到列表中。 void GetTadkList (CListBox&list) { CString strCaption //Caption of window. list.ResetContent () //Clear list box. //Get first Window in window list. ASSERT_VALID (AfxGetMainWnd ()) CWnd* pWnd=AfxGetMainWnd () ->GetWindow (GW_HWNDFIRST) //Walk window list. while (pWnd) { // I window visible, has a caption, and does not have an owner? if (pWnd ->IsWindowVisible() && pWnd ->GetWindowTextLength () &&! pWnd ->GetOwner ()) { //Add caption o window to list box. pWnd ->GetWindowText (strCaption) list.AddString (strCaption) } //Get next window in window list. pWnd=pWnd ->GetWindow(GW_HWNDNEXT) } }

(69) 如何确定Windows和Windows系统目录 有两个SDK函数可以完成该功能。GetWindowsDirectory和GetSystemDirectory,下例说明了如何使用这两个函数: TCHAR szDir [MAX_PATH] //Get the full path of the windows directory. ∶ : GetWindowsDirectory (szDir, MAX_PATH) TRACE ("Windows directory %s\n", szDir) //Get the full path of the windows system directory. ∶ : GetSystemDirectory (szDir, MAX_PATH) TRACE ("Windows system directory %s\n", szDir)

(70) 在哪儿创建临文件 调用SDK函数GetTemPath可以确定临时文件的目录,该函数首先为临时路径检测TMP环境变量:如果没有指定TMP,检测TMP环境变量,然后返回到当前目录。下例说明了如何创建一个临时文件。 … //get unique temporary file. CString strFile GetUniqueTempName (strFile) TRY { //Create file and write data.Note that file is closed //in the destructor of the CFile object. CFile file (strFile,CFile ::modeCreate | Cfile:: modeWrite) //write data } CATCH (CFileException, e) { //error opening file } END_CATCH … Void GetuniqueTempName (CString& strTempName) { //Get the temporary files directory. TCHAR szTempPath [MAX_PATH] DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath) ASSERT (dwResult) //Create a unique temporary file. TCHAR szTempFile [MAX_PATH] UINT nResult=GetTempFileName (szTempPath, _T ("~ex"),0,szTempfile) ASSERT (nResult) strTempName=szTempFile }

(71) 我怎样才能建立一个等待光标? 调 用 BeginWaitCursor 函 数 来 启 动 等 待 光 标,调 用 EndWaitCursor 函 数 来 结 束 等 待 光 标。要 注 意,二 者 都 要 调 用 app 的 成 员 函 数,如 下 所 示:      AfxGetApp()->BeginWaitCursor();      // 要做的事      AfxGetApp()->EndWaitCursor();

(72) 我在MDI框架中有个 form 视窗。它有个取消按钮,我需要当用户按取消按钮时可关闭form视窗。我应该如何关闭该文档? 调 用 OnCloseDocument 函 数。

(73) 如何访问桌面窗口 静态函数CWnd:: GetDesktopWindow 返回桌面窗口的指针。下例说明了MFC函数CFrameWnd::BeginModalStae是如何使用该函数进入内部窗口列表的。 void CFrameWnd::BeginModalState () { … //first count all windows that need to be disabled UINT nCount=0 HWND hWnd= :: GetWindow (:: GetDesktopWindow(), GW_CHILD) while (hWnd!=NULL) { if (:: IsWindowEnabled (hwnd) && CWnd::FromHandlePermanent (hWnd)!=NULL && AfxIsDescendant (pParent->m_hWnd, hWnd) && :: SendMessage (hWnd, WM_DISABLEMODAL, 0, 0)==0) { ++nCount } hWnd=:: GetWindow (hWnd, GW_HWNDNEXT) } …

(74) 什么是COLORREF? 我该怎样用它? COLORREF 是 一 个 32-bit 整 型 数 值,它 代 表 了 一 种 颜 色。你 可 以 使 用 RGB 函 数 来 初 始 化 COLORREF。例 如:      COLORREF color = RGB(0, 255, 0); RGB 函 数 接 收 三 个 0-255 数 值,一 个 代 表 红 色, 一 个 代 表 绿 色, 一 个 代 表 蓝 色。在 上 面的 例 子 中, 红 色 和 蓝 色 值 都 为 0,所 以 在 该 颜 色 中 没 有 红 色 和 蓝 色。绿 色 为 最 大 值 255。所 以 该 颜 色 为 绿 色。0,0,0 为 黑 色,255,255,255 为 白 色。 另 一 种 初 始 化 COLORREF 的 方 法 如 下 所 示:      CColorDialog colorDialog;      COLORREF color;      if( colorDialog.DoModal() == IDOK )      {          color = colorDialog.GetColor();      } 这 段 代 码 使 用 了 MFC 中 的 颜 色 对 话 框,它 需 要 文 件。

 

(75) AppWizard所产生的STDAFX文件是干什么用的? 它 主 要 是 协 助 产 生 预 编 译 头 文 件 的。通 常 你 是 不 需 要 修 改 它 的。

(76) 我在我的程序中是了CDWordArray。我向它添加了约10,000个整数,这使得它变得非常非常慢。为什么会这么糟? CDWordArray 是 很 好 用 的,只 是 因 为 你 没 有 指 定 数 组 的最大尺寸。因 此,当 你 添 加 新 元 素 时,该 类 会 从 堆 中 重 新 分 配 空 间。不 幸 的 是,该 类 会 在 每 次 插 入 新 元 素 时 都 为 数 组 重 新 分 配 空 间。如 果 你 向 它 添 加 了 很 多 新 元 素,所 有 这 些 分 配 和 复 制 数 组 的 操 作 会 就 会 使 它 变 慢。解 决 该 问 题 的 方 法 是,你 可 以 使 用 SetSize 函 数 的 第 二 个 参 数 来 改 变 这 种 重 新 分 配 的 频 率。例 如,如 果 你 把 该 参 数 设 置 为 500,则 每 次 数 组 空 间 超 出 时 它 才 重 新 分 配 并 添 加 500 个 新 空 间,而 不 是 1 个。这 样 一 来,你 就 可 以 不 用 重 新 分 配 而 添 加 了 另 外 499 个 元 素 空 间,这 也 会 大 大 提 高 程 序 的 运 行 速 度。

 

(77) 我该如何改变MDI框架窗口的子窗口的大小以使在窗口以一定的大小打开? 在 视 中 的 OnInitialUpdate 函 数 中 调 用 GetParentFrame 函 数。GetParentFrame 会 返 回 一 指 向 一 保 存 有 该 视 的 框 架 窗 口 的 指 针。然 后 调 用 在 框 架 窗 口 上 调 用 MoveWindow。

(78) 在我的程序的某些部分,我可以调用 MessageBox 函数来建立一个信息对话框,例如在视类中。但是,在其它部分我却不能,如文档类中。为什么?我怎样才能在我的应用程序类中建立一个信息对话框? MessageBox 函 数 来 自 CWnd 类,所 以 你 只 能 在 从 CWnd 继 承 的 类 ( 如 CView ) 中 调 用 它。但 是,MFC 也 提 供 了 AfxMessageBox 函 数,你 可 以 在 任 何 地 方 调 用 它。

 

(79) 我需要在我的程序中设置全局变量,以使文档中的所有类都能访问。我应该吧它放到哪儿? 把 该 变 量 放 到 该 应 用 程 序 类 的 头 文 件 中 的 attribute 处。然 后,在 程 序 的 任 何 地 方,你 都 可 以 用 下 面 的 方 法 来 访 问 该 变 量:      CMyApp *app = (CMyApp *)AfxGetApp();      app->MyGlobalVariable = ...

(80) 我听说MFC可以发现内存漏洞,我怎样使用该特性? 如 果 你 在 Debug 菜 单 中 的 Go 选 项 ( 不 是 Project 菜 单 中 的 Execute 选 项 ) 来 运 行 你 的 应 用 程 序,MFC 应 该 在 程 序 终 止 时 报 告 内 存 漏 洞。如 果 没 有,那 么 试 试 运 行 MFC Tracer 工 具 程 序 ( 在 VC++ 程 序 组 中 ),并 启 动 跟 踪。然 后 返 回 应 用 程 序。

(81) 我怎样才能在我的应用程序中循环浏览已经打开的文档? 使用CDocTemplate中未公开的GetFirstDocPosition()和GetNextDoc()函数。

 

(82)才能在我的应用程序中循环浏览已经打开的视? 使 用 CDocument 中 未 公 开 的 GetFirstViewPosition() 和 GetNextView() 函 数。

(83)数PreCreateWindow是干什么用的? PreCreateWindow 允 许 你 在 调 用 CreateWindow 之 前 来 改 变 窗 口 属 性。

(84)该怎样防止MFC在窗口标题栏上把文档名预置成应用程序名? 在 PreCreateWindow 函 数 中 删 除 FWS_PREFIXTITLE 标 志 的 窗 口 样 式:      cs.style &= ~FWS_PREFIXTITLE;

 

(85) 我应该怎样防止MFC在窗口标题栏上添加文档名? 在 PreCreateWindow 函 数 中 删 除 FWS_ADDTOTITLE 标 志 的 窗 口 样 式:      cs.style &= ~FWS_ADDTOTITLE ;

 

(86) 我应该如何改变视窗口的大小? 因 为 视 窗 口 实 际 上 是 框 架 窗 口 的 子 窗 口,所 以 你 必 须 改 变 框 架 窗 口 的 大 小,而 不 是 改 变 视 窗 口。使 用 CView 类 中 的 GetParentFrame() 函 数 获 得 指 向 框 架 窗 口 的 指 针,然 后 调 用 MoveWindow() 函 数 来 改 变 框 架 的 大 小。这 会 使 变 尺 寸 的 视 充 满 框 架 窗 口。

(87) 我有一无模式对话框。我怎样才能在窗口退出时删除CDialog对象? 把“delete this”加 到 PostNcDestroy 中。这 主 要 用 在 需 要 自 动 删 除 对 象 的 场 合。

 

(88) 为什么把“delete this”放在PostNcDestroy中而不是OnNcDestroy? OnNcDestroy 只 被 已 建 立 的 窗 口 调 用。如 果 建 立 窗 口 失 败 ( 如 PreCreateWindow ),则 没 有 窗 口 处 来 发 送 WM_NCDESTROY 消 息。PostNcDestroy 是 在 对 象 窗 口 被 完 全 删 除,在 OnNcDestroy 后,甚 至 在 窗 口 建 立 失 败 之 后 调 用 的。

 

(89) File菜单中的MRU列表是从哪儿来的?列表中的名字放在哪儿了?我怎样才能改变列表中项目的最大值? 在 应 用 程 序 类 的 InitInstance 函 数 中 对 LoadStdProfileSettings 的 调 用 中。该 调 用 接 受 一 个 参 数 ( 在 缺 省 情 况 下 如 果 没 有 传 递 值 则 为 4 )。MRU 文 件 名 是 从 INI 文 件 中 调 用 的。如 果 你 有 带 有 ID_FILE_MRU_FILE1 的 ID 的 菜 单 选 项,它 会 为 调 入 的 MRU 列 表 所 替 换。如 果 你 改 变 传 递 给 LoadStdProfileSettings 的 数 值 ( 最 大 为 16 ),则 你 就 改 变 了 所 装 如 文 件 名 的 最 大 值。

(90) 我在菜单中添加了新的项。但是,当我选该项时,在状态栏上没有出现任何提示信息。为什么? 打 开 资 源 文 件 中 的 菜 单 模 板。打 开 新 菜 单 选 项 的 属 性 对 话 框。在 对 话 框 的 底 部 的 Prompt 编 辑 框 中 ,你 可 以 如 下 指 定 状 态 栏 上 的 提 示 信 息 和 工 具 栏 上 的 提 示 信 息 ( 如 果 你 已 经 建 立 的 工 具 栏 按 钮 ):      Status bar string\nFlying tag

(91) 我怎样才能在应用程序的缺省系统菜单中加上一些东西? 系 统 菜 单 与 其 它 菜 单 类 似,你 可 以 添 加 或 删 除 项 目,这 需 要 使 用 CMenu 类 的 成 员 函 数。下 面 的 代 码 在 你 的 系 统 菜 单 后 面 添 加 一 个 新 菜 单 项:      CMenu *sysmenu;      sysmenu = m_pMainWnd->GetSystemMenu(FALSE);      sysmenu->AppendMenu(MF_STRING, 1000, "xxx"); 参 见 MFC 帮 助 文 件 中 的 CMenu 类。

(92) 我建立了一个对话框。但是当我显示该对话框时,第一个编辑框总是不能获得焦点,我必须单击它来使它获得焦点。我怎样才能使第一个编辑框在对话框打开时就获得焦点? 打 开 资 源 编 辑 器 中 的 对 话 框 模 板。在 Layout 菜单 中 选 择 Tab Order 选 项。按 你 的 需 求 单 击 对 话 框 中 的 控 制 来 重 新 排 列 这 些 控 制 的 tab 顺 序。

(93) 我怎样才能使一个窗口具有“always on top”特性? 在 调 用 OnFileNew 后,在 你 的 InitInstance 函 数 中 加 上 下 面 的 代 码: m_pMainWnd->SetWindowPos(&CWnd::wndTopMost,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);

(94)   我要为我的form view添加文档模板。我先建立了对话框模板,然后使用ClassWizard建立了基于CFormView的新类,它也是从CDocument继承来 的。我还建立了相应的资源并在InitInstance中添加了新的文档模板。但是,当我试图运行该程序时,出现了Assertion信息。为什么?

form 的 对 话 框 模 板 需 要 些 特 殊 设 置 以 便 可 用 于 CFromView。确 保 这 些 设 置 的 最 简 单 方 法 是 使 用 AppWizard 来 建 立 CFormView 应 用 程 序,并 查 看 AppWizard 所 建 立 的 对 话 框 模 板 所 选 择 的Styles Properties。你 会 发 现 该 对 话 框 模 板 具 有 下 列 样 式:没 有 标 题 栏、不 可 见 和“Child”。把 你 的 form view 的 对 话 框 属 性 变 成 这 样 就 可 以 了。 (95)   我在一对话框中有一列表框,我需要tabbed列表框中的项目。但是,当我处理含有tab字符(用AddString添加的)的列表项时,tab被显示成小黑块而没有展开。哪儿出错了?

在 对 话 框 模 版 中,打 开 列 表 框 的 属 性。确 保 选 择 了“Use Tabstops” 样 式。然 后,确 保 在 对 话 框 类 中 OnInitDialog 函 数 中 调 用 SetTabStops。 (96)   我建立了一个应用程序,并使用了CRecordset类。但是,当我运行该程序时,它试图要访问数据库,并给出“Internal Application Error”对话框。我应该怎样做?

通 常 情 况 下,当 你 的 程 序 中 向 数 据 库 发 送 信 息 的 SQL 语 句 出 现 问 题 时 才 出 现 该 对 话 框。例 如,参 见 下 面 的 例 子:      set.m_strFilter = "(ZipCode = '27111')"; 如 果 ZipCode 列 被 定 义 为 字 符 串 时 不 会 出 现 问 题,如 果 定 义 为 long,则 会 出 现“Internal Application Error”对 话 框,这 是 由 于 类 型 不 匹 配 的 缘 故。如 果 你 删 除 27111 的 单 引 号,则 不 会 出 现 问 题。当 你 看 到“Internal Application Error”时,最 好 检 查 一 下 试 图 要 发 送 给 数 据 库 的 SQL 语 句。 (97)   我用ClassWizard建立了一个类。但是,我把名字取错了,我想把它从项目中删除,应该如何做?

在 ClassWizard 对 话 框 关 闭 后,用 文 件 管 理 器 删 除 新 类 的 H 和 CPP 文 件。然 后 打 开 ClassWizard,它 会 提 示 丢 失 了 两 个 文 件,并 询 问 你 该 如 何 做。你 可 以 选 择 从 项 目 中 删 除 这 两 个 问 的 按 钮。

(98)     当我打开应用程序中的窗口时,我要传递该窗口的矩形尺寸。该矩形指定了窗口的外围大小,但是当我调用GetClientRect时,所得到的尺寸要比所希望的值要小(因为工具栏和窗口边框的缘故)。有其它方法来计算窗口的尺寸吗?

参 见 CWnd::CalcWindowRect。 (99)   我在文档类中设置了一个整型变量。但是,当我试图把该变量写入Serialize函数中的archive文件中时,出现了类型错误。而文档中的其它变量没有问题。为什么?

archive 类 只 重 载 某 些 类 型 的 >> 和 << 操 作 符。“int”类 型 没 有 在 其 中,也 许 是 因 为 int 变 量 在 Windows 3.1 与 Windows NT/95 有 所 不 同 的 缘 故 吧。“long”类 型 得 到 了 支 持,所 以 你 可 以 把 int 类 型 改 成 long 型。参 见 MFC 帮 助 文 件 中 CArchive 类。

(100)   如何控制菜单的大小? 我用MFC的CMenu生成了一个动态菜单(例如File,Edit,View...Help), 我想控制这个菜单的大小(长+高).

方法一:查找 WM_MEASUREITEM 和 MEASUREITEMSTRUCT. 方法二:查询系统::GetSystemMetric(SM_CXMENUSIZE).

     /* 你可以通过如下代码来获得文本的大小:          (A)获得被使用的字体 */

       NONCLIENTMETRICS ncm;      HFONT hFontMenu;      SIZE size;      size.cy = size.cy = 0;

     memset(&ncm, 0, sizeof(NONCLIENTMETRICS));      ncm.cbSize = sizeof(NONCLIENTMETRICS);      if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0))      {            hFontMenu = CreateFontIndirect(&ncm.lfMenuFont);            /*            (B) 获得菜单项的文本: */            char szText[_MAX_PATH];

           pMenu->GetMenuString(0, szText, _MAX_PATH, MF_BYPOSITION);            /*            然后,获得菜单项文本的高度: */            HFONT hFontOld;            HDC hDC;

           hDC = ::GetDC(NULL);            hFontOld = (HFONT) ::SelectObject(hDC, hFontMenu);            GetTextExtentPoint32(hDC, szText, lstrlen(szText), &size);            SelectObject(hDC, hFontOld);            ::ReleaseDC(NULL, hDC);      }      /*此时,size.cy即为高度,size.cx为宽度,你可以给菜单加上自定义的高度和宽度,通过比较,我发现宽度为4

比较合适。*/

(101)   改变LVIS_SELECTED的状态颜色? 我想将CListCtrl项和CTreeCtrl项在LVIS_SELECTED状态时的颜色变灰.

方法一:查找函数CustomDraw,它是IE4提供的公共控制,允许有你自己的代码. 方法二:生成一个draw控件,然后在DrawItem中处理文本颜色.

(102)   如何只存储文档的某一部分? 我只想存储文档的某一部分,能否象使用文件一样使用文档?(也就是有定位函数).将每个CArchive类设置为CFile类的派生类,这样你就能使用Seek等成员函数.

(103)   保存工具条菜单有bug吗?

使用浮动菜单条时,SaveBarState和LoadBarState出现了问题.如果菜单是浮动的,重起应用程序时它会出现在左上角,而它固定 在屏幕其它位置时,下一次启动就会出现在该位置,这是什么原因?你试试这个PToolBar->Create(this,..., ID_MYTOOLBAR); 你的工具条需要包括id,而不是象默认的工具条那样.

(104)   Tip of the day的bug

我创建了一个简单的mdi应用程序,使用.BSF(自定义的文档扩展名)作为它的文档我保存一个foo.bsf文档后,可以在资源管理器中双击该文 件打开mdi应用程序同时打开foo.bsf文档.但当我给mdi应用程序加上a tip of the day组件之后,从资源管理器中双击foo.bsf后,就会给我一个警告:ASSERT(::IsWindow(m_hWnd)),然后mdi应用程序就 死那了. 当从dde启动应用程序(例如:双击相关文档)时,"Tip of the Day"是有bug的.你可以看看函数"ShowTipAtStartup",它在"InitInstance"中调用,可以看到tip of the day作为一个模式对话框显示,在处理其它消息时它一直进行消息循环你可心修改ShowTipAtStartup使其从dde启动时不出现tip of the day. void CTipOfApp::ShowTipAtStartup(void)          {                  // CG: This function added by 'Tip of the Day' component.                  CCommandLineInfo cmdInfo;                  ParseCommandLine(cmdInfo);                  if (                          cmdInfo.m_bShowSplash &&                          cmdInfo.m_nShellCommand != CCommandLineInf:FileDDE                          )                  {                          CTipDlg dlg;                          if (dlg.m_bStartup)                                  dlg.DoModal();                  }          } 如果还有其它bug,你可以设定cmdInfo.m_nShellCommand的过滤. (105)   如何可以让我的程序可以显示在其它的窗口上面? 让用户选择"总是在最上面"最好是在系统菜单里加入一个选项.可以通过修改WM_SYSCOMMAND消息来发送用户的选择.菜单的命令标识(id)会作为一个参数传给OnSysCommand().要定义标识(id),将如下代码加入到CMainFrame.CPP中:      #define WM_ALWAYSONTOP WM_USER + 1 将"总在最上面"的菜单项加入到系统菜单中,将如下代码加入到函数CMainFrame::OnCreate()中:        CMenu* pSysMenu = GetSystemMenu(FALSE);        pSysMenu->AppendMenu(MF_SEPARATOR);        pSysMenu->AppendMenu(MF_STRING, WM_ALWAYSONTOP,                      "&Always On Top"); 使用ClassWizard,加入对WM_SYSCOMMAND消息的处理,你应该改变消息过滤器,使用系统可以处理这个消息. void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) {      switch ( nID )      {      case WM_ALWAYSONTOP:          if ( GetExStyle() & WS_EX_TOPMOST )          {              SetWindowPos(&wndNoTopMost, 0, 0, 0, 0,                  SWP_NOSIZE | SWP_NOMOVE);              GetSystemMenu(FALSE)->CheckMenuItem(WM_ALWAYSONTOP,                  MF_UNCHECKED);          }          else          {              SetWindowPos(&wndTopMost, 0, 0, 0, 0,                  SWP_NOSIZE | SWP_NOMOVE);              GetSystemMenu(FALSE)->CheckMenuItem(WM_ALWAYSONTOP,MF_CHECKED);          }          break;      default:          CFrameWnd::OnSysCommand(nID, lParam);      } } (106)     如何控制窗口框架的最大最小尺寸?

要控制一个框架的的最大最小尺寸,你需要做两件事情.在CFrameWnd的继承类中处理消息WM_GETMINMAXINFO,结构MINMAXINFO设置了整个窗口类的限制,因此记住要考虑工具条,卷动条等等的大小. // 最大最小尺寸的象素点 - 示例 #define MINX 200 #define MINY 300 #define MAXX 300 #define MAXY 400 void CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) {      CRect rectWindow;      GetWindowRect(&rectWindow);      CRect rectClient;      GetClientRect(&rectClient);        // get offset of toolbars, scrollbars, etc.      int nWidthOffset = rectWindow.Width() - rectClient.Width();      int nHeightOffset = rectWindow.Height() - rectClient.Height();      lpMMI->ptMinTrackSize.x = MINX + nWidthOffset;      lpMMI->ptMinTrackSize.y = MINY + nHeightOffset;      lpMMI->ptMaxTrackSize.x = MAXX + nWidthOffset;      lpMMI->ptMaxTrackSize.y = MAXY + nHeightOffset; } 第二步,在CFrameWnd的继承类的PreCreateWindow函数中去掉WS_MAXIMIZEBOX消息,否则在最大化时你将得不到预料的结果. BOOL CMyFrameWnd::PreCreateWindow(CREATESTRUCT& cs) {      cs.style &= ~WS_MAXIMIZEBOX;      return CFrameWnd::PreCreateWindow(cs); } (107)     如何改变窗口框架的颜色?

MDI框架的客户区被另一个窗口的框架所覆盖.为了改变客户区的背景色,你需要重画这个客户窗口.为了做到这点,你要处理消息WM_ERASEBKND产生一个新类,从CWnd继承,姑且称之为CMDIClient.给它加上一个成员变量, #include "MDIClient.h" class CMainFrame : public CMDIFrameWnd { ... protected: CMDIClient m_wndMDIClient; } 在CMainFrame中重载CMDIFrameWnd::OnCreateClient BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {      if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) )      {          m_wndMDIClient.SubclassWindow(m_hWndMDIClient);          return TRUE;      }      else          return FALSE; } 然后就可以加入对消息WM_ERASEBKGND的处理了. (108)     如何将应用程序窗口置于屏幕正中?

要将你的应用程序窗口放置在屏幕正中央,只须在MainFrame的OnCreate函数中加入: CenterWindow( GetDesktopWindow() );

转载请注明原文地址: https://www.6miu.com/read-42262.html

最新回复(0)