国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
VC程序中樹型控件節(jié)點拖動的完美實現(xiàn)
VC程序中樹型控件節(jié)點拖動的完美實現(xiàn)


(2006-04-05 08:13:29)

Visual C++中提供的MFC類CtreeCtrl(樹型控件)用來顯示具有一定層次結構的數(shù)據項時方便、直觀,所以它已經被廣泛地應用在各種軟件中,如資源管理器中的磁盤目錄就用的是樹型控件,我們在編程中也會經常用到這個控件

,但是這個控件也有缺陷,那就是它并不直接支持拖動節(jié)點等高級特性,這使得程序員在編程時使用它受到了很大限制,同時又給軟件用戶帶來了一些不便。為此,本實例通過從 CTreeCtrl 中派生了一個類 CXTreeCtrl ,實現(xiàn)樹型控件中節(jié)點的拖動。這個類具有如下的功能:⑴ 基本項目條拖動的實現(xiàn);⑵ 處理項目條的無意拖動;⑶ 能處理項目條拖動過程中的滾動問題;⑷ 拖動過程中節(jié)點會智能展開。程序編譯運行后的效果如圖所示:

圖一:樹型控件節(jié)點拖動示例

一、實現(xiàn)方法

我們針對上述自定義類的實現(xiàn)功能,介紹實現(xiàn)思路和方法。

(1)基本項目條拖動的實現(xiàn)

當我們要拖動樹型控件的一個項目條時,樹型控件會給它的父窗口發(fā)送一個TVN_BEGINDRAG通知消息,所以可以在此消息的響應函數(shù)中,調用 CTreeCtrl ::CreateDragImage ()函數(shù)創(chuàng)建表示當前項目條正處在拖動操作中的圖象,該函數(shù)創(chuàng)建的圖象由項目條的圖象和標簽文本組成。創(chuàng)建了拖動圖象后,調用CImageList::BeginDrag()函數(shù)指定拖動圖象的熱點位置,然后調用CImageList::DragEnter()函數(shù)顯示拖動圖象。接下來處理 WM_MOUSEMOVE 消息用于更新拖動圖象,我們想讓移動中的圖象經過某些項目時高亮度顯示,這可以調用 CTreeCtrl ::SelectDropTarget() 來實現(xiàn)。在調用 SelectDropTarget()函數(shù)之前,需要先調用CImageList::DragShowNolock ( false )函數(shù)來隱藏圖象列表,然后再調用CImageList::DragShowNolock ( true ) 函數(shù)來恢復圖象列表的顯示,這樣就不會在拖動過程中留下難看的軌跡。最后我們處理 WM_LBUTTONUP 消息用于完成拖動操作,在該消息響應函數(shù)中,我們需要完成結束拖動圖象的顯示、刪除拖動圖象、釋放鼠標、節(jié)點的拷貝/刪除等操作。在節(jié)點的拷貝/刪除操作中,如果是父節(jié)點拖到子節(jié)點上,我們可以先將父節(jié)點拷到根結點下的臨時節(jié)點中,再從臨時結點處拷到子節(jié)點,然后將根結點下的臨時節(jié)點刪除,這樣做的目的是防止產生異常。

(2)處理項目條的無意拖動

如果在鼠標按下時不小心移動了鼠標,這時系統(tǒng)就認為產生了一個移動操作,這就產生了誤操作。解決這個問題的方法是設置時間延遲,也就是說當用戶按下鼠標后必須在原位置停留一段時間,才能激活拖動操作。

(3)處理拖動過程中的滾動問題

當我們拖動樹型控件的項目條時,如果目的節(jié)點不可見,則需要拖動滾動條或收攏其它一些節(jié)點以使得目的節(jié)點顯示出來,無疑,這會給我們帶來很大的不便。為此就要給樹型控件添加自動滾動支持。首先設置一個定時器,在 WM_TIMER 消息中檢測鼠標的位置,如果靠近樹型控件的下邊緣,則使得控件向下滾動??拷线吘墑t向上滾動。滾動速度根據鼠標的位置確定。

(4)拖動過程中節(jié)點的智能展開

為了實現(xiàn)在拖動過程中鼠標停留在某個節(jié)點上一段時間后,該節(jié)點會自動展開的功能。設置一個定時器,當鼠標在拖動過程中停止在某個節(jié)點上時,定時器被啟動,再設置一變量保存當前的鼠標位置。

二、編程步驟

