正文

[ZT]VC小技巧(3)2006-11-30 09:12:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/otot/21078.html

分享到:

(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文件是干什么用的?它 主 要 是 协 助 产 生 预 编 译 头 文 件 的。通 常 你 是 不 需 要 修 改 它 的。

阅读(6374) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册