duilib进阶教程 -- 改进List控件(3)_支持多选+右键菜单(ctrl,shift, 鼠标滑动框选)(一)

2014-11-24 10:10:34 · 作者: · 浏览: 4

看到很多PC客户端的列表都支持多选,比如PP助手,华为网盘,duilib本身UIList却没有此功能的支持,于是想修改一把,完善这方面的劣势,而且相信用到的这个功能的也不少,尤其在开发文件管理相关的功能模块,多选的支持应该是必须的。

先上图

\

设计思路:

开始的时候,不知道从哪下手,通过度娘一番,渐渐思路清晰来,现在总结一下

1 Ctrl+左键,shift+左键多选列表项

分析这两个功能的业务逻辑。

Ctrl+左键多选,按下Ctrl键点击,主要有三种情况:

1 选中一个

2 再点击,又选中一个

3 再点击前一个,前一个选中状态消失

总结分析:ctrl按下的情况,点击,不会使前一个(一部分)选中项失去选中状态,而只是让当前点击的项改变选中状态,并将焦点移到当前项。

shift+左键,主要有4中情况:

1 点击选中一个(ID为2),向下选中一个(ID为5),则2-5被选中

2 再向下选中一个(ID为10),则2-10被选中

3 向上选中一个(ID为8),则2-8被选中

4 向上选中一个(ID为1),则1-2被选中。

总结分析:shift按下的情况,点击,是选中一个范围,起始项为焦点所在的项,shift点击的项为结束项。

ctrl和shift多选殊途同归,主要是在CListContainerElementUI的点击事件中做些改动,具体的就是UIEvent_BUTTONDOWN.

select() 控制是否选中

click() 控制其他控件的效果

在这两个函数中需检测是否按下了ctrl或shift键。

BOOL bCtrl = (GetKeyState(VK_CONTROL) & 0x8000);
BOOL bShift = (GetKeyState(VK_SHIFT) & 0x8000);

主要代码片段

UIList.cpp

void CListContainerElementUI::DoEvent(TEventUI& event)
{...

if( event.Type == UIEVENT_BUTTONDOWN )
{
if( IsEnabled() ){;
m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMCLICK);
Select(!m_bSelected);
Click();
if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
Invalidate();

}
return;
}
if( event.Type == UIEVENT_RBUTTONDOWN )
{
if( IsEnabled() ){
m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMCLICK);
if(m_bSelected){
//printf("右键菜单");
}else{
Select();
Click();
}
if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
Invalidate();
}
return;
}
if( event.Type == UIEVENT_BUTTONUP )
{
if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
return;
}
if( event.Type == UIEVENT_RBUTTONUP )
{
if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
return;
}
if( event.Type == UIEVENT_CONTEXTMENU )
{
if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
return;
}
if( event.Type == UIEVENT_MOUSEMOVE )
{
if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
return;
}
if( event.Type == UIEVENT_MOUSEENTER )
{
if( IsEnabled() ){
m_pManager->SendNotify(this, DUI_MSGTYPE_MOUSEENTER);
}
Hot();
Invalidate();
return;
}

...

}


bool CListContainerElementUI::Select(bool bSelect,bool bCallback)
{
BOOL bShift = (GetKeyState(VK_SHIFT) & 0x8000);
if( !IsEnabled() ) return false;
//if( bSelect == m_bSelected ) return true;
m_bSelected = bSelect;
if(bCallback && m_pOwner != NULL ) {
if(bShift){
m_pOwner->SelectRange(m_iIndex);
}else{
m_pOwner->SelectItem(m_iIndex);
}
}
Invalidate();


return true;
}


bool CListUI::SelectItem(int iIndex, bool bTakeFocus)
{
BOOL bCtrl = (GetKeyState(VK_CONTROL) & 0x8000);


//if( iIndex == m_iCurSel ) return true;


int iOldSel = m_iCurSel;
// We should first unselect the currently selected item
if(!bCtrl){
//if( m_iCurSel >= 0 ) {
for(int i=0;i if(i!=iIndex){
CControlUI* pControl = GetItemAt(i);
if( pControl != NULL) {
IListItemUI* pListItem = static_cast (pControl->GetInterface(_T("ListItem")));
if( pListItem != NULL ) pListItem->Select(false,false);
}
}
}


m_iCurSel = -1;
//}
}
if( iIndex < 0 ) return false;


CControlUI* pControl = GetItemAt(iIndex);
if( pControl == NULL ) return false;
if( !pControl->IsVisible() ) return false;
if( !pControl->IsEnabled() ) return false;


IListItemUI* pListItem = static_cast (pControl->GetInterface(_T("ListItem")));
if( pListItem == NULL ) return false;
m_iCurSel = iIndex;
if(!bCtrl){
if( !pListItem->Select(true,false) ) {
m_iCurSel = -1;
return false;
}
}
EnsureVisible(m_iCurSel);
if( bTakeFocus ) pControl->SetFocus();
if( m_pManager != NULL ) {
m_pManager->SendNotify(this, DUI_MSGTYPE_ITEM