使用 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& ...
随机推荐
- 为什么控制台console.log一个值,总是会多一个undefined
我们发现在浏览器控制台打印东西的时候,末尾总是会莫名其妙多出一个undefined? 这是为什么呢? 大胆猜测一下,应该执行的函数没有返回值,而浏览器默认要打印出执行函数的返回值,才会打印undefi ...
- 前端对比插件JS
https://github.com/kpdecker/jsdiff demo http://kpdecker.github.io/jsdiff/ 缺点:文件大于10M的就比较不了了 用于比对两段HT ...
- Android Studio断点调试
Android Studio断点调试 Android Studio包含一个debugger程序,可以帮助你在模拟器和真机上调试你的android应用.通过Android Studio的debugger ...
- nmap原理及使用方法
NMap,也就是Network Mapper,是Linux下的网络扫描和嗅探工具包. 1简介 nmap是一个网络连接端扫描软件,用来扫描网上电脑开放的网络连接端.确定哪些服务运行在哪些连接端,并且推断 ...
- WebService基于SoapHeader实现安全认证[webservice][.net][安全][soapheader]
摘 自: http://blog.sina.com.cn/s/blog_72b7a82d0100yyp8.html WebService基于SoapHeader实现安全认证[webservice][. ...
- 教你如何搭建vue项目
笔者工作也有一些时间,需要用vue写项目时也总是项目组长已经把项目搭建好了, 偶尔心血来潮想试着自己搭建一个vue项目 我们搭建vue项目呢主要是用到了vue-cli来搭建,但是前提是必须要已经安装好 ...
- PHP-时间小结
//获得本周(本天)时间戳的起始和结束//本周星期一时间戳$monday = mktime(0, 0, 0, date("m",strtotime("last Monda ...
- 使用jstack和TDA进行java线程dump分析
转载:http://blog.csdn.net/everlasting_188/article/details/51943095 1.jstack重点关注 命令行:jstack [-l][F] pid ...
- 动态网站技术CGI
递信息的规程.CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静三种主流的动态网站技术: ASP JSP PHP 除之外,此还要了解的动态网站技术 ...
- 适合移动手机使用的js环形菜单特效插件
blooming-menu是一款适合在移动手机上使用的js环形菜单插件.该环形菜单提供了众多的參数,通过结合CSS3动画制作出效果很炫酷的圆形菜单展开和隐藏动画效果. 以下是这个圆形菜单菜价的可用參数 ...