DuiLib : 复杂ListHeaderItem的拖动

来源:互联网 发布:vb 资源管理器侧边栏 编辑:程序博客网 时间:2024/06/07 00:52

我们使用 ListHeaderItem 时,为了实现复杂的题头样式, 会选择Container作为容器,放一些控件的组合.

这时,使用原生的DuiLibV391无法用鼠标拖动2个ListHeaderItem的结合部.


我这几天研究了这个问题

写了一个Demo验证了修改后的效果

工程下载点: srcListUiHeaderItemEx_2014_1006_2029.rar

效果图:


大家手头的DuiLib修改版本都不同,拿Diff工具比较不出来.

大家拿着我这版本,用起来会很不爽(重构了一些代码), 我说修改思路, 供需要的同学参考.


我先追 WM_SETCURSOR

    case WM_SETCURSOR:        {            if( LOWORD(lParam) != HTCLIENT )                break;            if( m_bMouseCapture )                return true;            POINT pt = { 0 };            ::GetCursorPos(&pt);            ::ScreenToClient(m_hWndPaint, &pt);            CControlUI* pControl = FindControl(pt);            if( pControl == NULL )                break;            if( (pControl->GetControlFlags() & UIFLAG_SETCURSOR) == 0 )                break;

发现复杂题头的Container不接受WM_SETCURSOR消息.

我将Container的GetControlFlags改成只要不禁止,就返回UIFLAG_SETCURSOR.

    UINT CContainerUI::GetControlFlags() const    {        if (IsEnabled())             return UIFLAG_SETCURSOR;        else             return 0;    }

然后执行 CContainerUI 的 pControl->Event(event);

BOOL CContainerUI::DoEvent(TEventUI& event){        std::wstring    strParentClassName = L"";        CControlUI*     pParentCtrl = NULL;if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND )         {if( m_pParent != NULL )                 m_pParent->DoEvent(event);else                 CControlUI::DoEvent(event);                return TRUE;}        if( event.Type == UIEVENT_SETCURSOR )        {            pParentCtrl = GetParent();            if ((NULL != pParentCtrl) && (pParentCtrl->GetSepWidth() > 0))            {                POINT pt = { 0 };                ::GetCursorPos(&pt);                // ::ScreenToClient(m_pPaintManager->GetPaintWindow(), &pt);                event.ptMouse = pt;                if (!pParentCtrl->DoEvent(event)) ///< 让父窗口决定是否显示光标                {                    ::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));                }            }            else            {                ::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));                return FALSE;            }        }

我让父窗口来决定是否要变换光标(其他样式变成拖动光标).

我写的xml文件如下: (以一个题头字段ListHeaderItem 为例)

                    <ListHeaderItem name="HeadItem_id" text="ID" width="104" height="30" textcolor="#FF6c6c6c" disabledtextcolor="#FFA7A6AA" align="center" font="1" normalimage="headerctrl_n.png" hotimage="headerctrl_h.png" pushedimage="headerctrl_d.png" sepimage="header_Item_boundary.png" sepwidth="1" >                                            <Container >                                      <HorizontalLayout sepwidth="1" >        <Container /> <!-- 拖动时需要, 可以使容器包裹的控件在宽度方向成比例移动 -->                <Container width="80" height="32">                </Container>                <Container width="16" height="30">                    <Button name="btn_sort_id" float="true" pos="0,7,16,16" width="16" height="16" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" align="center" normalimage="sort_no.png" hotimage="sort_no.png" pushedimage="sort_no.png" />                </Container>                <Container width="4" /> <!-- 拖动时需要, 和右边界保持一定距离, 拖动时,拖动光标的判断不会落在控件上 -->        <Container width="1" bkimage="header_Item_boundary.png" />            </HorizontalLayout>  </Container>                      </ListHeaderItem>

当 HorizontalLayout sepwidth="1" 时,  HorizontalLayout会进入光标的判断(原生版本,就有这个判断逻辑)

我将虚函数 DoEvent 由void 返回值,变成BOOL返回值, 这样就可以利用父窗口的判断,如果返回FALSE, 我们就在Container中就将光标设置成箭头.

如果父窗口已经处理了光标(已经设置成拖动光标或别的), 在Container中就不处理光标.


CHorizontalLayoutUI中的光标处理如下, 没有改动, 和原生版本相同

BOOL CHorizontalLayoutUI::DoEvent(TEventUI& event)

...

if( event.Type == UIEVENT_SETCURSOR ){RECT rcSeparator = GetThumbRect(false);                if (m_iSepWidth>=0)//111024 by cddjr, 增加分隔符区域,方便用户拖动                {                    rcSeparator.left -= 4;                    rcSeparator.right += 4;                }                else                    rcSeparator.right+=4;                // ::ScreenToClient(m_pPaintManager->GetPaintWindow(), &pt);                POINT pt;                pt.x = rcSeparator.left;                pt.y = rcSeparator.top;                ClientToScreen(m_pPaintManager->GetPaintWindow(), &pt);                rcSeparator.left = pt.x;                rcSeparator.top = pt.y;                pt.x = rcSeparator.right;                pt.y = rcSeparator.bottom;                ClientToScreen(m_pPaintManager->GetPaintWindow(), &pt);                rcSeparator.right = pt.x;                rcSeparator.bottom = pt.y;                if( IsEnabled() && ::PtInRect(&rcSeparator, event.ptMouse) )                {                    HCURSOR hCursor = ::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE));                    _ASSERT(NULL != hCursor);::SetCursor(hCursor);return TRUE;}                else                {                    return FALSE;                }}

我记得就改了这些, 剩下的就是调整一下xml文件就搞定这个显示效果.








0 0