//edit 文本框 import win.ui.ctrl.metaProperty; namespace win.ui.ctrl; class edit{ ctor(parent,tParam){ if(tParam){ if( tParam.readonly ) tParam.style |= 0x800/*_ES_READONLY*/ if( tParam.password ) tParam.style |= 0x20/*_ES_PASSWORD*/ else if( tParam.multiline ){ tParam.style |= 0x4/*_ES_MULTILINE*/ tParam.style |= 0x1000/*_ES_WANTRETURN*/; } if( tParam.num ) tParam.style |=0x2000/*_ES_NUMBER*/ if(! tParam.hidesel ) tParam.style |= 0x100/*_ES_NOHIDESEL*/ if ( !tParam.multiline ) { tParam.style |= 0x80/*_ES_AUTOHSCROLL*/; } if( tParam.autoscroll !== null ){ if( tParam.autoscroll ){ tParam.style = tParam.style | 0x40/*_ES_AUTOVSCROLL*/ | 0x80/*_ES_AUTOHSCROLL*/; } } else { if( tParam.autovscroll === null || tParam.autovscroll ) { tParam.style |= 0x40/*_ES_AUTOVSCROLL*/ ; } if( tParam.autohscroll === null || tParam.autohscroll ) { tParam.style |= 0x80/*_ES_AUTOHSCROLL*/ ; } } if( tParam.color !==null && tParam.bgcolor === null ) tParam.bgcolor = ::GetSysColor(0x5/*_COLOR_WINDOW*/ ); select(tParam.align) { case "center" tParam.style |= 0x1/*_ES_CENTER*/; case "right" tParam.style |= 0x2/*_ES_RIGHT*/; else tParam.style |= 0x0/*_ES_LEFT*/; } if(tParam.edge) tParam.exstyle |= 0x200/*_WS_EX_CLIENTEDGE*/; begin; var tabstop; if( tParam.tabstop ){ tabstop = tParam.multiline ? 0x9/*_VK_TAB*/ : 0xD/*_VK_RETURN*/; } var handleKeys = {[0xD/*_VK_RETURN*/]=1;[0x1B/*_VK_ESC*/]=1;[0x9/*_VK_TAB*/]=1;['A'#]=1} this.defaultTranslateAccelerator = function( msg ){ if( msg.message != 0x100/*_WM_KEYDOWN*/) return; var vk = msg.wParam; if(!handleKeys[vk]) return; var ctrl = ::GetKeyState( 0x11/*_VK_CONTROL*/ ) & 0x8000; var alt = ::GetKeyState( 0x12/*_VK_ALT*/ ) & 0x8000; var shift = ::GetKeyState( 0x10/*_VK_SHIFT*/ ) & 0x8000; if(vk ===0xD/*_VK_RETURN*/ && this.onOk ){ if(this.onOk(ctrl,alt,shift)){ return true; } } if(alt || shift) return; if( vk == 'A'# && ctrl ){ this.selectAll(); return true; } if( ctrl ) return; if( ( tabstop == vk ) && tabstop ){ owner.tabNext(true); return true; } if( vk == 0x1B/*_VK_ESC*/ ){ if(this.onCancel && this.onCancel()){ return true; } if( this.parent.onCancel ) this.parent.onCancel(); return true; } } end; this._commandFuncnames ={[0x300/*_EN_CHANGE*/]="onChange";[0x100/*_EN_SETFOCUS*/] ="onFocusGot";[0x200/*_EN_KILLFOCUS*/]="onFocusLost"} } } @_metaProperty; } edit._metaProperty = metaProperty( modified = { _get = function(){ return !!::SendMessage(owner[["hwnd"]],0xB8/*_EM_GETMODIFY*/); } _set = function( v ){ if(owner.onModified){ if(v==::SendMessage(owner[["hwnd"]],0xB8/*_EM_GETMODIFY*/)){ return; } } ::SendMessageInt(owner[["hwnd"]],0xB9/*_EM_SETMODIFY*/,v?1:0,0 ); if(owner.onModified){ owner.onModified(v); //@Deprecated } } }; getSel = function(){ var re,min,max = ::SendMessageByInt(owner[["hwnd"]],0xB0/*_EM_GETSEL*/,0,0); if( min >=0 ) { if( min == max ) return min; min = min +1; }; return min,max; } setSel = function(min=0,max){ if(max===null) {max = min;if(max>=0){min=max+1}}; elseif((min>max) && (max>0) ){ min,max = max,min; } if( min > 0 ) min = min - 1; ::SendMessageInt(owner[["hwnd"]],0xB1/*_EM_SETSEL*/,min ,max); } selType = function(){ return ::SendMessage(owner.hwnd,0x442/*_EM_SELECTIONTYPE*/); } setCueBannerText = function(s,alwaysShow){ ::User32.SendMessage(owner[["hwnd"]], 0x1501/*EM_SETCUEBANNER*/,!!alwaysShow,s!==null?tostring(s):s); }; lineCount = { _get = function(){ return ::SendMessage(owner[["hwnd"]],0xBA/*_EM_GETLINECOUNT*/); } }; lineLength = function(ind){ if(ind===null)ind = owner.lineFromChar(); elseif( ind < 0 ) ind = owner.lineCount + ind + 1; var chr = owner.lineToChar(ind)-1; if(chr>-1) return ::SendMessageInt(owner[["hwnd"]],0xC1/*_EM_LINELENGTH*/,chr,0); }; lineText = function(ind){ if(ind===null)ind = owner.lineFromChar(); elseif( ind < 0 ) ind = owner.lineCount + ind + 1; var chr = owner.lineToChar(ind)-1; if( chr < 0 ) return; var cch = ::SendMessageInt(owner[["hwnd"]],0xC1/*_EM_LINELENGTH*/,chr,0); if(!cch) return ""; var buffer = ..raw.buffer(cch* 2 + 4,{INT cch = cch} ); if( ::User32.SendMessage( owner[["hwnd"]],0xC4/*_EM_GETLINE*/,ind-1,buffer) ) return ..string.fromUtf16(buffer,,cch) }; lines = function(trim){ var this = owner; var c = this.lineCount; var i,line,next = 0; next = function(){ i++; if( i > c ) return; line = this.lineText(i); if(trim){ line = ..string.trim(line); if(!#line)return next(); } return line; } return next; }; lineFromChar = function(pos){ pos := owner.getSel(); return ::SendMessageInt(owner[["hwnd"]],0xC9/*_EM_LINEFROMCHAR*/,pos,0 )+1; }; lineToChar = function(line){ if(line===null)line = owner.lineFromChar(); elseif( line < 0 ) line = owner.lineCount + line + 1; line--; return ::SendMessageInt(owner[["hwnd"]],0xBB/*_EM_LINEINDEX*/,line,0 )+1; }; lineScroll = function(line,h=0){ if(!line)line=owner.lineCount ; ::SendMessageInt(owner[["hwnd"]],0xB6/*_EM_LINESCROLL*/,h,line-1 ); }; lineSel = function(line,text){ var a= owner.lineToChar(line); if(!a) return; var len = owner.lineLength(line) owner.setSel(a,a+len); if(text) owner.selText = text; }; scrollToLine = function(line){ var cl = owner.lineFromChar(owner.caretPos) owner.lineScroll(line-cl); }; scrollCaret = function(pos){ if(pos!==null) owner.caretPos = pos; ::SendMessage( owner[["hwnd"]] , 0xB7/*_EM_SCROLLCARET*/); }; canUndo = function(){ return !!::SendMessage(owner.hwnd,0xC6/*_EM_CANUNDO*/) }; canCopy = function(){ var min,max = owner.getSel(); return max && (max>=min); }; redo = function(){ ::SendMessage(owner.hwnd,0x454/*_EM_REDO*/) }; undo = function(){ ::SendMessage(owner.hwnd,0xC7/*_EM_UNDO*/ ) } clear = function(){ ::SendMessage(owner.hwnd,0x303/*_WM_CLEAR*/ ) }; copy = function(){ ::SendMessage(owner.hwnd,0x301/*_WM_COPY*/ ) }; cut = function(){ ::SendMessage(owner.hwnd,0x300/*_WM_CUT*/ ) }; paste = function(){ ::SendMessage(owner.hwnd,0x302/*_WM_PASTE*/ ) }; getLength = function(){ return ::SendMessage(owner[["hwnd"]],0xE/*_WM_GETTEXTLENGTH*/ ); }; selectAll = function(){ owner.setSel(0,-1); }; deselect = function(){ owner.setSel(-1,0); }; appendText = function(s,...){ var len = ::SendMessage(owner[["hwnd"]],0xE/*_WM_GETTEXTLENGTH*/ ); owner.setSel(len+1); if(s!==null){ if(type(s)=="table"){ if(!..table.next(s)) owner.setSelCharformat(null); else{ owner.setSelCharformat(s) if(s.text) { len = owner.appendText(s.text); } if(...!==null) { var len = owner.appendText(...); owner.setSelCharformat(null) return len; } elseif(#s){ var len = owner.appendText( ..table.unpack(s) ); owner.setSelCharformat(null) return len; } } } else{ s = ..string.toUtf16(s); ::SendMessage(owner[["hwnd"]],0xC2/*_EM_REPLACESEL*/,,s) len = ::SendMessage(owner[["hwnd"]],0xE/*_WM_GETTEXTLENGTH*/ ); owner.setSel(len+1); } } if(...===null) return len; return owner.appendText(...); }; print = function(...){ var args = {...}; var b,e,t = ..table.range(args); var stringify = ..JSON ? ..JSON.stringify : ( lambda(v) v@[["_tostring"]]?tostring(v):..table.tostring(v) ); var pretty = !!..JSON; for(i=b;e){ t = type(args[i]) ; if( t != "string" ) { if( t == "table" ) { args[i] = stringify(args[i],pretty); } else args[i] = tostring(args[i]); } else { args[i] = ..string.fromUtf16If(args[i]); } }; var str = ..string.crlf(..string.join(args,'\t')); owner.log(str,'\r\n'); }; printf = function(f,...){ if(f)owner.appendText( ..string.format(f,...),'\r\n'); owner.vScroll(); }; setFocus = function(b,e){ ..win.setFocus(owner.hwnd); if( b == null)owner.appendText(); else { if(e===null) { if( b> 0 ){ return owner.setSel(b); } else { return; } }; owner.setSel(b,(e:b)); } owner.scrollCaret(); }; log = function( ...){ var s = ..string.concat(owner.text, ... ); var len = ..string.len(s); var limit = owner.limit; if( (limit > 0) && (len > limit) ){ s = ..string.right(s,- ( len - limit + 1 ),true ); } owner.text = s; owner.appendText();//不可在此添加换行,因为这时候limit基本已经满了 owner.vScroll(); }; dump = function(v,...){ if( type(v) == type.table ) owner.log( ..table.tostring(v) ) else owner.log( (tostring(v) ) ) if(!...){ owner.log('\r\n'); return; } owner.log('\t'); if(!...)return; return owner.dump(...); }; validateText = function(cond,tip,tip2){ var text = owner.text; var valid; if(type.isString(cond)) valid = ..string.match(text,cond); else valid = cond(text); if(text != (valid || "") ){ owner.text = valid; if(tip){ owner.setFocus(); if(type.isString(tip)) owner.showErrorTip(tip,tip2); } return false; } return true; }; getClientRect = function(){ var rc = ::RECT(); ::SendMessageByStruct(owner[["hwnd"]],0xB2/*_EM_GETRECT*/,0,rc); return rc; }; setClientRect = function(rc,wParam=0){ var rc = ..table.assign(::RECT(),rc); ::SendMessageByStruct(owner[["hwnd"]],0xB3/*_EM_SETRECT*/,wParam,rc); }; inflateClientRect = function(x=0,y=0,wParam=0){ var rc = ::RECT(); ::SendMessageByStruct(owner[["hwnd"]],0xB2/*_EM_GETRECT*/,0,rc); rc.inflate(x,y); ::SendMessageByStruct(owner[["hwnd"]],0xB3/*_EM_SETRECT*/,wParam,rc); }; setPadding = function(t,r,b,l,noScale){ var scaleX,scaleY = owner[["dpiScaleY"]]:1,owner[["dpiScaleY"]]:1; if(noScale){ if(t) t = t/scaleY; if(r) r = r/scaleX; if(b) b = b/scaleY; if(l) l = l/scaleX; } if(owner.padding){ if(!t) t = owner.padding.t; if(!r) r = owner.padding.r; if(!b) b = owner.padding.b; if(!l) l = owner.padding.l; } owner.padding = (t||r||b||l) ? {t=t;r=r;b=b;l=l} :null; var rc = ..win.getClientRect(owner.hwnd); rc.top = rc.top+(t:0)*scaleY; rc.right = rc.right-(r:0)*scaleX; rc.left = rc.left+(l:0)*scaleX; rc.bottom = rc.bottom-(b:0)*scaleY; ::SendMessageByStruct(owner[["hwnd"]],0xB3/*_EM_SETRECT*/,0,rc); }; _preadjust = function(){ var p = owner.padding; if(p)owner.setPadding(p.t,p.r,p.b,p.l); }; readonly = { _get = function(){ return !!..win.getStyle(owner[["hwnd"]],0x800/*_ES_READONLY*/) } _set = function( v ){ ::User32.SendMessage(owner[["hwnd"]],0xCF/*_EM_SETREADONLY*/,v,0) } } leftText = function(p){ if(p===null)p = owner.caretPos; return ..string.left(owner.text,p,true); } rightText = function(p){ if(p===null){ p = owner.caretPos; if(p!==null) p = -(p+1); } if(p){ return ..string.right(owner.text,p,true); } } caretPos = { _get = function(){ var min,max = owner.getSel(); return max || min; } _set = function( v ){ owner.setSel(v); } }; selLine = { _get = function(){ var min,max = owner.getSel(); if( min!==null ){ return owner.lineFromChar(min); } return 1; } _set = function( v ){ var c = owner.lineToChar(v) if( c!==null ){ owner.lineScroll(v); return owner.setFocus(c-1); } } }; passwordChar = { _get = function(){ var c = ::SendMessage(owner[["hwnd"]],0xD2/*_EM_GETPASSWORDCHAR*/) if(c) return ..raw.str( {WORD bytes[1] = {c}},true); } _set = function( v ){ ::SendMessageInt(owner[["hwnd"]],0xCC/*_EM_SETPASSWORDCHAR*/,v?v[1]:0,0) owner.redraw(); } }; disableInputMethod = function(){ ::Imm32 := ..raw.loadDll("Imm32.dll"); var imc = ::Imm32.ImmGetContext(owner.hwnd); if (imc) { ::Imm32.ImmAssociateContext(owner.hwnd,null); ::Imm32.ImmReleaseContext(owner.hwnd,imc); } }; showBalloonTip = function(title,text,icon){ if(text===null) title,text = text,title; var ti = { INT cbSize; ustring title = title:""; ustring text = text:""; addr icon = icon; } ti.cbSize = ..raw.sizeof(ti); ::SendMessageByStruct(owner.hwnd,5379/*EM_SHOWBALLOONTIP*/,0,ti); }; showInfoTip = function(title,text,large){ return owner.showBalloonTip(title,text,large?4:1); }; showWarningTip = function(title,text,large){ return owner.showBalloonTip(title,text,large?5:2); }; showErrorTip = function(title,text,large){ return owner.showBalloonTip(title,text,large?6:3); }; popMenu = function(menuTable){ var this = owner; var menu = ..win.ui.popmenu( this._parentForm ); menu.addTable( { { '全选\tCtrl+A'; function(id){ this.setFocus(0,-1); } }; { /*分隔线*/ }; { '复制\tCtrl+C'; function(id){ this.copy() }; !this.canCopy() ? 1/*_MF_GRAYED*/ : 0}; { '剪切\tCtrl+X'; function(id){ this.cut() }; !this.canCopy() ? 1/*_MF_GRAYED*/ : 0 }; { '粘贴\tCtrl+V'; function(id){ this.paste() }; !this.canPaste() ? 1/*_MF_GRAYED*/ : 0 }; { '删除\tDel'; function(id){ this.selText = ""; }; !this.canCopy() ? 1/*_MF_GRAYED*/ : 0 }; { /*分隔线*/ }; this.canRedo() ? ( { '重做\tCtrl+Y'; function(id){ this.redo() } } ) : ( { '撤消\tCtrl+Z'; function(id){ this.undo() }; !this.canUndo() ? 1/*_MF_GRAYED*/ : 0 } ) ; } ); if(menuTable){ menu.addTable(menuTable); } menu.popup(); menu.close(); }; enablePopMenu = function(menuTable){ owner.wndproc = { [0x205/*_WM_RBUTTONUP*/] = function(hwnd,message,wParam,lParam){ var items = menuTable; if( type(menuTable) == "function" ) items = invoke(menuTable,owner); owner.popMenu(items); return true; } } }; /* richedit已重写下面的属性 */ canRedo = function(){ }; canPaste = function(){ return ::User32.IsClipboardFormatAvailable(1/*_CF_TEXT*/) || ::User32.IsClipboardFormatAvailable(7/*_CF_OEMTEXT*/) || ::User32.IsClipboardFormatAvailable(0x81/*_CF_DSPTEXT*/) || ::User32.IsClipboardFormatAvailable(0xD/*_CF_UNICODETEXT*/); }; limit = { _get = function(){ return ::SendMessage(owner[["hwnd"]], 0xD5/*_EM_GETLIMITTEXT*/); } _set = function( v ){ assert( type(v) == type.number ) ::SendMessage(owner[["hwnd"]], 0xC5/*_EM_LIMITTEXT*/, topointer(v) , null) } }; selText = { _get = function(){ var min,max = owner.getSel(); if( (min!==null) && ( max>=min) ){ return ..string.slice(owner.text,min,max,true); } } _set = function( str ){ ::User32.SendMessageW(owner[["hwnd"]],0xC2/*_EM_REPLACESEL*/,,str?tostring(str):"") } }; load = function(path){ if(!type.isString(path)) error("文件路径必须是字符串",2); owner.text = ..string.load(path); owner.modified = false; }; save = function(path){ if(!type.isString(path)) error("文件路径必须是字符串",2); var r,e = ..string.save(path,owner.text); owner.modified = false; return r,e; }; autoComplete = function(flags){ if(flags===null) flags = 0x21/*_SHACF_FILESYS_DIRS | _SHACF_FILESYSTEM*/; ::Shlwapi := ..raw.loadDll("Shlwapi.dll") ::Shlwapi.SHAutoComplete(owner.hwnd,flags); }; ); with edit._metaProperty{ getsel = getSel;//@Deprecated setsel = setSel;//@Deprecated } /***intellisense() !edit.setCueBannerText( = 指定单行文本框文本为空时的显示的默认提示文本 !edit.setCueBannerText(.("提示文本",是否一直显示) = 指定单行文本框默认提示文本。\n参数 @1 必须是字符串,\n参数 @2 可省略,默认仅失去焦点时显示。\n\nXP 系统不支持此函数、但调用不报错。\n注意 plus 控件提供支持XP系统的 setCueBannerText 函数 !edit.cls = 设计时类名 !edit.color = 获取或修改字体颜色数值 !edit.bgcolor= 获取或修改景颜色数值 !edit.className = 运行时类名 !edit.lineCount = 获取行数 !edit.setSel(.(起始位置,结束位置) = 设置选区,选区包含起始与结束位置。\n如果结束位置小于开始位置则自动交换参数位置。\n\n位置参数以字符为单位,1 为首字符。\n计算选区时 edit 控件控件将回车换行( CRLF '\r\\n' ) 计为两个字符单位。\nrichedit 控件将回车换行( CRLF )计为一个字符单位 !edit.setSel(.(当前位置) = 无选区。\n移动光标到指定位置的字符后面 !edit.getSel() = 获取选区起始位置,结束位置。\n选区包含起始与结束位置的字符,首字符位置为1\n开始位置在指定的字符前面,结束位置表示指定的字符后面\n只有一个返回值时表示无选区,并表示输入光标在指定字符后面\n返回0表示输入光标在最前面,并且无选区 !edit.selText = 获取或替换选区文本。\n指定 null 值设为空字符串,其他类型转为字符串写入。 !edit.selLine = 获取或设置当前行,\n光标移动到该行开始处,并且滚动到该行,\n设为-1跳转到最后一行 !edit.getLength() = 获取文本长度\n注意是按字符计数,而不是按字节计数 !edit.modified = 用户手动输入会修改此属性。\n调用 selText,appendText,appendLink 等模拟用户输入文本的函数会变更此属性为 true 。\n调用 load,save 会重置此属性为 false 。\n\n修改 text 属性、以及调用 log,print 等函数不会自动变更此属性。\nonChange 事件可使用此属性区分是否用户修改导致的变更。 !edit.validateText( = 校验输入文本。\n全部文本完全符合要求返回 true,否则返回 false。\n\n可在 onChange 事件内调用此函数实时校验输入。\n\n如果需要限制数字,\n更简单的方法是在窗体设计器中设置控件的『限制数字』属性为 true,\n也就是指定控件的创建参数 num 的值为 true。 !edit.validateText(.(模式串,错误标题,错误信息) = 用字符串参数 @1 指定的模式串校验控件的文本属性。\n将文本设为符合匹配的文本,如果找不到匹配文本设为空字符串。\n\n如果修改了文本且指定了字符串参数 @2,@3 ,\n则在控件内用气泡提示显示参数 @2,@3 指定的错误信息,\n并且将焦点切换到该控件,然后将输入光标设置到文本尾部。 !edit.validateText(.(模式串,错误信息) = 用字符串参数 @1 指定的模式串校验控件的文本属性。\n将文本设为符合匹配的文本,如果找不到匹配文本设为空字符串。\n\n如果修改了文本且指定了字符串参数 @2 ,\n则在控件内用气泡提示显示参数 @2 指定的错误信息,\n并且将焦点切换到该控件,然后将输入光标设置到文本尾部。 !edit.validateText(.(校验输入函数,错误信息) = 调用参数 @1 指定的函数校验控件的文本属性,\n该函数必须自参数中接收当前文本并返回合法文本或 null。\n然后将文本设为符合合法的文本,如果校验函数返回 null 设为空字符串。\n\n如果修改了文本且指定了字符串参数 @2 ,则在控件内用气泡提示显示参数 @2 指定的错误信息,\n并且将焦点切换到该控件,然后将输入光标设置到文本尾部。 !edit.validateText(.(限制金额示例,错误标题,错误信息) = @.validateText("<\d+\.\d\d>|<\d+\.\d>|<\d+\.>|<\d+>",\n "不能接受的字符","只能在此输入金额,小数点后不能超过 2 位!") !edit.text = 获取或写入编辑控件文本属性。\n可写入 UTF8 或 UTF16 字符串,写入 null 值转换为空字符串(""),\n其他类型值自动调用 tostring 转为字符串后写入。\n\nedit 或 richedit 控件的文本属性(text)都以回车换行(CRLF '\r\\n')表示换行。\nedit 控件不显示输入文本中缺少回车的单个换行符('\\n'),但 richedit 将其转换为回车换行('\r\\n')。\n注意双引号或反引号包围的原样字符串会将源码中的回车换行解析为'\\n',\n而块注释赋值为原样字符串时会将源码中的单换行解析为'\r\\n'。\n\n在计算选区时 edit 将 CRLF 计为两个字符单位,richedit 将 CRLF 计为一个字符单位。 !edit.value = 控件文本,text 属性的别名。 !edit.disabledText = 当指定文本时,禁用此控件并显示指定文本。\n指定为 null 时,启用此控件并恢复控件之前的正常文本。 !edit.hwnd = 控件句柄 !edit.id = 控件ID !edit.readonly = 是否只读\n只读时禁止编辑 !edit._parentForm = 返回创建控件的容器窗口(win.form对象),所有窗口控件都拥有此只读属性。\n对于使用窗体设计器创建的窗口,也就是返回设计时窗体容器。\n\n即使子窗口移除子窗口样式、更改父子关系,或以 orphanWindow显示,\n控件的 _parentForm 始终都不会改变\n!winform. !edit.getParent() = 返回父窗口\n!static. !edit.setParent(__/*控件对象*/) = 改变父窗口 !edit.hide = 当前控件窗口是否隐藏。\n仅检查当前窗口的可见性样式(窗口 是否移除了 _WS_VISIBLE 样式)。\n不考虑父窗口是否可见,不考虑是否被其他窗口遮挡。\n如果需要同时判断父窗口的可见性,应改用 win.isVisible 函数。\n\n以 `.` 前导的 `.hide()` 作为成员函数被调用时,\n作用等价于将 hide 属性设为 null 。 !edit.disabled = 控件时否禁用 !edit.left = 左侧坐标 !edit.right = 右侧坐标 !edit.top = 顶部坐标 !edit.bottom = 底部坐标 !edit.width = 宽度 !edit.height = 高度 !edit.limit = 字符数限制,注意不是以字节为单位,\n此限制主要用于限制用户输入,对读写text属性无效,\n如果设为0,单行文本框指定为0x7FFFFFFE,多行文本框指定为-1\n如果用于限制log,print等函数输出字符数时,值不能设置过大或设为0、负数等 !edit.log( __,'\r\n' ) = 追加字符串到文本框,可输入多个参数\n如果超出limit属性设定的字符数限制则移除头部多余的字符\n为提升性能,limit不可过大 !edit.dump(__/*变量*/) = 显示变量的值,支持多参数\n注意仅显示普通table,string,number等类型的值,不显示函数等 !edit.deselect() = 取消选定 !edit.print(.(->->->) = 将多个参数转换为字符串,\n并使用制表符分隔各参数追加到文本尾部\n并追加换行\n如果超出limit属性设定的字符数限制则移除头部多余的字符。\n为提升性能,limit 不可过大。\n\n对于 table 对象,aardio 会将其序列化为文本然后输出,\n如果当前已经导入了 JSON 库,则 table 对象自动转换为 JSON 后输出,\n可以用于调试代码显示变量的值。 !edit.printf(.(->->->) = 将多个参数调用string.format格式化后追加到文本尾部\n并追加换行 !edit.appendText( = 追加文本并移动光标插入点到文本尾部。 !edit.appendText(.(追加文本-->->) = 追加文本并移动光标插入点到文本尾部。\n可指定零个、或多个参数,参数可以是字符串、buffer、数值。\n传入其他类型参数会抛出异常。\n返回文本总长度 !edit.scrollCaret() = 滚动到输入光标处,可选用一个数值参数指定新的输入光标位置。 !edit.scrollToLine(.(指定行) = 将光标移动到指定行,并滚动到该行。 !edit.lineScroll(.(滚动行数) = 滚动条垂直滚动指定行数。\n如果不指定参数则滚动到最后一行 !edit.lineToChar(__/*指定行号*/) = 获取指定行首字符位置\n省略参数表示当前行,小于0表示自尾部倒数到指定行,-1表示最后一行 !edit.lineToChar() = 获取当前选定行首字符位置 !edit.lineFromChar(__/*指定位置*/) = 返回指定位置行数 !edit.lineFromChar() = 不指定参数则返回当前行 !edit.lineLength(__/*指定行号*/) = 返回指定行字符数\n省略参数表示当前行,小于0表示自尾部倒数到指定行,-1表示最后一行 !edit.lineText(__/*指定行号*/) = 获取指定行文本\n错误行号返回null空值\n省略参数表示当前行,小于0表示自尾部倒数到指定行,-1表示最后一行 !edit.lineSel(.(行号,替换文本) = 选择指定的行的全部文本,\n行号为-1时表示选取最后一行,\n可选使用参数@2指定一个字符串用于替换该行文本 !edit.redraw() = 刷新 !edit.setRedraw(false) = 禁止重绘 !edit.setRedraw(true) = 恢复重绘 !edit.show(true__) = 显示控件 !edit.getRect() = 控件区块位置(::RECT结构体) !edit.getRect(true) = 控件屏幕区块位置(::RECT结构体) !edit.setRect(rc) = 设置控件区块位置(::RECT结构体) !edit.setRect(rc,true) = 设置控件屏幕区块位置(::RECT结构体) !edit.getClientRect() = 控件文本客户区块位置(::RECT结构体)\n!rect. !edit.setClientRect(.(RECT区块) = 参数为指定文本客户区的RECT结构体\n文本框必须在设计时指定为多行\n在文本框改变大小必须重新设置 !edit.inflateClientRect(.(dx,dy) = 正数增大,负数缩小文本客户区\n文本框必须在设计时指定为多行\n在文本框改变大小必须重新设置 !edit.clientWidth = 控件窗口客户区宽度,只读属性。 !edit.clientHeight = 控件窗口客户区宽度,只读属性。 !edit.setPadding(.(上,右,下,左) = 设置文本边距,所有参数都可以省略。\n文本框必须在设计时指定为多行,\n在文本框改变大小后仍然可以保持此边距。\n\n边距默认应设置缩放前的原始值\n如果参数为 @5 为 true 则边距应为当前 DPI 缩放后的值 !edit.padding = 文本边距\n应通过 setPadding 函数设置该值 !edit.getFont() = 返回控件 LOGFONT 字体,\n返回对象的 h 值会按控件的 DPI 缩放设置自动还原为缩放前大小。\n!logfont. !edit.getFont(true) = 返回控件 LOGFONT 字体,\n返回对象的 h 值为字体实际大小,不会按控件 DPI 设置还原。\n返回字体会设置 noScale 属性为 true,\n使用控件的 setFont 函数或赋值 font 属性时,\nnoScale 属性为 true 的字体同样不会进行自动 DPI 缩放\n!logfont. !edit.setFont(__/*指定字体*/) = 指定 LOGFONT 字体对象,或逻辑字体句柄\n如果不指定 point 值并指定 h 值,字体会按控件的 DPI 缩放设置自动缩放。 !edit.setFont(混入字体属性) = @.setFont(h=-12;name="Tahoma"); !edit.font = 控件字体(LOGFONT 结构体),\n注意获取该属性总是返回新的 LOGFONT 对象,\n修改返回字体并不会更新控件字体,\n除非重新赋值。\n\n建议尽量优先使用 getFont 或 setFont 函数,\n以增强代码可读性\n\n字体会根据控件设置自动处理 DPI 缩放,不需要事先缩放字体大小 !edit.theme = 外观主题,例如\nwinform.button.theme = "Explorer"\nwinform.button.theme = false !edit.modifyStyle(.(remove,add,swpFlags) = 修改窗口样式,所有参数都是可选参数,\n@remove 用数值指定要移除的样式,可使用 _WS_ 前缀的常量\n@add 用数值指定要添加的样式,可使用 _WS_ 前缀的常量\n@swpFlags 可选用数值指定调整窗口选项,可使用 _SWP_ 前缀的常量\n如果指定了 @swpFlag ,则使用该参数调用::SetWindowPos\n细节请参考 win.modifyStyle 函数源码 !edit.modifyStyleEx(.(remove,add,swpFlags) = 修改窗口扩展样式,所有参数都是可选参数,\n@remove 用数值指定要移除的样式,可使用 _WS_EX_ 前缀的常量\n@add 用数值指定要添加的样式,可使用 _WS_EX_ 前缀的常量\n@swpFlags 可选用数值指定调整窗口选项,可使用 _SWP_ 前缀的常量\n如果指定了 @swpFlag ,则使用该参数调用::SetWindowPos\n细节请参考 win.modifyStyle 函数源码 !edit.capture = 是否捕获全局鼠标消息 !edit.close() = 关闭控件窗 !edit.invalidate(__/*可选使用::RECT()对象指定客户区*/) = 使窗口绘图区无效 !edit.invalidate(__/*可选使用::RECT()对象指定客户区*/,0) = 使窗口绘图区无效\n不刷新背景 !edit.update() = 重绘invalidate函数指定的区块 !edit.wrap = 是否启用自动换行,仅richedit支持 !edit.setFocus( = 设置焦点,可指定选区参数 !edit.tabNext(.(移动焦点,是否反向) = 获取下一个支持tab控制焦点的控件\n参数@1为true会自动移动焦点到该控件\n参数@2为true则获取上一个控件,否则获取下一个控件 !edit.disableInputMethod() = 在此控件中关闭输入法, 仅支持英文输入 !edit.tabNext() = !static. !edit.setFocus(.() = 设置焦点到文本框尾部 !edit.setFocus(.(0) = 设置焦点到文本框的指定位置,0 为文本开始位置。 !edit.setFocus(.(0,-1) = 全选并设置焦点。\n注意,不应使用其他负数作为参数。\n尾部倒计数应使用 getLength 函数获取文本长度与负数相加。 !edit.setFocus(.(-1) = 单个参数为负数时,仅设置焦点,不改变选区。 !edit.vScroll() = 滚动到底部 !edit.hScroll() = 滚动到右侧 !edit.vScroll(_SB__) = 滚动竖向滚动条 !edit.hScroll(_SB__) = 滚动横向滚动条 !edit.center(.(目标窗口) = 在目标窗口区域内居中,并调整以保证显示在父窗口或屏幕工作区内。\n\n参数 @1 可指定目标窗口或者目标窗口句柄,设为 0 表示桌面,\n省略目标窗口则默认取父窗口或所有者窗口。 !edit.setPos(.(x坐标,y坐标,宽,高,插入位置,参数) = 调整窗口位置或排序,所有参数可选\n同时指定x,y坐标则移动位置\n同时指定宽高则改变大小\n指定插入位置(句柄或_HWND前缀常量)则调整Z序 !edit.getPos() = 返回相对坐标,宽,高\nx,y,cx,cy=win.getPos(hwnd) !edit.selectAll() = 全选 !edit.redo() = 重做 !edit.undo() = 撤消 !edit.clear() = 清除选中文本 !edit.copy() = 复制 !edit.cut() = 剪切 !edit.paste() = 粘贴 !edit.canRedo() = 能否重做 !edit.canUndo() = 能否撤消 !edit.canPaste() = 能否粘贴 !edit.canCopy() = 能否复制,\n实际上也就是判断是否存在选区 !edit.enablePopMenu() = @.enablePopMenu(function(){\n return { \n { /*分隔线*/ }; \n { "自定义菜单项"; function(id){\n __/*enablePopMenu 用于启用文本框的右键菜单。\n可选指定要增加的菜单配置表(或返回菜单配置表的函数)作为参数。\n菜单配置表将作为参数传给 win.ui.popmenu 对象的 addTable 函数。\n格式请查看该函数说明函数。\n调用此函数必须事先引用 win.ui.menu 。*/\n }; !owner.canCopy() ? 1/*_MF_GRAYED*/ : 0}; \n }\n}) !edit.saveScale() = 根据控件当前位置、缩放比例,更新控件的设计时位置参数。\n以避免下次窗口缩放自适应调整控件当前位置更改被清除,\n控件所有调整位置的属性或成员函数已自动调用此函数。 !edit.reloadScale() = 按设计时位置参数、重新调整控件位置以适应窗口当前缩放比例。\n父窗口缩放时会自动执行此操作。\n默认在启动窗口消息循环时会自适应调整所有控件。\n所以在启动消息循环前添加控件不必调用此函数。 !edit.threadCallable() = 开启此控件的跨线程调用功能 !edit.orphanWindow(.(transparent,hwndBuddy,borderless) = 创建悬浮窗口。\n悬浮窗口是模仿子窗口外观效果的独立窗口,父窗口可自动调整子窗口到设定位置。\n可选参数 @transparent 为 true 则转换为分层透明窗口。\n可选利用 @hwndBuddy 参数指定外部进程窗口句柄的并附加在内部控件上以实现相同的效果。\n伙伴窗口总是会保持在悬浮窗口前面,并保持相同的大小、位置。\n可重复调用此函数更换伙伴窗口,旧的伙伴窗口必须自行关闭。\n可选指定 @borderless 参数 为 true 以移除 @hwndBuddy 的窗口边框。 !edit.lines(忽略空白) = @for line in ??.lines(true){ __/*遍历所有文本行,\n如果迭代器参数为true则清除每行首尾空格,并忽略空行*/ } !edit.isDialogMessage = @.isDialogMessage = function(hParent,msg){__/*在控件范围内替代父窗口的 isDialogMessage,\n可用于在控件范围内屏蔽对话框快捷键。\n可用于禁用 tab 控制键的多行文本框支持按 tab 输入制表符*/} !edit.translateAccelerator(msg) = @.translateAccelerator = function(msg){ var vk = msg.wParam; if( (vk == 0x9/*_VK_TAB*/ ) || (vk = 0xD/*_VK_RETURN*/) ){ if( msg.message == 0x100/*_WM_KEYDOWN*/) { owner.tabNext(true); return true;__/*在此事件中可拦截键盘消息并自定义快捷键\ntabNext函数切换到下一个支持tab控制键的控件\n如果这是一个快捷键返回true以取消该消息的默认行为*/ } } } !edit.onOk() = @.onOk = function(ctrl,alt,shift){ __/*在编辑框内按下回车触发此事件,返回 true 阻止默认事件。\n回调参数分别表示对应按钮是否已同时按下。*/ return true; } !edit.onCancel() = @.onCancel = function(){ __/*当前已按下ESC,返回true阻止默认事件*/ return true; } !edit.onChange() = @.onChange = function(){ if(!owner.modified) return; //只有用户输入导致更改时 modified 才会是 true owner.validateText("<\d+\.\d\d>|<\d+\.\d>|<\d+\.>|<\d+>" ,"请输入金额,小数点后不能超过 2 位!"); __/*响应事件,文本内容已变更,\nedit 控件启用多行时用 text 属性赋值文本不会触发此事件,\n设为单行 edit 修改 text 属性可触发此事件(使用 modified 属性区分)。\nlog,print 函数调用也是基于修改 text 属性实现,也不会触发此事件。\n但 appendText,selText 修改插入点文本的调用会触发此事件。*/ } !edit.onFocusGot() = @.onFocusGot = function(){ __/*响应事件,文本框已获得输入焦点*/ } !edit.onFocusLost() = @.onFocusLost = function(){ __/*响应事件,文本框已失去输入焦点*/ } !edit.onSize = @.onSize = function( width,height,wParam ) { \n __/*父窗口改变大小后会自动触发此事件函数。\n注意 onSize 是 adjust 事件的别名,作用相同\n所有 win.form 创建的窗体和控件都支持 onSize(或 adjust)事件,\n重复赋值 onSize(或 adjust)会追加事件触发器而非替换原来的值。\n\nwidth 参数为窗口客户区宽度,height 参数为窗口客户区高度,\nwParam 参数来自 _WM_SIZE 消息的 wParam 参数,一般不用管。\n一般不建议添加一个 wndproc 仅仅是为了处理 _WM_SIZE 消息,\n定义 onSize 事件是更好的选择。\n \n};*/ !edit.adjust = @.adjust = function( cx,cy,wParam ) { \n __/*父窗口改变大小后会自动触发此事件函数。\n注意 onSize 是 adjust 事件的别名,作用相同。\n所有 win.form 创建的窗体和控件都支持 adjust 事件,\n重复赋值 adjust 会追加事件触发器而非替换原来的值。\n\ncx 参数为窗口客户区宽度,cy 参数为窗口客户区高度,\nwParam 参数来自 _WM_SIZE 消息的 wParam 参数,一般不用管。\n一般不建议添加一个 wndproc 仅仅是为了处理 _WM_SIZE 消息,\n定义 adjust 事件是更好的选择。\n\n如果主动调用此函数,则检查并执行所有之前添加的 adjust 事件函数。\n省略调用参数时 cx,cy 参数默认设为窗口大小*/ \n}; !edit.preadjust = @.preadjust = function( cx,cy,wParam ) { \n __/*窗口缩放后重绘前、触发 adjust 事件之前触发此事件。\n所有 win.form 创建的窗体和控件都支持此事件,\n与 adjust 事件不同,对 preadjust 重复赋值则覆盖而不是追加事件。 \n\ncx 参数为窗口宽度,cy 参数为窗口高度,\nwParam 为 _WM_SIZE 消息参数。*/ \n}; !edit.resize(.(宽度,高度) = 如果指定了参数则调整窗口大小,\n无论是否实际调整窗口大小,发送 _WM_SIZE 消息给窗口 !edit.addCtrl(controlsPropertiesTable) = @.addCtrl(\n cls="spin";marginRight=2;marginTop=1;marginBottom=4;width=16;\n oncommand = function(id,event,pos){ \n if( pos && event == 0x4/*_SB_THUMBPOSITION*/ ){\n winform.edit.text = string.format("%.2f",pos / 100 )\n }\n }\n)__/*在 richedit 控件窗口内添加子窗口*/ !edit.passwordChar = 单行文本框可用此属性指定隐藏密码的占位字符,不适用于多行文本框。\n即使在创建控件时未启用密码样式此属性同样有效。\n例如指定为`*`则所有输入字符显示星号,指定为 null 正常显示文本 !edit.sendMessage(.(msg,wParam,lParam) = 发送窗口消息\n此函数用法请参考 ::User32.SendMessage !edit.postMessage(.(msg,wParam,lParam) = 投递窗口消息到消息队列中\n此函数用法请参考 ::User32.PostMessage !edit.publish("__/*发布消息名*/",) = 在窗口所在界面线程发布消息,\n运行界面线程所有所有调用subscribe函数订阅此消息的函数,\n可添加任意个触发参数 !edit.showBalloonTip( = 显示气泡提示,\n建议直接调用showInfoTip,showWarningTip 或 showErrorTip !edit.showBalloonTip(.(title,text,icon) = 在输入光标处显示汽泡提示,\n@title参数指定标题,\n@text参数指定文本,\nicon指定图标句柄,可省略 !edit.showBalloonTip(.(text) = 在输入光标处显示汽泡提示,\n@text参数指定文本 !edit.showInfoTip( = 在输入光标处显示汽泡提示 !edit.showInfoTip(.(title,text,large) = 在输入光标处显示汽泡提示,使用提示信息图标,\n@title参数指定标题,\n@text参数指定文本,\nlarge指定是否使用大图标,可省略 !edit.showInfoTip(.(text) = 在输入光标处显示汽泡提示,使用提示信息图标,\n@text参数指定文本 !edit.showWarningTip( = 在输入光标处显示汽泡提示,使用警告图标 !edit.showWarningTip(.(title,text,large) = 在输入光标处显示汽泡提示,使用警告图标,\n@title参数指定标题,\n@text参数指定文本,\nlarge指定是否使用大图标,可省略 !edit.showWarningTip(.(text) = 在输入光标处显示汽泡提示,使用警告图标,\n@text参数指定文本 !edit.showErrorTip( = 在输入光标处显示汽泡提示,使用错误图标 !edit.showErrorTip(.(title,text,large) = 在输入光标处显示汽泡提示,使用错误图标,\n@title参数指定标题,\n@text参数指定文本,\nlarge指定是否使用大图标,可省略 !edit.showErrorTip(.(text) = 在输入光标处显示汽泡提示,使用错误图标,\n@text参数指定文本 !edit.getRoot() = 获取顶层父窗口,这个函数会查找 orphanWindow 的父窗口 !edit._defWindowProc(hwnd,message,wParam,lParam) = 用于在 wndproc 回调中提前调用默认消息回调函数,\n所有窗口和控件定义了 wndproc 回调以后会自动创建这个函数,\n调用此函数以后,wndproc 必须指定非 null 返回值,\n以避免再次重复调用默认回调函数 !edit.translateCommand() = 允许转发转发子窗口的命令(_WM_COMMAND)与通知(_WM_NOTIFY)消息,\n避免子窗口 oncommand,onnotify 等回调失效。\n同时会处理子窗口的 _WM_CTLCOLORSTATIC 等消息,\n以避免部分外观属性失效 !edit.valid = 窗口是否有效,\n窗口未关闭返回 true ,\n窗口已关闭或正在关闭返回 false !edit.load(__) = 自参数 @1 指定的文件路径加载文本。 !edit.save(__) = 保存控件文本到参数 @1 指定的文件路径。 !edit.caretPos = 输入光标所在文本插入点位置,以字符为单位。\n有选区则返回选区最后一个字符的位置,\n无选区则返回插入点前面的字符位置。 !edit.leftText(__) = 获取参数 @1 指定位置之前的文本,\n以字符为单位,负数自右侧倒计数。\n不指定参数获取输和光标所在插入点之前的文本。 !edit.rightText(__) = 自文本尾部获取参数 @1 指定字符个数的文本,\n负数自左侧倒计数,以字符为单位。\n不指定参数获取输入光标所在插入点之后的文本。 !edit.autoComplete(__) = 启用自动完成功能。\n参数 @1 可用数值指定选项,IDE 中可用 _SHACF_ 前缀列出可用的自动完成常量。\n全部可用选项请参考 API 函数 ::Shlwapi.SHAutoComplete 的文档。\n\n如果不指定参数则默认指定为 `0x21/*_SHACF_FILESYS_DIRS | _SHACF_FILESYSTEM*/`\n以启用文件与目录路径的自动完成功能。\n\n使用 com.autoComplete 库可以自行指定自动完成列表的数据。 !edit.addCtrl() = !static. ?win.ui.ctrl.edit =!edit. win.ui.ctrl.edit() = 文本框控件\n!edit. win.ui.ctrl.edit = 文本框控件支持库 end intellisense***/