ListCtrl Checkbox多选问题

ListCtrl Checkbox多选问题

需求与目标:

标准的Listctrl是支持多选的,但这个多选只是把那些选中行变成高亮而已,我想要的效果是像svn提交代码的那个listctrl那样:
1.可以用鼠标框选,可以按ctrl或shift进行组合选择.这是listctrl本身支持的,只要设置对了风格就没问题,这个不是重点,跳过 :) 
2.在选择了多行之后,点击鼠标或按下空格,能够把所有选中行都选上(呵呵,这就是我想要的)

??没用过这个功能??马上装一个svn,BitComet也可以....

实现:

其实就是把所有的选中行的check box状态都设为true-->SetCheck就可以啦,当然发消息也可以:发LVM_SETITEMSTATE消息对LVIS_STATEIMAGEMASK进行处理就行。其实都一样。

问题:是你会发现,鼠标点击和空格本身我们不用处理listctrl都会自己处理,并改变当前选中行的check box状态,所以我们自己处理的时候就要对当前选中行直接“特殊处理”。否则的话:你刚刚设为TRUE的状态,马上就被listctrl自己处理的消息给改回去了。。。

解决方法:
1.屏蔽listctrl自己的消息,全部我们自己处理(空格消息这么处理会很方便,鼠标消息因为要得到点击的是哪一行,这么干会辛苦点,能偷懒就偷懒嘛~~)
2.还用listctrl自己的消息,但是我们处理完之后要多做一次状态设置,把被系统改的状态再次改回来(BOOL改了3次和改了1次是一样的嘛+_+)

部分代码:



/* *
* @Function : CDebeheListCtrl::OnNMClick
* @brief : 鼠标点击消息
* @param : pNMHDR
* @param : pResult
* @return : 
* @remark : 
*/
void  CDebeheListCtrl::OnNMClick(NMHDR *  pNMHDR, LRESULT *  pResult)
{
//  按下shift和ctrl时不马上选中
NMITEMACTIVATE *  pNMItemActivate  =  (NMITEMACTIVATE * )pNMHDR;
if  (pNMItemActivate -> iItem  ==   - 1
   
|| pNMItemActivate -> uKeyFlags  ==  LVKF_SHIFT
   
||  pNMItemActivate -> uKeyFlags  ==  LVKF_CONTROL)
{
   TRACE0(
" OnNMClick no use  " );
}

else   if (pNMItemActivate -> ptAction.x  >   0  
    
&&  pNMItemActivate -> ptAction.x  <  LISTCTRL_FIRST_COL_WIDTH)
{
   
if  (IsInSelected(pNMItemActivate -> iItem))
   
{
    CheckAllSelectedItems(pNMItemActivate
-> iItem);
    
this -> SetCheck(pNMItemActivate -> iItem,  ! GetCheck(pNMItemActivate -> iItem));
   }

}

}


/* *
* @Function : CheckAllSelectedItems
* @brief : 改变所有选中行的check box状态
* @param : nCurItem 当前选中的行
* @return : 
* @remark : 当前选中行nCurItem是-1的时候,自己计算check box的状态
*     nCurItem不为-1是,就直接用nCurItem行的状态取反来设置
*     大家(所有选中行)的状态
*/
BOOL CDebeheListCtrl::CheckAllSelectedItems(
int  nCurItem)
{
BOOL bCheck 
=  FALSE;
if  (nCurItem  ==   - 1 )
   bCheck 
=  CalcCheckState();
else
   bCheck 
=   ! GetCheck(nCurItem);

//  遍历选中行,设置状态
INT nItemIndex  =   - 1 ;   
nItemIndex 
=   this -> GetNextItem( - 1 , LVNI_SELECTED); 
if (nItemIndex  !=   - 1 )   
{
   SetCheck(nItemIndex, bCheck);
}
 
while (TRUE)   
{   
   nItemIndex 
=   this -> GetNextItem(nItemIndex, LVNI_SELECTED);   
   
if (nItemIndex  !=   - 1 )   
   
{
    SetCheck(nItemIndex, bCheck);
   }

   
else    
    
break ;   
}
 
return  TRUE;
}


/* *
* @Function : IsInSelected
* @brief : 判断nItem行,是否在选中行中
* @return : BOOL 
* @param : int nItem 要判断的行
* @remark : 
*/
BOOL CDebeheListCtrl::IsInSelected(
int  nItem)
{
//  得到当前选中行的,另一种方式,Copy from msdn
BOOL bRet  =  FALSE;
POSITION   pos   
=     this -> GetFirstSelectedItemPosition();   
if    (pos    ==    NULL)   
   TRACE0(
" No   items   were   selected!  " );   
else    
{   
   
while  (pos)   
   
{   
    
int    nNextItem    =     this -> GetNextSelectedItem(pos);   
    
if  (nItem  ==  nNextItem)
    
{
     bRet 
=  TRUE;
     
goto  Exit0;
    }

   }
   
}
   
Exit0:
return  bRet;
}


/* *
* @Function : CalcCheckState
* @brief : 如果当前选中行是-1,计算一下对选中行要设置的状态
* @return : BOOL 
* @remark : 除非所有的选中行状态都是TRUE,否则返回FALSE
*/
BOOL CDebeheListCtrl::CalcCheckState()
{
BOOL bRet 
=  FALSE;
BOOL bHavenChecked 
=  FALSE;
INT nItemIndex 
=   - 1 ;   
nItemIndex 
=   this -> GetNextItem( - 1 , LVNI_SELECTED); 
if (nItemIndex  !=   - 1 )   
{
   
if (GetCheck(nItemIndex))
   
{
    bHavenChecked 
=  TRUE;
    
goto  Exit0;
   }

}
 
while (TRUE)   
{   
   nItemIndex 
=   this -> GetNextItem(nItemIndex, LVNI_SELECTED);   
   
if (nItemIndex  !=   - 1 )   
   
{
    
if  (GetCheck(nItemIndex))
    
{
     bHavenChecked 
=  TRUE;
     
goto  Exit0;
    }

   }

   
else    
    
break ;   
}
 
Exit0:
bRet 
=   ! bHavenChecked;
return  bRet;
}


BOOL CDebeheListCtrl::PreTranslateMessage(MSG
*  pMsg) 
{
//  之所以处理这三个消息是我试出来的 +_+
//  不把他们截下来的话,listctrl默认的空格处理,
//  会让我们的逻辑变得复杂
if  (pMsg -> message  ==  WM_CHAR 
   
||  pMsg -> message  ==  WM_KEYDOWN 
   
||  pMsg -> message  ==  WM_KEYUP)
{
   
if  (pMsg -> message  ==  WM_KEYDOWN  &&  pMsg -> wParam  ==  VK_SPACE)
   
{
    
int  nSelected  =   this -> GetSelectedCount();
    
if  (nSelected  >   0 )
    
{
     
int  item  =   this -> GetSelectionMark();
     
if  (IsInSelected(item))
     
{
      CheckAllSelectedItems(item);
     }

     
else
     
{
      CheckAllSelectedItems(
- 1 );
     }

    }

   }

//  把双击消息屏蔽,不然点的太快会感觉像是bug
if  (pMsg -> message  ==  WM_LBUTTONDBLCLK)
   
return  TRUE;
   
return  TRUE;  //  切记return TRUE,不然默认的空格处理就会起作用
}  
return  CListCtrl::PreTranslateMessage(pMsg);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值