MFC:樹形控件


成員函數

函數名稱 功能
CTreeCtrlDlg(CWnd* pParent = NULL); 構造函數
void InitTreeFile(); 初始化樹形控件,如果復制或用其他對象初始化時需要調用
BOOL SetTreeRoot(const CString strPath); 設置根目錄
void SetUnwantedString(const std::vector vecStr); 設置不想顯示的子目錄
BOOL SetAcceptMsgWnd(const HWND hWnd); 設置接收消息的窗口句柄
CString GetPath(); 獲取當前被選中的目錄
BOOL SetTreeImageList(CImageList * ImgList, int nImgList); 設置當前控件目錄圖標
InitTreeFile()

該函數是在通過一個對象來初始化另一個對象或把一個對象賦值給另一個對象后需要調用該函數,以初始化控件。

例如:

CSelfUpdateTreeCtrl * pTreeFile;
pTreeFile = new CSelfUpdateTreeCtrl(m_TreeFile); // m_TreeFile是另一個控件
pTreeFile->Create(TVS_EDITLABELS | TVS_HASBUTTONS | WS_CHILD | WS_VISIBLE,
        rect,
        this,
        IDC_TREE_NODE);
pTreeFile->ShowWindow(SW_SHOWNORMAL);
pTreeFile->InitTreeFile(); // 這里調用初始化函數,初始化控件
SetTreeRoot(const CString strPath)

設置控件根目錄,在想要改變控件的根目錄或者在創建對象的時候沒有提供根目錄的時候調用。返回值為BOOL型,如果返回值是TRUE,則成功。如果返回值是FALSE,則失敗。

例如:

CSelfUpdateTreeCtrl treeCtrl;
treeCtrl.SetTreeRoot(_T("E:\\"));
SetUnwantedString(const std::vector vecStr)

不想有些目錄出現,則可通過該函數設置一些要屏蔽的目錄。

例如:

std::vector<CString> vecTemp;
vecTemp.push_back(_T("二值圖"));
vecTemp.push_back(_T("缺陷大圖"));
vecTemp.push_back(_T("實時圖"));
vecTemp.push_back(_T("差影圖"));
m_TreeFile.SetTreeRoot(m_strGlobalPath);
m_TreeFile.SetUnwantedString(vecTemp); // 設置不想顯示文件夾的字符串

SetAcceptMsgWnd(const HWND hWnd)

如果需要其他窗口響應控件的焦點變化的消息則需要調用該函數來設置接收消息的窗口。而響應的窗口需要響應相關的消息。其消息為:WM_SELFUPDATETREECTRL_SELCHANGED。返回值為BOOL型,如果返回值是TRUE,則成功。如果返回值是FALSE,則失敗。

例如:

std::vector<CString> vecTemp;
vecTemp.push_back(_T("二值圖"));
vecTemp.push_back(_T("缺陷大圖"));
vecTemp.push_back(_T("實時圖"));
vecTemp.push_back(_T("差影圖"));
m_TreeFile.SetTreeRoot(m_strGlobalPath);
m_TreeFile.SetUnwantedString(vecTemp);
m_TreeFile.SetAcceptMsgWnd(m_hWnd); // 設置接收消息的窗口

GetPath()

該函數是獲取當前選中的節點的絕對路徑。返回一個CString的,就是路徑地址。

例如:

afx_msg LRESULT CBrowseDlg::OnSelfUpdateTreeMsg(WPARAM wParam,LPARAM lParam)
{
    LoadInformation(m_TreeFile.GetPath());
    return 0;
}

SetTreeImageList(CImageList * ImgList, int nImgList)

設置控件中節點的圖標。返回值為BOOL型,如果返回值是TRUE,則成功。如果返回值是FALSE,則失敗。


HICON hIcon = theApp.LoadIcon(IDI_ICON_TREEFILE);
CImageList imgList;
imgList.Create(16, 16, ILC_COLOR32, 3, 3);
for (int i = 0; i < 8; i++)
{
    imgList.Add(hIcon);
}
m_TreeFile.SetTreeImageList(&imgList, LVSIL_NORMAL);

