VC中實現帶有背景位元影像的樹型控制項

來源:互聯網
上載者:User
  當前許多應用程式都在使用樹型控制項時為其添加了背景位元影像,增強控制項的魅力,然而對於Visual C++編程愛好者來說,使用Visual C++MFC提供的樹型控制項(CTreeCtrl)本身就是一個痛點,至於如何使該控制項能夠帶有背景位元影像,那就更加是一個令人困惑的問題了。本執行個體對CTreeCtrl類進行了增強,不僅使它帶有背景位元影像,而且解決了在點擊樹型控制項時背景位元影像閃動的問題,另外,通過在對話方塊中使用該控制項來顯示三級目錄,示範了樹型控制項的基本使用方法。為程式編譯後的運行:

圖一、帶背景圖的樹型控制項

   一、實現方法

  在實現樹型控制項的背景位元影像之前,我們首先介紹一下樹型控制項的基本使用方法。樹形控制項在系統中大量被使用,例如Windows資源管理員就是一個典型的例子。樹形控制項可以用於樹形的結構,其中有一個根接點(Root)然後下面有許多子結點,而每個子結點上又允許有一個或多個或沒有子結點。

  MFC中使用CTreeCtrl類來封裝樹形控制項的各種操作,通過調用BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );建立一個視窗,dwStyle中可以使用以下一些樹形控制項的專用風格:TVS_HASLINES 在父/子結點之間繪製連線;TVS_LINESATROOT 在根/子結點之間繪製連線;TVS_HASBUTTONS 在每一個結點前添加一個按鈕,用於表示當前結點是否已被展開;TVS_EDITLABELS 結點的顯示字元可以被編輯;TVS_SHOWSELALWAYS 在失去焦點時也顯示當前選中的結點;TVS_DISABLEDRAGDROP 不允許Drag/Drop;TVS_NOTOOLTIPS 不使用ToolTip顯示結點的顯示字元。

  在樹形控制項中每一個結點都有一個控制代碼(HTREEITEM),同時添加結點時必須提供的參數是該結點的父結點控制代碼(其中根Root結點只有一個,既不可以添加也不可以刪除),利用HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST )可以添加一個結點,pszItem為顯示的字元,hParent代表父結點的控制代碼,當前添加的結點會排在hInsertAfter表示的結點的後面,傳回值為當前建立的結點的控制代碼。

  如果你希望在每個結點前添加一個小表徵圖,就必需先調用CTreeCtrl類的成員函數CImageList* SetImageList( CImageList * pImageList, int nImageListType ),指明當前控制項所使用的映像列表(ImageList),nImageListType為TVSIL_NORMAL。在調用完成後控制項中使用圖片以設定的ImageList中圖片為準。然後調用HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST)添加結點,其中參數nImage為結點沒被選中時所使用圖片序號,nSelectedImage為結點被選中時所使用圖片序號。

  此外CTreeCtrl還提供了一些函數用於得到/修改控制項的狀態:

  ·HTREEITEM GetSelectedItem( )將返回當前選中的結點的控制代碼;

  ·BOOL SelectItem( HTREEITEM hItem )將選中指明結點;

  ·BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用於得到/修改某結點所使用表徵圖索引;

  ·CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem )用於得到/修改某一結點的顯示字元;

  ·BOOL DeleteItem( HTREEITEM hItem )用於刪除某一結點,BOOL DeleteAllItems( )將刪除所有結點。

  此外如果想遍曆樹可以使用下面的函數:

  ·HTREEITEM GetRootItem( )得到根結點;

  ·HTREEITEM GetChildItem( HTREEITEM hItem )得到子結點;

  ·HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem )得到指明結點的上/下一個兄弟結點;

  ·HTREEITEM GetParentItem( HTREEITEM hItem )得到父結點。

  樹形控制項的訊息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode為通知代碼,id為產生該訊息的視窗ID,memberFxn為處理函數,函數的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR為一資料結構,在具體使用時需要轉換成其他類型的結構。對於樹形控制項可能取值和對應的資料結構為:

  ·TVN_SELCHANGED 在所選中的結點發生改變後發送,所用結構:NMTREEVIEW;

  ·TVN_ITEMEXPANDED 在某結點被展開後發送,所用結構:NMTREEVIEW;

  ·TVN_BEGINLABELEDIT 在開始編輯結點字元時發送,所用結構:NMTVDISPINFO;

  ·TVN_ENDLABELEDIT 在結束編輯結點字元時發送,所用結構:NMTVDISPINFO;

  ·TVN_GETDISPINFO 在需要得到某結點資訊時發送,(如得到結點的顯示字元)所用結構:NMTVDISPINFO;

  對於Visual C++ MFC提供的標準樹型控制項CTreeCtrl來說,並不支援背景位元影像,所以如果需要實現背景位元影像就需要先讓其在記憶體CDC對象上對TREEVIEW預設繪圖,然後在選擇背景位元影像,與預設位元影像合成,即採用貼圖的方式,把標準的TREEVIEW視窗貼在底圖上。這個操作在記憶體中完成。同時為了避免閃爍,必須重載OnItemexpanding()和OnItemexpanded()這兩個函數。SetRedraw函數主要保證其不要在子節點彈出時重畫,而是在子節點已經擴充後重畫。為此,常式中定義了一個CTreeCtrl類的子類CmyTreeCtrl,並重載了以下幾個成員函數:

