使用 Bolt 实现 GridView 表格控件
用 Bolt 实现了一个表格控件:
1. 提供 Insert,Remove,Get,Set 接口,可以为表格增删数据;
2. 通过 ItemClass, ItemSetDataFunc 属性来指定显示数据所用的 itemObj;
3. 不会每个 data 都创建 itemObj 来显示, 只为需要显示的数据创建 itemObj;
4. 提供 AttachItemEvent 接口,可以监听 itemObj 向外发出的事件;
5. 根据屏幕大小,列数可以自适应;
6. 根据屏幕大小,每一列的宽度可以自适应;
gridview.xml
<xlue>
<control class="GridView">
<attr_def>
<attr name="ItemClass" type="string" /> <!-- 子控件类名 -->
<attr name="ItemWidth" type="int" /> <!-- 子控件宽度 -->
<attr name="ItemHeight" type="int" /> <!-- 子控件高度 -->
<attr name="ItemSetDataFunc" type="string" /> <!-- 子控件 SetData 函数名,GridView 自动调用子控件的 SetData 函数来为子控件设定数据 --> <attr name="ColumnNum" type="int">
<default>1</default>
</attr>
<attr name="AutoColumnCount" type="bool"> <!-- 列数根据 GridView 控件宽度自适应, 为 true 则 ColumnNum, AutoColumnWidth 属性失效 -->
<default>false</default>
</attr>
<attr name="AutoColumnWidth" type="bool"> <!-- 子控件的宽度根据 GridView 控件宽度自适应, 为 true 则 ItemWidth 属性失效 -->
<default>false</default>
</attr> <attr name="ColumnSpace" type="int"> <!-- 列与列之间的间隙 -->
<default>0</default>
</attr>
<attr name="RowSpace" type="int"> <!-- 行与行之间的间隙 -->
<default>0</default>
</attr> <attr name="ScrollBarBkg" type="string" /> <!-- 滚动条背景 texture id -->
<attr name="ScrollBarSliderNormal" type="string" /> <!-- 滚动条滑块 normal 态 texture id -->
<attr name="ScrollBarSliderHover" type="string" /> <!-- 滚动条滑块 hover 态 texture id -->
<attr name="ScrollBarSliderDown" type="string" /> <!-- 滚动条滑块 down 态 texture id -->
</attr_def>
<method_def>
<ResetData file="GridView.xml.lua" func="ResetData" />
<InsertData file="GridView.xml.lua" func="InsertData" />
<RemoveData file="GridView.xml.lua" func="RemoveData" /> <SetData file="GridView.xml.lua" func="SetData" />
<GetData file="GridView.xml.lua" func="GetData" /> <AttachItemEvent file="GridView.xml.lua" func="AttachItemEvent" /> <!-- 监听子控件的事件 -->
<DetachItemEvent file="GridView.xml.lua" func="DetachItemEvent" /> <!-- 取消监听子控件的事件 -->
</method_def>
<event_def>
</event_def>
<objtemplate>
<children>
<obj id="container" class="LayoutObject">
<attr>
<left>0</left>
<top>0</top>
<width>father.width</width>
<height>father.height</height>
<limitchild>1</limitchild>
</attr>
<eventlist>
<event name="OnPosChange" file="GridView.xml.lua" func="Container_OnPosChange" />
<event name="OnMouseWheel" file="GridView.xml.lua" func="Container_OnMouseWheel" />
</eventlist>
</obj>
<obj id="vscrollbar.bkg" class="TextureObject">
<attr>
<left>father.width-12</left>
<top>0</top>
<width>12</width>
<height>father.height</height>
<zorder>100</zorder>
</attr>
<children>
<obj id="vscrollbar.slider" class="TextureObject">
<attr>
<left>2</left>
<top>0</top>
<width>8</width>
<height>0</height>
<zorder>1000</zorder>
</attr>
<eventlist>
<event name="OnLButtonDown" file="GridView.xml.lua" func="VScrollBar_OnLButtonDown" />
<event name="OnLButtonUp" file="GridView.xml.lua" func="VScrollBar_OnLButtonUp" />
<event name="OnMouseMove" file="GridView.xml.lua" func="VScrollBar_OnMouseMove" />
<event name="OnMouseLeave" file="GridView.xml.lua" func="VScrollBar_OnMouseLeave" />
<event name="OnMouseWheel" file="GridView.xml.lua" func="Container_OnMouseWheel" redirect="father:container" />
</eventlist>
</obj>
</children>
</obj>
</children>
<eventlist>
<event name="OnInitControl" file="GridView.xml.lua" func="OnInitControl" />
<event name="OnDestroy" file="GridView.xml.lua" func="OnDestroy" />
</eventlist>
</objtemplate>
</control>
</xlue>
gridview.xml.lua
------------------------------- 以下是外部函数 -------------------------------- -- 重置列表
function ResetData(ctrlObj, dataList)
local attr = ctrlObj:GetAttribute() -- 列表置顶
attr.VirtualTop = -- 先清空,再添加新数据
ctrlObj:RemoveData(, #attr.IdexToDataMap)
ctrlObj:InsertData(, dataList)
end -- 在列表指定位置插入数据
function InsertData(ctrlObj, insertIndex, dataList)
local attr = ctrlObj:GetAttribute() if insertIndex == nil or dataList == nil then
return
end
if type(dataList) ~= "table" or #dataList == then
return
end
if insertIndex < or insertIndex > #attr.IdexToDataMap + then
return
end -- 更新 IdexToDataMap 表
for i, data in ipairs(dataList) do
local dataInfo = {}
dataInfo.data = data -- data 可能重复,所以不能当作 key, 这里把 data 放到 dataInfo 里面,就可以用 dataInfo 作 key 了
table.insert(attr.IdexToDataMap, insertIndex+i-, dataInfo)
end -- 更新 ItemToIdexMap 表
-- 因为插入了新数据, insertIndex 后面的 dataIndex 增加了 #dataList
for itemId, dataIndex in pairs(attr.ItemToIdexMap) do
if dataIndex >= insertIndex then
attr.ItemToIdexMap[itemId] = dataIndex + #dataList
end
end RefreshUI(ctrlObj)
end -- 删除数据
function RemoveData(ctrlObj, beginIndex, endIndex)
local attr = ctrlObj:GetAttribute() if beginIndex == nil or endIndex == nil then
return
end
if beginIndex < or beginIndex > #attr.IdexToDataMap then
return
end
if endIndex < beginIndex or endIndex > #attr.IdexToDataMap then
return
end -- 更新 IdexToDataMap 表
local removedDataList = {}
for i=beginIndex, endIndex do
table.insert(removedDataList, attr.IdexToDataMap[beginIndex])
table.remove(attr.IdexToDataMap, beginIndex)
end -- 更新 DataToItemMap 表
local removedItemList = {}
for _, removedDataInfo in ipairs(removedDataList) do
if attr.DataToItemMap[removedDataInfo] then
table.insert(removedItemList, attr.DataToItemMap[removedDataInfo])
attr.DataToItemMap[removedDataInfo] = nil
end
end -- 更新 ItemToIdexMap 表
for _, removedItemId in ipairs(removedItemList) do
if attr.ItemToIdexMap[removedItemId] then
-- 删掉不用的项
attr.ItemToIdexMap[removedItemId] = nil
RecycleItemObj(ctrlObj, removedItemId)
end
end
for itemId, dataIndex in pairs(attr.ItemToIdexMap) do
if dataIndex >= endIndex then
-- 因为删除了旧数据, endIndex 后面的 dataIndex 减少了 endIndex-beginIndex+1
attr.ItemToIdexMap[itemId] = dataIndex - (endIndex-beginIndex+)
end
end RefreshUI(ctrlObj)
end -- 设置数据
function SetData(ctrlObj, dataIndex, data)
local attr = ctrlObj:GetAttribute() -- 更新数据
if attr.IdexToDataMap[dataIndex] == nil then
return
end
attr.IdexToDataMap[dataIndex].data = data -- 更新界面
local dataInfo = attr.IdexToDataMap[dataIndex]
local itemId = attr.DataToItemMap[dataInfo]
if itemId == nil then
return
end
SetItemData(ctrlObj, itemId, data)
end -- 获取数据
function GetData(ctrlObj, dataIndex)
local attr = ctrlObj:GetAttribute() local dataInfo = attr.IdexToDataMap[dataIndex]
if dataInfo == nil then
return
end return dataInfo.data
end -- 监听 itemObj 发出的事件
function AttachItemEvent(ctrlObj, eventName, callback)
local attr = ctrlObj:GetAttribute() if eventName == nil or callback == nil then
return
end if attr.EventCookieMap[eventName] == nil then
attr.EventCookieMap[eventName] = {}
end -- 分配 cookie
local cookie = attr.EventCookieMap.CookieNum
attr.EventCookieMap.CookieNum = cookie +
-- 记录到 EventCookieMap 中
attr.EventCookieMap[eventName][cookie] = callback if attr.ItemCookieMap[eventName] ~= nil then
-- ItemCookieMap[eventName] 不为空,说明 itemObj 已经监听了这个事件
return cookie
end -- 为每个 itemObj 设置 eventName 的监听器
attr.ItemCookieMap[eventName] = {}
for _, itemId in pairs(attr.DataToItemMap) do
local itemObj = ctrlObj:GetControlObject(itemId)
local itemCookie = itemObj:AttachListener(eventName, true, function(...)
OnItemEvent(eventName, select(, ...))
end) -- 把 itemId 和 cookie 的对应关系记到表里面
attr.ItemCookieMap[eventName][itemId] = itemCookie
end return cookie
end -- 取消监听器
function DetachItemEvent(ctrlObj, eventName, cookie)
local attr = ctrlObj:GetAttribute() if eventName == nil or cookie == nil then
return
end
if attr.EventCookieMap[eventName] == nil then
return
end -- 去除 cookie 对应的监听器
attr.EventCookieMap[eventName][cookie] = nil local count =
for cookie, callback in pairs(attr.EventCookieMap[eventName]) do
count = count +
end
if count > then
return
end -- 如果已经没有人监听这个事件了,那么 itemObj 也不用监听这个事件了
if attr.ItemCookieMap[eventName] == nil then
return
end
for itemId, itemCookie in pairs(attr.ItemCookieMap[eventName]) do
local itemObj = ctrlObj:GetControlObject(itemId)
itemObj:RemoveListener(eventName, itemCookie)
end attr.ItemCookieMap[eventName] = nil
attr.EventCookieMap[eventName] = nil
end ------------------------------- 以下是事件函数 -------------------------------- function OnInitControl(ctrlObj)
local attr = ctrlObj:GetAttribute() -- 用三个 map 来记录 dataIndex, dataInfo, itemId 三者的关联,便于互相之间快速索引
attr.IdexToDataMap = {}
attr.DataToItemMap = {}
attr.ItemToIdexMap = {} -- 虚拟 Top ,指的是列表的第一个 dataInfo 在界面中应该处于的位置,依据这个来计算每个 dataInfo 的 top
attr.VirtualTop = -- 回收不用的 itemObj
attr.RecycleItemList = {}
attr.ItemIdCache = {}
attr.ItemIdMax = -- 记录外部调用 AttachItemEvent 时分配的 cookie 和 callback
attr.EventCookieMap = {}
attr.EventCookieMap.CookieNum = -- cookie 的分配就简单地 +1 好了
-- 记录每个 itemObj 关注事件所返回的 cookie
attr.ItemCookieMap = {} if attr.ScrollBarBkg ~= nil then
local vsbarBkgObj = ctrlObj:GetControlObject("vscrollbar.bkg")
vsbarBkgObj:SetTextureID(attr.ScrollBarBkg)
end
if attr.ScrollBarSliderNormal ~= nil then
local vsbarObj = ctrlObj:GetControlObject("vscrollbar.slider")
vsbarObj:SetTextureID(attr.ScrollBarSliderNormal)
end
end function OnDestroy(ctrlObj) end function Container_OnPosChange(containerObj, oldLeft, oldTop, oldRight, oldBottom, newLeft, newTop, newRight, newBottom)
local ctrlObj = containerObj:GetOwnerControl() local oldWidth, oldHeight = oldRight-oldLeft, oldBottom-oldTop
local newWidth, newHeight = newRight-newLeft, newBottom-newTop
if newWidth == oldWidth and newHeight == oldHeight then
-- 控件大小未改变,不需要需要刷新
return
end RefreshUI(ctrlObj)
end function Container_OnMouseWheel(containerObj, x, y, distance, flags)
local ctrlObj = containerObj:GetOwnerControl()
local attr = ctrlObj:GetAttribute() local moveDistance = distance /
attr.VirtualTop = attr.VirtualTop + moveDistance RefreshUI(ctrlObj)
end function VScrollBar_OnLButtonDown(vsbarObj, x, y, flags)
local ctrlObj = vsbarObj:GetOwnerControl()
local attr = ctrlObj:GetAttribute() vsbarObj:SetCaptureMouse(true) if attr.ScrollBarSliderDown then
vsbarObj:SetTextureID(attr.ScrollBarSliderDown)
end attr.VScrollBar_LButtonDown_PosY = y
end function VScrollBar_OnLButtonUp(vsbarObj, x, y, flags)
local ctrlObj = vsbarObj:GetOwnerControl()
local attr = ctrlObj:GetAttribute() vsbarObj:SetCaptureMouse(false) if attr.ScrollBarSliderNormal then
vsbarObj:SetTextureID(attr.ScrollBarSliderNormal)
end attr.VScrollBar_LButtonDown_PosY =
end function VScrollBar_OnMouseMove(vsbarObj, x, y, flags)
local ctrlObj = vsbarObj:GetOwnerControl()
local attr = ctrlObj:GetAttribute() if flags == then -- 鼠标左键被按下
local moveDistance = y - attr.VScrollBar_LButtonDown_PosY
moveDistance = - moveDistance
attr.VirtualTop = attr.VirtualTop + moveDistance RefreshUI(ctrlObj)
else
if attr.ScrollBarSliderHover then
vsbarObj:SetTextureID(attr.ScrollBarSliderHover)
end
end
end function VScrollBar_OnMouseLeave(vsbarObj, x, y)
local ctrlObj = vsbarObj:GetOwnerControl()
local attr = ctrlObj:GetAttribute() if attr.ScrollBarSliderNormal then
vsbarObj:SetTextureID(attr.ScrollBarSliderNormal)
end
end ------------------------------- 以下是私有函数 -------------------------------- function RefreshUI(ctrlObj)
-- 调整 列数
AdjustColumnNum(ctrlObj) -- 调整 列宽度
AdjustColumnWidth(ctrlObj) -- 调整 VirtualTop
AdjustVirtualTop(ctrlObj) -- 重新绑定 data 到 itemObj
RebindDataToItem(ctrlObj) -- 调整 itemObj 的位置
AdjustItemPos(ctrlObj) -- 调整滚动条位置
AdjustVScrollBarPos(ctrlObj)
end function AdjustColumnNum(ctrlObj)
local attr = ctrlObj:GetAttribute()
local containerObj = ctrlObj:GetControlObject("container") local l,t,r,b = containerObj:GetObjPos()
local containerWidth, containerHeight = r-l, b-t if attr.AutoColumnCount == true then
attr.ColumnNum = math.floor(containerWidth / (attr.ItemWidth+attr.ColumnSpace))
end
end function AdjustColumnWidth(ctrlObj)
local attr = ctrlObj:GetAttribute()
local containerObj = ctrlObj:GetControlObject("container") local l,t,r,b = containerObj:GetObjPos()
local containerWidth = r-l if attr.AutoColumnCount == false then
if attr.AutoColumnWidth == true then
attr.ItemWidth = math.floor((containerWidth+attr.ColumnSpace) / attr.ColumnNum)
end
end
end function AdjustVirtualTop(ctrlObj)
local attr = ctrlObj:GetAttribute()
local containerObj = ctrlObj:GetControlObject("container") local virtualBottom = attr.VirtualTop + math.ceil(#attr.IdexToDataMap / attr.ColumnNum) * (attr.ItemHeight+attr.RowSpace)
local l,t,r,b = containerObj:GetObjPos()
local containerHeight = b-t -- 不要让列表底部有间隙
if virtualBottom < containerHeight then
attr.VirtualTop = attr.VirtualTop + containerHeight - virtualBottom
end
-- 不要让列表顶部有间隙
if attr.VirtualTop > then
attr.VirtualTop =
end
end function RebindDataToItem(ctrlObj)
local attr = ctrlObj:GetAttribute()
local containerObj = ctrlObj:GetControlObject("container") -- 1. 计算哪些 dataInfo 处于可视范围
local visibleDataMap = {}
local l,t,r,b = containerObj:GetObjPos()
local containerHeight = b-t
local beginRow = math.floor( (-attr.VirtualTop) / (attr.ItemHeight+attr.RowSpace) )
local endRow = math.ceil( (containerHeight-attr.VirtualTop) / (attr.ItemHeight+attr.RowSpace) ) +
local beginIndex = beginRow * attr.ColumnNum +
local endIndex = endRow * attr.ColumnNum
beginIndex = math.min(beginIndex, #attr.IdexToDataMap)
endIndex = math.min(endIndex, #attr.IdexToDataMap) if beginIndex > and endIndex >= beginIndex then
for dataIndex=beginIndex, endIndex do
local dataInfo = attr.IdexToDataMap[dataIndex]
visibleDataMap[dataInfo] = dataIndex
end
end -- 2. 回收不用的 itemObj
local inVisibleDataMap = {}
for dataInfo, itemId in pairs(attr.DataToItemMap) do
if visibleDataMap[dataInfo] == nil then
inVisibleDataMap[dataInfo] = itemId
end
end
for dataInfo, itemId in pairs(inVisibleDataMap) do
attr.DataToItemMap[dataInfo] = nil
attr.ItemToIdexMap[itemId] = nil
RecycleItemObj(ctrlObj, itemId)
end -- 3. 为没有绑定 itemObj 的 dataInfo 进行绑定
for dataInfo, dataIndex in pairs(visibleDataMap) do
if attr.DataToItemMap[dataInfo] == nil then
local itemObj = CreateItemObj(ctrlObj)
local itemId = itemObj:GetID() attr.DataToItemMap[dataInfo] = itemId
attr.ItemToIdexMap[itemId] = dataIndex -- 初次绑定的 itemObj, 要调用 SetDataFunc
SetItemData(ctrlObj, itemId, dataInfo.data)
end
end -- 4. 清空不用的 itemObj
CleanItemObj(ctrlObj)
end function AdjustItemPos(ctrlObj)
local attr = ctrlObj:GetAttribute() local function CalculateItemPos(dataIndex)
local containerObj = ctrlObj:GetControlObject("container") local left = math.floor((dataIndex-) % attr.ColumnNum) * (attr.ItemWidth + attr.ColumnSpace)
local top = math.floor((dataIndex-) / attr.ColumnNum) * (attr.ItemHeight + attr.RowSpace) + attr.VirtualTop
local right = left + attr.ItemWidth
local bottom = top + attr.ItemHeight return left, top, right, bottom
end for dataInfo, itemId in pairs(attr.DataToItemMap) do
local itemObj = ctrlObj:GetControlObject(itemId)
local dataIndex = attr.ItemToIdexMap[itemId]
local left, top, right, bottom = CalculateItemPos(dataIndex)
local l,t,r,b = itemObj:GetObjPos()
if left ~= l or top ~= t or right ~= r or bottom ~= b then
itemObj:SetObjPos(left, top, right, bottom)
end
end
end function AdjustVScrollBarPos(ctrlObj)
local attr = ctrlObj:GetAttribute()
local vsbarObj = ctrlObj:GetControlObject("vscrollbar.slider")
local vsbarBkgObj = ctrlObj:GetControlObject("vscrollbar.bkg")
local containerObj = ctrlObj:GetControlObject("container") local listTop = attr.VirtualTop
local listBottom = attr.VirtualTop + math.ceil(#attr.IdexToDataMap / attr.ColumnNum) * (attr.ItemHeight+attr.RowSpace)
local listHeight = listBottom - listTop
local l,t,r,b = containerObj:GetObjPos()
local containerHeight = b-t
local l,t,r,b = vsbarBkgObj:GetObjPos()
local vsbarBkgHeight = b-t -- 大小
local vsbHeight =
if listHeight > containerHeight then
vsbHeight = vsbarBkgHeight * containerHeight / listHeight
end -- 位置
local vsbTop =
if listHeight > containerHeight then
vsbTop = vsbarBkgHeight * (-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 -- 滚动调消失时, 背景也要消失
if vsbHeight == then
vsbarBkgObj:SetVisible(false)
else
vsbarBkgObj:SetVisible(true)
end
end function CreateItemObj(ctrlObj)
local attr = ctrlObj:GetAttribute()
local containerObj = ctrlObj:GetControlObject("container")
local factory = XLGetObject("Xunlei.UIEngine.ObjectFactory") -- 回收站里有 itemObj, 直接返回
if #attr.RecycleItemList > then
local itemObj = attr.RecycleItemList[#attr.RecycleItemList]
table.remove(attr.RecycleItemList)
return itemObj
end -- 分配 itemId
local itemId = nil
if #attr.ItemIdCache > then
itemId = attr.ItemIdCache[#attr.ItemIdCache]
table.remove(attr.ItemIdCache)
else
itemId = "item" .. attr.ItemIdMax
attr.ItemIdMax = attr.ItemIdMax +
end -- 创建 itemObj
local itemObj = factory:CreateUIObject(itemId, attr.ItemClass)
containerObj:AddChild(itemObj) -- 设置监听器
for eventName, _ in pairs(attr.ItemCookieMap) do
local itemCookie = itemObj:AttachListener(eventName, true, function(...)
OnItemEvent(eventName, select(, ...))
end) -- 把 itemObj 和 cookie 的关系记到表里面
attr.ItemCookieMap[eventName][itemObj] = itemCookie
end return itemObj
end function RecycleItemObj(ctrlObj, itemId)
local attr = ctrlObj:GetAttribute()
local itemObj = ctrlObj:GetControlObject(itemId) if itemObj == nil then
return
end
table.insert(attr.RecycleItemList, itemObj)
end function CleanItemObj(ctrlObj)
local attr = ctrlObj:GetAttribute()
local containerObj = ctrlObj:GetControlObject("container") for i,itemObj in ipairs(attr.RecycleItemList) do
-- itemId 用不着了,回收到 ItemIdCache 里下次使用
local itemId = itemObj:GetID()
table.insert(attr.ItemIdCache, itemId) if attr.ItemCookieMap[eventName] then
attr.ItemCookieMap[eventName][itemObj] = nil
end containerObj:RemoveChild(itemObj)
end attr.RecycleItemList = {}
end function SetItemData(ctrlObj, itemId, data)
local attr = ctrlObj:GetAttribute()
local itemObj = ctrlObj:GetControlObject(itemId) if itemObj == nil then
return
end
itemObj[attr.ItemSetDataFunc](itemObj, data)
end -- itemObj 发出事件时的回调函数
function OnItemEvent(eventName, ...)
local itemObj = select(, ...)
local ctrlObj = itemObj:GetOwnerControl()
local attr = ctrlObj:GetAttribute()
local itemId = itemObj:GetID()
local dataIndex = attr.ItemToIdexMap[itemId] if attr.EventCookieMap[eventName] == nil then
return
end for cookie, callback in pairs(attr.EventCookieMap[eventName]) do
callback(ctrlObj, dataIndex, select(, ...))
end
end
使用 Bolt 实现 GridView 表格控件的更多相关文章
- Gridview表格控件
Gridview表格控件 效果图: 分析: 使用和ListvVew很像,都是经过适配器将数据绑定到控件上 具体步骤如下: 1.创建GridView控件,并指定列数 android:numColumns ...
- Android入门之GridView(表格控件)
GridView是一个表格控件,可以在每个单元格中显示自定义的View或者字符串.在这里我们要实现一个图标下方有文字的效果. 1.首先我们应自定义布局文件image_text.xml.代码如下: &l ...
- 深入浅出ExtJS 第三章 表格控件
3.1 表格的特性简介 >.Ext中的表格功能:包括排序/缓存/拖动/隐藏某一列/自动显示行号/列汇总/单元格编辑等实用功能; >.表格由类Ext.grid.GridPanel定义,继承自 ...
- 动态生成表格呈现还是将表格直接绑定gridview等控件呈现的开发方式选择依据
动态生成表格呈现还是将表格直接绑定gridview等控件呈现的开发方式选择依据:由存储过程决定,如果编写的存储过程可以生成需要呈现的表格则直接绑定,否则要动态生成表格
- C# DatrgridView表格控件的一些用法
public class useDatrgrivView { string conn = null; string sqlComm = null; DataSet das = null; DataGr ...
- 在GridControl表格控件中实现多层级主从表数据的展示
在一些应用场景中,我们需要实现多层级的数据表格显示,如常规的二级主从表数据展示,甚至也有多个层级展示的需求,那么我们如何通过DevExpress的GridControl控表格件实现这种业务需求呢?本篇 ...
- 如何在web中实现类似excel的表格控件
Execl功能非常强大,内置的很多函数或公式可以大大提高对数据的加工处理能力.那么在web中有没有类似的控件呢?经过一番搜寻,发现handsontable具备了基本的excel功能支持公式,同时能对数 ...
- 最好的Angular2表格控件
现在市面上有大量的JavaScript数据表格控件,包括开源的第三方的和自产自销的.可以说Wijmo的Flexgrid是目前适应Angular 2的最好的表格控件. Angular 2数据表格基本要求 ...
- 类型“GridView”的控件“GridView1”必须放在具有 runat=server 的窗体标记内。
错误的写法: if (this.GridView1.Rows.Count > 0) { string style = @"<style& ...
随机推荐
- python中出现 “'gbk' codec can't decode byte 0xf3 in position 20: illegal multibyte sequence”问题
其实是打开文件方法open()中的模式有r,w,a等. 请看: r 以只读方式打开文件.文件的指针将会放在文件的开头.这是默认模式. rb 以二进制格式打开一个文件用于只读.文件指针将会放在文件的开头 ...
- Navicat查看MySQL日志
Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable ...
- (转)NIO 文件锁定
文件锁定 概述 文件锁定初看起来可能让人迷惑.它 似乎 指的是防止程序或者用户访问特定文件.事实上,文件锁就像常规的 Java 对象锁 ― 它们是 劝告式的(advisory) 锁.它们不阻止任何形式 ...
- [Android Pro] android中permission_group与permisson区别、作用
转载:http://blog.csdn.net/feng88724/article/details/6409313 其实Android在定义 permission 时, 为每个Permission都进 ...
- 文本域光标操作(选、添、删、取)的jQuery扩展
; (function ($) { /* * 文本域光标操作(选.添.删.取)的jQuery扩展 @Mr.Think http://mrthink.net/text-field-jquery-exte ...
- CCPlatformConfig(设置执行平台 iOS android win32等。。。)
#ifndef __CC_PLATFORM_CONFIG_H__ #define __CC_PLATFORM_CONFIG_H__ /** Config of cocos2d-x project, p ...
- Spring集成ActiveMQ配置 --转
转自:http://suhuanzheng7784877.iteye.com/blog/969865 集成环境 Spring采用2.5.6版本,ActiveMQ使用的是5.4.2,从apache站点可 ...
- AngularJS路由设置方法
Module.config(['$routeProvider', function($routeProvider) { $routeProvider .when('/mall-home', { tem ...
- connect(mapStateToProps,mapDispatchToProps) 的写法
1.写法 import { connect } from 'redux'; import { loading, asyncRequset } from '../../actions/common'; ...
- openerp 6.0.2库存业务
一.复式库存(Double-Entry Stock Management)和库存移动(Stock Move) OpenERP的库存管理采取了独特的复式库存(Double-Entry Stock Man ...