使用案例

靜態案例

聲明為類成員變量

// 在頭文件中聲明為類
CSelfUpdateTreeCtrl m_TreeFile;

// 初始化控件
std::vector<CString> vecTemp;
vecTemp.push_back(_T("二值圖"));
vecTemp.push_back(_T("缺陷大圖"));
vecTemp.push_back(_T("實時圖"));
vecTemp.push_back(_T("差影圖"));
m_TreeFile.SetTreeRoot(m_strGlobalPath);
m_TreeFile.SetUnwantedString(vecTemp);
m_TreeFile.SetAcceptMsgWnd(m_hWnd);

HICON hIcon = theApp.LoadIcon(IDI_ICON_TREEFILE);
CImageList imgList;
imgList.Create(16, 16, ILC_COLOR32, 3, 3);
for (int i = 0; i < 8; i++)
{
    imgList.Add(hIcon);
}
m_TreeFile.SetTreeImageList(&imgList, LVSIL_NORMAL);

動態案例
CRect rect(300,0, 500,300);
m_pTreeFile = new CSelfUpdateTreeCtrl(m_TreeFile); // 動態創建樹形控件

m_pTreeFile->Create(TVS_EDITLABELS | TVS_HASBUTTONS | WS_CHILD | WS_VISIBLE,
    rect,
    this,
    IDC_TREE_NODE);
m_pTreeFile->ShowWindow(SW_SHOWNORMAL);
m_pTreeFile->InitTreeFile();

源代碼
// 頭文件
#pragma once
#include <vector>
// Tree結構

#define WM_SELFUPDATETREECTRL_SELCHANGED WM_USER + 779
// CSelfUpdateTreeCtrl

class CSelfUpdateTreeCtrl : public CTreeCtrl
{
	DECLARE_DYNAMIC(CSelfUpdateTreeCtrl)

public:
	CSelfUpdateTreeCtrl();
	CSelfUpdateTreeCtrl(CString strPath);
	virtual ~CSelfUpdateTreeCtrl();
    CSelfUpdateTreeCtrl(CSelfUpdateTreeCtrl & ob);
    CSelfUpdateTreeCtrl & operator= (CSelfUpdateTreeCtrl & ob);
protected:
	DECLARE_MESSAGE_MAP()

private:
	CString m_strRoot;                            // 根目錄
    HWND m_hAcceptMessage;                        // 接收消息的窗口
	std::vector<HTREEITEM> m_vecTreeTop;          // 目錄節點樹,每一個元素代表一個頂級目錄
    std::vector<HTREEITEM> m_vecHierarchy;        // 目錄節點用於遍歷頂級目錄下的子目錄
    std::vector<CString> m_vecUnwantedString;     // 不想出現在樹形結構上的目錄名稱列表
    CImageList m_ImgList;                      // 目錄樹圖標列表
    int m_nImgList;
    // 初始化根目錄
	BOOL InitRootDirectory();
    // 更新樹節點
    BOOL UpdateTreeNode(const unsigned long nIndex);
    // 判斷當前節點級別
    int JudgeFloor();
    // 插入樹節點
	BOOL InsertTreeNode(const CString strRoot, const unsigned long nIndex);
    // 遞歸插入
    BOOL InsertRecursion(const CString strRoot, int nFileNum, const unsigned long nIndex);
    // 拷貝圖標列表數據
    BOOL SetTreeImageList(CImageList * ImgList);
public:
    // 初始化樹形控件,如果復制或用其他對象初始化時需要調用
    void InitTreeFile();
    // 設置根目錄
	BOOL SetTreeRoot(const CString strPath);
    // 設置不想顯示的目錄
    void SetUnwantedString(const std::vector<CString> vecStr);
    // 設置接收消息的窗口
    BOOL SetAcceptMsgWnd(const HWND hWnd);
    // 獲取當前目錄
    CString GetPath();
    // 發送消息函數
    afx_msg void OnTvnSelchanged(NMHDR * pNMHDR, LRESULT * pResult);
    // 設置圖標列表
    BOOL SetTreeImageList(CImageList * ImgList, int nImgList);
};
// 源文件
// SelfUpdateTreeCtrl.cpp : 實現文件
//

