自定义Windows窗体滚动条

时间:2010-12-01 14:39:07

标签: .net vb.net winforms controls scrollbar

我在没有正确答案的情况下搜索了万维网。

在我的Windows窗体应用程序中,我想更改属于FlowLayoutPanel的滚动条的宽度。

“自动”添加滚动条,因为“流布局面板”的内容比“窗体”大。

从我在网上发现的情况来看,这似乎很棘手。

有没有解决方案?

干杯!

3 个答案:

答案 0 :(得分:17)

不,无法更改单个控件上显示的滚动条的宽度(尽管系统范围的设置会影响所有所有滚动条应用)。

丑陋的事实是低滚动条控制远比看起来复杂得多。基本上,FlowLayoutPanel上的滚动条是由Windows本身(而不是.NET Framework)绘制的,因为WS_HSCROLL和/或WS_VSCROLL窗口样式是为后面的控件设置的。场景。 FlowLayoutPanel不提供任何更改或修改这些内置滚动条绘制方式的工具。与WinForms中的其他更高级的修改不同,我们不能将这些消息发送到控件的窗口过程。更糟糕的是,滚动条是在FlowLayoutPanel的非客户区域中绘制的,这意味着我们不能仅覆盖其Paint事件并自己处理滚动条的绘制。

不幸的是,如果你真的想要自定义你的滚动条,你将不得不隐藏内置的滚动条并滚动自己的滚动条。它听起来并不像听起来那么困难,但是,如果你愿意的话。 CodeProject上的This article提供了一个很好的演练,可以创建自己的可换肤滚动条作为用户控件,并将其用作您选择的容器控件中的替换。

答案 1 :(得分:1)

Cody Gray's answer 100%正确,但我想在主题上添加更多参考资料。

背景

Windows窗体创建滚动条的方式是使用window styles WS_HSCROLLWS_VSCROLL。这些样式分别负责为给定的HWND启用水平和垂直滚动条。 HWND"窗口" 的本机资源句柄,在.NET术语中对应于Control

从Windows API的角度思考,我们必须在创建HWND时设置窗口样式。这是通过致电CreateWindowCreateWindowExSetWindowLong来完成的。当然,我们可能会开始考虑使用P/Invoke来帮助我们,但这将是一个很大的负担,因为这意味着我们需要从头开始重新实现Windows窗体。

幸运的是,Windows窗体公开了一个属性CreateParams,可以覆盖该属性以指定其他Control创建参数中的确切窗口样式。这个属性反过来由.NET框架使用,以便在HWND实例化时可以使用适当的样式创建Control

自定义滚动条

替换滚动条的Windows API功能实际上比看起来更简单;然而,这并不明显(对我而言,无论如何,我不得不筛选.NET源来找到答案)。为此,我们必须选择适当的Control继承来创建我们自己的自定义 ScrollableControl 。如果我们观察System.Windows.Forms.ScrollableControl的源代码,我们会看到使用以下样式:

CreateParams cp = base.CreateParams;

if (HScroll || HorizontalScroll.Visible) {
    cp.Style |= NativeMethods.WS_HSCROLL;
}
else {
    cp.Style &= (~NativeMethods.WS_HSCROLL);
}
if (VScroll || VerticalScroll.Visible) {
    cp.Style |= NativeMethods.WS_VSCROLL;
}
else {
    cp.Style &= (~NativeMethods.WS_VSCROLL);
}

因此,简而言之,当我们从ScrollableControl扩展时,将根据其内部逻辑启用本机水平和垂直滚动条。我们可以访问ScrollableControl窗口句柄,然后调用SetWindowLong隐藏滚动条;但是,我们需要跟踪ScrollableControl与Windows API交互的所有位置。实际上,根据是否应显示滚动条,调用内部函数Control.UpdateStylesCore()。这个功能有效地重新应用了上面的窗口样式,最好不要与之抗争。这将是一种更加清晰的方法,可以避开Windows API并直接从Control扩展。然后我们可以提供我们想要的任何API。

这意味着我们将考虑重新实施:

  1. 更新鼠标滚轮事件的滚动条。
  2. 根据单击自定义滚动条按钮和曲目/拇指更新滚动条。
  3. 根据添加/删除/移动/调整子控件的大小来更新滚动条。
  4. 创建自动滚动边距。
  5. 影响滚动条可见时的客户端区域的约束。
  6. 依旧......
  7. 或者,一种简单的方法可能是创建一个新的UserControl。这将允许我们使用Visual Studio设计器来简化滚动条按钮和轨道的配置。

    无论采用哪种方式,都需要了解ScrollableControl内部的工作原理,以便提供舒适的用户体验。

答案 2 :(得分:0)

对于C#而言,这与Cody Gray https://stackoverflow.com/a/4326046/4342139发表在“接受的答案”中的文章有关。我会在那里直接发表评论,但我为此欠缺声誉。

如果您和我一样,并按照科迪·格雷的回答写这篇文章,那么要隐藏滚动条,请使用内部和外部面板。这不是一个最佳的解决方案,坦率地说是“怪异和hacky”。​​我偶然发现了水平滚动条的类似问题,并设法找到了解决方案,同样的事情也适用于垂直滚动。这是一种不太hacky的方式(但不是很多),可以通过以下代码实现:

    panel1.AutoScroll = false;

    panel1.VerticalScroll.Maximum = 0;
    panel1.VerticalScroll.Visible = false;

    panel1.HorizontalScroll.Maximum = 0;
    panel1.HorizontalScroll.Visible = false;

    panel1.AutoScroll = true;

注意:从上面的代码中选择“垂直”或“水平”或两者。 将AutoScroll设置为false,然后再设置为true是至关重要的,否则将不应用设置或禁用AutoScroll。 将“垂直/水平滚动最大值”设置为0似乎只是需要做的事情,但是将Visible设置为false似乎并不会对它造成伤害(似乎根本不起作用,但也许我遗漏了一些东西)。