(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)}(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 rcViewGetClientRect (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 rcViewGetClientRect (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 stFontfont.GetObject (sizeof (LOGFONT), &stFont)return (stFont.lfBold)? TRUE: FALSE}//Return the size of a bitmap.CSize GetBitmapSize (const CBitmap&bitmap){BITMAP stBitmapbitmap.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 stBrushbrush.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 rcEllipsepDoc->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)}elsepDoc->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 rcViewGetClientRect (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 strTitleGetWindowText (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 rcClientGetClientRect (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 objectLOGFONT 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_NORMALstFont.ifClipPrecision=LCIP_LH_ANGLESstrcpy (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 strstr.Format (_T ("Cathy/tNorman/tOliver"))int nTabStop=20 //tabs are every 20 pixelspDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10)}(59) 如何快速地格式化一个CString对象调用CString:: Format,该函数和printf函数具有相同的参数,下例说明了如何使用Format函数://Get size of window.CRect rcWindowGetWindowRect (rcWindow)//Format message string.CString strMessagestrMessage.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 fitpDC->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 fitpDC->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}elseCMDIFrameWnd ::OnSysCommand (nID, lParam)}最后,一个设计良好的UI应用程序应当在系统菜单项加亮时在状态条显示一个帮助信息,这可以通过增加一个包含系统菜单基ID的串表的入口来实现。(63) 如何确定顶层菜单所占据的菜单行数这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度;最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代码实现。int CMainFrame:: GetMenuRows (){CRect rcFrame,rcClientGetWindowRect (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, UINTmessage){//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 strFileGetUniqueTempName (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 disabledUINT nCount=0HWND 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 400void 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::OnCreateClientBOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext){if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) ){m_wndMDIClient.SubclassWindow(m_hWndMDIClient);return TRUE;}elsereturn FALSE;}然后就可以加入对消息WM_ERASEBKGND的处理了.(108) 如何将应用程序窗口置于屏幕正中?要将你的应用程序窗口放置在屏幕正中央,只须在MainFrame的OnCreate函数中加入:CenterWindow( GetDesktopWindow() );
转载请注明原文地址: https://ibbs.8miu.com/read-900331.html