#include "stdafx.h"
#include "SelfUpdateTreeCtrl.h"
#include <algorithm>

// CSelfUpdateTreeCtrl

IMPLEMENT_DYNAMIC(CSelfUpdateTreeCtrl, CTreeCtrl)

CSelfUpdateTreeCtrl::CSelfUpdateTreeCtrl()
{
	m_strRoot = "";
    m_hAcceptMessage = NULL;
    m_nImgList = LVSIL_NORMAL;
}

CSelfUpdateTreeCtrl::CSelfUpdateTreeCtrl(CString strPath) : m_strRoot(strPath)
{
    m_hAcceptMessage = NULL;
    m_nImgList = LVSIL_NORMAL;
	InitRootDirectory();
}

CSelfUpdateTreeCtrl::~CSelfUpdateTreeCtrl()
{
   if ( NULL != m_ImgList.GetSafeHandle())
   {
       m_ImgList.DeleteImageList();
       ASSERT(m_ImgList.GetSafeHandle() == NULL);
   }
}

CSelfUpdateTreeCtrl::CSelfUpdateTreeCtrl(CSelfUpdateTreeCtrl & ob)
{
    m_strRoot = ob.m_strRoot;
    m_hAcceptMessage = ob.m_hAcceptMessage;
    if (!m_vecTreeTop.empty())
    {
        m_vecTreeTop.clear();
    }
    if (!m_vecHierarchy.empty())
    {
        m_vecHierarchy.clear();
    }
    if (!m_vecUnwantedString.empty())
    {
        m_vecUnwantedString.clear();
    }
    m_vecTreeTop = ob.m_vecTreeTop;
    m_vecHierarchy = ob.m_vecHierarchy;
    m_vecUnwantedString = ob.m_vecUnwantedString;
    //圖標列表
    m_nImgList = ob.m_nImgList;
    SetTreeImageList( &(ob.m_ImgList));
}



CSelfUpdateTreeCtrl & CSelfUpdateTreeCtrl::operator= (CSelfUpdateTreeCtrl & ob)
{
    //CTreeCtrl::operator= (ob);
    if (this == &ob)
        return * this;
    m_strRoot = ob.m_strRoot;
    m_hAcceptMessage = ob.m_hAcceptMessage;
    if (!m_vecTreeTop.empty())
    {
        m_vecTreeTop.clear();
    }
    if (!m_vecHierarchy.empty())
    {
        m_vecHierarchy.clear();
    }
    if (!m_vecUnwantedString.empty())
    {
        m_vecUnwantedString.clear();
    }
    m_vecTreeTop = ob.m_vecTreeTop;
    m_vecHierarchy = ob.m_vecHierarchy;
    m_vecUnwantedString = ob.m_vecUnwantedString;
    // 圖標列表
    m_nImgList = ob.m_nImgList;
    if (m_ImgList.GetSafeHandle())
    {
        m_ImgList.DeleteImageList();
        ASSERT(m_ImgList.GetSafeHandle() == NULL);
    }
    SetTreeImageList(&(ob.m_ImgList));

    return *this;
}

BEGIN_MESSAGE_MAP(CSelfUpdateTreeCtrl, CTreeCtrl)
    ON_NOTIFY_REFLECT(TVN_SELCHANGED, &CSelfUpdateTreeCtrl::OnTvnSelchanged)
END_MESSAGE_MAP()



// CSelfUpdateTreeCtrl 消息處理程序
BOOL CSelfUpdateTreeCtrl::SetTreeRoot(CString strPath)
{
	m_strRoot = strPath;
	return InitRootDirectory();
}