1、 新建一對話框工程DragTree,編輯資源,在對話框中加入一樹型控件IDC_TREE ,屬性設置為:Has Buttons、Has Lines、Lines at root、Edit Labels、Border;

2、 使用Class Wizard給該控件添加一個成員變量 m_wndTree ,在代碼部分將該控件的類型修改為CXTreeCtrl。

3、 在對話框的OnInitDialog()函數(shù)中添加代碼,初始化樹型控件的項目條;

4、 制作一個圖像資源(ID為IDB_TREEIMAGE),其中包含兩個小圖標,用來作為樹型控件項目條的顯示圖標;

5、 添加代碼,編譯運行程序。

三、程序代碼

// XTreeCtrl.h : header file

#if !defined(AFX_XTREECTRL_H__3EF12526_EF66_4FD9_A572_59476441D79A__INCLUDED_)

#define AFX_XTREECTRL_H__3EF12526_EF66_4FD9_A572_59476441D79A__INCLUDED_

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

class CXTreeCtrl : public CTreeCtrl

{

 // Construction

 public:

CXTreeCtrl();

// Attributes

 public:

// Operations

 public:

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CXTreeCtrl)

//}}AFX_VIRTUAL

// Implementation

 public:

virtual ~CXTreeCtrl();

// Generated message map functions

 protected:

UINT m_TimerTicks; //處理滾動的定時器所經過的時間

UINT m_nScrollTimerID; //處理滾動的定時器

CPoint m_HoverPoint; //鼠標位置

UINT m_nHoverTimerID; //鼠標敏感定時器

DWORD m_dwDragStart; //按下鼠標左鍵那一刻的時間

BOOL m_bDragging; //標識是否正在拖動過程中

CImageList* m_pDragImage; //拖動時顯示的圖象列表

HTREEITEM m_hItemDragS; //被拖動的標簽

HTREEITEM m_hItemDragD; //接受拖動的標簽

//{{AFX_MSG(CXTreeCtrl)

 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 void OnLButtonDown(UINT nFlags, CPoint point);

 afx_msg void OnTimer(UINT nIDEvent);

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

 private:

HTREEITEM CopyBranch(HTREEITEM htiBranch,HTREEITEM htiNewParent,HTREEITEM htiAfter);

HTREEITEM CopyItem(HTREEITEM hItem,HTREEITEM htiNewParent,HTREEITEM htiAfter);

};

#endif

//////////////////////////////////////////////////////////// CXTreeCtrl

#include "stdafx.h"

#include "DragTree.h"

#include "XTreeCtrl.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

#define DRAG_DELAY 60

CXTreeCtrl::CXTreeCtrl()

{

 m_bDragging = false;

}

CXTreeCtrl::~CXTreeCtrl()

{}

BEGIN_MESSAGE_MAP(CXTreeCtrl, CTreeCtrl)

//{{AFX_MSG_MAP(CXTreeCtrl)

 ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)

 ON_WM_MOUSEMOVE()

 ON_WM_LBUTTONUP()

 ON_WM_LBUTTONDOWN()

 ON_WM_TIMER()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

void CXTreeCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)

{

 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

 *pResult = 0;

 //如果是無意拖曳,則放棄操作

 if( (GetTickCount() - m_dwDragStart) < DRAG_DELAY )

return;

 m_hItemDragS = pNMTreeView->itemNew.hItem;

 m_hItemDragD = NULL;

 //得到用于拖動時顯示的圖象列表

 m_pDragImage = CreateDragImage( m_hItemDragS );

 if( !m_pDragImage )

return;

 m_bDragging = true;

 m_pDragImage->BeginDrag ( 0,CPoint(8,8) );

 CPoint pt = pNMTreeView->ptDrag;

 ClientToScreen( &pt );

 m_pDragImage->DragEnter ( this,pt ); //"this"將拖曳動作限制在該窗口

 SetCapture();

 m_nScrollTimerID = SetTimer( 2,40,NULL );

}

void CXTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)

