自动滚动 Rich/Textbox






4.12/5 (9投票s)
如何按指定像素滚动文本框
引言
我遇到了一个自动滚动richtextbox
的问题。例如:每 40 毫秒滚动一个像素。
使用 C# 在 Visual Studio 2005 下,我在表单上放置了一个新的 richtextbox
,并希望看到一个类似于 scroll(int pixels)
的方法,该方法位于 richtextbox
的可用方法中。
使用智能感知,我们得到以下相关选项:ScrollToCaret()
。
ScrollCaret()
将把我们的 textbox
滚动到给定的文本,这肯定不能满足我们的需求。
好的,那么我们还有什么? 令人惊讶的是,就这些了。
背景
那么我们如何实现平滑的自动滚动效果呢?
我们将使用 Win32 API SendMessage
方法向我们的 textbox
发送一个滚动消息,要求它以像素为单位滚动自身。
如果您不熟悉消息,我强烈建议阅读以下解释:message_loop。
那么滚动消息是什么样的呢?
使用 Microsoft Spy ++,我们将查看发送到我们的 textbox
的所有滚动消息。
首先,启动您的 ScrollTextBox
应用程序,它应该是一个带有 rich/textbox
的表单,其中包含一些文本。 这将为您提供一个滚轮来玩。
然后运行 Spy++ 并单击日志消息图标(ctrl + m)。
将范围拖放到您的 textbox
上,接下来单击“消息”选项卡,并在“消息组”下仅选择“滚动条”选项,单击“确定”。
应该会出现一个新对话框:“消息(窗口 000206B6),尽管您可能会得到一个不同的窗口号。”
现在使用向上/向下箭头或拖动滚轮来滚动您的 textbox
,并观看 Spy 记录 textbox
接收到的所有滚动消息。

一个典型的滚动消息
<0007>000206B6 S WM_VSCROLL nScrollCode:SB_THUMBTRACK nPos:16 hwndScrollBar:null)
<0007>
只是记录器行号WM_VSCROLL
是消息的类型,在我们的例子中是垂直滚动消息SB_THUMBTRACK
是消息的第一个参数。
第一个消息参数告诉我们执行的滚动类型。
在给出的示例中,我正在拖动滚轮。
下面给出了第一个参数值的完整列表
nPos
指定要滚动到的位置,它是第一个参数的一部分,并且仅适用于SB_THUMBPOSITION
或SB_THUMBTRACK
滚动。hwndScrollBar
是消息的第二个参数,并且始终为null
。
以下是 wParam
值到 WM_VSCROLL
消息的低位字列表
SB_LINEUP
SB_LINEDOWN
SB_THUMBPOSITION
SB_THUMBTRACK
SB_TOP
SB_BOTTOM
SB_ENDSCROLL
SB_PAGEDOWN
SB_PAGEUP
我们的简单应用程序将做什么,是使用 SB_THUMBTRACK
参数向 textbox
发送 WM_VSCROLL
消息。 它将把 wParam
的高位字设置为我们希望滚轮所在的位置。
导入 user32.dll
为了发送消息,我们需要从 Win32 API 导入 sendmessage
方法
[DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
protected static extern IntPtr SendMessage
(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
现在我们可以向我们获得的任何句柄发送消息。
int SB_LINEUP = 0;
ptrWparam = new IntPtr(SB_LINEUP);
ptrLparam = new IntPtr(0);
SendMessage(txtArea.Handle, WM_VSCROLL, ptrWparam, ptrLparam);
上面的代码将向上滚动 txtArea
一行。 要按 n 像素值滚动 textbox
,我们需要做更多的工作。
我们需要一种方法来确定我们的滚轮目前在哪里。 然后我们可以将它的位置增加一个像素值,剩下的就是使用新位置将新的 SB_THUMBTRACK
消息发送回 textbox
。 使用 Win32 API GetScrollInfo
方法,我们可以获取关于滚轮的各种信息
GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);
Hwnd
是我们textbox
的句柄。fnBar
是结构SCROLLINFO
的大小。lpsi
是一个将保存关于滚轮信息的结构。
SCROLLINFO
结构
struct SCROLLINFO
{
public uint cbSize;
public uint fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
有关结构的更多信息,请访问 MSDN。
我们需要的是 nPos
变量,它将保存当前的滚轮位置。 因此,我们的基本滚动方法将做类似这样的事情
// Scrolls a given textbox. handle: an handle to our textbox. pixles:
// number of pixels to scroll.
void scroll(IntPtr handle, int pixles)
{
// Get current scroller position
SCROLLINFO si = new SCROLLINFO();
si.cbSize = (uint)Marshal.SizeOf(si);
si.fMask = (uint)ScrollInfoMask.SIF_ALL;
GetScrollInfo(handle, (int)ScrollBarDirection.SB_VERT, ref si);
// Increase position by pixles
si.nPos += pixles;
// Reposition scroller
SetScrollInfo(handle, (int)ScrollBarDirection.SB_VERT, ref si, true);
// Send a WM_VSCROLL scroll message using SB_THUMBTRACK as wParam
// SB_THUMBTRACK: low-order word of wParam, si.nPos high-order word of wParam
IntPtr ptrWparam = new IntPtr(SB_THUMBTRACK + 0x10000 * si.nPos);
IntPtr ptrLparam = new IntPtr(0);
SendMessage(handle, WM_VSCROLL, ptrWparam, ptrLparam);
}
就这样,现在让 textbox
平稳地滚动自身。 使用计时器每 40 毫秒调用上述方法,并每次将滚轮位置增加 1 像素。
结束
令人惊讶的是,这个简单的“功能”并未内置到 textbox
功能中。
我花了一些时间寻找我问题的快速解决方案,但找不到一个。
所以我决定发布我的解决方案。 我希望它会派上用场,如果您有任何问题或意见,请随时发布或给我发电子邮件。
历史
- 2008 年 2 月 1 日:初始帖子