BOOL CSelfUpdateTreeCtrl::InitRootDirectory()
{
    if ("" == m_strRoot)
    {
        return FALSE;
    }
    if (!m_vecTreeTop.empty())
    {
        m_vecTreeTop.clear();
    }
    CFileFind file;
    CString strDirectory = m_strRoot;
    if ( strDirectory.Right(1) != "\\" )
    {
        strDirectory += _T("\\");
    }
    strDirectory += _T("*.*");
    BOOL bRet = file.FindFile(strDirectory);
    unsigned long ulNum = 0;// 給每個結點設置索引號
    while(bRet)
    {
        bRet = file.FindNextFile();  // 是否有下一個目錄
        if (file.IsDirectory() && !file.IsDots())
        {
            CString strPath = file.GetFilePath();
            CString strTitle = strPath.Right(strPath.GetLength()-strPath.ReverseFind('\\')-1);
            HTREEITEM hItem = InsertItem(strTitle, 0, 0, NULL);
            m_vecTreeTop.push_back(hItem);
            SetItemData(hItem, ulNum);
            ulNum++;
        }
    }
    file.Close();
    return TRUE;
}

void CSelfUpdateTreeCtrl::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    // TODO: 在此添加控件通知處理程序代碼
    // 獲取當前選中節點深度
    int nFloor = JudgeFloor();
    // 更新當前目錄
    if ( 0 == nFloor && !ItemHasChildren(GetSelectedItem()))
    {
        unsigned long ulNum = GetItemData(GetSelectedItem());
        UpdateTreeNode(ulNum);
    }
    else
    {
        if (m_hAcceptMessage)
        {
            ::PostMessage(m_hAcceptMessage, WM_SELFUPDATETREECTRL_SELCHANGED, 0, 0);
        }
    }
    *pResult = 0;
}

int CSelfUpdateTreeCtrl::JudgeFloor()
 {
     int nDepth = 0;
     HTREEITEM hCurrentNode = GetSelectedItem();
     while ( (hCurrentNode = GetParentItem(hCurrentNode)) != NULL)
     {
         nDepth++;
     }
     return nDepth;
 }

BOOL CSelfUpdateTreeCtrl::UpdateTreeNode(unsigned long nIndex)
{
    // 調用插入節點函數
    return InsertTreeNode(GetPath(), nIndex);
}

BOOL CSelfUpdateTreeCtrl::InsertTreeNode(CString strRoot, unsigned long nIndex)
{

    if ( "" == strRoot || nIndex >= m_vecTreeTop.size())
    {
        return FALSE;
    }
    BOOL bRet = InsertRecursion(strRoot, 0, nIndex);
    m_vecHierarchy.clear();
    return bRet;
}

BOOL CSelfUpdateTreeCtrl::InsertRecursion(CString strRoot, int nFileNum, unsigned long nIndex)
{
    nFileNum++;//這個一定要放在switch之前,不能放在下面
    CFileFind file;
    CString strDirectory = strRoot;
    if ( strDirectory.Right(1) != "\\" )
    {
        strDirectory += _T("\\");
    }
    strDirectory += _T("*.*");
    BOOL bRet = file.FindFile(strDirectory);
    while(bRet)
    {
        bRet = file.FindNextFile();  // 是否有下一個目錄
        if (file.IsDirectory() && !file.IsDots())
        {
            CString strPath = file.GetFilePath();
            CString strTitle = strPath.Right(strPath.GetLength()-strPath.ReverseFind('\\')-1);
            if(std::find(m_vecUnwantedString.begin(), m_vecUnwantedString.end(), strTitle) != m_vecUnwantedString.end())
            {
                continue;
            }
            switch( nFileNum )
            {
            case 1:
                if (m_vecHierarchy.empty())
                {
                     m_vecHierarchy.push_back(InsertItem(strTitle, nFileNum, nFileNum, m_vecTreeTop[nIndex]));
                }
                else
                {
                    m_vecHierarchy[nFileNum - 1] = InsertItem(strTitle, nFileNum, nFileNum,m_vecTreeTop[nIndex]);
                }
                break;
            default:
                if ( m_vecHierarchy.size() <= nFileNum - 1 )
                {
                    m_vecHierarchy.push_back(InsertItem(strTitle, nFileNum, nFileNum,m_vecHierarchy[nFileNum - 2]));
                }
                else
                {
                    m_vecHierarchy[nFileNum - 1] = InsertItem(strTitle, nFileNum, nFileNum,m_vecHierarchy[nFileNum - 2]);
                }
                break;
            }
            InsertRecursion(strPath, nFileNum, nIndex);//遞歸遍歷子目錄
        }
        else if( !file.IsDirectory() && !file.IsDots() )//如果不是一個目錄,並且也不是當前目錄
        {
            ;//暫時不處理其他類型的圖片
        }
    }//是否找到文件
    file.Close();
    return TRUE;
}

