|
Visual C++编程技巧83例
Visual C++编程技巧之八
57、为什么即使调用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); 给系统菜单添加一个菜单项需要进行下述三个步骤: 首先,使用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的串表的入口来实现。 这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度;最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代码实现。 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); } 调用SDK函数GetSysColor可以获取一个特定显示元素的颜色。下例说明了如何在MFC函数CMainFrameWnd:: OnNcPaint中调用该函数设置窗口标题颜色。 void CMiniFrameWnd:: OnNcPaint () { … dc.SetTextColor (:: GetSysColor (m_bActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT)); … } 在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); 调用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); } 调用SDK函数GetSystemMetrics,该函数可以检索有关windows显示信息,诸如标题大小、边界大小以及滚动条大小等等。 //Initialize CSize object with screen size. CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN)); 64、如何检索原先的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); } } 有两个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); 调用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; } 静态函数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); } … } |