利用plus美化和模拟滚动条代替listbox的系统滚动条
By
admin
at 2020-04-05 • 1人收藏 • 2873人看过
前面写了个音乐播放器, 提到因为嫌弃系统自带的滚动条太丑, 所以就不使用滚动条,直接用鼠标滚轮来操作.
但是, 如果有人的鼠标没滚轮呢?(^_^,虽然不大可能)
那么我们能不能模拟个滚动条呢? 而且可以任意美化就更完美了.
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回调了.
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; }; }