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()

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

例如:this

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,則失敗。code

例如:orm

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的,就是路徑地址。圖片

例如:ci

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()函數。

這裏是採用了緩加載目錄的方法,當初始化後會只加載頂級目錄,子目錄是沒有加載的。這樣能夠避免當目錄過多的時候致使加載時間過長的現象。子目錄是當焦點轉移到頂級目錄的時候才加載相關目錄下面的子目錄。

以下圖:

相關文章
相關標籤/搜索