利用plus美化和模拟滚动条代替listbox的系统滚动条
By
admin
at 2020-04-05 • 1人收藏 • 2674人看过
前面写了个音乐播放器, 提到因为嫌弃系统自带的滚动条太丑, 所以就不使用滚动条,直接用鼠标滚轮来操作.
但是, 如果有人的鼠标没滚轮呢?(^_^,虽然不大可能)
那么我们能不能模拟个滚动条呢? 而且可以任意美化就更完美了.
plus控件是aardio对系统组件的重大扩展 , 很多东西都可以用它来实现.
下面我就利用plus的trackbar特性来模拟滚动条的双向交互.
首先我们要获取listbox的鼠标滚轮消息, 以便转动滚轮的时候,模拟的滚动条能同时得到响应, 然后就可以改变trackbar的滑块的位置了.
当我们拖动trackbar的滑块的时候, 我们获取到这个消息, 然后在这个消息里发送移动listbox项的指令,使listbox移动.
下面是我封装的一个简易的测试代码库, 测试使用良好,哈哈
1. plusExbar.aardio 模拟滚动条扩展库
//plusExbar 模拟滚动条 class plusExbar{ //绑定的listbox,与之绑定的plus,listbox每项的行高,前景色,背景色 ctor( listbox,plus,iheight,foreColor=0xFF0097DE,backColor=0x757A7A7A ){ plus.skin({ background={ default=backColor }; color={ default=foreColor; } }) var max = listbox.count-..math.floor(listbox.height/iheight); var min = 0; plus.setTrackbarRange(max+1,1); if(max>0){ //锁定最小滑块大小20 if(..math.round(plus.height/max)<=20){ plus.foreTop = 20; var max = listbox.count-..math.floor((listbox.height-20)/iheight); }else{ plus.foreTop = ..math.round(plus.height/max); } }else { plus.foreTop = plus.height; } plus.progressPos = max+1; //..listboxExx(listbox).scrollFunc = function( num ){ listbox.scrollFunc = function( num ){ plus.progressPos +=num; } plus.onPosChanged = function( pos,thumbTrack ){ if(thumbTrack){ //console.log(pos,max+1-pos,max) var goto = max+1-pos+1; var index = listbox.hitTest(1,1); if(goto == index){ //null }else { if(goto>index){ for(i=1;goto-index;1){ ::SendMessageInt(listbox.hwnd, 0x115/*_WM_VSCROLL*/, 1, 0); } }else { for(i=1;index-goto;1){ ::SendMessageInt(listbox.hwnd, 0x115/*_WM_VSCROLL*/, 0, 0); } } } } } plus.orphanWindow(true) }; }
请将上面的代码放在工程的lib目录里.
2. 那么怎么使用呢?
我们首先要在窗口里 拖拽一个listbox , 然后加入上面的plusExbar库, 然后绑定它们即可
import win.ui; /*DSG{{*/ var winform = win.form(text="aardio form";right=432;bottom=469) winform.add( listbox={cls="listbox";left=15;top=12;right=352;bottom=426;edge=1;items={};z=1}; plus={cls="plus";left=360;top=12;right=367;bottom=292;bgcolor=-8750470;border={radius=4};color=14587648;foreTop=33;paddingLeft=1;paddingRight=1;z=2} ) /*}}*/ for(i=1;33){ winform.listbox.add("测试项目--"++i); } winform.listbox.wndproc = function(hwnd,message,wParam,lParam){ if(message == 0x20A/*_WM_MOUSEWHEEL*/){ //滚轮消息 var wheelDelta = ..raw.convert({int wParam=wParam },{word vk;word delta}).delta; if( wheelDelta > 0 ){ ::SendMessageInt(winform.listbox.hwnd, 0x115/*_WM_VSCROLL*/, 0, 0); if(winform.listbox.scrollFunc){ winform.listbox.scrollFunc(1); } }else { ::SendMessageInt(winform.listbox.hwnd, 0x115/*_WM_VSCROLL*/, 1, 0); if(winform.listbox.scrollFunc){ winform.listbox.scrollFunc(-1); } } return 0; }; } import plusExbar; plusExbar(winform.listbox,winform.plus,15,0xFFE057B6); winform.show(); win.loopMessage(); return winform;
那么我们运行, 就可以看到绑定成功了!
这个库如果配合我之前在音乐播放器里发的listboxExx自绘扩展库, 会非常适用, 好看.
当然, 此次的plusExbar滚动条扩展库也同样适用于listview这样的控件. 大可一试
2 个回复 | 最后更新于 2020-10-04
感谢: The Machine 提供修改版本
import win.ui; /*DSG{{*/ var winform = win.form(text="aardio form";right=759;bottom=469) winform.add( button={cls="button";text="添加50项目";left=499;top=128;right=640;bottom=167;z=2}; button2={cls="button";text="清空";left=502;top=202;right=643;bottom=241;z=3}; button3={cls="button";text="删除某项";left=502;top=270;right=643;bottom=309;z=4}; listbox={cls="listbox";left=81;top=32;right=366;bottom=411;items={};z=1} ) /*}}*/ import win.ui.ctrl.plus; class scrollbarEx{ ctor(ctrl,iWidth = 10,itemHeight = 15){//listbox,滚动条宽度、列表项行高 if(!ctrl[["hwnd"]]) error("参数必须是窗口对象",2); this = ctrl; var rc = this.getRect() rc.bottom += itemHeight; this.modifyStyle(,0x4000000/*_WS_CLIPSIBLINGS*/); var dyPlus = winform.add( plus = {cls="plus";left = rc.right-iWidth;top=rc.top; bottom=rc.bottom;width = iWidth;hide=1;bgcolor=-8750470;border={radius=5};color=14587648;foreTop=50;paddingLeft=1;paddingRight=1;dr=1;dt=1;db=1;z=1} ); sb = dyPlus.plus; ..win.setPos(sb.hwnd,,,,,0); ..win.setPos(this.hwnd,,,,,1); sb.skin(style) var max = this.count * itemHeight; //显示区域高度 = 总项目得高度 var overstep = (max - rc.height()) / itemHeight//溢出表项计数 = 超出窗口显示,额外的项目 var thumb = ..math.floor(rc.height() / max * sb.height); var trackPos = overstep; sb.setTrackbarRange(0,overstep); sb.foreTop = thumb; sb.progressPos = trackPos var step = 1 //..math.floor( (max + rc.height()) / sb.foreTop );//绝对高度的时候计算步进 sb.show(overstep > 0); sb.onPosChanged = function( pos,thumbTrack ){ if(thumbTrack){ trackPos = overstep - pos; //..io.print(trackPos) ::SendMessageInt(this.hwnd, 0x115/*_WM_VSCROLL*/,::MAKELONG(4/*_SB_THUMBPOSITION*/,trackPos), 0); } } this.wndproc = function(hwnd,message,wParam,lParam){ select(message) { case 0x20A/*_WM_MOUSEWHEEL*/ { if( ::HIWORD(wParam) & 0x8000){ if(sb.stepProgress(-step)){::SendMessageInt(this.hwnd, 0x115/*_WM_VSCROLL*/, 1/*_SB_LINEDOWN*/, 0);} }else { ::SendMessageInt(this.hwnd, 0x115/*_WM_VSCROLL*/, 0/*_SB_LINEUP*/, 0); sb.stepProgress(step); } return 0; }case 0x115/*_WM_VSCROLL*/{ //..io.print(::HIWORD(wParam),::LOWORD(wParam)) }case 0x200/*_WM_MOUSEMOVE*/{ if(wParam & 1/*_MK_LBUTTON*/){ var x,y = ..win.getMessagePos(lParam); var topIndex = ::SendMessageInt(this.hwnd,0x18E/*_LB_GETTOPINDEX*/,0,0); /*获取列表框中第一个可见项的索引。最初,索引 0 的项位于列表框的顶部, 但如果列表框内容已滚动,则另一项可能位于顶部。多列列表框中的第一个可见项是左上角项。*/ trackPos = overstep - topIndex; sb.progressPos = trackPos; } }case 0x181/*_LB_INSERTSTRING*/{//LB_ADDFILE、LB_ADDSTRING没有尝试,不知道要不要一起处理。 max = (this.count + 1) * itemHeight; //显示区域高度,在_LB_INSERTSTRING事件中,添加表项在事件之前发生实际表项数目要 + 1 overstep = (max - rc.height()) / itemHeight//溢出表项计数 thumb = ..math.floor(rc.height() / max * sb.height); var topIndex = ::SendMessageInt(this.hwnd,0x18E/*_LB_GETTOPINDEX*/,0,0); trackPos = overstep - topIndex; sb.setTrackbarRange(0,overstep); sb.foreTop = thumb; sb.progressPos = trackPos; sb.show(overstep > 0); }case 0x182/*_LB_DELETESTRING*/{ max = (this.count - 1) * itemHeight; //显示区域高度,在_LB_DELETESTRING事件中,删除表项在事件之后发生,实际表项数目要 - 1 overstep = (max - rc.height()) / itemHeight//溢出表项计数 thumb = ..math.floor(rc.height() / max * sb.height); trackPos = overstep; sb.setTrackbarRange(0,overstep); sb.foreTop = thumb; sb.progressPos = trackPos; sb.show(overstep > 0); }case 0x184/*_LB_RESETCONTENT*/{ sb.show(false); } } } }; } namespace scrollbarEx{ style = { background={ default=0xFFE1E1E1; }; color={ default = 0xffc4c4c4; hover = 0xFF999999; active = 0xFF999999; } } } io.open() for(i=1;50;1){ winform.listbox.add("这是测试项目--" ++ i ) } winform.button.oncommand = function(id,event){ for(i=51;100;1){ winform.listbox.add("这是测试项目--" ++ i ) } } winform.button2.oncommand = function(id,event){ winform.listbox.clear() } winform.button3.oncommand = function(id,event){ winform.listbox.delete(math.random(1,winform.listbox.count)) } scrollbarEx(winform.listbox) winform.show(); win.loopMessage();
登录后方可回帖
参考jacen在另外一个listview模拟滚动条的帖子里提供的简化代码, 这个listbox滚动条也可以再次简化.
将plusExbar模拟库里面增加如下代码, 然后winform里面就可以不必写listbox的wndproc回调了.