BOOL CMyTreeCtrl::SetBKImage(LPCTSTR LpszResource)
void CMyTreeCtrl::OnPaint()
void CMyTreeCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
void CMyTreeCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult)
BOOL CMyTreeCtrl::OnEraseBkgnd(CDC* pDC)

   二、編程步驟

  1、 啟動Visual C++6.0,產生一個基於對話方塊的項目Tree,在架構上放置一個樹形控製件,其ID標誌符為:IDC_TREE1;

  2、 建立CmyTreeCtrl類後,使用CLASSWIZARD為其添加訊息映射:

ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED,OnItemexpanded) ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding)

  訊息響應函數:

afx_msg void OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult);

  3、 將樹型控制項與CmyTreeCtrl類建立關聯,在對話方塊中添加變數CMyTreeCtrl m_CtrlTree;

  4、 製作一個準備作為樹形控制項背景的位元影像;

  5、 修改對話方塊的初始化函數BOOL CTreeDlg::OnInitDialog();

  6、 添加代碼,編譯運行程式。 

三、實現代碼

/////////////////////////////////////////////////
#if !defined(AFX_TREEDLG_H__D82DB384_F574_44A7_96DA_6EC9068E22B1__INCLUDED_)
#define AFX_TREEDLG_H__D82DB384_F574_44A7_96DA_6EC9068E22B1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////// CTreeDlg dialog
#include "MyTreeCtrl.h"
class CTreeDlg : public CDialog
{
 // Construction
 public:
  CTreeDlg(CWnd* pParent = NULL); // standard constructor

  // Dialog Data
  //{{AFX_DATA(CTreeDlg)
   enum { IDD = IDD_TREE_DIALOG };
   CMyTreeCtrl m_CtrlTree;
  //}}AFX_DATA

  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CTreeDlg)
   protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
  //}}AFX_VIRTUAL

  // Implementation
 protected:
  HICON m_hIcon;

  // Generated message map functions
  //{{AFX_MSG(CTreeDlg)
   virtual BOOL OnInitDialog();
   afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
   afx_msg void OnPaint();
   afx_msg HCURSOR OnQueryDragIcon();
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
};

#endif

////////////////////////////////// MyTreeCtrl.cpp : implementation file

#include "StdAfx.h"
#include "Tree.h"
#include "MyTreeCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

////////////////////////////// CMyTreeCtrl

CMyTreeCtrl::CMyTreeCtrl()
{}

CMyTreeCtrl::~CMyTreeCtrl()
{}

BEGIN_MESSAGE_MAP(CMyTreeCtrl, CTreeCtrl)
 //{{AFX_MSG_MAP(CMyTreeCtrl)
  ON_WM_PAINT()
  ON_WM_ERASEBKGND()
  ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemexpanded)
  ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyTreeCtrl message handlers
BOOL CMyTreeCtrl::SetBKImage(LPCTSTR LpszResource)
{
 // if this is not the first call then delete gdi objects
 if( m_bitmap.m_hObject != NULL )
  m_bitmap.DeleteObject();

  HBITMAP hbmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
LpszResource, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE);

 if( hbmp == NULL )
  return FALSE;
 m_bitmap.Attach( hbmp );
 return TRUE;
}

LRESULT CMyTreeCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
 // TODO: Add your specialized code here and/or call the base class
 return CTreeCtrl::WindowProc(message, wParam, lParam);
}

