码迷,mamicode.com
首页 > 其他好文 > 详细

使用 xlue 实现简单 listbox 控件

时间:2014-08-26 22:56:40      阅读:339      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   color   os   使用   io   for   ar   

基于 XLUE 实现的 listbox 控件
1. 提供增删查接口,将 obj 作为子控件添加到列表;
2. 提供 Attach/Detach 方法,可以将子控件的事件转发出来;
3. 支持滚动条;
4. 支持鼠标滚轮;


 

实现过程中的注意点:
1. 使用 ItemObjList 表存储 itemObj , ItemObjList 是一个数组,是 listbox 控件的数据模型;
2. 使用 EventCookieMap 表存储事件回调, Attach 时监听所有 itemObj 的事件,通过 Insert 添加的 itemObj,也要通过 EventCookieMap 表来确定需要监听哪些事件;
3. 鼠标滚轮的实现,子控件鼠标滚轮事件 RouteToFather ,滚动条鼠标滚轮事件重定向到 listbox 控件上;
4. 滚动条的实现,调整位置即可



代码:

simplelistbox.xml

<xlue>
    <control class="SimpleListBox">
        <attr_def>
            <attr name="VScrollBarNormalBkgID" type="string" />
            <attr name="VScrollBarHoverBkgID" type="string" />
            <attr name="VScrollBarDownBkgID" type="string" />
        </attr_def>
        <method_def>
            <AttachEvent file="simplelistbox.xml.lua" func="AttachEvent" />
            <DetachEvent file="simplelistbox.xml.lua" func="DetachEvent" />
            <InsertItem file="simplelistbox.xml.lua" func="InsertItem" />
            <RemoveItem file="simplelistbox.xml.lua" func="RemoveItem" />
            <ClearItem file="simplelistbox.xml.lua" func="ClearItem" />
            <GetItem file="simplelistbox.xml.lua" func="GetItem" />
            <GetItemNum file="simplelistbox.xml.lua" func="GetItemNum" />
        </method_def>
        <event_def>
        </event_def>
        <objtemplate>
            <children>
                <obj id="list.layout" class="LayoutObject">
                    <attr>
                        <left>0</left>
                        <top>0</top>
                        <width>father.width</width>
                        <height>father.height</height>
                        <limitchild>1</limitchild>
                    </attr>
                    <children>
                        <obj id="listbox.layout" class="LayoutObject">
                            <attr>
                                <left>0</left>
                                <top>0</top>
                                <width>father.width-4</width>
                                <height>0</height>
                            </attr>
                            <eventlist>
                                <event name="OnMouseWheel" file="simplelistbox.xml.lua" func="ListLayout_OnMouseWheel" />
                            </eventlist>
                        </obj>
                        <obj id="vscrollbar" class="TextureObject">
                            <attr>
                                <left>father.width-4</left>
                                <top>0</top>
                                <width>4</width>
                                <height>0</height>
                            </attr>
                            <eventlist>
                                <event name="OnLButtonDown" file="simplelistbox.xml.lua" func="VScrollBar_OnLButtonDown" />
                                <event name="OnLButtonUp" file="simplelistbox.xml.lua" func="VScrollBar_OnLButtonUp" />
                                <event name="OnMouseMove" file="simplelistbox.xml.lua" func="VScrollBar_OnMouseMove" />
                                <event name="OnMouseLeave" file="simplelistbox.xml.lua" func="VScrollBar_OnMouseLeave" />
                                <event name="OnMouseWheel" file="simplelistbox.xml.lua" func="ListLayout_OnMouseWheel" redirect="father:listbox.layout"/>
                            </eventlist>
                        </obj>
                    </children>
                </obj>
            </children>
            <eventlist>
                <event name="OnInitControl" file="simplelistbox.xml.lua" func="OnInitControl" />
                <event name="OnDestroy" file="simplelistbox.xml.lua" func="OnDestroy" />
            </eventlist>
        </objtemplate>
    </control>
</xlue>

simplelistbox.xml.lua

 

 

------------------ 以下为外部函数 -------------------

