主题: [转帖]编程技巧
精华帖 (0)   良好帖 (0)   新手帖(0)   垃圾帖 (0)      收藏
  • caterzh 我现在不在线,你找我吗?
  • 显示默认头像
  • 昵称:caterzh
  • 专家等级:新手上路
  • 专家分:0
  • 可用分等级:佃户
  • 精华:0
  • 帖子数:6
  • 结帖率: 100%
  • 注册时间:2005-09-15 14:21:00
发表于 2006-04-12 17:09:00
楼主

 [转帖]编程技巧

VC++:编程技巧

  VC++给人的第一感觉便是过于专业化,高深和晦涩。其实也并非如此,在基 本掌握了它之后你就会发现,VC++使用起来是很方便的。至于说难,那是有点。 但这并非是VC++的过错,而是Windows,这个庞大无比对用户亲切之至却对程序员 不那么友好的家伙。再说,VC++系出自名门,微软的哪样东西不是先把你服侍得 舒舒服服,然后再把你口袋中的钱掏个精光呢?好,下面就向大家介绍几个在使 用中的小技巧。

  1.使用中文

  VC++从1.5版到现在的6.0版,好像还没有出现过像VB一样的中文版。大概是 Microsoft认为能够用VC++编程的人英文水平都很高吧,但这对用户可不行啊。 VC++在中文平台下可以使用中文,但编译后那些按钮上的、对话框上的中文都成 ASCII码了。何故?因为VC++在安装时是默认按单词节字符安装的,而中文字符是 双字节编码,自然就不能正确显示了。要解决这个问题其实也很容易,将VC++光 盘上DEVSTUDIOSHAREDIDEBINIDE路径下的中文资源语言模块Appwzchs.dll拷贝至 硬盘DevStudioSharedIDEBINIDE路径下即可。

  2.位图按钮的使用

  我们知道Windows是一个图形界面的操作系统,如果在我们的应用程序中加入 一些图形的话,会起到锦上添花的效果。在VC++中使用位图,并不像在VB中信手 拈来那么简单。不过也并不复杂,其中以位图按钮用途较广。

  选定要使用位图的按钮(以OK按钮为例,假设其标识符为IDC_BtonOK),选 其属性中的Owner draw选项,此时,在对话框编辑器中就可看到原先显示在按钮 上的字符都消失了。将按钮的Caption改为OK(必须为大写)。打开Insert菜单, 单击其中的Resource选项,随后选择Bitmap。再按下Import(导入)按钮,将所 需位图导入项目(Project)。可以在Resource View窗口中通过右键单击刚才导 入的位图,将其ID(标识符)改为"OKU",注意:字符必须为大写,双引号及字母 U必不可少。字母U代表的按钮为按下状态时所显示的位图。此外还可使用后缀D、 F、X,分别表示按下、拥有输入焦点时、按钮处于无效状态时所显示的位图。通 过对同一个按钮的不同状态使用不同的位图,很容易做出具有动态效果的按钮。

  当将按钮所需使用的位图导入到项目中后,就应该在使用位图按钮的那个对 话框的类声明文件中加入位图按钮变量的定义CBitmapButton m_BtonOK。同时, 在适当的位置(一般是在对话框的OnInitDialog()函数中)加入如下语句: m_BtonOK.AutoLoad(IDC_BtonOK),使程序在运行时将位图装入内存并显示。至 此,创建位图按钮的整个步骤即告结束。

  上述方法不仅限于创建位图按钮,还可用于在对话框上显示简单的位图。嘘 ,告诉你一个小秘密,位图按钮所使用的颜色最多可达256种,而非位图编辑器中 的16种。但对于256色位图,当在导入VC++的位图编辑器后就不能使用该编辑器作 任何修改。否则在编译连接后,原先256色位图就变成16色位图了。

  3.通用对话框的使用

  在编程中,自己要设计存储或打开文件时的对话框是件很头疼的事。不过 Windows既然已经为我们提供好了现成的通用对话框,只管拿来用就是了。先在使 用文件对话框的类的类定义文件中加入对象定义CFileDialog m_OpenDialog(TRUE,"txt","*.txt")。随后,在需要使用该对话框的地方加入以 下语句:m_OpenDialog.Domodal();

  其调用规则为:

  CFileDialog(BOOL bOpenFileDialog,LPCTSTR lpszDefExt=NULL,LPCTSTR lpszFileName=NULL,DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPR OMPT,LPCTSTR lpszFilter=NULL,CWnd * pParentWnd=NULL); 第一个参数bOpenFileDialog为TRUE或FALSE。TRUE为打开文件;FALSE为保存文件。

  第二个参数lpszDefExt为缺省的扩展名。

  第三个参数lpszFileName为显示在文件名组合框的编辑框的文件名,一般可 选NULL第四个参数dwFlags为对话框风格,一般为OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,即隐藏只读选项和覆盖已有文件前提示。

  第五个参数LpszFilter为下拉列表枢中显示文件类型。

  第六个参数pParentWnd一般可选NULL。

  例如:在文件类型列表框的编辑框要显示"可执行文件(*.exe)",而在它的下 拉列表框中列出"小型可执行文件(*.com)、批处理文件(*.bat)、All Files(*.*)"内容,则变量定义如下:CFileDialogc m_OpenDialog(TRUE m_OpenDialog(TRUE,"exe",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"可 执行文件(*.exe) | *.exe|小型可执行文件(*.com)|*.com |批处理文件(*.bat) | *.bat | All Files (*.*) | *.* ||",NULL);说明:第五个参数lpszFilter为 一个指向字符串的指针,在列表框中要显示的字符后跟一个用"|"括起来的字符串 ,为要显示文件的文件类型。

  4.最高窗口的实现

  最高窗口就是总浮动在其他窗口上的,不会被一般窗口遮住的窗口,最高窗 口技术在编程中有着很广泛的应用。VC++中对基于SDI、MDI的运用程序,要实现 最高窗口,只要在框架窗口类CMainFrame中的PreCreateWindow()函数中加入 "cs.dwExStyle =WS_EX_TOPMOST;"即可。关于函数PreCreateWindow()及结构 CREATESTRUCT的详细信息可参见VC++的联机文档。

  而对基于对话框的运用程序,如何实现最高窗口却很少论及,以下便是一种 实现方法。

  重载要实观最高窗口的对话框的OnInitDialog()函数,方法是进入 ClassWizard,在Object ID列表框中选择该对话框的ID,在Message列表框中选择 WM_INITDIALOGG,单击Add Function按钮后,即对onlnitDialog函数进行了重载 。再按下Edit code按钮,加入以下语句:

  const CWnd * pWndInsertAfter;pWndInsertAfter = &wndTopMost;SetWindowPos(pWndInsertAfter,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE);函数SetWindowPos原型为BOOL SetWindowPos(const CWnd * pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags);pWndInsertAfter 为指向标识窗口类型的CWnd对象的指针。

  x,y为窗口左上角的坐标。

  cx,cy为窗口的宽与高。nFlags确定窗口的大小及位置。当为SWP_NOSIZE时 ,忽略cx,cy。当为SWP_NOMOVE时,忽略x,y。

  5.窗口最大化、最小化的实现

  当利用AppWizard生成运用程序框架时,VC++已经为我们在标题条上做好了最 大化,最小化及恢复按钮。但有时我们也想在其它地方使用这些功能。这就可采 用下面的办法。在指定的消息处理函效中加入下列语句,则程序在收到该条消息 后即执行窗口最小化。

  WINDOWPLACEMENT lwndpl;WINDOWPLACEMENT * lpwndpl;lpwndpl=&lwndpl;GetWindowPlacement(lpwndpl);lpwndpl->showCmd=SW_SHOWMINIMIZED;SetWindowPlacement(lpwndpl);函数BOOL GetWindowPlacement(WINDOWPLACEMENT * lpwndpl) const的作用为获取表示当前 窗口的布局的结构WINDOWPLACEMENT的结构变量指针。结构WINDOWPLACEMENT定义为:

  typedef struct tagWINDOWPLACEMENT {/* wndpl * / UINT length;UINT flags;UINT showCmd;POINT ptMinPosition;POINT ptMaxPosition;RECT rcNormalPosition;} WINDOWPLACEMENT;

  其中的成员变量showCmd确定当前窗口的状态。其取值一般为:

  SW_HIDE隐藏窗口。SW_MINIMIZE最小化指定的窗口。SW_RESTORE将最大化或 最小化的窗口恢复原来大小。SW_SHOW以原来的大小激话并显示窗口。 SW_SHOWMAXIMIZED激活并最大化窗口。函数BOOL SetWindowPlacement(const WINDOWPLACEMENT * lpwndpl)作用为按结构MENT的设置显示窗口。

  6.OCX控件的使用

  VC++的初学者可能会很羡慕VB或是C++Builder中那多得令人眼花缭乱且使用 方便的控件。其实,VC++中可使用的控件更多,只不过在通常的主界面上看不到 而已。如果打开Project菜单,选择Add To Project选项,在随后出现的子菜单中 ,选择Components And Controls,随后就可在Components andControls Gallery 对话框中的列表框中看到Developer Studio Components和Registered ActiveX Controls两个文件夹。随便打开一个文件夹,你会看到什么?这么多控件,够用 了吧。选定一个,要加入,单击Insert按钮;要帮助,单击More Info按钮。也可 以直接在对话框编辑器中,右键单击对话框空白处,选择Insert ActiveXControls选项,然后就自己挑选去吧。下面向大家介绍两个常用的控件作为例子。

  (1)在前面介绍的位图按钮中,可以用该方式在对话框中加入颜色最多仅 256色的位图,现在,利用Microsoft Forms 2.0 Image控件,你就可自由自在的 使用真彩色位图了。方法如下:右键单击要加入位图的对话框空白处,选择 Insert ActiveX Controls选项,随后选择Microsoft Forms 2.0 Image控件,加 入后,右键单击该控件,调整该控件的属性。在All标签列出的属性中,Picture 属性决定显示那一幅位图。属性调整完毕后,再编译连接,就一切OK了。

  (2)在你的程序中要具有Tips of the Day功能,那定能增色不少。像通用 对话框一样,你无需自己去费时费力,Microsoft已经为你做好了,方法如下:打 开Project菜单,选择Add To Project选项,在随后出现的子菜单中,选择 Components And Controls,打开Developer Studio Components选择Tip of the Day,将其加入到Project中去。再编译连接运行,Tips of the Day出来了。不过 此时Tips of the Day还没有任何内容。此时,需要打开project莱单,选择Add To Project选项,在打开的子菜单选择New,随后创建一个名为tips.txt的TXT文 件,并加入到Project中去。用回车符来区分每一条Tip,注意,每条Tip不能以 Tab跳格开头,且长度不能超过1000个字符。这样,加入Tip of the Day就大功告 成了。

  也许大家还记得,在用AppWizard创建运用程序框架时,有一步询问程序是否 需要ActiveX控件支持。因此,如果在创建运用程序框架时没有包含这一特性,后 来的Project就不能加入ActiveX控件了。但这也不是绝对的,利用函数 AfxEnableControlContainer()就可补上这一特性,在运用程序的 InitInstance()_函数中加入该函数,并在预编译文件StdAfx.h中加入#include即 可。

VC技巧 - 常用控制之二 可以使用Drag&Drop的CTreeView

CTreeViewExt是MFC使用者可重用的类,该类由CTreeView派生,可以用在文档- 视结构的应用程序中,并且支持Drag&Drop。 使用者所需要做的仅仅是将文件加到AppWizard产生的工程中,(CTreeView为基 类)并且将CTreeView替换为CTreeViewExt。并重载三个Virtual Function。

(WenYY:这很简单吧,下面是源代码,我会在必要的地方加上注释,但由于原作 者并未加,所以如果有出入请原谅,作者定义了三处虚拟函数,其作用是让使 用者重载后,加入自己的判断条件和结果处理的功能,很巧妙的思想: CopyItemProperties IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget); BOOL ItemCanBeDragged(HTREEITEM hItem);//检查是否可以对该ITEM实施Drag&Drop ) Header file #if !defined(AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_) #define AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // TreeViewExt.h : header file // ///////////////////////////////////////// // CTreeViewExt view class CTreeViewExt : public CTreeView { protected: CTreeViewExt(); // protected constructor used by dynamic creation DECLARE_DYNCREATE(CTreeViewExt) // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CTreeViewExt) protected: virtual void OnDraw(CDC* pDC); // overridden to draw this view //}}AFX_VIRTUAL // Implementation protected: HTREEITEM m_hDraggedItem; BOOL m_bDraggingNow; //标记 CImageList *m_pDragImageList; virtual ~CTreeViewExt(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif // Generated message map functions protected: virtual void CopyItemProperties(HTREEITEM hNewItem, HTREEITEM hDraggedItem); virtual BOOL IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget); virtual BOOL ItemCanBeDragged(HTREEITEM hItem);//检查是否可以对该ITEM实施Drag&Drop //{{AFX_MSG(CTreeViewExt) afx_msg void OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult);//必须重载的函数 afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. #endif // !defined(AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_) Implementation file // TreeViewExt.cpp : implementation file // #include "stdafx.h" #include "TreeViewExt.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////// // CTreeViewExt IMPLEMENT_DYNCREATE(CTreeViewExt, CTreeView) CTreeViewExt::CTreeViewExt() { m_bDraggingNow = FALSE; m_hDraggedItem = NULL; m_pDragImageList = NULL; } CTreeViewExt::~CTreeViewExt() { } BEGIN_MESSAGE_MAP(CTreeViewExt, CTreeView) //{{AFX_MSG_MAP(CTreeViewExt) ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////// // CTreeViewExt drawing void CTreeViewExt::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); // TOD add draw code here } ///////////////////////////////////////// // CTreeViewExt diagnostics #ifdef _DEBUG void CTreeViewExt::AssertValid() const { CTreeView::AssertValid(); } void CTreeViewExt::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////// // CTreeViewExt message handlers void CTreeViewExt::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; if (!m_bDraggingNow) {//先检查是否正在过程中 if (ItemCanBeDragged(pNMTreeView->itemNew.hItem)) {//查询条件,是否允许Drag&Drop CTreeCtrl& tree = GetTreeCtrl(); tree.SetCapture(); m_bDraggingNow = TRUE; m_hDraggedItem = pNMTreeView->itemNew.hItem;//保存变量 tree.Select(m_hDraggedItem, TVGN_CARET); m_pDragImageList = tree.CreateDragImage(m_hDraggedItem); m_pDragImageList->DragEnter(&tree, pNMTreeView->ptDrag); m_pDragImageList->BeginDrag(0, CPoint(0, 0)); } } *pResult = 0; } void CTreeViewExt::OnMouseMove(UINT nFlags, CPoint point) { if (m_bDraggingNow) { CTreeCtrl& tree = GetTreeCtrl(); m_pDragImageList->DragEnter(&tree, point); m_pDragImageList->DragMove(point); } CTreeView::OnMouseMove(nFlags, point); } void CTreeViewExt::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bDraggingNow) { ReleaseCapture(); m_bDraggingNow = FALSE; m_pDragImageList->EndDrag(); delete m_pDragImageList; m_pDragImageList = NULL; CTreeCtrl& tree = GetTreeCtrl(); UINT flags; HTREEITEM hTargetItem = tree.HitTest(point, &flags);//得到目标 if (hTargetItem != NULL && IsItemCanBeDroppedOn(m_hDraggedItem, hTargetItem)) {//查询是否可以成功完成,条件是开始时选中的Item和结束使选中的ITEM是否满足你的条件 HTREEITEM hNewItem = tree.InsertItem("Untitled", hTargetItem); CopyItemProperties(hNewItem, m_hDraggedItem);//进行处理 if (nFlags != MK_CONTROL) tree.DeleteItem(m_hDraggedItem); } m_hDraggedItem = NULL; } CTreeView::OnLButtonUp(nFlags, point); } BOOL CTreeViewExt::ItemCanBeDragged(HTREEITEM hItem) {//作用为决定现在是否能开始,可以作为一种运行时的选项 return FALSE; } BOOL CTreeViewExt::IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget) {//决定现在结束条件是否正常,如不正常则放弃这次操作 return FALSE; } void CTreeViewExt::CopyItemProperties(HTREEITEM hNewItem, HTREEITEM hDraggedItem) {//按照你的需要对两个ITEM进行处理。 }

有关属性对话框(property sheet )的几个提示 闻怡洋 下面的所有例子,都假定你从CPropertySheet中派生了新类。 1、隐藏APPLY按钮 使用 PSH_NOAPPLYNOW 标志. propsheet.m_psh.dwFlags |= PSH_NOAPPLYNOW; 2、增加新的子窗口 使用成员变量。CEdit m_edit. BOOL CMyPropSheet::OnInitDialog() { BOOL bResult = CPropertySheet::OnInitDialog(); CRect rectWnd; GetWindowRect(rectWnd); SetWindowPos(NULL, 0, 0, rectWnd.Width() + 100, rectWnd.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); m_edit.CreateEx( WS_EX_CLIENTEDGE, _T("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER, rectWnd.Width(), 20, 80, 24, m_hWnd, 0, 0 ); m_edit.SetFont( GetFont() ); CenterWindow(); return bResult; } 3、改变页片上的字体 在 OnInitDialog() 中: // m_fontEdit is a member variable // Create a bold font m_fontEdit.CreateFont( -8, 0, 0, 0, 700, 0, 0, 0, 1, 0, 0, 0, 0, _T("MS Sans Serif") ); GetTabControl()->SetFont( &m_fontEdit ); 4、使用Image m_imageTab为成员变量。 BOOL CMyPropSheet::OnInitDialog() { BOOL bResult = CPropertySheet::OnInitDialog(); m_imageTab.Create( IDB_TABIMAGES, 13, 1, RGB(255,255,255) ); CTabCtrl *pTab = GetTabControl(); pTab->SetImageList( &m_imageTab ); TC_ITEM tcItem; tcItem.mask = TCIF_IMAGE; for( int i = 0; i <3; i++ ) { tcItem.iImage = i; pTab->SetItem( i, &tcItem ); } return bResult; }  

为TreeCtrl中的项增加ToolTip 文洋译 要点:通过OnToolHitTest来增加ToolTip,CTreeCtrl::HitTest(...)的使用,TTN_NEEDTEXT消息的处理。 定义一个新类,有CTreeCtrl派生 Step 1:打开ToolTip 功能 void CTreeCtrlX::PreSubclassWindow() { CTreeCtrl::PreSubclassWindow(); EnableToolTips(TRUE); } Step 2: OnToolHitTest() 的重载 首先通过HitTest决定是否增加ToolTip,如果需要则返回非零。 在本例中ToolTip使用了LPSTR_TEXTCALLBACK,而没有立即设定显示字符串。 在本例只在鼠标指向每项的图片时才显示ToolTip

int CTreeCtrlX::OnToolHitTest(CPoint point, TOOLINFO * pTI) const { RECT rect; UINT nFlags; HTREEITEM hitem = HitTest( point, &nFlags ); if( nFlags & TVHT_ONITEMICON ) { CImageList *pImg = GetImageList( TVSIL_NORMAL ); IMAGEINFO imageinfo; pImg->GetImageInfo( 0, &imageinfo ); GetItemRect( hitem, &rect, TRUE ); rect.right = rect.left - 2; rect.left -= (imageinfo.rcImage.right + 2); pTI->hwnd = m_hWnd; pTI->uId = (UINT)hitem; pTI->lpszText = LPSTR_TEXTCALLBACK; pTI->rect = rect; return pTI->uId; } else if( nFlags & TVHT_ONITEMSTATEICON ) { CImageList *pImg = GetImageList( TVSIL_NORMAL ); IMAGEINFO imageinfo; pImg->GetImageInfo( 0, &imageinfo ); GetItemRect( hitem, &rect, TRUE ); rect.right = rect.left - (imageinfo.rcImage.right + 2); pImg = GetImageList( TVSIL_STATE ); rect.left = rect.right - imageinfo.rcImage.right ; pTI->hwnd = m_hWnd; pTI->uId = (UINT)hitem; pTI->lpszText = LPSTR_TEXTCALLBACK; pTI->rect = rect; // return value should be different from that used for item icon return pTI->uId*2; } return -1; } Step 3: ?? TTN_NEEDTEXT 由于在增加ToolTip是使用用了 LPSTR_TEXTCALLBACK,因此ToolTip在显示 时会发送该消息来得到显示字符串。 BEGIN_MESSAGE_MAP(CTreeCtrlX, CTreeCtrl) //{{AFX_MSG_MAP(CTreeCtrlX) : : //}}AFX_MSG_MAP ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText) END_MESSAGE_MAP() protected: //{{AFX_MSG(CTreeCtrlX) : : //}}AFX_MSG afx_msg BOOL OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ); DECLARE_MESSAGE_MAP() BOOL CTreeCtrlX::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ) { // need to handle both ANSI and UNICODE versions of the message TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR; TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR; CString strTipText; UINT nID = pNMHDR->idFrom; // Do not process the message from built in tooltip if( nID == (UINT)m_hWnd && (( pNMHDR->code == TTN_NEEDTEXTA && pTTTA->uFlags & TTF_IDISHWND ) || ( pNMHDR->code == TTN_NEEDTEXTW && pTTTW->uFlags & TTF_IDISHWND ) ) ) return FALSE; // Get the mouse position const MSG* pMessage; CPoint pt; pMessage = GetCurrentMessage(); ASSERT ( pMessage ); pt = pMessage->pt; ScreenToClient( &pt ); UINT nFlags; HTREEITEM hitem = HitTest( pt, &nFlags ); if( nFlags & TVHT_ONITEMICON ) { int nImage, nSelImage; GetItemImage( (HTREEITEM ) nID, nImage, nSelImage ); strTipText.Format( "Image : %d", nImage ); } else { strTipText.Format( "State : %d", GetItemState( (HTREEITEM ) nID, TVIS_STATEIMAGEMASK ) ); } #ifndef _UNICODE if (pNMHDR->code == TTN_NEEDTEXTA) lstrcpyn(pTTTA->szText, strTipText, 80); else _mbstowcsz(pTTTW->szText, strTipText, 80); #else if (pNMHDR->code == TTN_NEEDTEXTA) _wcstombsz(pTTTA->szText, strTipText, 80); else lstrcpyn(pTTTW->szText, strTipText, 80); #endif *pResult = 0; return TRUE; // message was handled }

VC技巧六 - 工具条和状态条

在状态条上显示当前时间 执行下面五个步骤: 编辑资源。添加一个ID为ID_INDICATOR_TIME的新字符串,并将其内容设置为 00:00(或者00:00:00)。状态条使用设置的初始值来计算Pane的大小。在应用程序 中可以通过调用CStatusBar::SetPaneInfo()函数来动态的改变Pane的大小。保存 资源。 编辑Mainfrm.cpp。状态条对象使用indicators[]数组中的数据并且按照其在数组 中的顺序生成状态条,在indicators[]数组的适当位置插入ID_INDICATOR_TIME。

在CMainFrame类中加入下列的消息映射 Mainfrm.h //{{AFX_MSG(CMainFrame) afx_msg void OnUpdateTime(CCmdUI *pCmdUI); //}}AFX_MSG Mainfrm.cpp BEGIN_MESSAGE_MAP(CMainFrame,CMDIFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_UPDATE_COMMAND_UI(ID_INDICATOR_TIME,OnUpdateTime) //}}AFX_MSG_MAP END_MESSAGE_MAP() 由于ID_INDICATOR_TIME是一个ID而不是一个类,所以上述消息映射只能手动加入 而不能使用ClassWizard。 注意:如果你的程序还需要增加OnTimer函数(使用ClassWizard),那么你应当先 使用ClassWizard加入ON_WM_TIMER消息映射,然后再手动加入上述消息映射,如 果次序相反,上述消息映射将会被ClassWizard删除掉。 编辑Mainfrm.cpp,加入下列函数: void CMainFrame::OnUpdateTime(CCmdUI *pCmdUI) {//状态条时间显示函数 CTime t = CTime::GetCurrentTime(); char szTime[6]; int nHour = t.GetHour(); int nMinute = t.GetMinute(); if (nHour > 12) nHour = nHour - 12;//如要按24小时制显示,请将此行注释掉 wsprintf(szTime, "%i:%02i", nHour, nMinute);//分秒一般习惯用两位表示 //把时间写到Pane m_wndStatusBar.SetPaneText(m_wndStatusBar.CommandToIndex (ID_INDICATOR_TIME), LPCSTR(szTime)); pCmdUI->Enable(); } 应用程序在有空闲时间(idle time)时调用这个函数。每当应用程序清空其消息队 列时,它将发送一个WM_IDLEUPDATECMDUI消息(新的idle time)。关于idle time 的更多帮助信息,请参看CWinApp::OnIdle()函数的帮助。 到目前为止,程序还存在一个问题:当用户不操作该应用程序时,应用程序接受 不到消息,也就谈不上清空消息队列,所以就不会有idle time,因此显示的时间 就不会得到刷新。我们将在第五步中解决这个问题。 在CMainFrame类OnCreate()中添加下列语句: m_nIDTimer = ::SetTimer(NULL, 0, 1000, NULL);//发送消息,以便更新状态条时间 上述语句每秒钟发送一个消息到应用程序的消息队列,当应用程序清空其消息队 列时,时间显示将被更新。在CMainFrame类析构函数中调用::KillTimer(NULL, m_nIDTimer) 更多信息 当模式对话框弹出时(例如Help的About对话框),应用程序的消息队列由对话框处 理。由于对话框的消息管理不包括idle time处理,所以OnUpdateTime函数不会被 调用。如果你要在应用中使用模式对话框,那么你的项目还要进行下面的改进(加 入TimerProc函数以处理WM_TIMER消息): 编辑Mainfrm.h和Mainfrm.cpp。在CMainFrame类中加入下列函数的声明及定义: Mainfrm.h static void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT uIDEvent, DWORD dwTime); Mainfrm.cpp void CALLBACK CMainFrame::TimerProc(HWND hwnd, UINT uMsg, UINT uIDEvent, DWORD dwTime) { CMainFrame *pMainWnd = (CMainFrame *)AfxGetApp()->m_pMainWnd; ASSERT(uIDEvent == pMainWnd->m_nIDTimer); CCmdUI cui; cui.m_nID = ID_INDICATOR_TIME; cui.m_nIndex = 4; cui.m_pMenu = NULL; cui.m_pOther = &pMainWnd->m_wndStatusBar; pMainWnd->OnUpdateTime(&cui);//调用OnUpdateTime()函数,更新时间显示 } 修改CMainFrame类OnCreate()函数中SetTimer的调用格式: m_nIDTimer = ::SetTimer(NULL, 0, 1000, TimerProc);

实现平面工具栏的最简单方法 张圣华 在前面两篇文章中,你已经学到了如何实现类似 Word97 的工具栏。如果你 不在乎工具栏上的 gripper (参见“如何实现类似 Word97 的工具栏”),则我可 以教你一种最简单的方法来实现。 在建立了工具栏之后,加上下面一句: m_wndToolBar.ModifyStyle(0, TBSTYLE_FLAT); 则你就可以实现不带有gripper的平面工具栏了。太简单了吧。

如何使能和禁止工具条的工具提示 如果设置了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 ); }

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

如何在代码中获取工具条和状态条的指针 缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有 一个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);

VC技巧三 - 界面

在MFC加入"这是什么?"的帮助提示 MFC在CPropertySheet中封装了属性,但不支持标题的"这是什么?"帮助提示.函数 CPropertySheet::OnNcCreate()屏蔽了扩展风格WS_EX_CONTEXTHELP, 因此,即使 你在构造函数中加入了扩展风格,它也不能出现在窗口中.

解决方法很简单,在继承类中设置好风格位,如下所示: BOOL CWhatsThisPropertySheet::OnNcCreate( LPCREATESTRUCT lpCreateStruct) ( if(!CPropertySheet::OnNcCreate(lpCreateStruct)) return FALSE; //显式地定义此风格 //CPropertySheet默认是关 ModifyStyleEx(0, WS_EX_CONTEXTHELP); return true; )

精通工具条 VC++的工具条有很多特性,但有时候也会让你感到困惑. 这里有一些使它们服服贴 贴的小技巧. 要移走一个工具条项,只须将它拖到空工具条的右边,然后点击右上角的关闭按钮. 注意显示在浮动工具条菜单条上的工具条的名称,可以通过右击菜单条来关闭 一 个工具条,使之挂起.反过来,激活一个挂起的工具条,右击你菜单条或另一个工具 条,然后选中 你想看到的工具条的名字. 如果你想同时开关好几个工具条,不用一个一个地去右击,使用菜单上的工具, 用 户化菜单命令,会出现工具条制表顺序对话框,然后进行选择. 这个对话框也允许 挂起干扰你的工具条,或者增大看不见工具条按钮的图标. 你可以在调试时使用和编辑代码时不同的工具条布局,而二者不互相干扰.当你发 现浮动工具条停在不期望的位置时,按住Ctrl键,然后用鼠标将它移到旁边去, 当 你停下来的时候,它不再回去,即使你把它放在另一个工具条的上面.

如何改变视窗的背景颜色

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; }

为MFC应用程序添加全屏幕显示功能

在CMainFrame类中添加下列成员变量和成员函数(使用ClassWizard),下面是这 些变量和函数的功能说明: 成员变量: BOOL m_bFullScreen; //全屏幕显示标志 CRect m_FullScreenWindowRect; //全屏幕显示窗口Rect WINDOWPLACEMENT m_wpPrev; //用于保存正常视图时的窗口位置信息 CToolBar * m_wndFullScreenBar; //全屏幕显示时的浮动工具条 成员函数: void OnMenuFullscreen(); //全屏幕显示的处理函数 void OnGetMinMaxInfo(); //捕获WM_GETMINMAXINFO消息以便允许你增加窗口大小 void OnUpdateViewFullScreen(); //更新“全屏幕显示”菜单的状态 源码 void CMainFrame::OnMenuFullscreen() {//全屏幕显示的处理函数 RECT rectDesktop; WINDOWPLACEMENT wpNew; if (m_bFullScreen) {//全屏幕显示模式 //隐藏工具条和状态条 m_wndStatusBar.ShowWindow(SW_HIDE); m_wndToolBar.ShowWindow(SW_HIDE); //保存正常视图时的窗口位置信息以便恢复原来状态 GetWindowPlacement (&m_wpPrev); m_wpPrev.length = sizeof m_wpPrev; //调整RECT为新的窗口尺寸 ::GetWindowRect ( ::GetDesktopWindow(), &rectDesktop ); ::AdjustWindowRectEx(&rectDesktop, GetStyle(), TRUE, GetExStyle()); //保存RECT以便OnGetMinMaxInfo()使用 m_FullScreenWindowRect = rectDesktop; wpNew = m_wpPrev; wpNew.showCmd = SW_SHOWNORMAL; wpNew.rcNormalPosition = rectDesktop; //生成新的工具条 m_wndFullScreenBar=new CToolBar; if(!m_wndFullScreenBar->Create(this, CBRS_SIZE_DYNAMIC|CBRS_FLOATING) || !m_wndFullScreenBar->LoadToolBar(IDR_FULLSCREEN)) { TRACE0("Failed to create toolbar\n"); return; // fail to create } //不允许工具条停泊 m_wndFullScreenBar->EnableDocking(FALSE); m_wndFullScreenBar->SetWindowPos(0,100,100,0,0,SWP_NOSIZE |SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW); m_wndFullScreenBar->SetWindowText(_T("全屏幕显示")); FloatControlBar(m_wndFullScreenBar, CPoint(100,100)); m_bFullScreen=TRUE; } else {//正常显示模式 //删除全屏幕工具条 m_wndFullScreenBar->DestroyWindow(); delete m_wndFullScreenBar; m_bFullScreen=FALSE; //恢复工具条和状态条 m_wndStatusBar.ShowWindow(SW_SHOWNORMAL); m_wndToolBar.ShowWindow(SW_SHOWNORMAL); wpNew = m_wpPrev; } //设置窗口显示状态 SetWindowPlacement ( &wpNew ); } void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { if (m_bFullScreen) { lpMMI->ptMaxSize.y = m_FullScreenWindowRect.Height(); lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y; lpMMI->ptMaxSize.x = m_FullScreenWindowRect.Width(); lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x; } } void CMainFrame::OnUpdateMenuFullscreen(CCmdUI* pCmdUI) {//更新菜单的状态 pCmdUI->Enable(); pCmdUI->SetCheck(m_bFullScreen); }

VC技巧四 - 工具条和状态条

增强型的状态条 首先在你的应用中添加一个新类,这个类的基类是CStatusBar类。本文中这个类 叫做CEnhanceStatusBar。 在头文件中声明以下的控件ID和标志: #define IDC_PROGRESS 3001 //进程条 #define IDC_INFOBUTTON 3002 //Info按钮 #define IDC_LEFTBUTTON 3003 //左移按钮 #define IDC_RIGHTBUTTON 3004 //右移按钮 #define ENHANCEBAR_PROGRESS 1 //进程条标志 #define ENHANCEBAR_INFO 2 //Info按钮标志 #define ENHANCEBAR_BUTTON 4 //左、右移按钮标志 将下列成员函数和成员变量添加到CEnhanceStatusBar类中,并且根据你的需要设 置其属性为public/protected/private: CBitmapButton LeftButton; //左移按钮 CBitmapButton RightButton; //右移按钮 CBitmapButton InfoButton; //Info按钮 CProgressCtrl ProgressControl; //进程条 //下面的四个成员函数返回各个控件: CBitmapButton& GetLeftButton() {return LeftButton;}; CBitmapButton& GetRightButton() {return RightButton;}; CBitmapButton& GetInfoButton() {return InfoButton;}; CProgressCtrl& GetProgressControl() {return ProgressControl;}; UINT ButtonWidth; //按钮宽度 UINT ButtonHeight; //按钮高度 UINT ButtonSpace; //按钮间距 int StatusFlags; //状态条标志 int ProgressPane; //进程条所在的pane标号 int ButtonPane; //按钮所在的pane标号 BOOL Create(CWnd* wnd, int flags, int progress, int button);//状态条生成函数 virtual BOOL AddButtonControl(); //添加按钮控件 virtual BOOL AddProgressControl(); //添加进程条控件 virtual void PositionControls(); //调整控件位置 virtual void DestroyControls(); //删除控件 //下面是为了测试按钮及进程条控件而添加的一些函数及变量 CStringList Messages; //一组CString,用于存贮讯息 POSITION CurrentMessagePosition; //当前讯息在List中的位置 virtual BOOL AddMessage(CString msg, int pos); //加入一条讯息 virtual BOOL ClearMessages(); //删除所有讯息 virtual void SetProgress(BOOL show, int range); //设置进程条 编写构造函数和析构函数,并给Create()函数加入代码: CEnhanceStatusBar::CEnhanceStatusBar() { //初始化参数 ButtonWidth = 14; ButtonHeight = 13; ButtonSpace = 3; CurrentMessagePosition = 0; StatusFlags = 0; ProgressPane = 0; ButtonPane = 0; } CEnhanceStatusBar::~CEnhanceStatusBar() { ClearMessages();//删除所有讯息 DestroyControls();//删除控件 } BOOL CEnhanceStatusBar::Create(CWnd* wnd, int flags, int progress, int button) { if (m_hWnd ==0) { if (!CStatusBar::Create(wnd)) return FALSE; } ClearMessages(); DestroyControls();//在通过菜单命令改变状态条格式时,这个调用很重要, //因为各控件只能生成一次,所以必须先删除 //得到标志和pane号 StatusFlags = flags;//flags标志状态条的格式,有无进程条和某些按钮等。 ProgressPane = progress;//progress表示状态条所在的pane号 ButtonPane = button;//button表示按钮所在的pane号 if (!AddProgressControl())//加入进程条 return FALSE; if (!AddButtonControl())//加入按钮 return FALSE; //加入你自己的控件 //if (!AddCustomControl()) // return FALSE; //加入你自己的控件 EnableToolTips(TRUE); PositionControls();//调整控件位置 //调整你自己的控件的位置 //PositionCustomControl(); //调整你自己的控件的位置 return TRUE; } 给AddButtonControl()、AddProgressControl()和DestroyControls()函数加入代码: BOOL CEnhanceStatusBar::AddButtonControl() { //设置ButtonRect CRect ButtonRect; ButtonRect.left = 100; ButtonRect.top = 2; ButtonRect.right = 114; ButtonRect.bottom = 15; //下面加入左移和右移按钮 if (StatusFlags & ENHANCEBAR_BUTTON) { if (!LeftButton.Create("",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW, ButtonRect,this, IDC_LEFTBUTTON)) { TRACE0("Failed to create LeftButton button\n"); return FALSE; } if (!LeftButton.LoadBitmaps(IDB_LEFTBUTTON,IDB_LEFTBUTTON_SEL,NULL, IDB_LEFTBUTTON_DIS)) { TRACE0("Failed to load LeftButton bitmap\n"); return FALSE; } LeftButton.EnableWindow(FALSE); if(!RightButton.Create("",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW, ButtonRect,this,IDC_RIGHTBUTTON)) { TRACE0("Failed to create RightButton button\n"); return FALSE; } if (!RightButton.LoadBitmaps(IDB_RIGHTBUTTON,IDB_RIGHTBUTTON_SEL, NULL,IDB_RIGHTBUTTON_DIS)) { TRACE0("Failed to load RightButton bitmap\n"); return FALSE; } RightButton.EnableWindow(FALSE); } //下面加入Info按钮 if (StatusFlags & ENHANCEBAR_INFO) { if (!InfoButton.Create("",WS_CHILD|WS_VISIBLE|BS_OWNERDRAW, ButtonRect,this,IDC_INFOBUTTON)) { TRACE0("Failed to create InfoButton\n"); return FALSE; } if (!InfoButton.LoadBitmaps(IDB_INFO,IDB_INFO_SEL,NULL,IDB_INFO_DIS)) { TRACE0("Failed to load InfoButton bitmap\n"); return FALSE; } InfoButton.EnableWindow(FALSE); } return TRUE; } BOOL CEnhanceStatusBar::AddProgressControl() { if (StatusFlags & ENHANCEBAR_PROGRESS) { //设置ProgressRect CRect ProgressRect; ProgressRect.left = 100; ProgressRec VC技巧五 - 工具条和状态条

VC++ 5.0式样的工具条 类似VC++ 5.0的工具条具有平面外观,左边带有一个“把手”,你可以通过鼠标 拖动这个“把手”来移动工具条。工具条各组间带有分隔线(如图所示)。当鼠标 在工具条上面移动时,工具条上的相应按钮会突出显示。本文所讨论的增强型工 具条CEnhanceToolBar类由CToolBar类所派生,是CToolBar类的补充和扩展。

如果你并不在乎工具条有没有“把手”的话,要生成平面工具条是十分简单的。 你只需要在CMainFrame的OnCreate()函数中添加一句话就可以(必须加在工具条生 成函数之后,因为MFC在生成工具条时要清除其式样): //MainFrm.cpp int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ...... if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } m_wndToolBar.ModifyStyle(0,TBSTYLE_FLAT);//设置工具条为平面格式 ...... } 如果你的计算机安装了版本为4.71.1712.3的COMCTL32.DLL(该动态库随IE 4一同 发行),那就更好了,你的工具条会自动绘制分隔线的。你可以通过鼠标拖动工具 条的非按钮区域来移动这种工具条。 如果你要得到更好看(更“专业”)的工具条,那么你还得跟着我一步步的做下去 : 添加一个新类,本文中叫做CEnhanceToolBar类,由CToolBar类派生。 为CEnhanceToolBar类添加成员变量和函数的声明,并且根据你的需要设置其属性 为public/protected/private。 //EnhanceToolBar.h // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CEnhanceToolBar) //按钮状态变化时调用此函数 virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); //}}AFX_VIRTUAL // Implementation public: void DrawGrip(CWindowDC *pDC, CRect& rectWindow);//“把手”绘制函数 void EraseNonClient();//擦除非客户区 void DrawSpace();//分隔线绘制函数 void RedrawBackground();//背景重绘函数 private: int ButtonNumber;//工具条的按钮数(包括分隔线) COLORREF HiLight, Shadow;//3D控件的加亮色和阴影色 添加成员函数的定义: //EnhanceToolBar.cpp void CEnhanceToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) {//按钮状态变化时调用此函数 static CUIntArray Styles; int Index; UINT dwStyle; for (Index = 0; Index { dwStyle = GetButtonStyle(Index); Styles.SetAtGrow(Index,dwStyle);//保存按钮的式样 } CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);//调用基类的处理函数 for (Index = 0; Index {//设置选中的按钮(checked button)为按下的状态 dwStyle = GetButtonStyle(Index); if (dwStyle & TBBS_DISABLED) return;//如果按钮为禁用状态,则返回(避免闪烁) if (dwStyle & TBBS_CHECKBOX) { if (dwStyle & TBBS_CHECKED) dwStyle |= TBBS_PRESSED; else dwStyle &= ~TBBS_PRESSED; SetButtonStyle(Index,dwStyle);//设置按钮的式样 } } //检查按钮的式样是否改变(按下或释放) for (Index = 0; Index { dwStyle = GetButtonStyle(Index); if (Styles[Index] != dwStyle) { RedrawBackground();//重新绘制背景 Invalidate();//重新绘制整个工具条 break;//已更新整个工具条,因此没必要继续循环 } } } void CEnhanceToolBar::DrawGrip(CWindowDC *pDC, CRect& rectWindow) {//绘制把手 if (IsFloating())//如果工具条是浮动状态,则不绘制“把手” return; CRect GripRect = rectWindow;//得到把手的矩形区域 GripRect.DeflateRect(1,1);//矩形区域的各边向中心靠近一个像素 if (m_dwStyle & CBRS_ORIENT_HORZ)//如果工具条为水平状态,“把手”在左边 { GripRect.right = GripRect.left + 3;//绘制第一条隆起的棱 pDC->Draw3dRect(GripRect, HiLight, Shadow); GripRect.OffsetRect(4,0);//绘制第二条隆起的棱 pDC->Draw3dRect(GripRect, HiLight, Shadow); } else//如果工具条为垂直状态,“把手”在顶部 { GripRect.bottom = GripRect.top + 3;//绘制第一条隆起的棱 pDC->Draw3dRect(GripRect, HiLight, Shadow); GripRect.OffsetRect(0,4);//绘制第二条隆起的棱 pDC->Draw3dRect(GripRect, HiLight, Shadow); } } void CEnhanceToolBar::DrawSpace() {//绘制分隔线 CClientDC dc(this); for (int Index = 0; Index { UINT dwStyle = GetButtonStyle(Index);//获得按钮的类型 if (dwStyle & TBBS_SEPARATOR)//如果是分隔线 { CRect rect; GetItemRect(Index,rect);//获得矩形区域 if (m_dwStyle & CBRS_ORIENT_HORZ)//工具条为水平时分隔线为垂直 { int w = rect.Width(); rect.DeflateRect((w-2)/2,0);//将矩形缩减为2~3个像素宽 dc.Draw3dRect(rect, Shadow, HiLight);//绘制分隔线 } else//分隔线为水平 { rect.left = rect.left - m_sizeButton.cx; rect.right = rect.left + m_sizeButton.cx; rect.top = rect.bottom+1; rect.bottom = rect.top+3; int h = rect.Height(); rect.DeflateRect(0,(h-2)/2);//将矩形缩减为2~3个像素高 dc.Draw3dRect(rect, Shadow, HiLight);//绘制分隔线 } } } } void CEnhanceToolBar::EraseNonClient() {//擦除非用户区 CWindowDC dc(this); CRect rectClient; GetClientRect(rectClient); CRect rectWindow; GetWindowRect(rectWindow); ScreenToClient(rectWindow); rectClient.OffsetRect(-rectWindow.left, -rectWindow.top); dc.ExcludeClipRect(rectClient); // 绘制非用户区的边界 rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top); DrawBorders(&dc, rectWindow); // 擦除非绘制部分 dc.IntersectClipRect(rectWindow); SendMessage(WM_ERASEBKGND, (WPARAM)dc.m_hDC); DrawGrip(&dc, rectWindow); //绘制“把手” } 由于平面工具条是透明的,所以当改变尺寸和移动时(例如当拖动工具条时)就需 要重绘背景。同样,当按钮状态改变时(按下或释放)也需要进行这种操作。

void CEnhanceToolBar::RedrawBackground() {//重新绘制背景 CWnd* pParent = GetParent();//获得父窗口指针 if (pParent) { CRect drawrect,rect; GetWindowRect(&rect);//获得工具条矩形区域 drawrect = rect; pParent->ScreenToClient(&drawrect);//转换为父窗口坐标 pParent->InvalidateRect(&drawrect);//重绘矩形区域 //绘制父窗口的其他工具条 for (CWnd* pSibling = pParent->GetWindow(GW_CHILD);pSibling; pSibling = pSibling->GetNextWindow(GW_HWNDNEXT)) { if (pSibling == this) continue; drawrect = rect; pSibling->ScreenToClient(&drawrect);//兄弟窗口的坐标 pSibling->InvalidateRect(&drawrect);//重绘矩形区域 } } } 利用ClassWizard给为CEnhanceToolBar类添加消息映射: //EnhanceToolBar.h //{{AFX_MSG(CEnhanceToolBar) afx_msg void OnPaint(); afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp); afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); //}}AFX_MSG //EnhanceToolBar.cpp BEGIN_MESSAGE_MAP(CEnhanceToolBar, CToolBar) //{{AFX_MSG_MAP(CEnhanceToolBar) ON_WM_PAINT() ON_WM_NCCALCSIZE() ON_WM_WINDOWPOSCHANGING() //}}AFX_MSG_MAP END_MESSAGE_MAP() 为消息映射函数添代码: void CEnhanceToolBar::OnPaint() { CToolBar::OnPaint();//绘制标准工具条 EraseNonClient();//擦除背景 DrawSpace();//绘制立体分隔线 } void CEnhanceToolBar::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) {// 计算非用户区域,用于调整“把手” CToolBar::OnNcCalcSize(bCalcValidRects,lpncsp); if (IsFloating())//如果工具条是浮动状态,则不绘制“把手” return; if (m_dwStyle & CBRS_ORIENT_HORZ)//如果工具条为水平状态,“把手”在左边 { lpncsp->rgrc[0].left += 2; lpncsp->rgrc[0].right += 2; } else//如果工具条为垂直状态,“把手”在顶部 { lpncsp->rgrc[0].top += 4; lpncsp->rgrc[0].bottom += 4; } } void CEnhanceToolBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) {//当尺寸、位置或Z方向次序变化时,程序框架调用此成员函数 CToolBar::OnWindowPosChanging(lpwndpos); RedrawBackground();//重新绘制背景 } 编写构造函数,加入下面的代码: CEnhanceToolBar::CEnhanceToolBar() { HiLight = ::GetSysColor(COLOR_3DHILIGHT);//获得3D控件的加亮色


  • simonsgh 我现在不在线,你找我吗?
  • 显示默认头像
  • 昵称:simonsgh
  • 专家等级:新手上路
  • 专家分:0
  • 可用分等级:佃户
  • 精华:0
  • 帖子数:87
  • 结帖率: 100%
  • 注册时间:2005-12-26 20:38:00
发表于 2006-04-12 19:34:00
第 1 楼

 

好东西,顶一下!!

  • chuccccc 我现在不在线,你找我吗?
  • 显示默认头像
  • 昵称:chuccccc
  • 专家等级:中级程序员
  • 专家分:2000
  • 可用分等级:佃户
  • 精华:0
  • 帖子数:1124
  • 结帖率: 100%
  • 注册时间:2005-12-22 11:39:00
发表于 2006-04-12 21:04:00
第 2 楼

 


  • txw8623595 我现在不在线,你找我吗?
  • 显示默认头像
  • 昵称:txw8623595
  • 专家等级:新手上路
  • 专家分:0
  • 可用分等级:佃户
  • 精华:0
  • 帖子数:45
  • 结帖率: 100%
  • 注册时间:2006-03-14 19:10:00
发表于 2006-04-12 23:22:00
第 3 楼

 

顶一下!


快速回复主题
您还未登录,不能回复帖子
phome.asia   程序员之家论坛
程序员之家 版权所有 Copyright 2004-2009 All Rights Reserved©2009 京 ICP 备 05027197 号 网站地图 关于我们 联系我们