Aardio - 虚表增强版

在原vlist的基础上增加部分功能

  • setColumns()  设置列标题文本,参数为文本数组
  • doubleBuffer()  启用双缓冲,防止闪烁
  • onSortColumn(cloumn,desc) 点击列标题进行排序
  • onClick(iItem,iSubItem)  鼠标左键点击项目事件
  • onDblClick(iItem,iSubItem)  鼠标左键双击项目事件
  • onRClick(iItem,iSubItem)  鼠标右键点击项目事件
  • onRDblClick(iItem,iSubItem)  鼠标右键双击项目事件
  • onKeyDown(vkey)  按键按下事件(对回车键无效)
  • onItemChanged(iItem)  列表项被改变事件
  • 过滤按键事件,只保留方向键等部分按键的默认事件。
  • 默认 整行选择
  • 默认 显示表格线
  • 默认 添加标题栏排序图标
//vlist 虚表控件(光庆增强版)
//在原vlist的基础上增加部分功能
//参考lujjjh的vlistview做了一些小的改进
//原帖 http://bbs.aardio.com/forum.php?mod=viewthread&tid=11729

import win.ui.ctrl.listview;
import win.imageList;
namespace win.ui.ctrl;

class vlist {
	ctor (parent,tParam) {
		if (tParam) {
			tParam.cls = "SysListView32";
			tParam.style |= 0x1000/*_LVS_OWNERDATA*/;
			if (tParam.edge)
				tParam.exstyle |= 0x200/*_WS_EX_CLIENTEDGE*/;  
			select tParam.mode {
				case "icon" tParam.style |= 0x0/*_LVS_ICON*/;
				case "list" tParam.style |= 0x3/*_LVS_LIST*/;
				case "smallicon" tParam.style |= 0x2/*_LVS_SMALLICON*/;
				else tParam.style |= 0x1/*_LVS_REPORT*/;
			}
			if (tParam.editable) tParam.style |= 0x200/*_LVS_EDITLABELS*/;
			if (tParam.hscroll) tParam.style |= 0x800/*_LVS_ALIGNLEFT*/;
			if (tParam.vscroll) tParam.style |= 0x0/*_LVS_ALIGNTOP*/;
			if (tParam.msel === false) tParam.style |= 0x4/*_LVS_SINGLESEL*/;
			if (tParam.asel === null || tParam.asel) tParam.style |= 0x8/*_LVS_SHOWSELALWAYS*/;
		}
	}
	