function AttachEvent(ctrlObj, eventName, callback)
    if type(eventName) ~= "string" or type(callback) ~= "function" then
        return
    end
    local attr = ctrlObj:GetAttribute()
    if attr.EventCookieMap[eventName] == nil then
        attr.EventCookieMap[eventName] = {}
    end
    local cookie = table.maxn(attr.EventCookieMap[eventName]) + 1
    attr.EventCookieMap[eventName][cookie] = callback
    
    for index,itemObj in ipairs(attr.ItemObjList) do
        local itemcookie,bRet = itemObj:AttachListener(eventName, true, function(...)
            for cookie,callback in pairs(attr.EventCookieMap[eventName]) do
                callback(index, ...)
            end
        end)
    end
    return cookie
end

function DetachEvent(ctrlObj, eventName, cookie)
    if type(eventName) ~= "string" or type(cookie) ~= "number" then
        return
    end
    local attr = ctrlObj:GetAttribute()
    if attr.EventCookieMap[eventName] == nil then
        return
    end
    attr.EventCookieMap[eventName][cookie] = nil
end

function InsertItem(ctrlObj, index, obj)
    if type(index) ~= "number" or obj == nil then
        return
    end
    local attr = ctrlObj:GetAttribute()
    local listLayout = ctrlObj:GetControlObject("listbox.layout")

    -- 插入item,调整位置
    listLayout:AddChild(obj)
    local l,t,r,b = obj:GetObjPos()
    local width,height = r-l,b-t
    if index <= 1 or #attr.ItemObjList == 0 then    -- 插入到最前
        for i,itemObj in ipairs(attr.ItemObjList) do
            local l,t,r,b = itemObj:GetObjPos()
            itemObj:SetObjPos(l,t+height,r,b+height)
        end
        obj:SetObjPos(0,0,width,height)
        index = 1
    elseif index > #attr.ItemObjList then    -- 插入到最后
        local lastObj = attr.ItemObjList[#attr.ItemObjList]
        local _,_,_,bottom = lastObj:GetObjPos()
        obj:SetObjPos(0,bottom,width,bottom+height)
        index = #attr.ItemObjList + 1
    else    -- 插入到中间
        local preObj = attr.ItemObjList[index-1]
        local _,_,_,bottom = preObj:GetObjPos()
        for i=index, #attr.ItemObjList do
            local itemObj = attr.ItemObjList[i]
            local l,t,r,b = itemObj:GetObjPos()
            itemObj:SetObjPos(l,t+height,r,b+height)
        end
        obj:SetObjPos(0,bottom,width,bottom+height)
    end
    table.insert(attr.ItemObjList, index, obj)
    
    -- 调整 listLayout 大小
    local lastObj = attr.ItemObjList[#attr.ItemObjList]
    local _,_,_,bottom = lastObj:GetObjPos()
    local l,t,r,b = listLayout:GetObjPos()
    listLayout:SetObjPos(l,t,r,t+bottom)
    
    -- 调整 VScrollBar 位置
    __AdjustVScrollBarPos(ctrlObj)
    
    -- 监听新添加item的事件
    for eventName,cookieTable in pairs(attr.EventCookieMap) do
        if table.maxn(cookieTable) > 0 then
            obj:AttachListener(eventName, true, function(...)
                for cookie, callback in pairs(cookieTable) do
                    callback(index, ...)
                end
            end)
        end
    end
    -- 监听OnPosChange,当 obj height 改变时要调整其它 itemObj 的位置
    obj:AttachListener("OnPosChange", true, function(obj,oldLeft,oldTop,oldRight,oldBottom,newLeft,newTop,newRight,newBottom)
        local oldHeight,newHeight = oldBottom-oldTop,newBottom-newTop
        if oldHeight == newHeight then
            return
        end
    
        local index = nil
        for i,itemObj in ipairs(attr.ItemObjList) do
            if itemObj:GetID() == obj:GetID() and obj:GetID() ~= nil then
                index = i 
                break
            end
        end
        if not index then
            return
        end
        for i=index+1,#attr.ItemObjList do
            local itemObj = attr.ItemObjList[i]
            local l,t,r,b = itemObj:GetObjPos()
            itemObj:SetObjPos(l,t+newHeight-oldHeight,r,b+newHeight-oldHeight)
        end
        -- 调整 VScrollBar 位置
        __AdjustVScrollBarPos(ctrlObj)
    end)
    -- 监听 OnMouseWheel ,在 itemObj 上的鼠标滚轮事件也要被响应
    obj:AttachListener("OnMouseWheel", true, function(obj, x, y, distance, flags)
        obj:RouteToFather()
    end)
end

function RemoveItem(ctrlObj, index)
    if type(index) ~= "number" then
        return
    end
    local attr = ctrlObj:GetAttribute()
    local listLayout = ctrlObj:GetControlObject("listbox.layout")
    if #attr.ItemObjList == 0 then
        return
    end
    
    if index <= 1 then
        index = 1
    elseif index > #attr.ItemObjList then
        index = #attr.ItemObjList
    end
    
    -- 删除 obj 调整其它 itemObj 位置
    local obj = attr.ItemObjList[index]
    local l,t,r,b = obj:GetObjPos()
    local width,height = r-l,b-t
    for i=index+1, #attr.ItemObjList do
        local itemObj = attr.ItemObjList[i]
        local l,t,r,b = itemObj:GetObjPos()
        itemObj:SetObjPos(l,t-height,r,b-height)
    end
    listLayout:RemoveChild(obj)
    table.remove(attr.ItemObjList, index)
    
    -- 调整 listLayout 高度
    local bottom = 0
    local lastObj = attr.ItemObjList[#attr.ItemObjList]
    if lastObj then
        _,_,_,bottom = lastObj:GetObjPos()
    end
    local l,t,r,b = listLayout:GetObjPos()
    listLayout:SetObjPos(l,t,r,t+bottom)
    
    -- 调整 VScrollBar 位置
    __AdjustVScrollBarPos(ctrlObj)
end

function ClearItem(ctrlObj)
    local attr = ctrlObj:GetAttribute()
    local listLayout = ctrlObj:GetControlObject("listbox.layout")
    listLayout:RemoveAllChild()
    attr.ItemObjList = {}
end

function GetItem(ctrlObj, index)
    if type(index) ~= "number" then
        return
    end
    local attr = ctrlObj:GetAttribute()
    return attr.ItemObjList[index]
end

function GetItemNum(ctrlObj)
    local attr = ctrlObj:GetAttribute()
    return #attr.ItemObjList
end

----------------- 以下为事件处理函数 ------------------

function OnInitControl(ctrlObj)
    local attr = ctrlObj:GetAttribute()
    attr.ItemObjList = {}
    attr.EventCookieMap = {}
    
    local vsbarObj = ctrlObj:GetControlObject("vscrollbar")
    if attr.VScrollBarNormalBkgID then
        vsbarObj:SetTextureID(attr.VScrollBarNormalBkgID)
    end
end

function OnDestroy(ctrlObj)

end

function ListLayout_OnMouseWheel(obj, x, y, distance, flags)
    local ctrlObj = obj:GetOwnerControl()
    local listLayout = ctrlObj:GetControlObject("listbox.layout")
    local fatherLayout = listLayout:GetParent()
    local left,top,right,bottom = listLayout:GetObjPos()
    local _,fatherTop,_,fatherBottom = fatherLayout:GetObjPos()
    local fatherHeight = fatherBottom-fatherTop
    
    -- distance 为正数时, listLayout 向下移动,反之向上移动
    local moveDistance = distance/10
    if moveDistance > 0 and top + moveDistance > 0 then    -- 向下移动到顶了
        if top < 0 then
            listLayout:SetObjPos(left,0,right,bottom-top)
        end
    elseif moveDistance < 0 and bottom + moveDistance < fatherHeight then    -- 向上移动到底了
        if bottom > fatherHeight then
            listLayout:SetObjPos(left,fatherHeight-(bottom-top),right,fatherHeight)
        end
    else
        listLayout:SetObjPos(left,top+moveDistance,right,bottom+moveDistance)
    end
    __AdjustVScrollBarPos(ctrlObj)
end

function VScrollBar_OnLButtonDown(vsbarObj)
    vsbarObj:SetCaptureMouse(true)
    local ctrlObj = vsbarObj:GetOwnerControl()
    local attr = ctrlObj:GetAttribute()
    if attr.VScrollBarDownBkgID then
        vsbarObj:SetTextureID(attr.VScrollBarDownBkgID)
    end
end

function VScrollBar_OnLButtonUp(vsbarObj)
    vsbarObj:SetCaptureMouse(false)
    local ctrlObj = vsbarObj:GetOwnerControl()
    local attr = ctrlObj:GetAttribute()
    if attr.VScrollBarNormalBkgID then
        vsbarObj:SetTextureID(attr.VScrollBarNormalBkgID)
    end
end

function VScrollBar_OnMouseMove(vsbarObj, x, y, flags)
    if flags == 1 then    -- 鼠标左键被按下
        local listLayout = vsbarObj:GetOwnerControl():GetControlObject("listbox.layout")
        local fatherLayout = vsbarObj:GetParent()
        local _,listTop,_,listBottom = listLayout:GetObjPos()
        local _,fatherTop,_,fatherBottom = fatherLayout:GetObjPos()
        local listHeight,fatherHeight = listBottom-listTop,fatherBottom-fatherTop
        local _,vsbTop,_,vsbBottom = vsbarObj:GetObjPos()
        local vsbHeight = vsbBottom-vsbTop
        
        -- 调整 VScrollBar 的位置
        local vsbTop = y
        if y < 0 then
            vsbTop = 0
        elseif y > fatherHeight - vsbHeight then
            vsbTop = fatherHeight - vsbHeight
        end
        local l,t,r,b = vsbarObj:GetObjPos()
        if t ~= vsbTop then
            vsbarObj:SetObjPos(l,vsbTop,r,vsbTop+vsbHeight)
        end
        
        -- 调整 listLayout 的位置
        local listTop = 0
        listTop = -listHeight * vsbTop/fatherHeight
        local l,t,r,b = listLayout:GetObjPos()
        if t ~= listTop then
            listLayout:SetObjPos(l,listTop,r,listTop+listHeight)
        end
    end
    
    if flags ~= 1 then
        local ctrlObj = vsbarObj:GetOwnerControl()
        local attr = ctrlObj:GetAttribute()
        if attr.VScrollBarHoverBkgID then
            vsbarObj:SetTextureID(attr.VScrollBarHoverBkgID)
        end
    end
end

function VScrollBar_OnMouseLeave(vsbarObj)
    local ctrlObj = vsbarObj:GetOwnerControl()
    local attr = ctrlObj:GetAttribute()
    if attr.VScrollBarNormalBkgID then
        vsbarObj:SetTextureID(attr.VScrollBarNormalBkgID)
    end
end

-------------------- 以下为内部函数 -------------------

function __AdjustVScrollBarPos(ctrlObj)
    local listLayout = ctrlObj:GetControlObject("listbox.layout")
    local fatherLayout = listLayout:GetParent()
    local vsbarObj = ctrlObj:GetControlObject("vscrollbar")
    
    local _,listTop,_,listBottom = listLayout:GetObjPos()
    local _,fatherTop,_,fatherBottom = fatherLayout:GetObjPos()
    local listHeight,fatherHeight = listBottom-listTop,fatherBottom-fatherTop
    
    -- 大小
    local vsbHeight = 0
    if listHeight > fatherHeight then
        vsbHeight = fatherHeight * fatherHeight/listHeight 
    end
    -- 位置
    local vsbTop = 0
    if listHeight > fatherHeight then
        vsbTop = fatherHeight * (-listTop)/listHeight
    end
    
    local l,t,r,b = vsbarObj:GetObjPos()
    if t ~= vsbTop or b-t ~= vsbHeight then
        vsbarObj:SetObjPos(l,vsbTop,r,vsbTop+vsbHeight)
    end
end

使用 xlue 实现简单 listbox 控件

标签:des   style   blog   color   os   使用   io   for   ar   

原文地址:http://www.cnblogs.com/zuibunan/p/3938338.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!