自己写的duilib树控件,如发现BUG和可优化地方请在下面回复
2012-10-22 14:11
183 查看
.h文件源代码
#ifndef __TREE_LAYOUT_H__
#define __TREE_LAYOUT_H__
namespace DuiLib{
#define kTreeDataInterface _T("TreeData")
#define kTreeLayoutInterface _T("TreeLayout")
#define kTreeChildElementInterface _T("TreeChildElement")
#define kTreeElementInterface _T("TreeElement")
class CTreeLayoutUI;
class CTreeElementUI;
typedef int ( *TREESORTPROC)(CTreeElementUI * pFirst, CTreeElementUI * pSecond, CTreeLayoutUI * pTree);
//数据节点
class UILIB_API CTreeDataUI :public CHorizontalLayoutUI
{
public:
CTreeDataUI();
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
};
//树子节点
class UILIB_API CTreeChildElementUI : public CVerticalLayoutUI
{
public:
CTreeChildElementUI();
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
virtual bool GetVisible();
};
//树节点
class UILIB_API CTreeElementUI : public CVerticalLayoutUI
{
public:
CTreeElementUI();
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
public:
CTreeDataUI * GetDataElement();
};
//树
class UILIB_API CTreeLayoutUI : public CVerticalLayoutUI
{
public:
CTreeLayoutUI(void);
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
UINT GetControlFlags() const;
void DoEvent(TEventUI& event);
void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
public:
LPCTSTR GetItemHotImage();
void SetItemHotImage(LPCTSTR pStrImage);
LPCTSTR GetItemSelectedImage();
void SetItemSelectedImage(LPCTSTR pStrImage);
void SetItemHotColor(DWORD dwColor);
DWORD GetItemHotColor() const;
void SetItemSelectedColor(DWORD dwColor);
DWORD GetItemSelectedColor() const;
void DrawItemBk(HDC hDC);
void DoPaint(HDC hDC, const RECT& rcPaint);
public:
bool Add(CTreeElementUI* pParent, CTreeElementUI * pControl, bool bInsertLast = true);
bool Remove(CTreeElementUI* pControl, bool bDelete);
void RemoveAll();
CTreeElementUI * GetRootItem();
CTreeElementUI * GetNextItem(CTreeElementUI * pElement);
CTreeElementUI * GetChildItem(CTreeElementUI * pElement);
void Expand(CTreeElementUI * pElement, UINT nCode);
bool IsExpand(CTreeElementUI * pElement);
bool ItemHasChildren(CTreeElementUI * pElement);
void SelectItem(CTreeElementUI * pElement, UINT nCode);
CTreeElementUI * GetSelectedItem();
CTreeElementUI * GetParentItem(CTreeElementUI * pElement);
CTreeElementUI * HitTest(POINT pt);
RECT GetItemRect(CTreeElementUI * pElement);
void SortChildren(CContainerUI * pElement, TREESORTPROC pSortProc);
void SetIndent(int nIndentation);
int GetIndent();
protected:
//收缩节点
void CollapseElement(CTreeElementUI * pElement);
//展开节点
void ExpandElement(CTreeElementUI * pElement);
void QuickSort(CContainerUI * pElement, TREESORTPROC pSortProc, int nFirst, int nEnd);
protected:
CTreeElementUI *m_pSelectedItem;
CTreeElementUI *m_pUpHotItem;
DWORD m_dwItemHotColor;
DWORD m_dwItemSelectedColor;
CStdString
m_sItemHotImage;
CStdString
m_sItemSelectedImage;
int m_nIndentation;//缩进值
};
}
#endif
.cpp文件源代码
#include "StdAfx.h"
#include "UITree.h"
namespace DuiLib{
//////////////////////////数据节点//////////////////////////////////////////////////
CTreeDataUI::CTreeDataUI()
{
}
LPCTSTR CTreeDataUI::GetClass() const
{
return _T("TreeDataUI");
}
LPVOID CTreeDataUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, kTreeDataInterface) == 0 ) return static_cast<CTreeDataUI*>(this);
return CContainerUI::GetInterface(pstrName);
}
//////////////////////////树子节点//////////////////////////////////////////////////
CTreeChildElementUI::CTreeChildElementUI()
{
}
LPCTSTR CTreeChildElementUI::GetClass() const
{
return _T("TreeChildElementUI");
}
LPVOID CTreeChildElementUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, kTreeChildElementInterface) == 0 ) return static_cast<CTreeChildElementUI*>(this);
return CContainerUI::GetInterface(pstrName);
}
bool CTreeChildElementUI::GetVisible()
{
return m_bVisible;
}
//////////////////////////树节点////////////////////////////////////////////////////
CTreeElementUI::CTreeElementUI()
{
}
LPCTSTR CTreeElementUI::GetClass() const
{
return _T("TreeElementUI");
}
LPVOID CTreeElementUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, kTreeElementInterface) == 0 ) return static_cast<CTreeElementUI*>(this);
return CContainerUI::GetInterface(pstrName);
}
CTreeDataUI * CTreeElementUI::GetDataElement()
{
CTreeDataUI * pTreeData = NULL;
for (int i = 0; i < GetCount(); i++)
{
pTreeData = static_cast<CTreeDataUI *>(GetItemAt(i)->GetInterface(kTreeDataInterface));
if (pTreeData) break;
}
return pTreeData;
}
////////////////////////////树///////////////////////////////////////////////////////
CTreeLayoutUI::CTreeLayoutUI(void)
{
m_dwItemHotColor = 0xFFE9F5FF;
m_dwItemSelectedColor = 0xFFC1E3FF;
m_pSelectedItem = NULL;
m_pUpHotItem = NULL;
m_nIndentation = 10;
}
LPCTSTR CTreeLayoutUI::GetClass() const
{
return _T("TreeLayoutUI");
}
LPVOID CTreeLayoutUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, kTreeLayoutInterface) == 0 ) return static_cast<CTreeLayoutUI*>(this);
return CContainerUI::GetInterface(pstrName);
}
UINT CTreeLayoutUI::GetControlFlags() const
{
if( IsEnabled() && m_iSepHeight != 0 ) return UIFLAG_SETCURSOR;
else return 0;
}
void CTreeLayoutUI::DoEvent(TEventUI& event)
{
if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
if( m_pParent != NULL ) m_pParent->DoEvent(event);
else CControlUI::DoEvent(event);
return;
}
if( event.Type == UIEVENT_SETFOCUS )
{
m_bFocused = true;
return;
}
if( event.Type == UIEVENT_KILLFOCUS )
{
m_bFocused = false;
return;
}
if( m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsVisible() && m_pVerticalScrollBar->IsEnabled() )
{
if( event.Type == UIEVENT_KEYDOWN )
{
switch( event.chKey ) {
case VK_DOWN:
LineDown();
return;
case VK_UP:
LineUp();
return;
case VK_NEXT:
PageDown();
return;
case VK_PRIOR:
PageUp();
return;
case VK_HOME:
HomeUp();
return;
case VK_END:
EndDown();
return;
}
}
else if( event.Type == UIEVENT_SCROLLWHEEL )
{
switch( LOWORD(event.wParam) ) {
case SB_LINEUP:
LineUp();
return;
case SB_LINEDOWN:
LineDown();
return;
}
}
}
else if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() && m_pHorizontalScrollBar->IsEnabled() ) {
if( event.Type == UIEVENT_KEYDOWN )
{
switch( event.chKey ) {
case VK_DOWN:
LineRight();
return;
case VK_UP:
LineLeft();
return;
case VK_NEXT:
PageRight();
return;
case VK_PRIOR:
PageLeft();
return;
case VK_HOME:
HomeLeft();
return;
case VK_END:
EndRight();
return;
}
}
else if( event.Type == UIEVENT_SCROLLWHEEL )
{
switch( LOWORD(event.wParam) ) {
case SB_LINEUP:
LineLeft();
return;
case SB_LINEDOWN:
LineRight();
return;
}
}
}
//鼠标事件
if( event.Type == UIEVENT_DBLCLICK )
{
if( IsEnabled() ) {
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
m_pSelectedItem = NULL;
if (pElement){
if (NULL == GetChildItem(pElement)){
m_pSelectedItem = pElement;
}
m_pManager->SendNotify(this, _T("treedbclick"), 0, MAKELPARAM(pt.x, pt.y));
}
Invalidate();
}
return;
}
if( event.Type == UIEVENT_KEYDOWN && IsEnabled() )
{
if( event.chKey == VK_RETURN ) {
Activate();
Invalidate();
return;
}
}
if( event.Type == UIEVENT_BUTTONDOWN )
{
if( IsEnabled() ){
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
m_pSelectedItem = NULL;
if (pElement){
if (NULL == GetChildItem(pElement)){
m_pSelectedItem = pElement;
}
m_pManager->SendNotify(this, _T("treeclick"), 0, MAKELPARAM(pt.x, pt.y));
}
Invalidate();
}
return;
}
if( event.Type == UIEVENT_RBUTTONUP )
{
if( IsEnabled() ){
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
m_pSelectedItem = NULL;
if (pElement){
if (NULL == GetChildItem(pElement)){
m_pSelectedItem = pElement;
}
m_pManager->SendNotify(this, _T("treerclick"), 0, MAKELPARAM(pt.x, pt.y));
}
Invalidate();
}
return;
}
if( event.Type == UIEVENT_MOUSEENTER )
{
if( IsEnabled() ) {
m_uButtonState |= UISTATE_HOT;
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
if (m_pUpHotItem != pElement){
if (pElement){
m_pManager->SendNotify(this, _T("treeitemhot"), 0, MAKELPARAM(pt.x, pt.y));
m_pUpHotItem = pElement;
}
}
Invalidate();
}
return;
}
if( event.Type == UIEVENT_MOUSELEAVE )
{
if( (m_uButtonState & UISTATE_HOT) != 0 ) {
m_uButtonState &= ~UISTATE_HOT;
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
if (m_pUpHotItem != pElement){
m_pManager->SendNotify(this, _T("treeitemleave"), 0, MAKELPARAM(pt.x, pt.y));
m_pUpHotItem = NULL;
}
Invalidate();
}
return;
}
CControlUI::DoEvent(event);
}
void CTreeLayoutUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
if( _tcscmp(pstrName, _T("itemhotimage")) == 0 ) SetItemHotImage(pstrValue);
if( _tcscmp(pstrName, _T("itemselectedimage")) == 0 ) SetItemSelectedImage(pstrValue);
else if( _tcscmp(pstrName, _T("itemhotcolor")) == 0 ) {
if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetItemHotColor(clrColor);
}
else if( _tcscmp(pstrName, _T("itemselectedcolor")) == 0 ) {
if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetItemSelectedColor(clrColor);
}
else __super::SetAttribute(pstrName, pstrValue);
}
LPCTSTR CTreeLayoutUI::GetItemHotImage()
{
return m_sItemHotImage;
}
void CTreeLayoutUI::SetItemHotImage(LPCTSTR pStrImage)
{
m_sItemHotImage = pStrImage;
Invalidate();
}
LPCTSTR CTreeLayoutUI::GetItemSelectedImage()
{
return m_sItemSelectedImage;
}
void CTreeLayoutUI::SetItemSelectedImage(LPCTSTR pStrImage)
{
m_sItemSelectedImage = pStrImage;
Invalidate();
}
void CTreeLayoutUI::SetItemHotColor(DWORD dwColor)
{
m_dwItemHotColor = dwColor;
}
DWORD CTreeLayoutUI::GetItemHotColor() const
{
return m_dwItemHotColor;
}
void CTreeLayoutUI::SetItemSelectedColor(DWORD dwColor)
{
m_dwItemSelectedColor = dwColor;
}
DWORD CTreeLayoutUI::GetItemSelectedColor() const
{
return m_dwItemSelectedColor;
}
void CTreeLayoutUI::DrawItemBk(HDC hDC)
{
DWORD iBackColor = 0;
RECT rcHotItem = {0};
RECT rcSelectedItem = {0};
if (m_pUpHotItem && (m_pSelectedItem != m_pUpHotItem)){
rcHotItem = GetItemRect(m_pUpHotItem);
iBackColor = GetItemHotColor();
if ( iBackColor != 0 ) {
CRenderEngine::DrawColor(hDC, rcHotItem, GetAdjustColor(iBackColor));
}
if( !m_sItemHotImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sItemHotImage) ) m_sItemHotImage.Empty();
else return;
}
}
if (m_pSelectedItem){
iBackColor = GetItemSelectedColor();
rcSelectedItem = GetItemRect(m_pSelectedItem);
if ( iBackColor != 0 ) {
CRenderEngine::DrawColor(hDC, rcSelectedItem, GetAdjustColor(iBackColor));
}
if( !m_sItemSelectedImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sItemSelectedImage) ) m_sItemSelectedImage.Empty();
else return;
}
}
if( m_sBkImage.IsEmpty() ) {
if( !m_sBkImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sBkImage) ) m_sBkImage.Empty();
else return;
}
}
}
void CTreeLayoutUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
DrawItemBk(hDC);
__super::DoPaint(hDC, rcPaint);
}
/*******************************************************************
* 函数名称: Add
* 功 能: 添加节点
* 参 数: pParent父节点,pControl需要添加的控件,bInsertLast是添加在父节点后还是前
* 返 回 值: 添加成功返回true,否则返回false
* 作 者: houbin
* 创建日期: 2012年6月29日星期五
*******************************************************************/
bool CTreeLayoutUI::Add(CTreeElementUI* pParent, CTreeElementUI * pControl, bool bInsertLast)
{
bool bRet = false;
do
{
if (NULL == pControl) break;
//查询自己节点中是否有子节点
{
CTreeChildElementUI * pChildElementUI = NULL;
for(int n = 0; n < pControl->GetCount(); n++){
pChildElementUI = static_cast<CTreeChildElementUI *>(pControl->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElementUI) break;
}
if (NULL == pChildElementUI){
CTreeChildElementUI * pChild = NULL;
try{
pChildElementUI = new CTreeChildElementUI();
pControl->Add(pChildElementUI);
}
catch (...){
if (pChildElementUI){
delete pChildElementUI;
pChildElementUI = NULL;
break;
}
}
}
}
if (pParent){
//检查父控件是否有子控件对象
CTreeChildElementUI * pChildElementUI = NULL;
for(int n = 0; n < pParent->GetCount(); n++){
pChildElementUI = static_cast<CTreeChildElementUI *>(pParent->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElementUI) break;
}
if (NULL == pChildElementUI){
break;
}
//添加子节点
if (bInsertLast){
bRet = pChildElementUI->Add(pControl);
}
else{
bRet = pChildElementUI->AddAt(pControl, 0);
}
}
else{
if (bInsertLast){
bRet = __super::Add(pControl);
}
else{
bRet = __super::AddAt(pControl, 0);
}
}
} while (0);
if (bRet){
//设置所有相关父节点的高度
if (pParent){
//设置缩进
CTreeChildElementUI * pChildElementUI = NULL;
for(int n = 0; n < pParent->GetCount(); n++){
pChildElementUI = static_cast<CTreeChildElementUI *>(pParent->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElementUI) break;
}
if (pChildElementUI){
pChildElementUI->SetPadding(CRect(GetIndent(), 0, 0, 0));
}
while(pParent){
if (!IsExpand(pParent)) break;
int nHeight = pParent->GetFixedHeight() + pControl->GetFixedHeight();
pParent->SetFixedHeight(nHeight);
pParent = GetParentItem(pParent);
}
}
}
return bRet;
}
/*******************************************************************
* 函数名称: Remove
* 功 能: 删除指定节点
* 参 数: pControl要删除的节点,bDelete删除的时候是否把节点的内存数据也删除
* 返 回 值: 删除成功返回true,否则返回false
* 作 者: houbin
* 创建日期: 2012年6月29日星期五
*******************************************************************/
bool CTreeLayoutUI::Remove(CTreeElementUI* pControl, bool bDelete)
{
bool bRet = false;
do
{
if (pControl == NULL) break;
CControlUI * pParentControl = pControl->GetParent();
if (NULL == pParentControl) break;
if (static_cast<CTreeChildElementUI*>(pParentControl->GetInterface(kTreeChildElementInterface))){
CTreeChildElementUI * pChildElement = static_cast<CTreeChildElementUI*>(pParentControl->GetInterface(kTreeChildElementInterface));
int nDelHeight = pControl->GetFixedHeight();
if (bDelete){
bRet = pChildElement->Remove(pControl);
}
else{
bRet = pChildElement->Erase(pControl);
}
//设置父节点的高度
if (bRet){
CTreeElementUI * pParentElement = static_cast<CTreeElementUI*>(pChildElement->GetParent()->GetInterface(kTreeElementInterface));
while(pParentElement){
if (!IsExpand(pParentElement)) break;
int nHeight = pParentElement->GetFixedHeight() - nDelHeight;
pParentElement->SetFixedHeight(nHeight);
pParentElement = GetParentItem(pParentElement);
}
}
}
else if (static_cast<CTreeLayoutUI*>(pParentControl->GetInterface(kTreeLayoutInterface)) == this){
if (bDelete){
bRet = __super::Remove(pControl);
}
else{
bRet = __super::Erase(pControl);
}
}
m_pSelectedItem = NULL;
m_pUpHotItem = NULL;
} while (0);
return bRet;
}
/*******************************************************************
* 函数名称: RemoveAll
* 功 能: 删除树
* 参 数: 无
* 返 回 值: 无
* 作 者: houbin
* 创建日期: 2012年6月29日星期五
*******************************************************************/
void CTreeLayoutUI::RemoveAll()
{
__super::RemoveAll();
m_pSelectedItem = NULL;
m_pUpHotItem = NULL;
}
/*******************************************************************
* 函数名称: GetRootItem
* 功 能: 获取跟节点
* 参 数: 无
* 返 回 值: 返回根节点指针
* 作 者: houbin
* 创建日期: 2012年7月2日星期一
*******************************************************************/
CTreeElementUI * CTreeLayoutUI::GetRootItem()
{
CTreeElementUI * pElementUI = NULL;
for( int i = 0; i < GetCount(); i++ ) {
if( static_cast<CTreeElementUI*>(GetItemAt(i)->GetInterface(kTreeElementInterface)) != NULL ) {
pElementUI = static_cast<CTreeElementUI*>(GetItemAt(i)->GetInterface(kTreeElementInterface));
break;
}
}
return pElementUI;
}
/*******************************************************************
* 函数名称: GetNextItem
* 功 能: 获取下一个节点
* 参 数: 当前节点指针
* 返 回 值: 下一个节点指针
* 作 者: houbin
* 创建日期: 2012年7月2日星期一
*******************************************************************/
CTreeElementUI * CTreeLayoutUI::GetNextItem(CTreeElementUI * pElement)
{
CTreeElementUI * pElementRet = NULL;
do
{
if (NULL == pElement) break;
CContainerUI * pParentElement = static_cast<CContainerUI *>(pElement->GetParent());
if (NULL == pParentElement) break;
int nIndex = pParentElement->GetItemIndex(pElement);
for(int i = nIndex + 1; i < pParentElement->GetCount(); i++)
{
pElementRet = static_cast<CTreeElementUI *>(pParentElement->GetItemAt(i)->GetInterface(kTreeElementInterface));
if (pElementRet) break;
}
} while (0);
return pElementRet;
}
/*******************************************************************
* 函数名称: GetChildItem
* 功 能: 获取节点的子节点
* 参 数: pElement需要获取的子节点控件
* 返 回 值: 成功返回直接点指针,否则返回NULL
* 作 者: houbin
* 创建日期: 2012年6月29日星期五
*******************************************************************/
CTreeElementUI * CTreeLayoutUI::GetChildItem(CTreeElementUI * pElement)
{
CTreeElementUI * pElementRet = NULL;
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElementUI = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElementUI = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElementUI) break;
}
if (NULL == pChildElementUI) break;
if (pChildElementUI->GetCount() <= 0) break;
pElementRet = static_cast<CTreeElementUI*>(pChildElementUI->GetItemAt(0)->GetInterface(kTreeElementInterface));
} while (0);
return pElementRet;
}
//收缩节点
void CTreeLayoutUI::CollapseElement(CTreeElementUI * pElement)
{
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElement = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElement) break;
}
if (NULL == pChildElement) break;
if (!IsExpand(pElement)) break;
pChildElement->SetVisible(false);
CTreeDataUI * pDataUI = pElement->GetDataElement();
if (pDataUI){
int nOldHeight = pElement->GetFixedHeight();
int nHeight = pDataUI->GetFixedHeight();
pElement->SetFixedHeight(nHeight);
//设置父节点的高度
CTreeElementUI * pParentElement = GetParentItem(pElement);
while(pParentElement)
{
//父节点展开,则设置展开的高度
if (IsExpand(pParentElement)){
int nParentHeight = pParentElement->GetFixedHeight() + nHeight - nOldHeight;
pParentElement->SetFixedHeight(nParentHeight);
}
pParentElement = GetParentItem(pParentElement);
}
//设置父节点高度完毕////////////
}
} while (0);
}
//展开节点
void CTreeLayoutUI::ExpandElement(CTreeElementUI * pElement)
{
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElement = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElement) break;
}
if (NULL == pChildElement) break;
if (IsExpand(pElement)) break;
pChildElement->SetVisible(true);
CTreeDataUI * pDataUI = pElement->GetDataElement();
if (pDataUI){
int nOldHeight = pElement->GetFixedHeight();
int nHeight = pDataUI->GetFixedHeight();
CTreeElementUI * pChildNode = GetChildItem(pElement);
while(pChildNode)
{
nHeight += pChildNode->GetFixedHeight();
pChildNode = GetNextItem(pChildNode);
}
pElement->SetFixedHeight(nHeight);
//设置父节点的高度
CTreeElementUI * pParentElement = GetParentItem(pElement);
while(pParentElement)
{
//父节点展开,则设置展开的高度
if (IsExpand(pParentElement)){
int nParentHeight = pParentElement->GetFixedHeight() + nHeight - nOldHeight;
pParentElement->SetFixedHeight(nParentHeight);
}
pParentElement = GetParentItem(pParentElement);
}
//设置父节点高度完毕////////////
}
} while (0);
}
void CTreeLayoutUI::Expand(CTreeElementUI * pElement, UINT nCode)
{
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElement = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElement) break;
}
if (NULL == pChildElement) break;
if (TVE_COLLAPSE == nCode){
CollapseElement(pElement);
}
if(TVE_EXPAND == nCode){
ExpandElement(pElement);
}
if(TVE_TOGGLE == nCode){
//如果是收缩则展开,如果展开则收缩
if (IsExpand(pElement)){
CollapseElement(pElement);
}
else{
ExpandElement(pElement);
}
}
} while (0);
}
/*******************************************************************
* 函数名称: IsExpand
* 功 能: 检测指定节点是否展开
* 参 数: pElement节点
* 返 回 值: true为展开,false为没有展开
* 作 者: houbin
* 创建日期: 2012年7月2日星期一
*******************************************************************/
bool CTreeLayoutUI::IsExpand(CTreeElementUI * pElement)
{
bool bRet = false;
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElement = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElement) break;
}
if (NULL == pChildElement) break;
bRet = pChildElement->GetVisible();
} while (0);
return bRet;
}
bool CTreeLayoutUI::ItemHasChildren(CTreeElementUI * pElement)
{
bool bRet = false;
if (GetChildItem(pElement))
{
bRet = true;
}
return bRet;
}
void CTreeLayoutUI::SelectItem(CTreeElementUI * pElement, UINT nCode)
{
}
CTreeElementUI * CTreeLayoutUI::GetSelectedItem()
{
return m_pSelectedItem;
}
CTreeElementUI * CTreeLayoutUI::GetParentItem(CTreeElementUI * pElement)
{
CTreeElementUI * pElementRet = NULL;
do
{
if (NULL == pElement) break;
CControlUI * pParent = pElement->GetParent();
if (pParent && (pParent = pParent->GetParent())){
pElementRet = static_cast<CTreeElementUI*>(pParent->GetInterface(kTreeElementInterface));
}
} while (0);
return pElementRet;
}
CTreeElementUI * CTreeLayoutUI::HitTest(POINT pt)
{
CTreeElementUI * pElementRet = NULL;
CControlUI * pControl = GetManager()->FindSubControlByPoint(this, pt);
while(pControl)
{
if (pControl->GetInterface(kTreeLayoutInterface)){
break;
}
else if (pControl->GetInterface(kTreeChildElementInterface)){
break;
}
else if (pControl->GetInterface(kTreeElementInterface)){
pElementRet = static_cast<CTreeElementUI *>(pControl->GetInterface(kTreeElementInterface));
break;
}
else{
pControl = pControl->GetParent();
}
}
return pElementRet;
}
RECT CTreeLayoutUI::GetItemRect(CTreeElementUI * pElement)
{
RECT rcItem = {0};
RECT rc = {0};
do
{
if (NULL == pElement) break;
CTreeDataUI * pDataUI = NULL;
for (int i = 0; i < pElement->GetCount(); i++){
pDataUI = static_cast<CTreeDataUI *>(pElement->GetItemAt(i)->GetInterface(kTreeDataInterface));
if (pDataUI) break;
}
if (NULL == pDataUI) break;
rc = GetPos();
rcItem = pDataUI->GetPos();
rcItem.left = rc.left;
} while (0);
return rcItem;
}
void CTreeLayoutUI::QuickSort(CContainerUI * pElement, TREESORTPROC pSortProc, int nFirst, int nEnd)
{
int i = nFirst;
int j = nEnd;
do
{
CTreeElementUI * pControlFirst = NULL;
CTreeElementUI * pControlEnd = NULL;
CTreeElementUI * pKeyControl = NULL;
if (NULL == pElement) break;
if (NULL == pSortProc) break;
pKeyControl = static_cast<CTreeElementUI *>(pElement->GetItemAt(nFirst));
if (NULL == pKeyControl) break;
if (nEnd >= pElement->GetCount()) break;
while(i < j)
{
//从右往左,把右边最小的数据放在最前面
while( (i < j) && (pSortProc(pKeyControl, static_cast<CTreeElementUI *>(pElement->GetItemAt(j)), this) <= 0) ) j--;
pControlFirst = static_cast<CTreeElementUI *>(pElement->GetItemAt(i));
pControlEnd = static_cast<CTreeElementUI *>(pElement->GetItemAt(j));
if (pControlFirst && pControlEnd){
pElement->Erase(pControlEnd);
pElement->AddAt(pControlEnd, i);
pElement->Erase(pControlFirst);
pElement->AddAt(pControlFirst, j);
}
//从左往右,把左边最大的值放在最右边
while( (i < j) && (pSortProc(static_cast<CTreeElementUI *>(pElement->GetItemAt(i)), pKeyControl, this) <= 0) ) i++;
pControlFirst = static_cast<CTreeElementUI *>(pElement->GetItemAt(i));
pControlEnd = static_cast<CTreeElementUI *>(pElement->GetItemAt(j));
if (pControlFirst && pControlEnd){
pElement->Erase(pControlEnd);
pElement->AddAt(pControlEnd, i);
pElement->Erase(pControlFirst);
pElement->AddAt(pControlFirst, j);
}
}
//把KEY插入到中间
pControlFirst = static_cast<CTreeElementUI *>(pElement->GetItemAt(i));
if (pControlFirst){
int nIndex = pElement->GetItemIndex(pKeyControl);
if (nIndex != i){
pElement->Erase(pKeyControl);
pElement->AddAt(pKeyControl, i);
pElement->Erase(pControlFirst);
pElement->AddAt(pControlFirst, nIndex);
}
}
if (nFirst < i-1) QuickSort(pElement, pSortProc, nFirst, i-1);//对左侧分区域进行快速排序
if (i+1 < nEnd) QuickSort(pElement, pSortProc, i+1, nEnd);//对右侧分区域进行快速排序
} while (0);
}
void CTreeLayoutUI::SortChildren(CContainerUI * pElement, TREESORTPROC pSortProc)
{
if (pElement)
{
CTreeElementUI * pNode = static_cast<CTreeElementUI *>(pElement->GetInterface(kTreeElementInterface));
if (pNode){
CTreeChildElementUI * pChildElement = NULL;
for (int i = 0; i < pElement->GetCount(); i++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(i)->GetInterface(kTreeChildElementInterface));
if (pChildElement) break;
}
if (pChildElement){
QuickSort(pChildElement, pSortProc, 0, pChildElement->GetCount() - 1);
}
}
else{
CTreeLayoutUI * pTreeLayout = static_cast<CTreeLayoutUI *>(pElement->GetInterface(kTreeLayoutInterface));
if (pTreeLayout){
QuickSort(pTreeLayout, pSortProc, 0, pTreeLayout->GetCount() - 1);
}
}
Invalidate();
}
}
void CTreeLayoutUI::SetIndent(int nIndentation)
{
m_nIndentation = nIndentation;
}
int CTreeLayoutUI::GetIndent()
{
return m_nIndentation;
}
}
修改DUILIB的CContainerUI,添加下面两个接口
bool CContainerUI::Erase(CControlUI* pControl)
{
if( pControl == NULL) return false;
for( int it = 0; it < m_items.GetSize(); it++ ) {
if( static_cast<CControlUI*>(m_items[it]) == pControl ) {
NeedUpdate();
return m_items.Remove(it);
}
}
return false;
}
bool CContainerUI::Erase(int iIndex)
{
CControlUI* pControl = GetItemAt(iIndex);
if (pControl != NULL) {
return CContainerUI::Erase(pControl);
}
return false;
}
#ifndef __TREE_LAYOUT_H__
#define __TREE_LAYOUT_H__
namespace DuiLib{
#define kTreeDataInterface _T("TreeData")
#define kTreeLayoutInterface _T("TreeLayout")
#define kTreeChildElementInterface _T("TreeChildElement")
#define kTreeElementInterface _T("TreeElement")
class CTreeLayoutUI;
class CTreeElementUI;
typedef int ( *TREESORTPROC)(CTreeElementUI * pFirst, CTreeElementUI * pSecond, CTreeLayoutUI * pTree);
//数据节点
class UILIB_API CTreeDataUI :public CHorizontalLayoutUI
{
public:
CTreeDataUI();
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
};
//树子节点
class UILIB_API CTreeChildElementUI : public CVerticalLayoutUI
{
public:
CTreeChildElementUI();
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
virtual bool GetVisible();
};
//树节点
class UILIB_API CTreeElementUI : public CVerticalLayoutUI
{
public:
CTreeElementUI();
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
public:
CTreeDataUI * GetDataElement();
};
//树
class UILIB_API CTreeLayoutUI : public CVerticalLayoutUI
{
public:
CTreeLayoutUI(void);
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
UINT GetControlFlags() const;
void DoEvent(TEventUI& event);
void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
public:
LPCTSTR GetItemHotImage();
void SetItemHotImage(LPCTSTR pStrImage);
LPCTSTR GetItemSelectedImage();
void SetItemSelectedImage(LPCTSTR pStrImage);
void SetItemHotColor(DWORD dwColor);
DWORD GetItemHotColor() const;
void SetItemSelectedColor(DWORD dwColor);
DWORD GetItemSelectedColor() const;
void DrawItemBk(HDC hDC);
void DoPaint(HDC hDC, const RECT& rcPaint);
public:
bool Add(CTreeElementUI* pParent, CTreeElementUI * pControl, bool bInsertLast = true);
bool Remove(CTreeElementUI* pControl, bool bDelete);
void RemoveAll();
CTreeElementUI * GetRootItem();
CTreeElementUI * GetNextItem(CTreeElementUI * pElement);
CTreeElementUI * GetChildItem(CTreeElementUI * pElement);
void Expand(CTreeElementUI * pElement, UINT nCode);
bool IsExpand(CTreeElementUI * pElement);
bool ItemHasChildren(CTreeElementUI * pElement);
void SelectItem(CTreeElementUI * pElement, UINT nCode);
CTreeElementUI * GetSelectedItem();
CTreeElementUI * GetParentItem(CTreeElementUI * pElement);
CTreeElementUI * HitTest(POINT pt);
RECT GetItemRect(CTreeElementUI * pElement);
void SortChildren(CContainerUI * pElement, TREESORTPROC pSortProc);
void SetIndent(int nIndentation);
int GetIndent();
protected:
//收缩节点
void CollapseElement(CTreeElementUI * pElement);
//展开节点
void ExpandElement(CTreeElementUI * pElement);
void QuickSort(CContainerUI * pElement, TREESORTPROC pSortProc, int nFirst, int nEnd);
protected:
CTreeElementUI *m_pSelectedItem;
CTreeElementUI *m_pUpHotItem;
DWORD m_dwItemHotColor;
DWORD m_dwItemSelectedColor;
CStdString
m_sItemHotImage;
CStdString
m_sItemSelectedImage;
int m_nIndentation;//缩进值
};
}
#endif
.cpp文件源代码
#include "StdAfx.h"
#include "UITree.h"
namespace DuiLib{
//////////////////////////数据节点//////////////////////////////////////////////////
CTreeDataUI::CTreeDataUI()
{
}
LPCTSTR CTreeDataUI::GetClass() const
{
return _T("TreeDataUI");
}
LPVOID CTreeDataUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, kTreeDataInterface) == 0 ) return static_cast<CTreeDataUI*>(this);
return CContainerUI::GetInterface(pstrName);
}
//////////////////////////树子节点//////////////////////////////////////////////////
CTreeChildElementUI::CTreeChildElementUI()
{
}
LPCTSTR CTreeChildElementUI::GetClass() const
{
return _T("TreeChildElementUI");
}
LPVOID CTreeChildElementUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, kTreeChildElementInterface) == 0 ) return static_cast<CTreeChildElementUI*>(this);
return CContainerUI::GetInterface(pstrName);
}
bool CTreeChildElementUI::GetVisible()
{
return m_bVisible;
}
//////////////////////////树节点////////////////////////////////////////////////////
CTreeElementUI::CTreeElementUI()
{
}
LPCTSTR CTreeElementUI::GetClass() const
{
return _T("TreeElementUI");
}
LPVOID CTreeElementUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, kTreeElementInterface) == 0 ) return static_cast<CTreeElementUI*>(this);
return CContainerUI::GetInterface(pstrName);
}
CTreeDataUI * CTreeElementUI::GetDataElement()
{
CTreeDataUI * pTreeData = NULL;
for (int i = 0; i < GetCount(); i++)
{
pTreeData = static_cast<CTreeDataUI *>(GetItemAt(i)->GetInterface(kTreeDataInterface));
if (pTreeData) break;
}
return pTreeData;
}
////////////////////////////树///////////////////////////////////////////////////////
CTreeLayoutUI::CTreeLayoutUI(void)
{
m_dwItemHotColor = 0xFFE9F5FF;
m_dwItemSelectedColor = 0xFFC1E3FF;
m_pSelectedItem = NULL;
m_pUpHotItem = NULL;
m_nIndentation = 10;
}
LPCTSTR CTreeLayoutUI::GetClass() const
{
return _T("TreeLayoutUI");
}
LPVOID CTreeLayoutUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, kTreeLayoutInterface) == 0 ) return static_cast<CTreeLayoutUI*>(this);
return CContainerUI::GetInterface(pstrName);
}
UINT CTreeLayoutUI::GetControlFlags() const
{
if( IsEnabled() && m_iSepHeight != 0 ) return UIFLAG_SETCURSOR;
else return 0;
}
void CTreeLayoutUI::DoEvent(TEventUI& event)
{
if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
if( m_pParent != NULL ) m_pParent->DoEvent(event);
else CControlUI::DoEvent(event);
return;
}
if( event.Type == UIEVENT_SETFOCUS )
{
m_bFocused = true;
return;
}
if( event.Type == UIEVENT_KILLFOCUS )
{
m_bFocused = false;
return;
}
if( m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsVisible() && m_pVerticalScrollBar->IsEnabled() )
{
if( event.Type == UIEVENT_KEYDOWN )
{
switch( event.chKey ) {
case VK_DOWN:
LineDown();
return;
case VK_UP:
LineUp();
return;
case VK_NEXT:
PageDown();
return;
case VK_PRIOR:
PageUp();
return;
case VK_HOME:
HomeUp();
return;
case VK_END:
EndDown();
return;
}
}
else if( event.Type == UIEVENT_SCROLLWHEEL )
{
switch( LOWORD(event.wParam) ) {
case SB_LINEUP:
LineUp();
return;
case SB_LINEDOWN:
LineDown();
return;
}
}
}
else if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() && m_pHorizontalScrollBar->IsEnabled() ) {
if( event.Type == UIEVENT_KEYDOWN )
{
switch( event.chKey ) {
case VK_DOWN:
LineRight();
return;
case VK_UP:
LineLeft();
return;
case VK_NEXT:
PageRight();
return;
case VK_PRIOR:
PageLeft();
return;
case VK_HOME:
HomeLeft();
return;
case VK_END:
EndRight();
return;
}
}
else if( event.Type == UIEVENT_SCROLLWHEEL )
{
switch( LOWORD(event.wParam) ) {
case SB_LINEUP:
LineLeft();
return;
case SB_LINEDOWN:
LineRight();
return;
}
}
}
//鼠标事件
if( event.Type == UIEVENT_DBLCLICK )
{
if( IsEnabled() ) {
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
m_pSelectedItem = NULL;
if (pElement){
if (NULL == GetChildItem(pElement)){
m_pSelectedItem = pElement;
}
m_pManager->SendNotify(this, _T("treedbclick"), 0, MAKELPARAM(pt.x, pt.y));
}
Invalidate();
}
return;
}
if( event.Type == UIEVENT_KEYDOWN && IsEnabled() )
{
if( event.chKey == VK_RETURN ) {
Activate();
Invalidate();
return;
}
}
if( event.Type == UIEVENT_BUTTONDOWN )
{
if( IsEnabled() ){
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
m_pSelectedItem = NULL;
if (pElement){
if (NULL == GetChildItem(pElement)){
m_pSelectedItem = pElement;
}
m_pManager->SendNotify(this, _T("treeclick"), 0, MAKELPARAM(pt.x, pt.y));
}
Invalidate();
}
return;
}
if( event.Type == UIEVENT_RBUTTONUP )
{
if( IsEnabled() ){
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
m_pSelectedItem = NULL;
if (pElement){
if (NULL == GetChildItem(pElement)){
m_pSelectedItem = pElement;
}
m_pManager->SendNotify(this, _T("treerclick"), 0, MAKELPARAM(pt.x, pt.y));
}
Invalidate();
}
return;
}
if( event.Type == UIEVENT_MOUSEENTER )
{
if( IsEnabled() ) {
m_uButtonState |= UISTATE_HOT;
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
if (m_pUpHotItem != pElement){
if (pElement){
m_pManager->SendNotify(this, _T("treeitemhot"), 0, MAKELPARAM(pt.x, pt.y));
m_pUpHotItem = pElement;
}
}
Invalidate();
}
return;
}
if( event.Type == UIEVENT_MOUSELEAVE )
{
if( (m_uButtonState & UISTATE_HOT) != 0 ) {
m_uButtonState &= ~UISTATE_HOT;
POINT pt = {0};
::GetCursorPos(&pt);
::ScreenToClient(GetManager()->GetPaintWindow(), &pt);
CTreeElementUI * pElement = static_cast<CTreeElementUI *>(HitTest(pt));
if (m_pUpHotItem != pElement){
m_pManager->SendNotify(this, _T("treeitemleave"), 0, MAKELPARAM(pt.x, pt.y));
m_pUpHotItem = NULL;
}
Invalidate();
}
return;
}
CControlUI::DoEvent(event);
}
void CTreeLayoutUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
if( _tcscmp(pstrName, _T("itemhotimage")) == 0 ) SetItemHotImage(pstrValue);
if( _tcscmp(pstrName, _T("itemselectedimage")) == 0 ) SetItemSelectedImage(pstrValue);
else if( _tcscmp(pstrName, _T("itemhotcolor")) == 0 ) {
if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetItemHotColor(clrColor);
}
else if( _tcscmp(pstrName, _T("itemselectedcolor")) == 0 ) {
if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
LPTSTR pstr = NULL;
DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
SetItemSelectedColor(clrColor);
}
else __super::SetAttribute(pstrName, pstrValue);
}
LPCTSTR CTreeLayoutUI::GetItemHotImage()
{
return m_sItemHotImage;
}
void CTreeLayoutUI::SetItemHotImage(LPCTSTR pStrImage)
{
m_sItemHotImage = pStrImage;
Invalidate();
}
LPCTSTR CTreeLayoutUI::GetItemSelectedImage()
{
return m_sItemSelectedImage;
}
void CTreeLayoutUI::SetItemSelectedImage(LPCTSTR pStrImage)
{
m_sItemSelectedImage = pStrImage;
Invalidate();
}
void CTreeLayoutUI::SetItemHotColor(DWORD dwColor)
{
m_dwItemHotColor = dwColor;
}
DWORD CTreeLayoutUI::GetItemHotColor() const
{
return m_dwItemHotColor;
}
void CTreeLayoutUI::SetItemSelectedColor(DWORD dwColor)
{
m_dwItemSelectedColor = dwColor;
}
DWORD CTreeLayoutUI::GetItemSelectedColor() const
{
return m_dwItemSelectedColor;
}
void CTreeLayoutUI::DrawItemBk(HDC hDC)
{
DWORD iBackColor = 0;
RECT rcHotItem = {0};
RECT rcSelectedItem = {0};
if (m_pUpHotItem && (m_pSelectedItem != m_pUpHotItem)){
rcHotItem = GetItemRect(m_pUpHotItem);
iBackColor = GetItemHotColor();
if ( iBackColor != 0 ) {
CRenderEngine::DrawColor(hDC, rcHotItem, GetAdjustColor(iBackColor));
}
if( !m_sItemHotImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sItemHotImage) ) m_sItemHotImage.Empty();
else return;
}
}
if (m_pSelectedItem){
iBackColor = GetItemSelectedColor();
rcSelectedItem = GetItemRect(m_pSelectedItem);
if ( iBackColor != 0 ) {
CRenderEngine::DrawColor(hDC, rcSelectedItem, GetAdjustColor(iBackColor));
}
if( !m_sItemSelectedImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sItemSelectedImage) ) m_sItemSelectedImage.Empty();
else return;
}
}
if( m_sBkImage.IsEmpty() ) {
if( !m_sBkImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sBkImage) ) m_sBkImage.Empty();
else return;
}
}
}
void CTreeLayoutUI::DoPaint(HDC hDC, const RECT& rcPaint)
{
DrawItemBk(hDC);
__super::DoPaint(hDC, rcPaint);
}
/*******************************************************************
* 函数名称: Add
* 功 能: 添加节点
* 参 数: pParent父节点,pControl需要添加的控件,bInsertLast是添加在父节点后还是前
* 返 回 值: 添加成功返回true,否则返回false
* 作 者: houbin
* 创建日期: 2012年6月29日星期五
*******************************************************************/
bool CTreeLayoutUI::Add(CTreeElementUI* pParent, CTreeElementUI * pControl, bool bInsertLast)
{
bool bRet = false;
do
{
if (NULL == pControl) break;
//查询自己节点中是否有子节点
{
CTreeChildElementUI * pChildElementUI = NULL;
for(int n = 0; n < pControl->GetCount(); n++){
pChildElementUI = static_cast<CTreeChildElementUI *>(pControl->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElementUI) break;
}
if (NULL == pChildElementUI){
CTreeChildElementUI * pChild = NULL;
try{
pChildElementUI = new CTreeChildElementUI();
pControl->Add(pChildElementUI);
}
catch (...){
if (pChildElementUI){
delete pChildElementUI;
pChildElementUI = NULL;
break;
}
}
}
}
if (pParent){
//检查父控件是否有子控件对象
CTreeChildElementUI * pChildElementUI = NULL;
for(int n = 0; n < pParent->GetCount(); n++){
pChildElementUI = static_cast<CTreeChildElementUI *>(pParent->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElementUI) break;
}
if (NULL == pChildElementUI){
break;
}
//添加子节点
if (bInsertLast){
bRet = pChildElementUI->Add(pControl);
}
else{
bRet = pChildElementUI->AddAt(pControl, 0);
}
}
else{
if (bInsertLast){
bRet = __super::Add(pControl);
}
else{
bRet = __super::AddAt(pControl, 0);
}
}
} while (0);
if (bRet){
//设置所有相关父节点的高度
if (pParent){
//设置缩进
CTreeChildElementUI * pChildElementUI = NULL;
for(int n = 0; n < pParent->GetCount(); n++){
pChildElementUI = static_cast<CTreeChildElementUI *>(pParent->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElementUI) break;
}
if (pChildElementUI){
pChildElementUI->SetPadding(CRect(GetIndent(), 0, 0, 0));
}
while(pParent){
if (!IsExpand(pParent)) break;
int nHeight = pParent->GetFixedHeight() + pControl->GetFixedHeight();
pParent->SetFixedHeight(nHeight);
pParent = GetParentItem(pParent);
}
}
}
return bRet;
}
/*******************************************************************
* 函数名称: Remove
* 功 能: 删除指定节点
* 参 数: pControl要删除的节点,bDelete删除的时候是否把节点的内存数据也删除
* 返 回 值: 删除成功返回true,否则返回false
* 作 者: houbin
* 创建日期: 2012年6月29日星期五
*******************************************************************/
bool CTreeLayoutUI::Remove(CTreeElementUI* pControl, bool bDelete)
{
bool bRet = false;
do
{
if (pControl == NULL) break;
CControlUI * pParentControl = pControl->GetParent();
if (NULL == pParentControl) break;
if (static_cast<CTreeChildElementUI*>(pParentControl->GetInterface(kTreeChildElementInterface))){
CTreeChildElementUI * pChildElement = static_cast<CTreeChildElementUI*>(pParentControl->GetInterface(kTreeChildElementInterface));
int nDelHeight = pControl->GetFixedHeight();
if (bDelete){
bRet = pChildElement->Remove(pControl);
}
else{
bRet = pChildElement->Erase(pControl);
}
//设置父节点的高度
if (bRet){
CTreeElementUI * pParentElement = static_cast<CTreeElementUI*>(pChildElement->GetParent()->GetInterface(kTreeElementInterface));
while(pParentElement){
if (!IsExpand(pParentElement)) break;
int nHeight = pParentElement->GetFixedHeight() - nDelHeight;
pParentElement->SetFixedHeight(nHeight);
pParentElement = GetParentItem(pParentElement);
}
}
}
else if (static_cast<CTreeLayoutUI*>(pParentControl->GetInterface(kTreeLayoutInterface)) == this){
if (bDelete){
bRet = __super::Remove(pControl);
}
else{
bRet = __super::Erase(pControl);
}
}
m_pSelectedItem = NULL;
m_pUpHotItem = NULL;
} while (0);
return bRet;
}
/*******************************************************************
* 函数名称: RemoveAll
* 功 能: 删除树
* 参 数: 无
* 返 回 值: 无
* 作 者: houbin
* 创建日期: 2012年6月29日星期五
*******************************************************************/
void CTreeLayoutUI::RemoveAll()
{
__super::RemoveAll();
m_pSelectedItem = NULL;
m_pUpHotItem = NULL;
}
/*******************************************************************
* 函数名称: GetRootItem
* 功 能: 获取跟节点
* 参 数: 无
* 返 回 值: 返回根节点指针
* 作 者: houbin
* 创建日期: 2012年7月2日星期一
*******************************************************************/
CTreeElementUI * CTreeLayoutUI::GetRootItem()
{
CTreeElementUI * pElementUI = NULL;
for( int i = 0; i < GetCount(); i++ ) {
if( static_cast<CTreeElementUI*>(GetItemAt(i)->GetInterface(kTreeElementInterface)) != NULL ) {
pElementUI = static_cast<CTreeElementUI*>(GetItemAt(i)->GetInterface(kTreeElementInterface));
break;
}
}
return pElementUI;
}
/*******************************************************************
* 函数名称: GetNextItem
* 功 能: 获取下一个节点
* 参 数: 当前节点指针
* 返 回 值: 下一个节点指针
* 作 者: houbin
* 创建日期: 2012年7月2日星期一
*******************************************************************/
CTreeElementUI * CTreeLayoutUI::GetNextItem(CTreeElementUI * pElement)
{
CTreeElementUI * pElementRet = NULL;
do
{
if (NULL == pElement) break;
CContainerUI * pParentElement = static_cast<CContainerUI *>(pElement->GetParent());
if (NULL == pParentElement) break;
int nIndex = pParentElement->GetItemIndex(pElement);
for(int i = nIndex + 1; i < pParentElement->GetCount(); i++)
{
pElementRet = static_cast<CTreeElementUI *>(pParentElement->GetItemAt(i)->GetInterface(kTreeElementInterface));
if (pElementRet) break;
}
} while (0);
return pElementRet;
}
/*******************************************************************
* 函数名称: GetChildItem
* 功 能: 获取节点的子节点
* 参 数: pElement需要获取的子节点控件
* 返 回 值: 成功返回直接点指针,否则返回NULL
* 作 者: houbin
* 创建日期: 2012年6月29日星期五
*******************************************************************/
CTreeElementUI * CTreeLayoutUI::GetChildItem(CTreeElementUI * pElement)
{
CTreeElementUI * pElementRet = NULL;
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElementUI = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElementUI = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElementUI) break;
}
if (NULL == pChildElementUI) break;
if (pChildElementUI->GetCount() <= 0) break;
pElementRet = static_cast<CTreeElementUI*>(pChildElementUI->GetItemAt(0)->GetInterface(kTreeElementInterface));
} while (0);
return pElementRet;
}
//收缩节点
void CTreeLayoutUI::CollapseElement(CTreeElementUI * pElement)
{
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElement = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElement) break;
}
if (NULL == pChildElement) break;
if (!IsExpand(pElement)) break;
pChildElement->SetVisible(false);
CTreeDataUI * pDataUI = pElement->GetDataElement();
if (pDataUI){
int nOldHeight = pElement->GetFixedHeight();
int nHeight = pDataUI->GetFixedHeight();
pElement->SetFixedHeight(nHeight);
//设置父节点的高度
CTreeElementUI * pParentElement = GetParentItem(pElement);
while(pParentElement)
{
//父节点展开,则设置展开的高度
if (IsExpand(pParentElement)){
int nParentHeight = pParentElement->GetFixedHeight() + nHeight - nOldHeight;
pParentElement->SetFixedHeight(nParentHeight);
}
pParentElement = GetParentItem(pParentElement);
}
//设置父节点高度完毕////////////
}
} while (0);
}
//展开节点
void CTreeLayoutUI::ExpandElement(CTreeElementUI * pElement)
{
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElement = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElement) break;
}
if (NULL == pChildElement) break;
if (IsExpand(pElement)) break;
pChildElement->SetVisible(true);
CTreeDataUI * pDataUI = pElement->GetDataElement();
if (pDataUI){
int nOldHeight = pElement->GetFixedHeight();
int nHeight = pDataUI->GetFixedHeight();
CTreeElementUI * pChildNode = GetChildItem(pElement);
while(pChildNode)
{
nHeight += pChildNode->GetFixedHeight();
pChildNode = GetNextItem(pChildNode);
}
pElement->SetFixedHeight(nHeight);
//设置父节点的高度
CTreeElementUI * pParentElement = GetParentItem(pElement);
while(pParentElement)
{
//父节点展开,则设置展开的高度
if (IsExpand(pParentElement)){
int nParentHeight = pParentElement->GetFixedHeight() + nHeight - nOldHeight;
pParentElement->SetFixedHeight(nParentHeight);
}
pParentElement = GetParentItem(pParentElement);
}
//设置父节点高度完毕////////////
}
} while (0);
}
void CTreeLayoutUI::Expand(CTreeElementUI * pElement, UINT nCode)
{
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElement = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElement) break;
}
if (NULL == pChildElement) break;
if (TVE_COLLAPSE == nCode){
CollapseElement(pElement);
}
if(TVE_EXPAND == nCode){
ExpandElement(pElement);
}
if(TVE_TOGGLE == nCode){
//如果是收缩则展开,如果展开则收缩
if (IsExpand(pElement)){
CollapseElement(pElement);
}
else{
ExpandElement(pElement);
}
}
} while (0);
}
/*******************************************************************
* 函数名称: IsExpand
* 功 能: 检测指定节点是否展开
* 参 数: pElement节点
* 返 回 值: true为展开,false为没有展开
* 作 者: houbin
* 创建日期: 2012年7月2日星期一
*******************************************************************/
bool CTreeLayoutUI::IsExpand(CTreeElementUI * pElement)
{
bool bRet = false;
do
{
if (NULL == pElement) break;
CTreeChildElementUI * pChildElement = NULL;
for(int n = 0; n < pElement->GetCount(); n++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(n)->GetInterface(kTreeChildElementInterface));
if(NULL != pChildElement) break;
}
if (NULL == pChildElement) break;
bRet = pChildElement->GetVisible();
} while (0);
return bRet;
}
bool CTreeLayoutUI::ItemHasChildren(CTreeElementUI * pElement)
{
bool bRet = false;
if (GetChildItem(pElement))
{
bRet = true;
}
return bRet;
}
void CTreeLayoutUI::SelectItem(CTreeElementUI * pElement, UINT nCode)
{
}
CTreeElementUI * CTreeLayoutUI::GetSelectedItem()
{
return m_pSelectedItem;
}
CTreeElementUI * CTreeLayoutUI::GetParentItem(CTreeElementUI * pElement)
{
CTreeElementUI * pElementRet = NULL;
do
{
if (NULL == pElement) break;
CControlUI * pParent = pElement->GetParent();
if (pParent && (pParent = pParent->GetParent())){
pElementRet = static_cast<CTreeElementUI*>(pParent->GetInterface(kTreeElementInterface));
}
} while (0);
return pElementRet;
}
CTreeElementUI * CTreeLayoutUI::HitTest(POINT pt)
{
CTreeElementUI * pElementRet = NULL;
CControlUI * pControl = GetManager()->FindSubControlByPoint(this, pt);
while(pControl)
{
if (pControl->GetInterface(kTreeLayoutInterface)){
break;
}
else if (pControl->GetInterface(kTreeChildElementInterface)){
break;
}
else if (pControl->GetInterface(kTreeElementInterface)){
pElementRet = static_cast<CTreeElementUI *>(pControl->GetInterface(kTreeElementInterface));
break;
}
else{
pControl = pControl->GetParent();
}
}
return pElementRet;
}
RECT CTreeLayoutUI::GetItemRect(CTreeElementUI * pElement)
{
RECT rcItem = {0};
RECT rc = {0};
do
{
if (NULL == pElement) break;
CTreeDataUI * pDataUI = NULL;
for (int i = 0; i < pElement->GetCount(); i++){
pDataUI = static_cast<CTreeDataUI *>(pElement->GetItemAt(i)->GetInterface(kTreeDataInterface));
if (pDataUI) break;
}
if (NULL == pDataUI) break;
rc = GetPos();
rcItem = pDataUI->GetPos();
rcItem.left = rc.left;
} while (0);
return rcItem;
}
void CTreeLayoutUI::QuickSort(CContainerUI * pElement, TREESORTPROC pSortProc, int nFirst, int nEnd)
{
int i = nFirst;
int j = nEnd;
do
{
CTreeElementUI * pControlFirst = NULL;
CTreeElementUI * pControlEnd = NULL;
CTreeElementUI * pKeyControl = NULL;
if (NULL == pElement) break;
if (NULL == pSortProc) break;
pKeyControl = static_cast<CTreeElementUI *>(pElement->GetItemAt(nFirst));
if (NULL == pKeyControl) break;
if (nEnd >= pElement->GetCount()) break;
while(i < j)
{
//从右往左,把右边最小的数据放在最前面
while( (i < j) && (pSortProc(pKeyControl, static_cast<CTreeElementUI *>(pElement->GetItemAt(j)), this) <= 0) ) j--;
pControlFirst = static_cast<CTreeElementUI *>(pElement->GetItemAt(i));
pControlEnd = static_cast<CTreeElementUI *>(pElement->GetItemAt(j));
if (pControlFirst && pControlEnd){
pElement->Erase(pControlEnd);
pElement->AddAt(pControlEnd, i);
pElement->Erase(pControlFirst);
pElement->AddAt(pControlFirst, j);
}
//从左往右,把左边最大的值放在最右边
while( (i < j) && (pSortProc(static_cast<CTreeElementUI *>(pElement->GetItemAt(i)), pKeyControl, this) <= 0) ) i++;
pControlFirst = static_cast<CTreeElementUI *>(pElement->GetItemAt(i));
pControlEnd = static_cast<CTreeElementUI *>(pElement->GetItemAt(j));
if (pControlFirst && pControlEnd){
pElement->Erase(pControlEnd);
pElement->AddAt(pControlEnd, i);
pElement->Erase(pControlFirst);
pElement->AddAt(pControlFirst, j);
}
}
//把KEY插入到中间
pControlFirst = static_cast<CTreeElementUI *>(pElement->GetItemAt(i));
if (pControlFirst){
int nIndex = pElement->GetItemIndex(pKeyControl);
if (nIndex != i){
pElement->Erase(pKeyControl);
pElement->AddAt(pKeyControl, i);
pElement->Erase(pControlFirst);
pElement->AddAt(pControlFirst, nIndex);
}
}
if (nFirst < i-1) QuickSort(pElement, pSortProc, nFirst, i-1);//对左侧分区域进行快速排序
if (i+1 < nEnd) QuickSort(pElement, pSortProc, i+1, nEnd);//对右侧分区域进行快速排序
} while (0);
}
void CTreeLayoutUI::SortChildren(CContainerUI * pElement, TREESORTPROC pSortProc)
{
if (pElement)
{
CTreeElementUI * pNode = static_cast<CTreeElementUI *>(pElement->GetInterface(kTreeElementInterface));
if (pNode){
CTreeChildElementUI * pChildElement = NULL;
for (int i = 0; i < pElement->GetCount(); i++){
pChildElement = static_cast<CTreeChildElementUI *>(pElement->GetItemAt(i)->GetInterface(kTreeChildElementInterface));
if (pChildElement) break;
}
if (pChildElement){
QuickSort(pChildElement, pSortProc, 0, pChildElement->GetCount() - 1);
}
}
else{
CTreeLayoutUI * pTreeLayout = static_cast<CTreeLayoutUI *>(pElement->GetInterface(kTreeLayoutInterface));
if (pTreeLayout){
QuickSort(pTreeLayout, pSortProc, 0, pTreeLayout->GetCount() - 1);
}
}
Invalidate();
}
}
void CTreeLayoutUI::SetIndent(int nIndentation)
{
m_nIndentation = nIndentation;
}
int CTreeLayoutUI::GetIndent()
{
return m_nIndentation;
}
}
修改DUILIB的CContainerUI,添加下面两个接口
bool CContainerUI::Erase(CControlUI* pControl)
{
if( pControl == NULL) return false;
for( int it = 0; it < m_items.GetSize(); it++ ) {
if( static_cast<CControlUI*>(m_items[it]) == pControl ) {
NeedUpdate();
return m_items.Remove(it);
}
}
return false;
}
bool CContainerUI::Erase(int iIndex)
{
CControlUI* pControl = GetItemAt(iIndex);
if (pControl != NULL) {
return CContainerUI::Erase(pControl);
}
return false;
}
相关文章推荐
- 错误:在使用自己绘制控件时,发现有些地方鼠标点击时没有效果
- duilib 修复padding属性导致其他控件自动计算宽高度错误的bug和导致自己宽高度错误的bug
- duilib 修复padding属性导致其他控件自动计算宽高度错误的bug和导致自己宽高度错误的bug
- 编程中发现的小bug记录下来,提醒自己,也帮助大家
- 为什么程序员发现不了自己的BUG?
- 为什么程序员老是发现不了自己写的bug??
- duilib 修复combo控件打开下拉菜单后不会自动定位到上次选择的位置上的bug
- 自己考虑招人的事情,才发现自己简历问题出在什么地方
- duilib修复ActiveXUI控件bug,以支持flash透明动态背景
- 今天发现自己的程序有个小bug,细节不可小觑呀
- Android下拉刷新上拉加载控件,对所有View通用! 非常好用,暂未发现bug
- duilib修复ActiveXUI控件bug,以支持flash透明动态背景
- 为什么程序员发现不了自己的BUG?
- duilib中加入自己定义控件之后怎么可以在xml文件里配置使用
- 扩展duilib edit控件的提示功能和多种文字颜色(解决edit为password显示不正常的bug)
- linuxC第六章实现自己ls上的某些可以优化的地方
- 为什么程序员发现不了自己的BUG
- duilib 修复Text控件无法设置宽度的bug,增加自动加算宽度的属性
- duilib中CTextUI控件设置文字时不刷新显示的bug
- 知识地图项目中当前暂时搁置,后期需要优化的地方--给自己记录一下