void CMyTreeCtrl::OnPaint()
{
 CPaintDC dc(this); // device context for painting
 CRect rcclient;
 GetClientRect(&rcclient);

 // create a compatible memory dc
 CDC memdc;
 memdc.CreateCompatibleDC(&dc);
 CBitmap bitmap;
 bitmap.CreateCompatibleBitmap(&dc, rcclient.Width(), rcclient.Height());
 memdc.SelectObject( &bitmap );
 CWnd::DefWindowProc(WM_PAINT, (WPARAM)memdc.m_hDC , 0);
 CDC maskdc;
 maskdc.CreateCompatibleDC(&dc);
 CBitmap maskbitmap;
 maskbitmap.CreateBitmap(rcclient.Width(), rcclient.Height(), 1, 1, NULL);
 maskdc.SelectObject( &maskbitmap );
 maskdc.BitBlt( 0, 0, rcclient.Width(), rcclient.Height(), &memdc,
 rcclient.left, rcclient.top, SRCCOPY);
 CBrush brush;
 brush.CreatePatternBrush(&m_bitmap);
 dc.FillRect(rcclient, &brush);
 memdc.SetBkColor(RGB(0,0,0));
 memdc.SetTextColor(RGB(255,255,255));
 memdc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &maskdc, rcclient.left,  rcclient.top, SRCAND);
 dc.SetBkColor(RGB(255,255,255));
 dc.SetTextColor(RGB(0,0,0));
 dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &maskdc, rcclient.left, rcclient.top, SRCAND);
 dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(), &memdc, rcclient.left, rcclient.top,SRCPAINT);
 brush.DeleteObject();
}

BOOL CMyTreeCtrl::OnEraseBkgnd(CDC* pDC)
{
 // TODO: Add your message handler code here and/or call default
 return TRUE;
}

void CMyTreeCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult)
{
 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
 // TODO: Add your control notification handler code here
 Invalidate();
 SetRedraw(TRUE);
 *pResult = 0;
}

void CMyTreeCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
 // TODO: Add your control notification handler code here
 SetRedraw(FALSE);

 *pResult = 0;
}

///////////////////////////////////////////////////////
BOOL CTreeDlg::OnInitDialog()
{
 CDialog::OnInitDialog();
 // Add "About..." menu item to system menu.
 // IDM_ABOUTBOX must be in the system command range.
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);
 CMenu* pSysMenu = GetSystemMenu(FALSE);
 if (pSysMenu != NULL)
 {
  CString strAboutMenu;
  strAboutMenu.LoadString(IDS_ABOUTBOX);
  if (!strAboutMenu.IsEmpty())
  {
   pSysMenu-> AppendMenu(MF_SEPARATOR);
   pSysMenu-> AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  }
 }
 // Set the icon for this dialog. The framework does this automatically
 // when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE); // Set big icon
 // TODO: Add extra initialization here
 m_CtrlTree.SetBKImage("IDB_BITMAP1");
 SetIcon(m_hIcon, FALSE); // Set small icon
 TVINSERTSTRUCT tvInsert;
 tvInsert.hParent = NULL;
 tvInsert.hInsertAfter = NULL;
 tvInsert.item.mask = TVIF_TEXT;
 tvInsert.item.pszText = _T("Visual C++編程執行個體");
 HTREEITEM hCountry = m_CtrlTree.InsertItem(&tvInsert);
 HTREEITEM hPA = m_CtrlTree.InsertItem(TVIF_TEXT,
 _T("文章中心"), 0, 0, 0, 0, 0, hCountry, NULL);
 HTREEITEM hWA = m_CtrlTree.InsertItem(_T("程式碼中樞"),0, 0, hCountry, hPA);
 m_CtrlTree.InsertItem(_T("全螢幕程式的實現"), hPA, TVI_SORT);
 m_CtrlTree.InsertItem(_T("實現視窗的任意分割"), hPA, TVI_SORT);
 m_CtrlTree.InsertItem(_T("實現菜單的自繪"), hPA, TVI_SORT);
 m_CtrlTree.InsertItem(_T("實現全螢幕顯示的代碼"), hWA, TVI_SORT);
 m_CtrlTree.InsertItem(_T("視窗任意分割的代碼"), hWA, TVI_SORT);
 m_CtrlTree.InsertItem(_T("菜單自繪代碼"), hWA, TVI_SORT);
 m_CtrlTree.Expand(hCountry,TVE_EXPAND);
 return TRUE; // return TRUE unless you set the focus to a control
}

   四、小結

  到此為止,本例通過實現樹形控制項的背景位元影像介紹了一些樹狀檢視控制項編程方法,包括樹狀檢視控制項的建立、節點值的賦予等。當然,它應用的方面很廣,使用方法也很多。這裡僅僅是涉及到了構建樹狀檢視控制項的基本架構,讀者朋友們可以在此基礎上,可進行擴充,從而完成更強大的功能,感興趣的讀者不妨自己擴充該控制項試試。

出處:天極開發

原文地址:http://www.7880.com/Info/Article-7cf793c0.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.