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

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

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

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

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

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


登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...