65.9K
CodeProject 正在变化。 阅读更多。
Home

自动滚动 Rich/Textbox

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.12/5 (9投票s)

2008年2月1日

CPOL

4分钟阅读

viewsIcon

179728

downloadIcon

3708

如何按指定像素滚动文本框

引言

我遇到了一个自动滚动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 接收到的所有滚动消息。

scrollMsg.JPG

一个典型的滚动消息

<0007>000206B6 S WM_VSCROLL nScrollCode:SB_THUMBTRACK nPos:16 hwndScrollBar:null) 
  • <0007> 只是记录器行号
  • WM_VSCROLL 是消息的类型,在我们的例子中是垂直滚动消息
  • SB_THUMBTRACK 是消息的第一个参数。
    第一个消息参数告诉我们执行的滚动类型。
    在给出的示例中,我正在拖动滚轮。

下面给出了第一个参数值的完整列表

  • nPos 指定要滚动到的位置,它是第一个参数的一部分,并且仅适用于 SB_THUMBPOSITIONSB_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 日:初始帖子
© . All rights reserved.