利用plus美化和模拟滚动条代替listbox的系统滚动条

By admin at 2020-04-05 • 1人收藏 • 1248人看过

前面写了个音乐播放器, 提到因为嫌弃系统自带的滚动条太丑, 所以就不使用滚动条,直接用鼠标滚轮来操作.

但是, 如果有人的鼠标没滚轮呢?(^_^,虽然不大可能)

那么我们能不能模拟个滚动条呢? 而且可以任意美化就更完美了.

plus控件是aardio对系统组件的重大扩展 , 很多东西都可以用它来实现.

下面我就利用plus的trackbar特性来模拟滚动条的双向交互.

GIF.gif



  1. 首先我们要获取listbox的鼠标滚轮消息, 以便转动滚轮的时候,模拟的滚动条能同时得到响应, 然后就可以改变trackbar的滑块的位置了.

  2. 当我们拖动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自绘扩展库, 会非常适用, 好看.

GIF2.gif

当然, 此次的plusExbar滚动条扩展库也同样适用于listview这样的控件. 大可一试


2 个回复 | 最后更新于 2020-10-04
2020-04-09   #1

参考jacen在另外一个listview模拟滚动条的帖子里提供的简化代码, 这个listbox滚动条也可以再次简化.

将plusExbar模拟库里面增加如下代码, 然后winform里面就可以不必写listbox的wndproc回调了.

listbox.wndproc = function(hwnd,message,wParam,lParam){
    if(message == 0x20A/*_WM_MOUSEWHEEL*/){ 
        if( ::HIWORD(wParam) & 0x8000  ){ 
            if( plus.stepProgress(-1,true) ){
                ::SendMessageInt(listbox.hwnd, 0x115/*_WM_VSCROLL*/, 1, 0);
            }  
        }
        else { 
            ::SendMessageInt(listbox.hwnd, 0x115/*_WM_VSCROLL*/, 0, 0);
            plus.stepProgress(1,true)
             
        }
        return 0;
    };
}


2020-10-25   #2

感谢: The Machine 提供修改版本

GIF.gif

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();


登录后方可回帖

登 录
信息栏
本站永久域名:HtmLayout.Cn
纯私人站,当笔记本用的,学到哪写到哪,目前在学aardio+halcon机器视觉.
加入本站专享群:783804676
AARDIO语言QQ大群:70517368
Aardio 官方站:Aardio官方
Aardio最新功能:Aardio官方更新日志
C大Aardio论坛:Aar爱好者论坛
本 站 主 站:Stm32cube中文网
Sciter中文在线文档Sciter在线学习文档
赞助商:才仁机械




Loading...