//grid 简单数据视图 import win.ui.ctrl.edit; import win.imageList; namespace win.ui; class grid{ ctor( listview ){ this = listview; this.fullRow = 1; this.gridLines = 1; this.readonlyColums = {}; var reloadImageList = function(scaleX){ if(this.columnImageList){ this.setColumnImageList(null); this.columnImageList.destroy(); } var w,h = 16,15; if(scaleX>=3){ this.columnImageList = ..win.imageList(w*3,h*3); this.columnImageList.add('GIF89a\x60\x00-\x00\x80\x00\x00\x80\x80\x80\xFF\x00\xFF!\xFF\x0BNETSCAPE2.0\x03\x01\x00\x00\x00!\xF9\x04\x04\x00\x00\x00\x00,\x00\x00\x00\x00\x60\x00-\x00\x00\x02u\x8C\x8F\xA9\xCB\xED\x0F\xA3\x9C\xB4\xDA\x8B\xB3\xDE\xBC\xFB\x0F\x86\xE2H\x96\xE6\x89\xA6\xEA\xCA\xB6\xEE\x0B\xC7\xF2L\xD7\xF6\x8D\xE7%\xC0\xEF\xFC\x0F\x0C\x0AW?\x9F\xF08T\x15I\xC8&\x10\xD54:{J\xA4tJ\xB42\xA7K\x13\xB7+\x8AV\xBF\xD7\xE7\x98[\x06o\xBF\xC9\x91\xDA\xCBn\x87\xA9\xA9\xB8<\xF4\xD6\xE9\xF7\xFC\xBE\xFF\x0F\x18(8HXhx\x88\x98\xA8\xB8\xC8\xD8\xE8\xF8\x08\x19)YQ\x00\x00;',0xff00ff); } elseif(scaleX>=2.0){ this.columnImageList = ..win.imageList(w*2,h*2); this.columnImageList.add('GIF89a@\x00\x1E\x00\x80\x00\x00\x80\x80\x80\xFF\x00\xFF!\xFF\x0BNETSCAPE2.0\x03\x01\x00\x00\x00!\xF9\x04\x04\x00\x00\x00\x00,\x00\x00\x00\x00@\x00\x1E\x00\x00\x02I\x8C\x8F\xA9\xCB\xED\x0F\xA3\x9C\xB4\xDA\x8B\xB3\xDE\xBC\xFB\x0F\x86\xE2H\x96\xE6\xE9\x01\x80\xA6\xB6\xEE\x9B\xAE\xD9K\xB7\x1C\xCD\xD6j\xEC\xE6\xFA\xAD\x93ap\x9D\xA0\xF0B\xF4\x19\x8F\x96]q\xE9\x1C2Q\xD4\xAA\xF5\x8A\xCDj\xB7\xDC\xAE\xF7\x0B\x0E\x8B\xC7\xA3\x02\x00;',0xff00ff); } else{ this.columnImageList = ..win.imageList(w,h); this.columnImageList.add('GIF89a\x20\x00\x0F\x00\x80\x00\x00\x80\x80\x80\xFF\x00\xFF!\xF9\x04\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x20\x00\x0F\x00\x00\x02\x1F\x8C\x8F\xA9\xCB\xED\x0F\xA3\x9C\xB4N\xF0\x80\xDE8k\xBFA\x5C\xD7\x84\x20\x97Y\xEA\xCA\xB6\xEE\x0B\xC7F\x01\x00;',0xff00ff); } this.setColumnImageList(this.columnImageList); } reloadImageList(listview.dpiScaleX||1); this.__afterDpiChanged = function(scaleX,scaleY){ if(this.columnImageList) reloadImageList(scaleX); } this._onDestroy = function(){ if(this.columnImageList){ this.setColumnImageList(null); this.columnImageList.destroy(); this.columnImageList = null; } } this.addCtrl( editBox = { cls="edit";font = LOGFONT( h = 12 );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); } } } } ) }; 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; } if( this.readonlyColums[iSubItem] ) return; 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; }; setReadonlyColumns = function(...){ if(...==-1) this.readonlyColums ={@{_get = lambda() true }} elseif(this.readonlyColums@) this.readonlyColums = {}; var c = type(...) === "table" ? ... : {...} for(i,idx in c) this.readonlyColums[idx] = 1; }; prenotify = { [0xFFFFFFFD/*_NM_DBLCLK*/] = function(id,code,ptr){ var event = this.getNotifyMessage(code,ptr); if( ! event.iItem && event.iSubItem ) return ; if(this.onDoubleClick) this.onDoubleClick(event.iItem,event.iSubItem,event); this.editBox.event = event; this.beginEdit(); }; [0xFFFFFF65/*_LVN_KEYDOWN*/] = function(id,code,ptr){ var nmkey = ..raw.convert(ptr,{ struct hdr = ::NMHDR(); WORD vkey; INT flags; }); var vk = nmkey.vkey; var edit = this.editBox; if(!edit.event) edit.event = {}; edit.event.iItem = this.getSelection(); if( vk == 0x20/*_VK_SPACE*/ ){ if(!edit.event.iSubItem)edit.event.iSubItem=1; this.beginEdit(); } }; [0xFFFFFF94/*_LVN_COLUMNCLICK*/] = function(id,code,ptr){ var nm = this.getNotifyMessage(code,ptr) var desc = this.getColumnImage(nm.iSubItem) == 0; if(this.onSortColumn){ if( this.onSortColumn(nm.iSubItem,desc) ){ this.clearColumnImage(); this.setColumnImage(nm.iSubItem, desc ? 1 : 0); } } }; } } /**intellisense() win.ui.grid(__) = 参数必须指定一个 listview 控件对象。\n返回一个可编辑单元格的列表视图对象,返回对象继承了 listview 控件的所有属性与方法。\n\n鼠标左键单击单元格、或者按空格键开始编辑,\n按回车完成编辑,ESC 键撤消编辑,回车+上下方向键快速移动到其他项,\n用户完成编辑后会触发onEditChanged事件.\n!listview. win.ui.grid() = !win_ui_grid. !win_ui_grid.editBox = 实现编辑功能的edit控件\n此功能需要扩展listview并实现了编辑功能的的控件才能支持\n!edit. !win_ui_grid.onEditChanged(text,iItem,iSubItem) = @.onEditChanged = function(text,iItem,iSubItem){ __/*控件完成编辑,并且文本已变更,\ntext为改变后的文本,iItem为行号,iSubItem为列号\n此功能需要扩展listview并实现了编辑功能的的控件才能支持\n返回false可中止更新显示文本*/ } !win_ui_grid.onEditEnd(iItem,iSubItem) = @.onEditChanged = function(iItem,iSubItem){ __/*控件完成编辑*/ } !win_ui_grid.onSortColumn(column,desc) = @.onSortColumn = function(column,desc){ __/*点击列排序时回调此函数\n@column参数为列序号,1为首列,@desc参数指定是否倒序\n返回true排序,否则不排序*/ return true; } !win_ui_grid.setTable( = 用 listview 控件显示数据表(包含名值对的对象或数组组成的数组)。\n此函数会自动清空控件之前的所有项。\n如果没有创建任何列,则自动创建标题列。\n如果要重新创建列,请先调用 clear 函数并指定参数为 true 以清空原来的列。 !win_ui_grid.setTable(.(dataTable) = 参数 @dataTable 指定要加载的数据表。\n数据表应当包含行组成的数组。\n数据行可以是数组,也可以是名值,值用 tostring 转为文本显示。\n可选通过数据表的 fields 字段指定要显示的索引数组(键名或索引数值)。\n\n如果视图控件的标题列为空,则用显示键名(或数组值)创建标题列。\n如果数据行为数组,第一行填充到标题列以后,默认从第二行加载数据。\n\n可用 startIndex 属性或元属性自定义要加载的起始行。\n可用 length 属性自定义要加载的行数,默认加载所有行。\n\nsqlite,access,sqlServer 等数据库对象,\n提供的 getTable 函数可获取通过 fields 字段指定列名数组的数据表。 !win_ui_grid.getTable(__) = 返回数据表。\n如果参数 @1 指定列名数组(被复制为返回表的 fields 字段),\n则返回的每行数据都是名值对,否则返回的每行数据都是文本数组。\n\n如果参数 @1 为 true,则返回的文本数组第一行为列标题文本数组。 !win_ui_grid.columns = 读取或设置所有的列。\n值为由所有列配置信息的数组,每个列的配置也是一个数组。\n表示单个列的数组格式为 `[标题,列宽,对齐格式]`,\n写入列配置时对齐格式可省略。 !win_ui_grid.setColumns(__) = 用一个字符串数组指定要显示的列\n如果参数为空则清空所有列 !win_ui_grid.setReadonlyColumns(__) = 可以使用一个或多个参数指定要禁止编辑的列序号,\n也可以用一个数组参数指定多个列序号。\n\n如果参数为 -1,则禁止编辑所有列 !win_ui_grid.setColumnText(.(位置,文本) = 设置指定列文本 !win_ui_grid.getColumnText(__) = 取指定列文本 !win_ui_grid.setColumnWidth(.(列宽,列序号,->->->) = 设置列宽,可指定一个或多个列序号。\n这里不能指定宽度为 -1 。 !win_ui_grid.delColumn(__) = 删除指定列 !win_ui_grid.columnCount = 列总数 !win_ui_grid.setColumn(.({cx=100},列序号) = 改变列宽,参数@1必须是个表对象 !win_ui_grid.setColumn(.(列参数表,列序号) = 参数一指定 wLVCOLUMN 结构体成员键值的参数表,\n也可以是LVCOLUMN结构体对象,自动设置掩码参数. !win_ui_grid.clear() = 清空所有行 !win_ui_grid.clear(true) = 清空所有行,并且清空所有列 !win_ui_grid.beginEdit(.(行,列) = 切换到编辑状态 !win_ui_grid.selected = 获取或设置所有选中项,这是包含所有选中的项目行索引的数组。\n设为 null 或空表清除所有选中项。\n\n也可以使用 eachSelected 方法创建迭代器并且 for in 循环遍历所有选中项。 !win_ui_grid.setSelected(__/*项索引*/) = 选中项,注意是选中列表项而不是勾选复选框 !win_ui_grid.setSelected(__/*项索引*/,false) = 取消选中项,注意是选中而不是勾选复选框 !win_ui_grid.getSelected(__/*项索引*/) = 指定项是否选中状态 !win_ui_grid.setItemText(.(文本,行,列) = 设置项目指定列文本,\n参数一也可是指定多列文本的数组\n设置的文本如果不是指针或空值则自动转换为字符串,\n不指定行序号则默认取当前选中焦点行,\n不指定列则默认设为1 !win_ui_grid.getItemText(.(行,列,缓冲区长度) = 返回指定项指定列文本,列默认值为1,\n如果列指定为-1,则返回一个包含所有列文本的数组,\n缓冲区最大字符数默认为520,\n不指定行序号则默认取当前选中焦点行,\n不指定列则默认设为 1 !win_ui_grid.getItemData(__/*行序号*/) = 获取指定行绑定的数据。\n可用 setItemData 方法绑定数据到指定行。\n setTable 方法也会自动绑定源数据表。 !win_ui_grid.setItemData(.(行序号,数据) = 绑定数据到指定行。\n数据仅与行号关联,与具体的列表项无关。\n删除或改变列表项不会修改绑定的数据表。\n但清空控件,设置 items 属性都会清除关联的数据表,\n调用 setTable 方法也会绑定新的源数据表。 !win_ui_grid.each(起始索引,选项) = @for itemIndex in ??.each(){ __/*遍历所有项*/ } !win_ui_grid.eachSelected(col) = @for item,value in ??.eachSelected(){ __/*从后向前倒序遍历所有选中项,\n迭代变量 item 为选中项目的行号。\n迭代变量 value 为 @col 参数所指定列的文本值\n@col 参数省略则默认为1。\n\n也可以使用 listview 控件的 selected 属性直接返回所有已选中的行号。*/ } !win_ui_grid.onGetDispItem = @.onGetDispItem = function(item,row,col){ __/*处理 _LVN_GETDISPINFOW 通知消息\n参数 @item 为 LVITEM 结构体,@row 为当前行号,@col 为当前列号,\n返回 item 或包含 item 部分字段则更新 LVITEM 结构体*/ return {text="要显示的文本"}; } !win_ui_grid.onItemChanged = @.onItemChanged = function(item,subItem,nmListView){ __/*项目变更触发此事件。\nitem 为变更为焦点的项序号,subItem 为列序号,nmListView 为 NMLISTVIEW 结构体*/ } !win_ui_grid.onFocusedChanged = @.onFocusedChanged = function(item,subItem,nmListView){ __/*焦点项变更触发此事件。\nitem 为变更为焦点的项序号,subItem 为列序号,nmListView 为 NMLISTVIEW 结构体*/ } !win_ui_grid.onSelChanged = @.onSelChanged = function(selected,item,subItem,nmListView){ __/*选中项更触发此事件。\nselected 为是否选中,item 为变更项序号,\nsubItem 为列序号,nmListView 为 NMLISTVIEW 结构体*/ } !win_ui_grid.onCheckedChanged = @.onCheckedChanged = function(checked,item){ __/*勾选状态变更触发此事件。\nchecked 为是否勾选,item 为变更项序号*/ } !win_ui_grid.onRightClick = @.onRightClick = function(item,subItem,nmListView){ __/*右键点击项目触发此事件。\nitem 为变更为焦点的项序号,subItem 为列序号,nmListView 为 NMLISTVIEW 结构体*/ } !win_ui_grid.onClick = @.onClick = functionitem,subItem,nmListView){ __/*左键单击项目触发此事件。\nitem 为变更为焦点的项序号,subItem 为列序号,nmListView 为 NMLISTVIEW 结构体*/ } !win_ui_grid.onDoubleClick = @.onDoubleClick = function(item,subItem,nmListView){ __/*左键双击项目触发此事件。\nitem 为变更为焦点的项序号,subItem 为列序号,nmListView 为 NMLISTVIEW 结构体*/ } end intellisense**/