创建一个标准控件(CScrollBar)and 并且自己处理一些消息。
CScrollBar不支持owner_draw和custom_draw, 所以我们只能从WM_PAINT消息进行完全重绘。
明显我们需要处理WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE来更新滚动条位置。
为了模仿标准scrollbar控件,我们支持所有WM_VSCROLL请求。用其他消息模仿,而非WM_VSCROLL消息。
你可能注意到 标准滚动条 对于多次重复的 点击事件 只处理一次。
别忘记 捕获 鼠标在 滚动条外的 鼠标消息。
再多说一个重点,对于SBM_SETSCROLLINFO的处理。 我已经发现,当控件接收这个消息时,它看起来和标准控件一样,直到repaint重画消息被调用。 所以,我必须强制去处理这个notification.如下:
LRESULT CMyScrollbar::OnSetScrollInfo( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ ){ const BOOL fRedraw = ( BOOL ) wParam; LRESULT res = DefWindowProc( uMsg, ( WPARAM ) FALSE, lParam ); if ( fRedraw ) { Invalidate(); } return res;}
为了方便使用,滚动条控件中 包含了一个 伙伴hwnd, 他直接指向一个窗口,可以发送WM_VSCROLL来改变滚动位置。
如果我们希望使用 自定义的 scrolling, 我们不得不使用LVS_NOSCROLL类型的listview控件。
结果是 控件完全停止了对滚动的处理。 该怎么办? 看起来 只有 模仿滚动消息WM_VSCROLL。
来继承它,我们决定来记住 当前第一个可见的item位置 并且 改变它 当滚动事件被触发(用m_IndexOffset来记忆滚动条位置。) 听起来很困难? 但这是最重要的一个,相对其他更多容易处理的问题。
多说两句,我为什么在OnPrePaint绘画。 正如你所知, 我们可以返回CDRF_NOTIFYITEMDRAW值为每个重绘的item接收附加的消息。
问题出在我们使用 普通listview的过程。 因为我们阻止了scolling(现在使用的是LVS_NOSCROLL style), we work on the first GetCountPerPage
items. 在每次我们因为client获得WM_PAINT时, 意味着这些item需要重绘, 我们不知道哪个具体的item需要重绘: 有相对坐标和绝对指向。
所以,我决定去杀掉两个问题通过一种方法: 不要在意item的indices, 我们需要尽可能简单的重绘,
不要忘记使用WM_MEASUREITEM消息, 如果需要来改变list control item 高度。
WM_CTLCOLORXXX消息用来检索 控件保存着的画刷(滚动条,list, 单选)。每个控件使用自己的画刷,因为他们创建有自己的区域。
来源:https://www.cnblogs.com/oleeceo/archive/2011/04/06/2007332.html