	onCreate = function () {
		this.fullRow = true;
		this.gridLines = true;
		this.setColumnImageList(columnImageList);
		this._prenotify = function(id, code, ptr) {
			if (code = 0xFFFFFF4F/*_LVN_GETDISPINFOW*/) { 
				var dispInfo = ptr ? owner.getNotifyDispInfo(code, ptr); 
				var item = dispInfo.item;
				var data = this.dataAdapter.getItem(item.iItem,item.iSubItem);
				if (type(data) === "table"){
					..table.mixin(item, data);
				}
				else{
					item.text = tostring(data); 
				}
				owner.setNotifyDispInfo(ptr,dispInfo);
				return 1;
			}
			elseif(code=0xFFFFFF94/*_LVN_COLUMNCLICK*/) {
    			var nm = this.getNotifyMessage(code,ptr)
    			var desc = this.getColumnImage(nm.iSubItem) == 0;
    			if(this.onSortColumn){
    				this.clearColumnImage()
    				if( this.onSortColumn(nm.iSubItem,desc) ){
    					this.setColumnImage(nm.iSubItem, desc ? 1 : 0);
    				}
    			} 
    		}
    		elseif(code=0xFFFFFFFE/*_NM_CLICK*/){
        		var event = this.getNotifyMessage(code,ptr);
        		if( ! event.iItem && event.iSubItem ) return ;
        		if(this.onClick){
   					this.onClick(event.iItem,event.iSubItem);
    			} 
    		}
    		elseif(code=0xFFFFFFFD/*_NM_DBLCLK*/){
        		var event = this.getNotifyMessage(code,ptr);
        		if( ! event.iItem && event.iSubItem ) return ;
        		if(this.onDblClick){
   					this.onDblClick(event.iItem,event.iSubItem);
    			} 
    		}
    		elseif(code=0xFFFFFFFB/*_NM_RCLICK*/){
        		var event = this.getNotifyMessage(code,ptr);
        		if( ! event.iItem && event.iSubItem ) return ;
        		if(this.onRClick){
   					this.onRClick(event.iItem,event.iSubItem);
    			} 
    		}    	
    		elseif(code=0xFFFFFFFA/*_NM_RDBLCLK*/){
        		var event = this.getNotifyMessage(code,ptr);
        		if( ! event.iItem && event.iSubItem ) return ;
        		if(this.onRDblClick){
   					this.onRDblClick(event.iItem,event.iSubItem);
    			} 
    		}    
    		elseif(code=0xFFFFFF9B/*_LVN_ITEMCHANGED*/){
        		var event = this.getNotifyMessage(code,ptr);
        		if( (event.uChanged & 0x8/*_LVIF_STATE*/) 
        			&& (event.uNewState & 0x2/*_LVIS_SELECTED*/) ){
        				if(this.onItemChanged){
   							this.onItemChanged(event.iItem);
    					}	
        		}
    		}    
       		elseif(code=0xFFFFFF65/*_LVN_KEYDOWN*/){
    			var nmkey = ..raw.convert(ptr,{
  					struct hdr = ::NMHDR();
  					WORD vkey;
  					INT flags;
				});
 	      		if(this.onKeyDown){
   					if (this.onKeyDown(nmkey.vkey)) return true; 
    			} 
    			/**
    			只支持以下按键的默认事件:
    			0x21/*_VK_PGUP*/,
    			0x22/*_VK_PGDN*/,
    			0x23/*_VK_END*/,
    			0x24/*_VK_HOME*/,
    			0x25/*_VK_LEFT*/,
    			0x26/*_VK_UP*/,
    			0x27/*_VK_RIGHT*/
    			0x28/*_VK_DOWN*/,
    			**/
    			if (nmkey.vkey<0x21 || nmkey.vkey>0x28) return true;
    		}
		}
	}
	createAdapter = function(dataSource,...){
		var ad =classAdapter(this, dataSource,...)
		ad.update(); 
		return ad;
	}
	createTableAdapter = function(dataSource,...){
		var ad =tableAdapter(this, dataSource,...)
		ad.update(); 
		return ad;
	}
	createAdoAdapter = function(dataSource,...){
		var ad = adoAdapter(this, dataSource,...)
		ad.update();
		return ad;
	}
	createSqliteAdapter = function(dataSource,...){
	    var ad =sqliteAdapter(this, dataSource,...)
	    ad.update();
	    return ad; 
	}
    _onDestroy = function () {
		if( this.dataAdapter ) {
			this.dataAdapter.__close(); 
		};
	}
	doubleBuffer = function(){
		this.setExtended(0x10000/*_LVS_EX_DOUBLEBUFFER*/);
	}

    @_metaProperty;
}

namespace vlist {
	_metaProperty = ..win.ui.ctrl.listview._metaProperty; 
    columnImageList = ..win.imageList(16, 15);
	columnImageList.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);
	class baseAdapter {
		ctor (listview,dataSource) {
			this._listview = listview;
			this._dataSource = dataSource;
			if( listview.dataAdapter ) listview.dataAdapter.__close();
			listview.dataAdapter = this; 
		}
		update = function(){
			::SendMessageInt(listview.hwnd, 0x102F/*_LVM_SETITEMCOUNT*/,this.count(), 0x2/*_LVSICF_NOSCROLL*/);
		}
		__close = function(){ this._listview.dataAdapter = null; if( this.close )  this.close() };
	}
	var baseAdapter = baseAdapter;
	
	class classAdapter {
		ctor (listview,dataSource,columns, ...) {
			this = baseAdapter(listview,dataSource);
			var instance = this._dataSource(columns,...);
		};
		count = function () {
			return instance.count();
		};
		getItem = function (row, col) {
			return instance.getItem(row, col);
		}
	}
	
	class tableAdapter {
		ctor (listview,dataSource,columns, ...) {
			this = baseAdapter(listview,dataSource);
			this._columns = columns;
		};
		count = function () {
			return #(dataSource);
		};
		getItem = function (row, col) {
			if (columns) return dataSource[row][columns[col]];
			else return dataSource[row][col];
		}
	}
	
	class adoAdapter {
		ctor (listview,dataSource, ...) {
			this = baseAdapter(listview,dataSource);
		};
		count = function () {
			var count = dataSource.getRecordCount();
			if (count === -1) error("请以静态方式打开记录集。",3);
			return count;
		};
		getItem = function (row, col) {
			dataSource.Move(row - 1, 1/*_adBookmarkFirst*/); 
			return dataSource(col - 1).value;
		}
		close = function(){ if(dataSource) { dataSource.close(); dataSource = null; } };
	}

	class sqliteAdapter {
		ctor (listview,dataSource,sql) { 
			this = baseAdapter(listview,dataSource);
			this.rowIdx = null; 
		};
		count = function () { 
			var row = dataSource.stepQuery( ..string.replace(sql,"^\s*<@@SELECT@>.+?<@@FROM@>\s+","SELECT COUNT(*) FROM ",1), )
			if(!row) error("sql必须是SELECT ... FROM 语句",3); 
			return row["COUNT(*)"];
		};
		getItem = function (row, col) {
			if( this.rowIdx == row ){ 
				return this.row[col] 
			} 
			var stmt = dataSource.prepare( sql + " Limit 1 Offset " + row-1);
			this.row = stmt.stepResult()
			stmt.finalize();;
			this.rowIdx = row;
			return this.row[col];
		}
	}
}

