改造listview使其实现表格内编辑框editbox和下拉列表框combobox功能
By
admin
at 2022-10-29 • 1人收藏 • 2682人看过
一直以来winform的listview都只是作为数据输出显示来用, 想要实现数据的双向操作比较难
之前都需要用其他表格类控件实现这个双击编辑文本,双击实现下拉列表框选择文本功能, 而且其中有很大一部分是ocx组件,
那么就需要在客户电脑上regsvr32 注册它, 这样就需要管理员权限, 这样操作并不是很好,
于是考虑着手动改造listview使其满足我的需求.
还好, aardio范例里有个数据视图win.ui.grid的库可供参考, 我就是根据这个库内的实现方法来升级改造的.
下面我在原listview grid基础上增加了, 双击指定列 可直接编辑文本 / 弹出下拉框选择文本 功能.

listviewEX.aardio 库代码如下:
//listview 扩展
import win.ui.ctrl.edit;
import win.ui.ctrl.combobox;
namespace win.ui;
class listviewEx{
ctor( listview ){
this = listview;
this.fullRow = 1;
this.gridLines = 1;
this.columnsEditbox = {};//记录编辑框列号
this.columnsCombobox = {};//记录下拉框列号和列表值
//添加下拉框模板
this.addCtrl(
combobox = {
cls="combobox";font = LOGFONT( h = -19 );left = 0;top = 0;
right = 50;bottom = 50;autoResize = false ;hide = 1;edge = 1;mode="dropdownlist";
wndproc = function( hwnd, message, wParam, lParam ){
var update;
var event = owner.event;
if( message == 308 ) {
update = true;
}
if( update ){
owner.show(false);
var t = this.getItemText(event.iItem,event.iSubItem );
if( t!= owner.text ){
if( this.onEditChanged ) {
if( false === this.onEditChanged(owner.text, event.iItem, event.iSubItem))
return;
}
this.setItemText( owner.text, event.iItem, event.iSubItem );
}
if(this.onEditEnd){
this.onEditEnd(event.iItem, event.iSubItem);
}
}
}
}
);
//添加编辑框模板
this.addCtrl(
editBox = {
cls="edit";font = LOGFONT( h = -19 );left = 0;top = 0;
right = 50;bottom = 50;autoResize = false ;hide = 1;edge = 1;
wndproc = function( hwnd, message, wParam, lParam ){
var update;
var event = owner.event;
if( ( message = 0x8/*_WM_KILLFOCUS*/) || (message == 0x101/*_WM_KEYUP*/ && wParam == 0xD/*_VK_RETURN*/ ) ) {
update = true;
}
elseif(message == 0x201/*_WM_LBUTTONDOWN*/ ){
var x,y = ..win.getMessagePos(lParam)
var rc = this.editBox.getClientRect();
if( ! ::PtInRect(rc,x,y) ) update = true;
this.editBox.capture = !update;
}
elseif(message == 0x101/*_WM_KEYUP*/){
if( wParam == 0xD/*_VK_RETURN*/ ) update = true;
elseif( wParam == 0x1B/*_VK_ESC*/){
owner.text = this.getItemText(event.iItem,event.iSubItem );
update = true;
}
}
if( update ){
owner.show(false);
var t = this.getItemText(event.iItem,event.iSubItem );
if( t!= owner.text ){
if( this.onEditChanged ) {
if( false === this.onEditChanged(owner.text, event.iItem, event.iSubItem))
return;
}
this.setItemText( owner.text, event.iItem, event.iSubItem );
}
if(this.onEditEnd){
this.onEditEnd(event.iItem, event.iSubItem);
}
}
}
}
)
};
//绘制下拉框
beginCombobox = function(iItem,iSubItem){
var combobox = this.combobox;
if( ..win.isVisible(combobox.hwnd) ) return;
var event = this.combobox.event;
if(iItem===null && iSubItem===null) {
iItem = event.iItem;
iSubItem = event.iSubItem;
}
else {
event = {
iItem = iItem;
iSubItem = iSubItem;
};
combobox.event = event;
}
combobox.items = this.columnsCombobox[iSubItem];
combobox.selText=this.getItemText(iItem,iSubItem);
var rc=this.getItemRect(iItem,iSubItem,,2/*_LVIR_LABEL*/ );
rc.inflate(2,2);
combobox.setRect(rc);
combobox.showDropDown();
return true;
};
//绘制编辑框
beginEdit = function(iItem,iSubItem){
var edit = this.editBox;
if( ..win.isVisible(edit.hwnd) ) return;
var event = this.editBox.event;
if(iItem===null && iSubItem===null) {
iItem = event.iItem;
iSubItem = event.iSubItem;
}
else {
event = {
iItem = iItem;
iSubItem = iSubItem;
};
edit.event = event;
}
edit.text=this.getItemText(iItem,iSubItem);
var rc=this.getItemRect(iItem,iSubItem,,2/*_LVIR_LABEL*/ );
rc.inflate(2,2);
edit.setRect(rc);
edit.show();
edit.setFocus();
edit.capture = true;
return true;
};
//设置下拉框模式 列号/下拉值
setcolumnsCombobox = function(iSubItem,tab,...){
var c = type(tab) === "table" ? tab : {tab,...}
this.columnsCombobox[iSubItem] = c;
};
//设置编辑框模式 列号
setcolumnsEditbox = function(...){
var c = type(...) === "table" ? ... : {...}
for(i,idx in c) this.columnsEditbox[idx] = 1;
};
prenotify = {
[0xFFFFFFFD/*_NM_DBLCLK*/] = function(id,code,ptr){
var event = this.getNotifyMessage(code,ptr);
if( ! event.iItem && event.iSubItem ) return ;
//启用 编辑框
if( this.columnsEditbox[event.iSubItem] ){
this.editBox.event = event;
this.beginEdit();
};
//启用 下拉框
if( this.columnsCombobox[event.iSubItem] ){
this.combobox.event = event;
this.beginCombobox();
};
};
}
}
/**intellisense()
win.ui.listviewEx(__) = 参数必须指定一个listview控件对象\n返回一个可编辑单元格的列表视图对象,\n\n鼠标左键单击单元格、或者按空格键开始编辑,\n回车完成编辑,ESC键撤消编辑,回车+上下方向键快速移动到其他项,\n用户完成编辑后会触发onEditChanged事件.\n!listview.
win.ui.listviewEx() = !win_ui_listviewEx.
!win_ui_listviewEx.edit = 实现编辑功能的edit控件\n此功能需要扩展listview并实现了编辑功能的的控件才能支持\n!edit.
!win_ui_listviewEx.combobox = 实现编辑功能的edit控件\n此功能需要扩展listview并实现了编辑功能的的控件才能支持\n!combobox.
!win_ui_listviewEx.onEditChanged(text,iItem,iSubItem) = @.onEditChanged = function(text,iItem,iSubItem){
__/*控件完成编辑,并且文本已变更,\ntext为改变后的文本,iItem为行号,iSubItem为列号\n此功能需要扩展listview并实现了编辑功能的的控件才能支持\n返回false可中止更新显示文本*/
}
!win_ui_listviewEx.onEditEnd(iItem,iSubItem) = @.onEditEnd = function(iItem,iSubItem){
__/*控件完成编辑*/
}
!win_ui_listviewEx.setTable(__) = 用listview控件显示数据表\n此函数会自动清空控件之前的所有项,\n如果没有创建任何列,则自动创建列\n\n数据表应当包含行组成的数组,\n每行的数据列必须是由列名和列值组成的键值对\n数据表应使用fields包含需要显示的列名称数组\n可以通过fields控制要显的列、以及要显示的顺序\n\n使用sqlite,access,sqlServer等数据库对象提供的getTable函数可获取符合此规格的数据表
!win_ui_listviewEx.setColumns(__) = 用一个字符串数组指定要显示的列\n如果参数为空则清空所有列
!win_ui_listviewEx.setcolumnsCombobox(__) = 可以使用一个或多个参数指定要禁止编辑的列序号,\n也可以用一个数组参数指定多个列序号
!win_ui_listviewEx.setcolumnsEditbox(__) = 可以使用一个或多个参数指定要编辑的列序号,\n也可以用一个数组参数指定多个列序号
!win_ui_listviewEx.clear() = 清空所有行
!win_ui_listviewEx.clear(true) = 清空所有行,并且清空所有列
end intellisense**/使用的方法如下:
import win.ui;
/*DSG{{*/
mainForm = win.form(text="testListviewEx";right=740;bottom=315;bgcolor=16777215)
mainForm.add(
listview={cls="listview";left=13;top=8;right=729;bottom=309;border=1;db=1;dl=1;dr=1;dt=1;font=LOGFONT(h=-13);fullRow=1;gridLines=1;msel=false;vscroll=1;z=1}
)
/*}}*/
import console
console.open()
import win.ui.listviewEx;
var grid = win.ui.listviewEx(mainForm.listview);
grid.setcolumnsEditbox(2);
grid.setcolumnsCombobox(3,"10","1000","2000","5000");
grid.setcolumnsCombobox(4,{"Z+","Z-","ZNP+","ZNP-"});
grid.setcolumnsCombobox(5,{"急停","减速停"});
grid.onEditChanged = function(text,iItem,iSubItem){
console.log("onEditChanged",text,iItem,iSubItem)
}
import win.imageList;
var iml = win.imageList(1,30);
mainForm.listview.setImageList( iml,1/*_LVSIL_NORMAL*/ );
mainForm.listview.setColumns(
{"轴号","加减速时间","单脉冲运动量","找零方式","停止方式"},
{60,120,120,100,100},
{2,2,2,2,2},
);
var axisData = {};
for(i=1;20;1){
axisData[i]={};
axisData[i][1] = "轴"++i;
axisData[i][2] = "0.1";
axisData[i][3] = "1";
axisData[i][4] = "Z+";
axisData[i][5] = "急停";
}
mainForm.listview.items = axisData;
mainForm.show();
return win.loopMessage();主要看上面部分, 上面声明完所有的列功能, 下面还是用listview自己的功能实现代码.
示例工程下载:
欢迎大家来共同升级这个listviewEx库, 因为这个是第一个版本, 难免有很多繁琐或者bug存在.
如果有好的建议或者对代码进行了功能升级, 欢迎在下方留言分享.
谢谢
8 个回复 | 最后更新于 2025-06-13
the100s
2022-10-31
#1
厉害了
不知道你有没有注意,利用原生拓展的listview有时候,数据量比较大的时候,或者光标焦点还在的时候,会出现丢失和闪烁的情况。我之前写过一版,功能比这个可能要稍微多一些,但是使用过程中不理想,代码如下,抛砖引玉,希望大家能搞出更好的
//listviewExx拓展
/*这个库主要是通过父窗体创建唯一控件,然后修改控件的父窗体为listview实现
原因是lisveiw.addCtrl创建的combobox无法正确利用tracker处理消息(因为combobox是符合控件,由editbox和listbox组成的,其他控件都可以),
先在这里记录,待以后有空了研究
*/
import fonts.fontAwesome;
import win.debounce
import win.imageList
import win.ui.ctrl.combobox; //对于组合控件,动态创建时必须要先导入库
import win.ui.ctrl.datetimepick;
import math
import time
namespace bmt.ctrl;
class listviewExx{
ctor( lvCtrl ){
this=assert(lvCtrl,"请先指定listview对象");
this = lvCtrl;
this.ctrlSetting={}; //定义一个公共表,用于存放combobox的值
this.lvClr ={}; //设置背景色和字体颜色
this.currentRow=0; //当前选中的行号
this.currentCol=0; //当前选中的列号
this.currentCls=false; //当前显示的cls
this.bgclr135 = null; //奇数行背景颜色
this.bgclr246 = null; //偶数行背景颜色
this.fontclr135 = null; //奇数行字体颜色
this.fontclr246 = null; //偶数行字体颜色
//设置列标题图标
var iml = ..win.imageList(12,12); //排序时的小箭头,图像为w24*h12,分割宽度就是w12*h12 的整数倍
//iml.add('GIF\56\57a \0\15\0\x80\0\0\x80\x80\x80\xff\0\xff\33\xf9\4\0\0\0\0\0\44\0\0\0\0 \0\15\0\0\2\31\x8c\x8f\xa9\xcb\xed\15\xa3\x9c\xb4N\xf0\x80\xde\56k\xbfA\\\xd7\x84 \x97Y\xea\xca\xb6\xee\11\xc7F\1\0;', 0xff00ff);
iml.add('\x47\x49\x46\x38\x39\x61\x18\0\x0C\0\x91\0\0\0\0\0\xFF\xFF\xFF\xFF\0\xFF\xFF\xFF\xFF\x21\xF9\x04\x01\0\0\x03\0\x2C\0\0\0\0\x18\0\x0C\0\0\x02\x2C\x94\x05\x09\xC7\x96\x7D\x94\x82\x6E\x41\x29\xE9\x6B\xF3\x4D\x6E\x31\xDB\x18\x46\xE5\x75\x82\x94\xB9\x56\x2D\x92\x92\xAE\x0A\x2E\xDE\x26\xA6\x30\xA6\xE3\xF5\x87\x6A\x65\x0E\x05\0\x3B', 0xff00ff);
this.setColumnImageList(iml);
this.setFont(point=12;name='FontAwesome') //font=LOGFONT(h=-18;name='FontAwesome')
this.setExtended(0x10000/*_LVS_EX_DOUBLEBUFFER*/)//启用双缓冲,避免拖动滚动条时闪烁
this.gridLines=1
var _tm = ..time().getMilliTime();
var _cbb = "combobox"++_tm;
var _ddl = "ddl"++_tm;
var _edit = "edit"++_tm;
var _date = "date"++_tm;
//var _ckb = "ckb"++_tm;
this.parent.add(
[_cbb ] = {cls="combobox";items={};mode="dropdown"; notify = true;hide=1;vscroll=1;hscroll=1;z=1;}; //动态添加combobox类型按钮控件
[_ddl] = {cls="combobox";items={};mode="dropdownlist";notify = true;hide=1;edge=1;vscroll=1;hscroll=1;z=1;}; //动态添加dropdownlist 类型按钮控件
//[_ckb] = {cls="checkbox";text="选定";checked=false;notify = true;hide=1;z=1;}; //动态添checkbox类型按钮控件
[_edit] = {cls="edit";hide=1;edge=1;notify = true;z=1;}; //新增编辑功能
[_date]={cls="datetimepick";hide=1;edge=1;style=2;z=1} //新增日期控件
);
/*将父窗口空间过继到listview下面来*/
this.parent[_cbb].setParent(this)
this.parent[_ddl].setParent(this)
//this.parent[_ckb].setParent(this)
this.parent[_edit].setParent(this)
this.parent[_date].setParent(this)
/*方便操作,伪装成listview成员*/
this.combobox = this.parent[_cbb];
this.dropdownlist = this.parent[_ddl];
//this.ckbox = this.parent[_ckb];
this.editbox = this.parent[_edit];
this.dateBox = this.parent[_date];
/*以下处理combobox的消息回调 */
this.combobox.blockInnerCmd=false; //用于控制combobox内部预制的oncommand指令,主要原因是_precommand是只读的
//this.combobox.itemMustExist=false; //用于控制combobox的item值,当为true,则输入的值必须是item中的值,否则可以自由输入
var cbbUpdate=..win.debounce(function(){ //延迟刷新combobox值 ;
this.combobox.blockInnerCmd = true
this.combobox.showDropDown(false)
this.combobox.show(false)
this.currentCls = false;
var r,c=this.getCtrlRowAndCol(this.combobox) //根据combobox的位置,计算出所在listview的位置
var text = this.combobox.text
try{ this.combobox.itemMustExist = this.ctrlSetting[c][r][["itemMustExist"]] : this.ctrlSetting[c][["itemMustExist"]] }
//需要严格校验combobox中item必须存在,则修改listview前进行判断
if(this.combobox.itemMustExist){
if(!..table.find(this.combobox.items,text)){ //输入的值不是已经存在的值,则不修改原有的listview值
text = ""
this.combobox.blockInnerCmd = false
return ;
}
}
this.setItemText(text,r,c)
this.combobox.blockInnerCmd = false
},100)
this.combobox.sortItems=..win.debounce(function(){ //根据输入值,筛选combobox原始items列表,并替换在本次显示时临时更新
//对于特别长的列表,可定义该函数,当输入item中关键字后,会自动调用此函数排序结果
this.combobox.blockInnerCmd = true //阻断消息
var oItems=this.getCtrlAttr(this.currentCol,this.currentRow) //获取原始items值
var text= ..string.replace( this.combobox.editBox.text,"\s","")
var items = ..table.filter( oItems, lambda(v) ..string.indexOf(v,text) )
this.combobox.listBox.items=items
/*延时处理,防止鼠标丢失*/
this.setTimeout(function(){
this.combobox.showDropDown(text);
this.combobox.editBox.text=text;
this.combobox.editBox.setFocus();
this.combobox.blockInnerCmd = false //重新启用消息
})
},100)
this.combobox._precommand=function(id,event){
if(this.combobox.blockInnerCmd){return} //防止下面处理combobox时,会产生无效的消息;这里需要做阻断消息
select(event) {
case 4,9/*1,2,4,8,9,10,11*/{ ///*消息框失去焦点*/
cbbUpdate()
}
case 5 { //长列表筛选,可根据输入的关键字筛选结果
if(this.combobox.sortItems){
this.combobox.sortItems()
}
}
}
};
this.dropdownlist._precommand=function(id,event){
select(event) {
case 8/*_CBN_CLOSEUP*/{ //消息框失去焦点
this.setItemText(this.dropdownlist.selText,this.currentRow,this.currentCol)
this.dropdownlist.show(false)
this.currentCls = false;
}
}
};
this.editbox.wndproc =..win.debounce(function(hwnd, message, wParam, lParam){ //延迟刷新edit值 ;
var update;
select(message) {
case 0x101/*_WM_KEYUP*/ {
if( wParam == 0xD/*_VK_RETURN*/ ) update=true;
elseif( wParam == 0x1B/*_VK_ESC*/){
this.editbox.text = this.editbox.otext //重置为原始字符
update=true
}
}
case 0x8/*_WM_KILLFOCUS*/,133 {update=true}
};
if(update){
var r,c=this.getCtrlRowAndCol(this.editbox) //根据combobox的位置,计算出所在listview的位置
this.setItemText(this.editbox.text,r,c)
this.editbox.show(false)
this.currentCls = false;
}
},50)
/*dateBox回调*/
this.dateBox.prenotify = function(id,code,ptr){
select(code) {
case 0xFFFFFD0F/*_DTN_CLOSEUP*/,0xFFFFFFF8/*_NM_KILLFOCUS*/{ //失去焦点或月历关闭后更新
if(this.dateBox.checked){ //只有启用时间日历控件时才修改值,否则不修改
this.setItemText(this.dateBox.text,this.currentRow,this.currentCol)
this.dateBox.show(false)
this.currentCls = false;
}
}
}
};
};
//-----------------------共用功能区部分----------------------------------
/*排序*/
sortItems = function(){
var sortColumn =this.itemSortColumn;
var itemData = this.items;
if(sortColumn<0){
var i = ..math.abs(sortColumn)
..table.sort(itemData,lambda(a) ( owner[i]:"") > (a[i]:"") )
}
else {
..table.sort(itemData,lambda(a) ( owner[sortColumn]:"") < (a[sortColumn]:"") )
}
this.items = itemData;
this.clearColumnImage()
this.setColumnImage(..math.abs(sortColumn), sortColumn<0 ? 1 : 0);
}
_prenotify = function (id,code,ptr) { //预回调,可能和标准库冲突,慎用
select(code) {
case 0xFFFFFF94/*_LVN_COLUMNCLICK*/ { //排序
if(this.sortItems){
this.itemSortColumn := 1;
var notifyMsg = this.getNotifyMessage(code,ptr)
if(this.itemSortColumn = notifyMsg.iSubItem) this.itemSortColumn = -notifyMsg.iSubItem;
else this.itemSortColumn = notifyMsg.iSubItem;
this.sortItems();
}
}
case 0xFFFFFF4C/*_LVN_BEGINSCROLL*/ { //开始滚动列表,则隐藏当前显示的控件;因为不隐藏控件会显示到别的位置上
try{
this[this.currentCls].show(false)
this[this.currentCls].showDropDown(false)
}
}
case 0xFFFFFFFE/*_NM_CLICK*/ { //单击显示控件
try{//隐藏上个控件
this[this.currentCls].show(false)
this[this.currentCls].showDropDown(false)
}
//保存当前点击的行列号
this.currentRow,this.currentCol = owner.hitTest()
owner.showCtrl(this.currentRow,this.currentCol)
};
case 0xFFFFFFF4/*_NM_CUSTOMDRAW*/ {
var lvcd = this.getNotifyCustomDraw(code,ptr);
if( lvcd.nmcd.dwDrawStage == 0x10001/*_CDDS_ITEMPREPAINT*/) return 0x20/*_CDRF_NOTIFYSUBITEMDRAW*/;
elseif( lvcd.nmcd.dwDrawStage == 1/*_CDDS_PREPAINT*/ ) return 0x20/*_CDRF_NOTIFYITEMDRAW*/;
elseif( lvcd.nmcd.dwDrawStage == ( 0x10001/*_CDDS_ITEMPREPAINT*/ | 0x20000/*_CDDS_SUBITEM*/) ){
//注意这里 iSubItem 的索引自0开始( 其他函数通常自1开始 )
var r,c=lvcd.nmcd.dwItemSpec,lvcd.iSubItem //获得行列号
if(lvcd.nmcd.rc.bottom){ //bottom底边大于0时,r,c同时加1
c++
r++
/*更新checkbox控件值*/
var value,ctrl=this.getCtrlAttr(c,r)
var text = this.getItemText(r,c)
if(ctrl=="ckbox" and !#text) this.setItemText(value,r,c)
/*更新字体颜色和背景颜色*/
var clr=this.getclr(r,c) //注意每次重绘都要对每个设置,不然就是变成对整行整列设置了
/*设置特定的值*/
lvcd.clrText = clr.textClr
: ( r%2 ? this.fontclr135 : this.fontclr246)
: this.color
: 0x000000
lvcd.clrTextBk = clr.bkClr
: ( r%2 ? this.bgclr135 : this.bgclr246)
: this.bgcolor
: 0xffffff
lvcd.update()
return 0/*_CDRF_DODEFAULT*/
}
}
}
}
};
/*
函数说明:计算控件显示位置
函数参数:1、row行号;2、col列号;3、csl要显示的控件
*/
calcRect=function(r,c,cls){
var rc=this.getItemRect(r,c)
if(c==1){ //第一列获取的是整行的宽度
var rc2=owner.getItemRect(r,2)
rc.right=rc2.left
}
var rcForm=owner.getRect(true)
if(cls=="ckbox"){ //复选框需要调整位置
rcForm.left += 7
rcForm.top +=2
}
//计算要显示在的位置
rc.left += rcForm.left+1
rc.right += rcForm.left+2
rc.top += rcForm.top
rc.bottom += rcForm.top
return rc;
};
/*
函数说明:计算控件位置所在的listview行列号,返回row,col
函数参数:1、ctrlObj
*/
getCtrlRowAndCol=function(ctrlObj){
var rc=ctrlObj.getRect(true) //根据combobox的位置计算出所在listview单元格位置
return this.hitTest(rc.left+5,rc.top+5,true);
};
/*
函数说明:设置指定行列的值和控件类型
函数参数:1、row行号;2、col列号;3、控件默认值;4、控件类型;5、itemMustExist,combobox的输入值是否必须为已存在项目
*/
setCtrlAttr=function(c,r,value,cls,itemMustExist){ //设置
this.ctrlSetting[c] := {}
if(r){
this.ctrlSetting[c][r]:= {}
this.ctrlSetting[c][r].value=value
this.ctrlSetting[c][r]["cls"]=cls //cls设置为当前列要显示的控件类型
if(cls=="combobox") this.ctrlSetting[c][r]["itemMustExist"]=itemMustExist //combobox的输入值是否必须为已存在项目
}else {
this.ctrlSetting[c]["default"]=value //default作为列默认值
this.ctrlSetting[c]["cls"]=cls; //cls设置为当前列要显示的控件类型
if(cls=="combobox") this.ctrlSetting[c]["itemMustExist"]=itemMustExist //combobox的输入值是否必须为已存在项目
}
};
/*
函数说明:获取指定行列的值和控件类型
函数参数:1、row行号;2、col列号
函数返回:value,cls
*/
getCtrlAttr=function(c,r){
var value=this.ctrlSetting[[c]][[r]][["value"]] //尝试获取特定值
: this.ctrlSetting[[c]][["default"]] //不存在时则获取默认值(如果设置过整列)
var cls =this.ctrlSetting[[c]][[r]][["cls"]] //尝试获取特定值
: this.ctrlSetting[[c]][["cls"]] //不存在时则获取默认值(如果设置过整列)
return value,cls;
};
/*
函数说明:在listview点击的位置,显示设置的控件
函数参数:1、行号;2、列号
*/
showCtrl=function(r,c){
//获取下拉选项表
var value,cls= this.getCtrlAttr(c,r)
if(!cls or cls="none") return ; //没有控件值的,或单独设置不可用的
this.currentCls=cls; //记录当前显示的cls值
var itemText=this.getItemText(this.currentRow,this.currentCol )
var rc = this.calcRect(r,c,cls) //计算要显示到的位置
select(cls) {
case "dropdownlist", "combobox"{
//this[cls].disabled=false
this[cls].items=value
this[cls].selText=itemText
if(cls=="combobox"){this[cls].text=itemText}
}
case "editbox" {
this.editbox.otext=itemText; //记录原始值
this.editbox.text=this.editbox.otext; //设置当前值
}
case "ckbox"{ //切换开关状态
if(..string.startWith( itemText,'\uF05E') ) itemText = ..string.replace(itemText,'^\uF05E','\uF05D'); //如果是关状态,则切换为开
elseif(..string.startWith( itemText,'\uF05D') ) itemText = ..string.replace(itemText,'^\uF05D','\uF05E'); //如果是开状态,则切换为关
else itemText = value; //如果未设置过, 则设置默认值
this.setItemText(itemText,this.currentRow,this.currentCol)
return ;
}
case "dateBox" {
this.dateBox.time=#time ? ..time(itemText) : ..time()
this.dateBox.checked = true //设置默认状态为选中状态
}
}
this[cls].setRect(rc,true) //winform.combobox.setRect(rc,true)
this[cls].show(true)
this[cls].setFocus()
};
/*
函数说明:设置指定的行,列位置的combobox的Items值;注意设置后,其他控件将不可用
函数参数:1、items表;2;列号;3、[行号];设置行号则表示对单个单元格设置,否则设置整列;4、itemMustExist输入值是否必须为列表中已存在的值;5、enable=true;默认启用
*/
setCombobox=function(items,c,r,itemMustExist,enable=true){
var mode= enable ? "combobox" : "none"
this.setCtrlAttr(c,r,items,mode,itemMustExist)
};
/*
函数说明:设置指定的行,列位置的dropdownlist的Items值;注意设置后,其他控件将不可用
函数参数:1、items表;2;列号;3、[行号];设置行号则表示对单个单元格设置,否则设置整列;4、enable=true;默认启用
*/
setDropdownlist=function(items,c,r,enable=true){
var mode= enable ? "dropdownlist" : "none"
this.setCtrlAttr(c,r,items,mode)
};
/*
函数说明:设置指定的行,列位置的ckb的选中值;注意设置后,其他控件将不可用
函数参数: 1、列号;2、[行号];设置行号则表示对单个单元格设置,否则设置整列;
3、checked=false;4、text=“要显示的字”;默认为"选定"
5、enable=true;默认启用
*/
setCheckbox=function(c,r,checked=false,text="选定",enable=true){
var value = (checked ? '\uF05D' : '\uF05E') ++ text
var mode= enable ? "ckbox" : "none"
this.setCtrlAttr(c,r,value,mode) //如何修改状态
};
/*
函数说明:设置指定的行,列位置可编辑情况;注意设置Editable,其他控件将不可用
函数参数:1、单独的列号或列的集合;2、[行号];设置行号则表示对单个单元格设置,否则设置整列;4、enable=true;默认启用
*/
setEditable=function(columnTab,r,enable=true){
if(type(columnTab)!=type.table) columnTab={columnTab} //将非tab转换成tab
var mode= enable ? "editbox" : "none"
for(i=1;#columnTab;1){
var c=columnTab[i]
this.setCtrlAttr(c,r,,mode)
}
};
/*
函数说明:在指定的行,列位置设置日期控件;注意设置Editable,其他控件将不可用
函数参数:1、列号;2、[行号];设置行号则表示对单个单元格设置,否则设置整列;3、enable=true;默认启用
*/
setDateBox=function(c,r,enable=true){
var mode= enable ? "dateBox" : "none"
this.setCtrlAttr(c,r,"",mode)
};
/*
函数说明:设置指定行列的文字颜色
函数参数:1、clr颜色值;2、clrType颜色类型;3、[row行号];4、[col列号]
*/
setclr=function(clr,clrType,r,c){
// clrType = "textClr" : "bkClr"
if(r and c){ //设置单个单元格颜色
this.lvClr[c] := {} //初始化列字体色
this.lvClr[c][r] := {} //初始化行字体色
this.lvClr[c][r][clrType]=clr //记录单元格颜色
}
elseif(c){ //设置整列颜色
this.lvClr[c] := {} //初始化列字体色
this.lvClr[c].default := {} //初始化行字体色
this.lvClr[c].default[clrType]=clr //记录单元格颜色
}
elseif(r){ //设置整行颜色
this.lvClr.default := {} //初始化列字体色
this.lvClr.default[r] := {} //初始化行字体色
this.lvClr.default[r][clrType]=clr //记录单元格颜色
}
};
/*
函数说明:获取指定行列的文字颜色和背景颜色
函数参数:1、row行号;2、col列号
函数返回:clr={textClr=;bkClr=}
*/
getclr=function(r,c){
var clr={}
clr.textClr = this.lvClr[[c]][[r]][["textClr"]] //直接获取颜色值
: this.lvClr[[c]][["default"]][["textClr"]] //不存在则获取列默认值
: this.lvClr[["default"]][[r]][["textClr"]] //不存在则获取行默认值
//这里有个问题,如果行和列都设置过颜色,那么只能已列的颜色为主,行颜色无效了,待解决后设置的生效
clr.bkClr = this.lvClr[[c]][[r]][["bkClr"]] //直接获取颜色值
: this.lvClr[[c]][["default"]][["bkClr"]] //不存在则获取列默认值
: this.lvClr[["default"]][[r]][["bkClr"]] //不存在则获取行默认值
//这里有个问题,如果行和列都设置过颜色,那么只能已列的颜色为主,行颜色无效了,待解决为后设置的生效
return clr;
};
/*函数说明:设置指定行列的背景颜色;函数参数:1、clr;2、[row行号];3、[col列号]*/
setBkclr=function(clr,r,c){ this.setclr(clr,"bkClr",r,c) };
/*函数说明:设置指定行列的文字颜色;函数参数:1、clr;2、[row行号];3、[col列号]*/
setTextclr=function(clr,r,c){ this.setclr(clr,"textClr",r,c) };
/*函数说明:获取指定列的值;函数参数:col列号*/
getOneColumnText=function(c){
var text={}
for(i=1;#this.items;1){
var line=this.items[i]
..table.push(text,line[c])
}
return text;
};
/*函数说明:获取指定行的值;函数参数:row列号*/
getOneRowText=function(r){ return this.items[[r]];};
/*函数说明:设置标题值;函数参数:title={{t1;t2;t3};{width1;width2;width3}}*/
setTitle=function(titles){
var text=titles[1]
var widths=titles[2]
for(i=1;#text;1){
this.insertColumn(text[i],widths[[i]])
}
};
/*函数说明:显示或隐藏列标题;函数参数:true|false*/
showHead=function(flag=true){
if(flag) this.modifyStyle(0x4000/*_LVS_NOCOLUMNHEADER*/);
else this.modifyStyle(,0x4000/*_LVS_NOCOLUMNHEADER*/);
};
/*设置行高,参数h[=15]*/
setRowHeight = function(h=15){
var imageList = ..win.imageList(1, h);//行高
this.setImageList( imageList, 1/*_LVSIL_SMALL*/);
};
/*设置文本大小,参数h[=15]*/
setFontSize = function(s=15){
this.setFont({point=s});
this.redraw()
};
}
/**intellisense(bmt.ctrl)
listviewExx=listview拓展库
listviewExx(__listview)=包装一个listview,为其增加各种控件\n参数listview控件
listviewExx()=!bmt_lvEx.
listviewExx=!listview.
end intellisense**/
/**intellisense(!bmt_lvEx.)
currentRow=当前显示控件在listview中的行号,设置后
currentCol=当前显示控件在listview中的列号
combobox=listview的combobox控件文本编辑框\n!combobox.
dropdownlist=listview的dropdownlist控件文本编辑框\n!combobox.
editbox=listview的文本编辑框\n!edit.
ckbox=listview的复选框\n!checkbox.
dateBox=listview的日期时间控件\n!datetimepick.
showCtrl(.(r,c)=在listview点击的位置,显示设置的控件,一般情况下不用调用此函数\n函数参数:1、行号;2、列号
setCombobox(.(items,c,r,itemMustExist,enable)=设置或修改指定的行,列位置的combobox的Items值;注意设置后,其他控件将不可用\n1、items表;\n2;列号;\n3、行号[可选],使用则表示对单个单元格设置,否则设置整列;\n4、itemMustExist输入的列表值必须已经存在(相当于一个可以输入值进行筛选的ddl用了);\n5、enable=true;默认启用
setDropdownlist(.(items,c,r,enable)=设置或修改指定的行,列位置的dropdownlist的Items值;注意设置后,其他控件将不可用\n1、items表;2;列号;3、行号[可选],使用则表示对单个单元格设置,否则设置整列;4、enable=true;默认启用
setEditable(.(columnTab,r,enable)=设置指定的行,列位置可编辑情况;注意设置Editable,其他控件将不可用\n函数参数:1、单独的列号或列的集合;2、[行号];设置行号则表示对单个单元格设置,否则设置整列;4、enable=true;默认启用
setCheckbox(.(c,r,checked,text,enable) = 设置指定的行,列位置的ckb的选中值;注意设置后,其他控件将不可用\n参数1、列号;\n参数2、[行号];设置行号则表示对单个单元格设置,否则设置整列;\n3、checked=false;\n4、text=“要显示的字”;默认为"选定"\n5、enable=true;默认启用
setDateBox(.(c,r,enable)=在指定的行,列位置设置日期控件;注意设置Editable,其他控件将不可用\n参数:1、列号;\n参数2、[行号];设置行号则表示对单个单元格设置,否则设置整列;\参数3、enable=true;默认启用
setBkclr(.(clr,r,c)=设置指定行列的背景颜色\n函数参数:1、clr;2、[row行号];3、[col列号]\n同时使用行列则设置指定单元格,只使用一个话,若只指定行或列则表示整行或整列
setTextclr(.(clr,r,c)=设置指定行列的文字颜色\n函数参数:1、clr;2、[row行号];3、[col列号]\n同时使用行列则设置指定单元格,只使用一个话;若只指定行或列则表示整行或整列
getOneColumnText(__c)=获取指定列的值;参数:col列序号\n即使无效的列序号也会返回空表
getOneRowText(__r)=获取指定行的值;参数:row行序号\n无效的行序号也会返回null
getCtrlAttr(.(c,r)=获取指定行列的值(value|items)和控件类型(cls)\n函数参数:1、row行号;2、col列号\n函数返回:value,cls
setCtrlAttr(.(c,r,value,cls)=设置指定行列的值和控件类型\n函数参数:1、row行号;2、col列号;3、控件默认值;4、控件类型;\n5、itemMustExist,combobox的输入值是否必须为已存在项目,仅对cbb有效
showHead(__true)=添加或移除列标题,true=移除;false=添加
setRowHeight(__15)=设置行高,参数h[=15]
setFontSize(__15)=设置文本大小,参数s[=15]
sortItems() = @.sortItems=function(){/*自定义点击列标题时的排序函数,默认按ansi大小排序*/\n}
end intellisense**/
/**intellisense()
!bmt_lvEx.setTitle(title)=@.setTitle({/*设置标题值*/\n{"序号";"姓名";"性别"};\n{200;200;-1}\n})
!bmt_lvEx.bgclr135 = @.bgclr135 = 0xeecc66;/*奇数行颜色*/
!bmt_lvEx.bgclr246 = @.bgclr246 = 0x66ccee;/*偶数行颜色*/
!bmt_lvEx.fontclr135 = @.fontclr135 = 0xff4400;/*奇数行字体颜色*/
!bmt_lvEx.fontclr246 = @.fontclr246 = 0x0044ff;/*偶数行字体颜色*/
!bmt_lvEx.combobox.blockInnerCmd=用于控制combobox内部预制的oncommand指令,如果需要额外写listview.combobox.oncommand,请将此项设为true
!bmt_lvEx.combobox.itemMustExist=用于控制combobox的item值,当为true,则输入的值必须是item中的值,否则可以自由输入
!bmt_lvEx.combobox.sortItems() = @.sortItems=/*删除这个大括号->->*/{
win.debounce(function(){
/*对于有特别多的item的combobox,可定义该函数,当输入值发生变化(_CBN_EDITCHANGE)时会自动调用此函数排序结果*/
owner.blockInnerCmd = true /*阻断消息*/
var oItems=owner.parent.getCtrlAttr(owner.parent.currentCol,owner.parent.currentRow) /*获取原始items值*/
var text= string.replace( owner.editBox.text,"\s","")
if(!#text){ /*输入内容被清空*/
owner.items=oItems
}else {
var items = {}
for(i=1;#oItems;1){
if(string.indexOf(oItems[i],text)){
table.push(items,oItems[i])
}
}
owner.items=items
}
owner.showDropDown(text);
owner.blockInnerCmd = false /*重新启用消息*/
},200)
/*删除这个大括号->->*/}
end intellisense**/登录后方可回帖