void CSelfUpdateTreeCtrl::SetUnwantedString(std::vector<CString> vecStr)
{
    m_vecUnwantedString = vecStr;
}

 BOOL CSelfUpdateTreeCtrl::SetAcceptMsgWnd(HWND hWnd)
 {
     if (hWnd)
     {
         m_hAcceptMessage = hWnd;
         return TRUE;
     }
     else
     {
         return FALSE;
     }
 }

CString CSelfUpdateTreeCtrl::GetPath()
{
    HTREEITEM CurrentNode = GetSelectedItem();
    HTREEITEM ParentNode = GetParentItem(CurrentNode);
    CString strPath = GetItemText(ParentNode);
    CString strSelf = GetItemText(CurrentNode);
    if ("" == strPath)
    {
        strPath += strSelf+_T("\\");
    }
    else
    {
        strPath += _T("\\") + strSelf+_T("\\");
    }
    while((ParentNode = GetParentItem(ParentNode))!=NULL)
    {
        CString strTemp = GetItemText(ParentNode);
        strPath = strTemp + _T("\\") + strPath;
    }
    strPath = m_strRoot + _T("\\") + strPath;
    return strPath;
}

BOOL CSelfUpdateTreeCtrl::SetTreeImageList(CImageList * ImgList, int nImgList)
{
    if ((NULL == ImgList->GetSafeHandle()) || (ImgList == &m_ImgList))
    {
        return FALSE;
    }
    if ( m_ImgList.GetSafeHandle() )
    {
        m_ImgList.DeleteImageList();
        ASSERT( m_ImgList.GetSafeHandle() == NULL);
    }
    m_ImgList.Create(ImgList);
    m_nImgList = nImgList;
    SetImageList(&m_ImgList, m_nImgList);
    return TRUE;
}

BOOL CSelfUpdateTreeCtrl::SetTreeImageList(CImageList * ImgList)
{
    if ((NULL == ImgList->GetSafeHandle()) || (ImgList == &m_ImgList))
    {
        return FALSE;
    }
    if ( m_ImgList.GetSafeHandle() )
    {
        m_ImgList.DeleteImageList();
        ASSERT( m_ImgList.GetSafeHandle() == NULL);
    }
    m_ImgList.Create(ImgList);
    return TRUE;
}

 void CSelfUpdateTreeCtrl::InitTreeFile()
 {
     if (!m_vecTreeTop.empty())
     {
         m_vecTreeTop.clear();
         DeleteAllItems();
     }
     SetImageList(&m_ImgList, m_nImgList);
     InitRootDirectory();
 }

附言

該類繼承自類CTreeCtrl,重載了“=”操作符和拷貝構造函數,可以直接把一個對象賦值給另一個對象,或者用一個對象初始化另一個對象。但是之后需要調用InitTreeFile()函數。

這里是采用了緩加載目錄的方法,當初始化后會只加載頂級目錄,子目錄是沒有加載的。這樣可以避免當目錄過多的時候導致加載時間過長的現象。子目錄是當焦點轉移到頂級目錄的時候才加載相關目錄下面的子目錄。

如下圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM