基于 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]) +
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 <= or #attr.ItemObjList == 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(,,width,height)
index =
elseif index > #attr.ItemObjList then -- 插入到最后
local lastObj = attr.ItemObjList[#attr.ItemObjList]
local _,_,_,bottom = lastObj:GetObjPos()
obj:SetObjPos(,bottom,width,bottom+height)
index = #attr.ItemObjList +
else -- 插入到中间
local preObj = attr.ItemObjList[index-]
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(,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) > 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+,#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 == then
return
end if index <= then
index =
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+, #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 =
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/
if moveDistance > and top + moveDistance > then -- 向下移动到顶了
if top < then
listLayout:SetObjPos(left,,right,bottom-top)
end
elseif moveDistance < 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 == 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 < then
vsbTop =
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 =
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 ~= 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 =
if listHeight > fatherHeight then
vsbHeight = fatherHeight * fatherHeight/listHeight
end
-- 位置
local vsbTop =
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 控件的更多相关文章

  1. MFC中Listbox控件的简单使用

    MFC中listbox控件是为了显示一系列的文本,每个文本占一行.   Listbox控件可以设置属性为: LBS_CHILD   :(默认)子窗口 LBS_Visible :(默认)可视 LBS_M ...

  2. C# LIstbox 解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合”的问题

    解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合”的问题 分类: winform2008-05-24 02:33 2592人阅读 评论(11) 收藏 举报 winf ...

  3. UWP入门(八)--几个简单的控件

    原文:UWP入门(八)--几个简单的控件 每天看几个,要不聊几天我就可以看完啦,加油! 看效果 1. CheckBox <TextBlock Grid.Row="0" Tex ...

  4. 编写有提示的listbox控件 2008-06-29 17:13

    在MFC中几乎所有的控件都有信息提示,而惟有listbox却没有这样的一个功能,每当我们把鼠标移到listbox上控件时,啥玩意儿都没有是不是很气馁啊,所以我今天特地写了一个简单的有提示的listbo ...

  5. asp.net中的ListBox控件添加双击事件

    问题:在Aspx页里的ListBox A中添加双击事件,将选中项添加到另一个ListBox B中,双击ListBox B中的选中项,删除当前选中项 页面: <asp:ListBox ID=&qu ...

  6. WPF中ListBox控件在选择模式(SelectionMode)为Single时仍然出现多个Item被选中的问题

    最近在学习WPF过程中使用到了ListBox控件,在使用时遇到下面的奇怪问题: 代码如下: listBox.Items.Add("绘图"); listBox.Items.Add(& ...

  7. MATLAB GUI程序设计中ListBox控件在运行期间消失的原因及解决方法

    在运行期间,ListBox控件突然消失,同时给出如下错误提示: Warning: single-selection listbox control requires that Value be an ...

  8. 异步方式向WPF ListBox控件中一条一条添加记录

    向ListBox绑定数据源时,如果数据量过大,可能会使得程序卡死,这是就需要一条一条的向ListBox的数据源中添加记录了,下面是个小Demo: 1.前台代码,就是一个ListBox控件 <Wi ...

  9. asp.net Listbox控件用法

    2008-02-18 19:56 来源: 作者: ListBox(列表框)控件可以显示一组项目的列表,用户可以根据需要从中选择一个或多个选项.列表框可以为用户提供所有选项的列表.虽然也可设置列表框为多 ...

随机推荐

  1. LINUX之文件操作权限讲解

    r(Read,读取):对文件而言,具有读取文件内容的权限:对目录来说,具有浏览目 录的权限. w(Write,写入):对文件而言,具有新增.修改文件内容的权限:对目录来说,具有删除.移动目录内文件的权 ...

  2. oracle 10g函数大全--字符型函数

    ASCII(x1) [功能]:返回字符表达式最左端字符的ASCII 码值. [参数]:x1,字符表达式 [返回]:数值型 [示例] SQL> select ascii('A') A,ascii( ...

  3. java缓存适合使用的情况

    并非所有的情况都适合于使用二级缓存,需要根据具体情况来决定.同时可以针对某一个持久化对象配置其具体的缓存策略. 适合于使用二级缓存的情况: 1.数据不会被第三方修改 一般情况下,会被hibernate ...

  4. Java内存缓存

    1.缓存为什么要存在 应用服务器资源是有限的,数据库每秒中接受请求的次数也是有限的.如果利用有限的资源来提供尽可能大的吞吐量呢,一个办法:减少计 算量,缩短请求流程(减少网络io或者硬盘io),这时候 ...

  5. PLSQL Developer连接远程Oracle方法(非安装client)

    远程连接Oracle比較麻烦,通常须要安装oracle的客户端才干实现. 通过instantclient能够比較简单的连接远程的Oracle. 1.新建文件夹D:\Oracle_Cleint用于存放相 ...

  6. ThreadLocal的简单应用

    概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式.前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一 ...

  7. threadlocal 变量 跟synchronized 关键字的关系

    为什么叫threadloca变量呢,经过大量的查资料发现threadlocal并不是之前理解的控制线程用的东西,它其实也属于一类变量,只不过是线程的局部变量,它的作用就是实现线程间对该变量的唯一线程调 ...

  8. OpenCV 之 直方图处理

    1  图像直方图 1.1  定义 统计各个像素值,在整幅图像中出现次数的一个分布函数.        1.2  标准化 $\quad p_r(r_k) = \frac{n_k}{MN} \qquad ...

  9. 【转载】Android控件属性大全

    控件属性: android属性 Android功能强大,界面华丽,但是众多的布局属性就害苦了开发者,下面这篇文章结合了网上不少资料, 第一类:属性值为true或falseandroid:layout_ ...

  10. Android布局属性集合

    <!-- android:id  —— 为控件指定相应的ID android:text —— 指定控件当中显示的文字,需要注意的是,这里尽量使用strings.xml文件当中的字符串 andro ...