一、 由于diulib不支持list控件的多选修改。下面是修改的原理。
Ctrl+左键多选,按下Ctrl键点击,主要有三种情况:
- 选中一个
- 再点击,又选中一个
- 再点击前一个,前一个选中状态消失
总结分析:ctrl按下的情况,点击,不会使前一个(一部分)选中项失去选中状态,而只是让当前点击的项改变选中状态,并将焦点移到当前项。
shift+左键,主要有4中情况
- 点击选中一个(ID为2),向下选中一个(ID为5),则2-5被选中 
- 再向下选中一个(ID为10),则2-10被选中 
- 向上选中一个(ID为8),则2-8被选中 
- 向上选中一个(ID为1),则1-2被选中。 
总结分析:shift按下的情况,点击,是选中一个范围,起始项为焦点所在的项,shift点击的项为结束项。
二、代码修改
UIList.cpp将Select修改如下:
bool CListElementUI::Select(bool bSelect, bool bCallback)
{
    BOOL bShift = (GetKeyState(VK_SHIFT) & 0x8000);
    BOOL bCtrl = (GetKeyState(VK_CONTROL) & 0x8000);
    if (!IsEnabled()) return false;
    //if( bSelect == m_bSelected ) return true;
    if (bCtrl) {
        m_bSelected = !m_bSelected;
    }
    else {
        m_bSelected = bSelect;
    }
    if (m_bSelected == false) {
        Hot(false);
    }
    else {
        Hot(true);
    }
    if (bCallback && m_pOwner != NULL) {
        if (bShift) {
            m_pOwner->SelectRange(m_iIndex);
        }
        else {
            m_pOwner->SelectItem(m_iIndex);
        }
    }
    Invalidate();
    return true;
}
添加hot函数:
bool CListElementUI::Hot(bool bHot)
{
    if (!IsEnabled()) return false;
    if (bHot)
    {
        m_uButtonState |= UISTATE_HOT;
    }
    else {
        if ((m_uButtonState & UISTATE_HOT) != 0) {
            m_uButtonState &= ~UISTATE_HOT;
        }
    }
    //m_pOwner->HotItem(m_iIndex, bHot);
    Invalidate();
    return true;
}
修改SelectItem函数的实现:
bool CListUI::SelectItem(int iIndex, bool bTakeFocus)
{
    BOOL bCtrl = (GetKeyState(VK_CONTROL) & 0x8000);
    //if( iIndex == m_iCurSel ) return true; 
    //int iTempSel = -1;
    // We should first unselect the currently selected item 
    if (!bCtrl) {
        //if( m_iCurSel >= 0 ) { 
        for (int i = 0;i < GetCount();i++) {
            if (i != iIndex) {
                CControlUI* pControl = GetItemAt(i);
                if (pControl != NULL) {
                    IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
                    if (pListItem != NULL) {
                        if (pListItem->IsSelected()) {
                            pListItem->Select(false,false);
                        }
                    }
                }
            }
        }
        m_iCurSel = -1;
        //} 
    }
    if (iIndex == m_iCurSel) return true;
    int iOldSel = m_iCurSel;
    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<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
    if (pListItem == NULL) return false;
    m_iCurSel = iIndex;
    /*if (!bCtrl) {
        if (!pListItem->Select(true)) {
            m_iCurSel = -1;
            return false;
        }
    }*/
    EnsureVisible(m_iCurSel);
    if (bTakeFocus) pControl->SetFocus();
    if (m_pManager != NULL) {
        m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMSELECT, m_iCurSel, iOldSel);
    }
    return true;
}
添加下面的函数:
bool CListUI::SelectRange(int iIndex, bool bTakeFocus)
{
    int i = 0;
    int iFirst = m_iCurSel;
    int iLast = iIndex;
    int iCount = GetCount();
    if (iFirst == iLast) return true;
    CControlUI* pControl = GetItemAt(iIndex);
    if (pControl == NULL) return false;
    if (!pControl->IsVisible()) return false;
    if (!pControl->IsEnabled()) return false;
    IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
    if (pListItem == NULL) return false;
    if (!pListItem->Select(true,false)) {
        m_iCurSel = -1;
        return false;
    }
    EnsureVisible(iIndex);
    if (bTakeFocus) pControl->SetFocus();
    if (m_pManager != NULL) {
        m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMSELECT, iIndex, m_iCurSel);
    }
    //locate (and select) either first or last
    // (so order is arbitrary)
    while (i < iCount) {
        if (i == iFirst || i == iLast) {
            i++;
            break;
        }
        CControlUI* pControl = GetItemAt(i);
        if (pControl != NULL) {
            IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
            if (pListItem != NULL) pListItem->Select(false, false);
        }
        i++;
    }
    // select rest of range
    while (i < iCount) {
        CControlUI* pControl = GetItemAt(i);
        if (pControl != NULL) {
            IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
            if (pListItem != NULL) pListItem->Select(true, false);
        }
        if (i == iFirst || i == iLast) {
            i++;
            break;
        }
        i++;
    }
    // unselect rest of range
    while (i < iCount) {
        CControlUI* pControl = GetItemAt(i);
        if (pControl != NULL) {
            IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(_T("ListItem")));
            if (pListItem != NULL) pListItem->Select(false, false);
        }
        i++;
    }
    return true;
}
● UIList.h在class IListOwnerUI中添加虚函数:
virtual bool SelectRange(int iIndex, bool bTakeFocus = false) = 0;//@xdrt81y@20140218@支持shift多选
在class IListItemUI中替换select函数的声明:
virtual bool Select(bool bSelect = true, bool bCallback = true) = 0;
在class UILIB_API CListUI中添加函数声明:
bool SelectRange(int iIndex, bool bTakeFocus = false);//@xdrt81y@20140218@支持shift多选
在class UILIB_API CListElementUI中修改函数声明:
bool Select(bool bSelect = true, bool bCallback = true);
在class UILIB_API CListContainerElementUI中修改声明:
bool Select(bool bSelect = true, bool bCallback = true);
● UICombo.cpp添加函数实现:
bool CComboUI::SelectRange(int iIndex, bool bTakeFocus)
{
    return true;
}
● UICombo.h添加函数声明:
bool SelectRange(int iIndex, bool bTakeFocus = false);//@xdrt81y@20140218
文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/duilib/duilib-clistui-surpport-multilines-select-with-ctrl-shift-key.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)