/**intellisense()
?win.ui.ctrl.vlist = !ctrl_vlist.
!ctrl_vlist.setColumns(__) = 设置列文本,参数为文本数组。
!ctrl_vlist.doubleBuffer() = 启用双缓冲,防止闪烁。
!ctrl_vlist.onItemChanged(iItem) = @.onItemChanged = function(iItem){
    /*列表项被改变事件,iItem:改变后的列表项*/
	__
}
!ctrl_vlist.onSortColumn(cloumn,desc) = @.onSortColumn = function(cloumn,desc){
	/*点击列标题进行排序。column:列号,从1开始。desc:是否倒序。返回true排序,否则不排序*/
	__
	return true;
} 
!ctrl_vlist.onClick(iItem,iSubItem) = @.onClick = function(iItem/*项目*/,iSubItem/*子项目*/){
	/*鼠标左键点击项目事件*/
	__
} 
!ctrl_vlist.onDblClick(iItem,iSubItem) = @.onDblClick = function(iItem/*项目*/,iSubItem/*子项目*/){
	/*鼠标左键双击项目事件*/
	__
} 
!ctrl_vlist.onRClick(iItem,iSubItem) = @.onRClick = function(iItem/*项目*/,iSubItem/*子项目*/){
	/*鼠标右键点击项目事件*/
	__
} 
!ctrl_vlist.onRDblClick(iItem,iSubItem) = @.onRDblClick = function(iItem/*项目*/,iSubItem/*子项目*/){
	/*鼠标右键双击项目事件*/
	__
} 
!ctrl_vlist.onKeyDown(vkey) = @.onKeyDown = function(vkey/*键代码*/){
    var index = owner.selIndex;
	/*按键按下事件,返回true则阻止默认事件*/
	__
} 
!ctrl_vlist.getColumn() = !lvcolumn.
!ctrl_vlist.getColumn(.(列参数表,列序号) = 参数一可以为空,或是指定LVCOLUMN结构体成员键值的参数表,\n返回LVCOLUMN结构体
!ctrl_vlist.setColumn(.({cx=100},列序号) = 改变列宽
!ctrl_vlist.setColumn(.(列参数表,列序号) = 参数一指定LVCOLUMN结构体成员键值的参数表,\n也可以是LVCOLUMN结构体对象,自动设置掩码参数.
!ctrl_vlist.getEditControl() = 开始编辑时返回编辑控件,\n此控件在完成编辑后会自动销毁,不必手动销毁\n取消发送_WM_CANCELMODE消息即可\n!edit.
?.getEditControl = !edit.
!ctrl_vlist.editLable(.(行序号) = 编辑指定项,无参数则编辑选定项\n此函数成功返回编辑文本框句柄\n返则返回0
!ctrl_vlist.setItemPos(__/*项索引*/,x,y) = 设置图标项坐标
!ctrl_vlist.count = 项目总数
!ctrl_vlist.insertColumn(.(列名,列宽,位置,样式) = 第一个参数可以是标题字符串,图像索引,\n或者指定LVCOLUMN结构体成员的table对象,\n\n其他参数都是可选参数,\n样式使用_LVCFMT_前缀的常量指定,\n例如_LVCFMT_LEFT为文本左对齐,\n如果列宽为-1,则自动调用fillParent(ind)函数填充剩余空间
!ctrl_vlist.setColumnText(.(位置,文本) = 设置指定列文本
!ctrl_vlist.getColumnText(__) = 取指定列文本
!ctrl_vlist.delColumn(__) = 删除指定列
!ctrl_vlist.columnCount = 列总数
!ctrl_vlist.clear() = 清空所有项
!ctrl_vlist.getNextItem(.(起始索引,选项) = 参数二为一个或多个 _LVNI_ 前缀的常量合并\n默认为 _LVNI_ALL \n起始索引默认为0 
!ctrl_vlist.getFocused() = 获取当前焦点项位置,返回数值,\n不存在焦点项则返回0
!ctrl_vlist.getSelection(.(起始索引)  = 获取选中项,返回数值,\n不存在选中项则返回0\n可选指定起始索引,默认为0		
!ctrl_vlist.addItem(.(文本,位置,图像索引) = 位置参数可省略,默认为count值\n图像索引可省略,默认为-1\n文本可以是一个指定多列文本的table数组\n返回新增项行号
!ctrl_vlist.addItem(.(LVITEM对象,位置) = 参数一可以是指定一个或多个LVITEM对象成员的table对象\ntext成员指定项目文件,也可以是一个指定多列文本的数组\n位置参数可省略,默认为count值
!ctrl_vlist.setItemText(.(文本,行,列) = 设置项目指定列文本,\n参数一也可是指定多列文本的数组(table对象),\n其他参数可选
!ctrl_vlist.getItemText(.(行,列,缓冲区长度) = 列默认值为1,缓冲区最大字符数默认为100
!ctrl_vlist.getItemRect(.(行,列,RECT,选项) = 返回表示项目表示项目区块的RECT结构体,\n除第一个参数以外,其他参数为可选参数,\n如果不指定列则返回所在行区块,\n使用_LVIR_前缀常量指定选项
!ctrl_vlist.getItemRect() = !rect.
!ctrl_vlist.hitTest(.(x坐标,y坐标,是否屏幕坐标) = 该函数返回指定坐标的行号,参数三可省略,默认为false.\n如果不指定任何参数,则自动调用 win.getMessagePos() 获取消息坐标\n该函数有第二、第三个返回值并可能为0
!ctrl_vlist.setSelected(__/*项索引*/) = 选中项
!ctrl_vlist.setSelected(__/*项索引*/,false) = 取消选中项
!ctrl_vlist.getSelected(__/*项索引*/) = 指定项是否选中状态
!ctrl_vlist.getChecked(__) = 返回指定索引项是否选中
!ctrl_vlist.setChecked(__) = 选定指定索引项
!ctrl_vlist.setItemState(.(项索引,状态位,掩码) = 设置状态,参数三如果省略则使用参数二的值.
!ctrl_vlist.getItemState(.(项索引,状掩码 ) = 读取状态值
!ctrl_vlist.selIndex = 当前选定项索引
!ctrl_vlist.fullRow = 是否选中整行
!ctrl_vlist.hwnd = 控件句柄
!ctrl_vlist.id = 控件ID
!ctrl_vlist._parentForm = 控件所在的父窗口(指win.form对象)\n!winform.
!ctrl_vlist.getParent() = 返回父窗口\n!static.
!ctrl_vlist.setParent(__/*控件对象*/) = 改变父窗口 
!ctrl_vlist.disabled = 是否禁用
!ctrl_vlist.left = 左侧坐标
!ctrl_vlist.right = 右侧坐标
!ctrl_vlist.top = 顶部坐标
!ctrl_vlist.bottom = 底部坐标 
!ctrl_vlist.width = 宽度
!ctrl_vlist.height = 高度
!ctrl_vlist.redraw() = 刷新
!ctrl_vlist.setRedraw(false) = 禁止重绘
!ctrl_vlist.setRedraw(true) = 恢复重绘
!ctrl_vlist.show(true__) = 显示控件
!ctrl_vlist.getRect() = 控件区块位置(::RECT结构体)
!ctrl_vlist.getRect(true) = 控件屏幕区块位置(::RECT结构体)  
!ctrl_vlist.setRect(rc) = 设置控件区块位置(::RECT结构体)  
!ctrl_vlist.setRect(rc,true) = 设置控件屏幕区块位置(::RECT结构体)
!ctrl_vlist.getClientRect() =  控件客户区块位置(::RECT结构体)\n!rect.
!ctrl_vlist.getFont() = 控件字体(::LOGFONT结构体)\n!logfont.
!ctrl_vlist.setFont(__/*指定字体*/) = 指定LOGFONT字体对象,或逻辑字体句柄 
!ctrl_vlist.setFont(混入字体属性) = @.setFont(point=10;name="宋体");
!ctrl_vlist.clientRect =  获取控件客户区块位置(::RECT结构体)
!ctrl_vlist.theme = 外观主题,例如\nwinform.button.theme = "Explorer"\nwinform.button.theme = false
!ctrl_vlist.delItem(__) = 参数为数值,移除指定索引的项目
!ctrl_vlist.items = 列表项集合(第一列)\ntable对象 
!ctrl_vlist.modifyStyle(.(remove,add) = 如果指定第三个参数,则使用此参数调用::SetWidnowPos 
!ctrl_vlist.modifyStyleEx(.(remove,add) = 如果指定第三个参数,则使用此参数调用::SetWidnowPos
!ctrl_vlist.capture = 是否捕获全局鼠标消息
!ctrl_vlist.close() = 关闭控件窗口
!ctrl_vlist.setExtended(_LVS_EX__) = 启用树视图指定扩展样式
!ctrl_vlist.setExtended(_LVS_EX__,false) = 取消树视图指定扩展样式
!ctrl_vlist.getExtended() = 获取树视图扩展样式
!ctrl_vlist.getExtended(_LVS_EX__) = 获取树视图指定扩展样式
!ctrl_vlist.gridLines = 是否显示网格线
!ctrl_vlist.setFocus() = 设置焦点 
!ctrl_vlist.setPos(.(x坐标,y坐标,宽,高,插入位置,参数) = 调整窗口位置或排序,所有参数可选\n同时指定x,y坐标则移动位置\n同时指定宽高则改变大小\n指定插入位置(句柄或_HWND前缀常量)则调整Z序
!ctrl_vlist.getPos() = 返回相对坐标,宽,高\nx,y,cx,cy=win.getPos(hwnd)
!ctrl_vlist.getTileViewInfo() = 返回排列显示相关属性
!ctrl_vlist.setTileViewInfo() = 设置排列显示相关属性
!ctrl_vlist.ensureVisible() = 保证显示选中项
!ctrl_vlist.ensureVisible(__) = 保证显示指定项
!ctrl_vlist.getImageList( _LVSIL__ ) = 获取指定图像列表,\n可选使用 _LVSIL_ 前缀常量指定类型
!ctrl_vlist.setImageList( imageList,_LVSIL__ ) = 获取指定图像列表,\n可选使用 _LVSIL_ 前缀常量指定类型
!ctrl_vlist.fillParent(.(列序号) = 使指定列自适应父窗口宽度,\n如果不指定列默认调整最后一列
!ctrl_vlist.adjust = @.adjust = function(cx,cy){
    winform.listview.fillParent(/*列序号*/);
}
!ctrl_vlist.findItem(.(查找文本,起始位置,是否部份匹配,是否返回查询) = 使用文本查找匹配项,\n除第一个参数外,所有参数可选,默认支持部份匹配,并查找所有项
!ctrl_vlist.addCtrl = @.addCtrl(\n	edit ={ cls="edit";left=0;top=0;right=50;bottom=50;autoResize=false ;hide=1;edge=1;  }\n)
!ctrl_vlist.createAdoAdapter(__/*ADO数据源*/) = 设置数据源\nSQL查询语句必须显示的指定要显示的字段以及顺序
!ctrl_vlist.createAdapter( 类对象 ) = @.createAdapter( class {\n    count = function () {\n        return 10;\n    }  \n    getItem = function (row, col) {\n        return ..string.random(3);\n    }\n    close = function () {\n        \n    }\n});
!ctrl_vlist.createTableAdapter(.(table对象,列名数组) = 设置数据源,参数@2可选
!ctrl_vlist.createSqliteAdapter(.(sqlite连接对象,sql语句) = 设置数据源\nsql必须使用SELECT 显示的字段列表 FROM开始 
!ctrl_vlist.createAdapter() = !ctrl_vlist_adapte.
!ctrl_vlist.createTableAdapter() = !ctrl_vlist_adapte.
!ctrl_vlist.createAdoAdapter() = !ctrl_vlist_adapte.
!ctrl_vlist.createSqliteAdapter() = !ctrl_vlist_adapte.
!ctrl_vlist.dataAdapter = 数据源适配器\n!ctrl_vlist_adapte.
!ctrl_vlist_adapte.update() = 更新数据源
!ctrl_vlist_adapte.close = @.close = function(){
    __/*自定义数据连接关闭操作*/
}
end intellisense**/

猜你喜欢

转载自blog.csdn.net/sdlgq/article/details/112896327
今日推荐