{

 HTREEITEM hItem;

 UINT flags;

 //檢測鼠標敏感定時器是否存在,如果存在則刪除,刪除后再定時

 if( m_nHoverTimerID )

 {

KillTimer( m_nHoverTimerID );

m_nHoverTimerID = 0;

 }

 m_nHoverTimerID = SetTimer( 1,800,NULL ); //定時為 0.8 秒則自動展開

 m_HoverPoint = point;

 if( m_bDragging )

 {

CPoint pt = point;

CImageList::DragMove( pt );

//鼠標經過時高亮顯示

CImageList::DragShowNolock( false ); //避免鼠標經過時留下難看的痕跡

if( (hItem = HitTest(point,&flags)) != NULL )

{

 SelectDropTarget( hItem );

 m_hItemDragD = hItem;

}

CImageList::DragShowNolock( true );

//當條目被拖曳到左邊緣時,將條目放在根下

CRect rect;

GetClientRect( &rect );

if( point.x < rect.left + 20 )

 m_hItemDragD = NULL;

 }

 CTreeCtrl::OnMouseMove(nFlags, point);

}

void CXTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)

{

 CTreeCtrl::OnLButtonUp(nFlags, point);

 if( m_bDragging )

 {

m_bDragging = FALSE;

CImageList::DragLeave( this );

CImageList::EndDrag();

ReleaseCapture();

delete m_pDragImage;

SelectDropTarget( NULL );

if( m_hItemDragS == m_hItemDragD )

{

 KillTimer( m_nScrollTimerID );

 return;

}

Expand( m_hItemDragD,TVE_EXPAND );

HTREEITEM htiParent = m_hItemDragD;

while( (htiParent = GetParentItem(htiParent)) != NULL )

{

 if( htiParent == m_hItemDragS )

 {

HTREEITEM htiNewTemp = CopyBranch( m_hItemDragS,NULL,TVI_LAST );

HTREEITEM htiNew = CopyBranch( htiNewTemp,m_hItemDragD,TVI_LAST );

DeleteItem( htiNewTemp );

SelectItem( htiNew );

KillTimer( m_nScrollTimerID );

return;

 }

}

HTREEITEM htiNew = CopyBranch( m_hItemDragS,m_hItemDragD,TVI_LAST );

DeleteItem( m_hItemDragS );

SelectItem( htiNew );

KillTimer( m_nScrollTimerID );

 }

}

HTREEITEM CXTreeCtrl::CopyItem(HTREEITEM hItem, HTREEITEM htiNewParent, HTREEITEM htiAfter) //拷貝條目

{

 TV_INSERTSTRUCT tvstruct;

 HTREEITEM hNewItem;

 CString sText;

 //得到源條目的信息

 tvstruct.item.hItem = hItem;

 tvstruct.item.mask=TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;

 GetItem( &tvstruct.item );

 sText = GetItemText( hItem );

 tvstruct.item.cchTextMax = sText.GetLength ();

 tvstruct.item.pszText = sText.LockBuffer ();

 //將條目插入到合適的位置

 tvstruct.hParent = htiNewParent;

 tvstruct.hInsertAfter = htiAfter;

 tvstruct.item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT;

 hNewItem = InsertItem( &tvstruct );

 sText.ReleaseBuffer ();

 //限制拷貝條目數(shù)據和條目狀態(tài)

 SetItemData( hNewItem,GetItemData(hItem) );

 SetItemState( hNewItem,GetItemState(hItem,TVIS_STATEIMAGEMASK),TVIS_STATEIMAGEMASK);

 return hNewItem;

}

HTREEITEM CXTreeCtrl::CopyBranch(HTREEITEM htiBranch, HTREEITEM htiNewParent, HTREEITEM htiAfter) //拷貝分支

{

 HTREEITEM hChild;

 HTREEITEM hNewItem = CopyItem( htiBranch,htiNewParent,htiAfter );

 hChild = GetChildItem( htiBranch );

 while( hChild != NULL )

 {

CopyBranch( hChild,hNewItem,htiAfter );

hChild = GetNextSiblingItem( hChild );

 }

 return hNewItem;

}

void CXTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) //處理無意拖曳

{

 m_dwDragStart = GetTickCount();

 CTreeCtrl::OnLButtonDown(nFlags, point);

}

void CXTreeCtrl::OnTimer(UINT nIDEvent)

