一、为什么需要动态添加?
由于我不知道我的List头的项目到底是哪些,我的List中有多少行数据需要添加,动态添加就比较合适,方便。
二、实现
1、Xml配置
2、C++代码
CHorizontalLayoutUI * pHor = static_cast(m_PaintManager.FindControl(_T("ListContainer")));
CListUI * pList = new CListUI;
pList->ApplyAttributeList(_T("name=\"ShowList\" float=\"true\" pos=\"30,0,0,0\" width=\"740\" height=\"450\" sepheight=\"1\" itemalign=\"center\" itembkcolor=\"#FFE2DDDF\" itemaltbk=\"true\""));
pHor->Add(pList);
//CListUI * pList = static_cast(m_PaintManager.FindControl(_T("ShowList")));
pList->RemoveAll();
CListHeaderUI * pHeader = new CListHeaderUI;
pList->Add(pHeader);
//CListHeaderUI *pHeader = static_cast(m_PaintManager.FindControl(_T("Listheader")));
CListHeaderItemUI *pListHeaderItemIP = new CListHeaderItemUI;
pListHeaderItemIP->ApplyAttributeList(_T("text=\"IP\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemCmd = new CListHeaderItemUI;
pListHeaderItemCmd->ApplyAttributeList(_T("text=\"Command\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemDb = new CListHeaderItemUI;
pListHeaderItemDb->ApplyAttributeList(_T("text=\"DbName\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemUser = new CListHeaderItemUI;
pListHeaderItemUser->ApplyAttributeList(_T("text=\"User\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemInfo = new CListHeaderItemUI;
pListHeaderItemInfo->ApplyAttributeList(_T("text=\"Info\" itemendellipsis=\"true\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemTime = new CListHeaderItemUI;
pListHeaderItemTime->ApplyAttributeList(_T("text=\"Time\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
pList->Add(pListHeaderItemIP);
pList->Add(pListHeaderItemCmd);
pList->Add(pListHeaderItemDb);
pList->Add(pListHeaderItemUser);
pList->Add(pListHeaderItemInfo);
pList->Add(pListHeaderItemTime);
//pList->Add(pHeader);
for(VEC_MYSQLSYSINFO_ITOR it = vecsysinfo.begin(); it != vecsysinfo.end(); it++ )
{
CListTextElementUI *pListElement = new CListTextElementUI;
//pListElement->ApplyAttributeList(_T("textcolor=\"#FF000000\""));
pList->Add(pListElement);
pListElement->SetText(0,Utf82T(it->strHost.c_str()).c_str());
pListElement->SetText(1, Utf82T(it->strCmd.c_str()).c_str());
pListElement->SetText(2, Utf82T(it->strDb.c_str()).c_str());
pListElement->SetText(3, Utf82T(it->strUser.c_str()).c_str());
pListElement->SetText(4, Utf82T(it->strInfo.c_str()).c_str());;
TString strPort;
TCHAR tcPort[10];
_itow(it->nTime, tcPort, 10);
pListElement->SetText(5, tcPort);
}
3、运行效果图
所有的都动态添加
xml配置
C++代码
VEC_MYSQLSYSINFO vecsysinfo;
int nNums = m_MySqlOper->ShowConnectNum(vecsysinfo);//从数据库查询数据
CHorizontalLayoutUI * pHorExtra = static_cast(m_PaintManager.FindControl(_T("ShowExtra")));
CLabelUI * pConNum = new CLabelUI;
pConNum->ApplyAttributeList(_T("text=\"连接数量:\" float=\"true\" pos=\"300,0,0,0\" width=\"100\" height=\"30\" align=\"right\""));
TString strText = Format(_T("连接数量:%d"), nNums);
pConNum->SetText(strText.c_str());
pHorExtra->Add(pConNum);
CHorizontalLayoutUI * pHor = static_cast(m_PaintManager.FindControl(_T("ListContainer")));
CListUI * pList = new CListUI;
pList->ApplyAttributeList(_T("name=\"ShowList\" childpadding=\"1\" itemlinecolor=\"#FFF4F4F4\" bkcolor=\"#FFC0C0C0\" float=\"true\" pos=\"30,0,0,0\" width=\"740\" height=\"450\" sepheight=\"1\" itemalign=\"center\" itembkcolor=\"#FFE2DDDF\" itemaltbk=\"true\""));
//CListUI * pList = static_cast(m_PaintManager.FindControl(_T("ShowList")));
//pList->RemoveAll();
CListHeaderUI * pHeader = new CListHeaderUI;
pHeader->ApplyAttributeList(_T("bkcolor=\"#FF36CA61\""));
//CListHeaderUI *pHeader = static_cast(m_PaintManager.FindControl(_T("Listheader")));
CListHeaderItemUI *pListHeaderItemIP = new CListHeaderItemUI;
pListHeaderItemIP->ApplyAttributeList(_T("text=\"IP\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemCmd = new CListHeaderItemUI;
pListHeaderItemCmd->ApplyAttributeList(_T("text=\"Command\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemDb = new CListHeaderItemUI;
pListHeaderItemDb->ApplyAttributeList(_T("text=\"DbName\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemUser = new CListHeaderItemUI;
pListHeaderItemUser->ApplyAttributeList(_T("text=\"User\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemInfo = new CListHeaderItemUI;
pListHeaderItemInfo->ApplyAttributeList(_T("text=\"Info\" itemendellipsis=\"true\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemTime = new CListHeaderItemUI;
pListHeaderItemTime->ApplyAttributeList(_T("text=\"Time\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
// pList->Add(pListHeaderItemIP);
// pList->Add(pListHeaderItemCmd);
// pList->Add(pListHeaderItemDb);
// pList->Add(pListHeaderItemUser);
// pList->Add(pListHeaderItemInfo);
// pList->Add(pListHeaderItemTime);
//两种方式,上面直接添加到List上面比较稳妥,但是结构没有添加到ListHeader清晰
pHeader->Add(pListHeaderItemIP);
pHeader->Add(pListHeaderItemCmd);
pHeader->Add(pListHeaderItemDb);
pHeader->Add(pListHeaderItemUser);
pHeader->Add(pListHeaderItemInfo);
pHeader->Add(pListHeaderItemTime);
pList->Add(pHeader);
//pHeader->Add(pListHeaderItemTime);
for(VEC_MYSQLSYSINFO_ITOR it = vecsysinfo.begin(); it != vecsysinfo.end(); it++ )
{
CListTextElementUI *pListElement = new CListTextElementUI;
//pListElement->ApplyAttributeList(_T("textcolor=\"#FF000000\""));
pList->Add(pListElement);
pListElement->SetText(0,Utf82T(it->strHost.c_str()).c_str());
pListElement->SetText(1, Utf82T(it->strCmd.c_str()).c_str());
pListElement->SetText(2, Utf82T(it->strDb.c_str()).c_str());
pListElement->SetText(3, Utf82T(it->strUser.c_str()).c_str());
pListElement->SetText(4, Utf82T(it->strInfo.c_str()).c_str());;
TString strPort;
TCHAR tcPort[10];
_itow(it->nTime, tcPort, 10);
pListElement->SetText(5, tcPort);
}
pHor->Add(pList);
三、有趣的东西(xml配置了代码不识别)
xml配置
C++代码
CListUI * pList = static_cast(m_PaintManager.FindControl(_T("ShowList")));
//pList->RemoveAll();
//CListHeaderUI * pHeader = new CListHeaderUI;
//pList->Add(pHeader);
//CListHeaderUI *pHeader = static_cast(m_PaintManager.FindControl(_T("Listheader")));
CListHeaderItemUI *pListHeaderItemIP = new CListHeaderItemUI;
pListHeaderItemIP->ApplyAttributeList(_T("text=\"IP\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemCmd = new CListHeaderItemUI;
pListHeaderItemCmd->ApplyAttributeList(_T("text=\"Command\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemDb = new CListHeaderItemUI;
pListHeaderItemDb->ApplyAttributeList(_T("text=\"DbName\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemUser = new CListHeaderItemUI;
pListHeaderItemUser->ApplyAttributeList(_T("text=\"User\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemInfo = new CListHeaderItemUI;
pListHeaderItemInfo->ApplyAttributeList(_T("text=\"Info\" itemendellipsis=\"true\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemTime = new CListHeaderItemUI;
pListHeaderItemTime->ApplyAttributeList(_T("text=\"Time\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
pList->Add(pListHeaderItemIP);
pList->Add(pListHeaderItemCmd);
pList->Add(pListHeaderItemDb);
pList->Add(pListHeaderItemUser);
pList->Add(pListHeaderItemInfo);
pList->Add(pListHeaderItemTime);
//pList->Add(pHeader);
for(VEC_MYSQLSYSINFO_ITOR it = vecsysinfo.begin(); it != vecsysinfo.end(); it++ )
{
CListTextElementUI *pListElement = new CListTextElementUI;
//pListElement->ApplyAttributeList(_T("textcolor=\"#FF000000\""));
pList->Add(pListElement);
pListElement->SetText(0,Utf82T(it->strHost.c_str()).c_str());
pListElement->SetText(1, Utf82T(it->strCmd.c_str()).c_str());
pListElement->SetText(2, Utf82T(it->strDb.c_str()).c_str());
pListElement->SetText(3, Utf82T(it->strUser.c_str()).c_str());
pListElement->SetText(4, Utf82T(it->strInfo.c_str()).c_str());;
TString strPort;
TCHAR tcPort[10];
_itow(it->nTime, tcPort, 10);
pListElement->SetText(5, tcPort);
}
效果图
解决方案
在找到List之后也动态添加一个ListHeader;xml中可以将ListHeader删除,或者不删除都是可以的;如果是CListTextElementUI
,CListTextElementUI的添加需要在SetText调用之前
CListUI * pList = static_cast(m_PaintManager.FindControl(_T("ShowList")));
//pList->RemoveAll();
CListHeaderUI * pHeader = new CListHeaderUI; //此处添加新的CListHeaderUI
pList->Add(pHeader);
//CListHeaderUI *pHeader = static_cast(m_PaintManager.FindControl(_T("Listheader")));
CListHeaderItemUI *pListHeaderItemIP = new CListHeaderItemUI;
pListHeaderItemIP->ApplyAttributeList(_T("text=\"IP\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemCmd = new CListHeaderItemUI;
pListHeaderItemCmd->ApplyAttributeList(_T("text=\"Command\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemDb = new CListHeaderItemUI;
pListHeaderItemDb->ApplyAttributeList(_T("text=\"DbName\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemUser = new CListHeaderItemUI;
pListHeaderItemUser->ApplyAttributeList(_T("text=\"User\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemInfo = new CListHeaderItemUI;
pListHeaderItemInfo->ApplyAttributeList(_T("text=\"Info\" itemendellipsis=\"true\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
CListHeaderItemUI *pListHeaderItemTime = new CListHeaderItemUI;
pListHeaderItemTime->ApplyAttributeList(_T("text=\"Time\" width=\"100\" height=\"30\" sepwidth=\"1\"" ));
pList->Add(pListHeaderItemIP);
pList->Add(pListHeaderItemCmd);
pList->Add(pListHeaderItemDb);
pList->Add(pListHeaderItemUser);
pList->Add(pListHeaderItemInfo);
pList->Add(pListHeaderItemTime);
//pList->Add(pHeader);
for(VEC_MYSQLSYSINFO_ITOR it = vecsysinfo.begin(); it != vecsysinfo.end(); it++ )
{
CListTextElementUI *pListElement = new CListTextElementUI;
//pListElement->ApplyAttributeList(_T("textcolor=\"#FF000000\""));
pList->Add(pListElement);
pListElement->SetText(0,Utf82T(it->strHost.c_str()).c_str());
pListElement->SetText(1, Utf82T(it->strCmd.c_str()).c_str());
pListElement->SetText(2, Utf82T(it->strDb.c_str()).c_str());
pListElement->SetText(3, Utf82T(it->strUser.c_str()).c_str());
pListElement->SetText(4, Utf82T(it->strInfo.c_str()).c_str());;
TString strPort;
TCHAR tcPort[10];
_itow(it->nTime, tcPort, 10);
pListElement->SetText(5, tcPort);
}
修复效果图
关于CListTextElementUI 如果是没有 添加CListHeaderUI 是无法显示的, 而且在使用的时候一定需要先添加到CListUI中, 否则无法显示;
1、
void CListTextElementUI::SetText(int iIndex, LPCTSTR pstrText)
{
if( m_pOwner == NULL ) return;//如果没有父类直接返回, 无法设置值
TListInfoUI* pInfo = m_pOwner->GetListInfo();
if( iIndex < 0 || iIndex >= pInfo->nColumns ) return;//如果iIndex小于0或者如果nColumns==0 (也就是没有任何Header), 超过Header 的索引部分无法设置
while( m_aTexts.GetSize() < pInfo->nColumns ) { m_aTexts.Add(NULL); }
CDuiString* pText = static_cast(m_aTexts[iIndex]);
if( (pText == NULL && pstrText == NULL) || (pText && *pText == pstrText) ) return;
if ( pText ) {delete pText; pText = NULL;}
m_aTexts.SetAt(iIndex, new CDuiString(pstrText));
Invalidate();
}
bool CListUI::Add(CControlUI* pControl)
{
// Override the Add() method so we can add items specifically to
// the intended widgets. Headers are assumed to be
// answer the correct interface so we can add multiple list headers.
if( pControl->GetInterface(_T("ListHeader")) != NULL ) {
if( m_pHeader != pControl && m_pHeader->GetCount() == 0 ) {
CVerticalLayoutUI::Remove(m_pHeader);
m_pHeader = static_cast(pControl);
}
m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
return CVerticalLayoutUI::AddAt(pControl, 0);
}
// We also need to recognize header sub-items
if( _tcsstr(pControl->GetClass(), _T("ListHeaderItemUI")) != NULL ) {
bool ret = m_pHeader->Add(pControl);
m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
return ret;
}
// The list items should know about us
IListItemUI* pListItem = static_cast(pControl->GetInterface(_T("ListItem")));
if( pListItem != NULL ) {
pListItem->SetOwner(this);
pListItem->SetIndex(GetCount());
}
return m_pList->Add(pControl);
}
2、
void CListContainerElementUI::SetPos(RECT rc, bool bNeedInvalidate)
{
CHorizontalLayoutUI::SetPos(rc, bNeedInvalidate);
if( m_pOwner == NULL ) return;
UINT uListType = m_pOwner->GetListType();
if(uListType != LT_LIST && uListType != LT_TREE) return;
CListUI* pList = static_cast(m_pOwner);
if (uListType == LT_TREE)
{
pList = (CListUI*)pList->CControlUI::GetInterface(_T("List"));
if (pList == NULL) return;
}
CListHeaderUI *pHeader = pList->GetHeader();
if (pHeader == NULL || !pHeader->IsVisible()) return;
int nCount = m_items.GetSize();
for (int i = 0; i < nCount; i++)
{
CControlUI *pListItem = static_cast(m_items[i]);
CControlUI *pHeaderItem = pHeader->GetItemAt(i);
if (pHeaderItem == NULL) return;
RECT rcHeaderItem = pHeaderItem->GetPos();
if (pListItem != NULL && !(rcHeaderItem.left ==0 && rcHeaderItem.right ==0) )
{
RECT rt = pListItem->GetPos();
rt.left = rcHeaderItem.left;
rt.right = rcHeaderItem.right;
pListItem->SetPos(rt);
}
}
}
3、
class UILIB_API CListElementUI : public CControlUI, public IListItemUI
{
public:
CListElementUI();
LPCTSTR GetClass() const;
UINT GetControlFlags() const;
LPVOID GetInterface(LPCTSTR pstrName);
void SetEnabled(bool bEnable = true);
int GetIndex() const;
void SetIndex(int iIndex);
IListOwnerUI* GetOwner();
void SetOwner(CControlUI* pOwner);
void SetVisible(bool bVisible = true);
bool IsSelected() const;
bool Select(bool bSelect = true);
bool SelectMulti(bool bSelect = true);
bool IsExpanded() const;
bool Expand(bool bExpand = true);
void Invalidate(); // 直接CControl::Invalidate会导致滚动条刷新,重写减少刷新区域
bool Activate();
void DoEvent(TEventUI& event);
void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
void DrawItemBk(HDC hDC, const RECT& rcItem);
protected:
int m_iIndex;
bool m_bSelected;
UINT m_uButtonState;
IListOwnerUI* m_pOwner;
};
/////////////////////////////////////////////////////////////////////////////////////
//
class UILIB_API CListLabelElementUI : public CListElementUI
{
DECLARE_DUICONTROL(CListLabelElementUI)
public:
CListLabelElementUI();
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
void DoEvent(TEventUI& event);
SIZE EstimateSize(SIZE szAvailable);
void DoPaint(HDC hDC, const RECT& rcPaint);
void DrawItemText(HDC hDC, const RECT& rcItem);
};
从1处源码分析 TListInfoUI* pInfo = m_pOwner->GetListInfo(); 通过IListOwnerUI* m_pOwner 获取是否添加了Header, 添加了Header, 但是ListHeader 中没有添加任何一个 ListHeaderItemUI , 因此在1,2处代码中, 都有用到的m_ListInfo.nColumns 就为0, 因此在CListTextElementUI 类中的SetText 直接返回,所以表现没有结果显示, CListContainerElementUI 在SetPos中也是如此。
从CListContainerElementUI 的SetPos中也可以看出, 其和CListTextElementUI 是一样的;但是从源码中看CListLabelElementUI, 由于继承自CListElementUI 这两个类中都没有接口中指定一定需要Header,其实只是一个简单控件,所以不需要头,Add到List都是可以正常显示的。
总结
CListHeaderUI * pHeader = new CListHeaderUI;添加列表头
CListHeaderItemUI *pListHeaderItemUser = new CListHeaderItemUI; 添加列表头项目
CListTextElementUI *pListElement = new CListTextElementUI;添加列表行
pList->Add(pListHeaderItemIP);将这些元素添加到列表;所有的都是添加到List;虽然列表头项目感觉应该添加到CListHeaderUI,实际上不是,添加进去之后,如果是先将CListHeaderUI添加到CListUI(这样后面添加的行元素就没有添加到CListUI中,显示是显示的CListUI,所以结果是显示了空白,可以看到行,但是看不到值),得到的结果也是CListTextElementUI元素显示是空的;所以动态添加元素的顺序相对重要(其实也就是结构,必须将结构弄清楚)。