(26) 如何编程结束应用程序?这是个很简单又是编程中经常要遇到的问题.向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示是否保存修改过的数据.Example: AfxGetMainWindow()->SendMessage(WM_CLOSE) 还可以创建一个自定义的函数 Terminate Windowvoid 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 rountinewill 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 CSampleDialogASSERT_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 elsedwStyle & = ~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 fontm_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 _QUALITYVARIABLE_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* pdcconst 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 buttonm_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 CButtonASSERT_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 uppercasevoid 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{…privateCOLORREF m_clrFor // foreground colorCOLORREF m_clrBack //background colorCbrush m_brush //background brush…}其次,在类的构造函数中,初始化数据中。CMyListBox : : CMyListBox (){//Initialize data members .m_clrFore =RGB (255 , 255 , 0) //yellow textm_clrBack=RGB (0 , 0 , 255) // blue backgroundm_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)}

评论