{

 //鼠標敏感節(jié)點

 if( nIDEvent == m_nHoverTimerID )

 {

KillTimer( m_nHoverTimerID );

m_nHoverTimerID = 0;

HTREEITEM trItem = 0;

UINT uFlag = 0;

trItem = HitTest( m_HoverPoint,&uFlag );

if( trItem && m_bDragging )

{

 SelectItem( trItem );

 Expand( trItem,TVE_EXPAND );

}

 }

 //處理拖曳過程中的滾動問題

 else if( nIDEvent == m_nScrollTimerID )

 {

m_TimerTicks++;

CPoint pt;

GetCursorPos( &pt );

CRect rect;

GetClientRect( &rect );

ClientToScreen( &rect );

HTREEITEM hItem = GetFirstVisibleItem();

if( pt.y < rect.top +10 )

{

 //向上滾動

 int slowscroll = 6 - (rect.top + 10 - pt.y )/20;

 if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)) )

 {

CImageList::DragShowNolock ( false );

SendMessage( WM_VSCROLL,SB_LINEUP );

SelectDropTarget( hItem );

m_hItemDragD = hItem;

CImageList::DragShowNolock ( true );

 }

}

else if( pt.y > rect.bottom - 10 )

{

 //向下滾動

 int slowscroll = 6 - (pt.y - rect.bottom + 10)/20;

 if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)) )

 {

CImageList::DragShowNolock ( false );

SendMessage( WM_VSCROLL,SB_LINEDOWN );

int nCount = GetVisibleCount();

for( int i=0 ; i

 hItem = GetNextVisibleItem( hItem );

 if( hItem )

SelectDropTarget( hItem );

 m_hItemDragD = hItem;

 CImageList::DragShowNolock ( true );

 }

}

 }

 else

CTreeCtrl::OnTimer(nIDEvent);

}

////////////////////////////////////////////////////////////

BOOL CDragTreeDlg::OnInitDialog()

{

 CDialog::OnInitDialog();

 …………………….//此處代碼省略

 // TODO: Add extra initialization here

 m_image.Create ( IDB_TREEIMAGE,16,1,RGB(255,255,255) );

 m_wndTree.SetImageList ( &m_image,TVSIL_NORMAL );

 HTREEITEM hti1 = m_wndTree.InsertItem ( _T("唐詩"),0,1 );

 HTREEITEM hti2 = m_wndTree.InsertItem ( _T("宋詞"),0,1 );

 HTREEITEM hti3 = m_wndTree.InsertItem ( _T("元曲"),0,1 );

 HTREEITEM hti4 = m_wndTree.InsertItem ( _T("李白"),0,1,hti1 );

 m_wndTree.InsertItem ( _T("靜夜思(床前明月光)"),0,1,hti4 );

 m_wndTree.InsertItem ( _T("將進酒(君不見黃河之水天上來)"),0,1,hti4 );

 m_wndTree.InsertItem ( _T("望廬山瀑布(日照香爐生紫煙)"),0,1,hti4 );

 m_wndTree.InsertItem ( _T("蜀道難(噫吁戲,危乎高哉)"),0,1,hti4 );

 HTREEITEM hti5 = m_wndTree.InsertItem ( _T("杜甫"),0,1,hti1 );

 m_wndTree.InsertItem ( _T("蜀相(丞相祠堂何處尋)"),0,1,hti5 );

 m_wndTree.InsertItem ( _T("春望(國破山河在)"),0,1,hti5 );

 m_wndTree.InsertItem ( _T("茅屋為秋風所破歌(八月秋高風怒號)"),0,1,hti5 );

 HTREEITEM hti6 = m_wndTree.InsertItem ( _T("白居易"),0,1,hti1 );

 m_wndTree.InsertItem ( _T("長恨歌(漢皇重色思傾國)"),0,1,hti6 );

 m_wndTree.InsertItem ( _T("琵琶行並序(潯陽江頭夜送客)"),0,1,hti6 );

 m_wndTree.InsertItem ( _T("李清照"),0,1,hti2 );

 m_wndTree.InsertItem ( _T("柳永"),0,1,hti2 );

 return TRUE; // return TRUE unless you set the focus to a control

}

四、小結

本實例介紹了樹型控件如何實現(xiàn)項目條的拖動,它的實現(xiàn)思路主要是利用了定時器,不同的定時器來實現(xiàn)不同的功能,另外,讀者朋友在學習中要主要掌握CimageList類的幾個成員函數(shù)的用法。

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
MFC中CImageList(圖形列表控件)和CTreeCtrl(樹形列表控件)的簡單用法
【材料整理】VC 樹形控件 例子及相關知識
MFC樹形控件(CTreeCtrl)用法(下)
VC?CTreeCtrl用法總結
輕松實現(xiàn)類VC界面
ListCtrl CTreeCtrl 操作 - 常見操作實例代碼 - <font size=5>石柱森林</fo...
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服