自绘滚动条记录

 

 


给软件换肤,滚动条通常是个雷区,一般就跳过了。因为不但要给自己的控件绘制滚动条,还要给微软的控件绘制滚动条。当我们用到ComboBox/ListCtrl/Tree甚至是IE控件和第三方控件的时候,头自然就大了。所以网上一直有自绘难莫过滚动条的说法,看了一些帖子,下载了一些代码,学习一下:)

 

我用CListCtrl做了个试验。一开始,我就发现滚动条不是独立的窗口,调用GetScrollBarCtrl自然无法得到任何结果。通过截获控件的WM_NCPAINT消息,确定它在非客户区绘制了滚动条。然后我替换了控件的WindowProc处理函数,在相关函数处理后,再重绘滚动条。结果看起来貌似可以,但有两点遗憾:一是滚动条有不明显的闪动,二是用鼠标拖拽滚动条滑块的时候,还是会出现系统默认的滚动条。原来滚动条的拖动是在uxtheme.dll里处理的(winXP),比较正统的处理办法是截获相关函数调用重绘(HOOK达不到这一点,要用一点简单的汇编才行)。考虑到老的win98/2000等,还是算了吧,再说winXP也不年轻了,呵呵。本想放手,抱着最后的一线希望:如果拖动的时候把滚动条挖掉,用桌面DC重绘可不可以呢,但还要求在挖掉的区域又反应?这要看微软的机制给不给面子。用SPY++可以观察到拖动调用了WM_SYSCOMMAND,可以截获。拖动过程中调用了WM_VSCROLL,仍然要处理。结果还算不失望,于是第二个bug解决了。

另外还有第二种方法:给控件加一个CScrollBar子窗口,覆盖到滚动条的位置。这也是目前普遍用到的办法。使用CScrollBar比较复杂(和内置滚动条相比较),滚动条和视图之间的同步要自己处理。但这种滚动条实现自绘比较简单,通常子类化就可以了。所以这种方法对于自己实现的特殊控件,比较容易;而对于系统内置的滚动条,就鞭长莫及了。

 

总结一下:

1.微软的滚动条有两种:一种是从CWnd继承而来的CScrollBar,为方便用户提供的一个控件,和普通控件一样,可以自绘;另外一种是内置的滚动条,主要用于View系列和控件,对其功能进行了封装,没有提供介入的接口。

2.自绘滚动条有上面提到的两种方法:替换WindowProc函数或者添加滚动条控件。

3.网上的例子基本是添加的子窗口,coolsb是比较强大的一个库,用C写的而不是C++,但有个bug,就是我上面提到的拖动。

4.今天CSDN上有人新发布了源码(李俊 skinsb.lib),相当的好,方法和coolsb第二种方法一样。极力推荐。

http://download.csdn.net/source/1013411

 

附注(对于内建的滚动条)

   

理想的方案:让系统去计算,而在显示的时候自绘。但画控制条的时候,不只有NCPaint的时候,有些系统函数里直接绘制了,不通过消息。也就找不到一个合适的控制点,取截获所有的系统绘制,结果就是闪动(自己绘制和系统绘制交替)

 

 

 

    coolsb有两套方法,一是coolsb.lib,二是coolsb_detours.lib。基本思路都是截获系统默认信息通路,不让系统知道滚动条信息(这样系统不会绘制,也就不会闪动),自己处理计算、存储滚动条的大小和位置,并在非客户区绘制滚动条工作。不同的是coolsb.lib截获WM_VSCROLL WM_HSCROLL WM_SIZE消息,而coolsb_detours.lib截获的是Get/Set ScrollInfo Get/Set ScrollPos Get/Set ScrollPos ShowScrollBar等一系列API函数。这种控件只能个别对待,对于所有的treelistviewcomboxedit等控件,还要一个一个做标识。

coolsb.lib提供了testmfctesttest贴图滚动条的bug:放大到没有滚动条的时候,其实还是有滚动条的,可以拖动开始初,会显现出系统滚动条mfctest没有贴图滚动条。coolsb_detours.lib只在winNTwin2000winXP系统下可用。

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
可以使用C语言结合LCD库来实现在LCD上显示滚动条,并通过触摸滑块来改变界面的显示。具体实现方式可以参考以下步骤: 1. 首先需要在LCD上绘制一个滚动条的背景,可以使用LCD库提供的绘图函数来实现。 2. 接着需要在滚动条上添加一个滑块,可以使用LCD库提供的绘图函数来实现。 3. 在滑块上添加触摸事件,可以使用触摸屏库提供的触摸事件处理函数来实现。 4. 当滑块被拖动时,需要根据滑块的位置来计算出相应的界面显示内容,并更新LCD上的显示。 以下是示例代码: ```c #include <stdio.h> #include "lcd.h" #include "touch.h" #define BAR_X 50 #define BAR_Y 100 #define BAR_WIDTH 200 #define BAR_HEIGHT 20 #define SLIDER_WIDTH 20 #define SLIDER_HEIGHT 40 int main() { // 初始化LCD和触摸屏 lcd_init(); touch_init(); // 绘制滚动条背景 lcd_draw_rect(BAR_X, BAR_Y, BAR_WIDTH, BAR_HEIGHT, COLOR_GRAY); // 绘制滑块 int slider_x = BAR_X; int slider_y = BAR_Y - (SLIDER_HEIGHT - BAR_HEIGHT) / 2; lcd_draw_rect(slider_x, slider_y, SLIDER_WIDTH, SLIDER_HEIGHT, COLOR_BLUE); // 循环处理触摸事件 while (1) { touch_event_t event = touch_get_event(); if (event.type == TOUCH_EVENT_PRESS) { // 判断触摸点是否在滑块上 if (event.x >= slider_x && event.x < slider_x + SLIDER_WIDTH && event.y >= slider_y && event.y < slider_y + SLIDER_HEIGHT) { // 记录滑块的初始位置 int start_x = event.x; // 循环处理拖动事件 while (1) { event = touch_get_event(); if (event.type == TOUCH_EVENT_RELEASE) { break; } // 计算滑块的新位置 int new_x = slider_x + event.x - start_x; if (new_x < BAR_X) { new_x = BAR_X; } if (new_x > BAR_X + BAR_WIDTH - SLIDER_WIDTH) { new_x = BAR_X + BAR_WIDTH - SLIDER_WIDTH; } // 更新滑块位置 lcd_draw_rect(slider_x, slider_y, SLIDER_WIDTH, SLIDER_HEIGHT, COLOR_GRAY); slider_x = new_x; lcd_draw_rect(slider_x, slider_y, SLIDER_WIDTH, SLIDER_HEIGHT, COLOR_BLUE); // 更新界面显示 // TODO: 根据滑块位置计算出相应的界面显示内容,并更新LCD上的显示 } } } } return 0; } ```
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值