【问题标题】:Customize Windows Form Scrollbar自定义 Windows 窗体滚动条
【发布时间】:2011-05-18 13:10:13
【问题描述】:

我搜索了万维网,但没有找到正确的答案。

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

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

从我在网上找到的内容来看,这似乎很棘手。

有什么解决办法吗?

干杯!

【问题讨论】:

    标签: .net vb.net winforms controls scrollbar


    【解决方案1】:

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

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

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

    【讨论】:

    • 非常感谢科迪·格雷的回答!我将查看您链接的文章。我希望这可以帮助其他正在寻找相同信息的人。
    • @Anders:我刚刚意识到这篇文章是用 C# 编写的,而您的问题被标记为 VB.NET,但两者之间的转换相对简单。如果遇到麻烦,请尝试使用在线转换器之一like the one provided by DeveloperFusion。我很高兴能帮上忙!
    • 是的,那不是问题:) 如果我能得到它的逻辑,我会自己做。你知道不能偷懒! ;) 感谢您的提醒!
    【解决方案2】:

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

    背景

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

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

    幸运的是,Windows 窗体公开了一个属性 CreateParams,可以重写该属性以指定确切的窗口样式以及其他 Control 创建参数。该属性反过来被 .NET 框架使用,因此它可以在 Control 被实例化时创建具有适当样式的 HWND

    自定义滚动条

    为滚动条替换 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 样式,最好不要与之抗争。避开 Windows API 并直接从Control 扩展将是一种更简洁的方法。然后我们可以提供我们想要的任何 API。

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

    1. 为鼠标滚轮事件更新滚动条。
    2. 根据单击自定义滚动条按钮和曲目/拇指来更新滚动条。
    3. 根据添加/删除/移动/调整子控件大小来更新滚动条。
    4. 创建自动滚动边距。
    5. 影响滚动条何时可见的客户区约束。
    6. 等等……

    或者,一种简单的方法可能是创建一个新的UserControl。这将允许我们使用 Visual Studio 设计器来简化配置我们的滚动条按钮和轨道。

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

    【讨论】:

      【解决方案3】:

      这对于 C# 以及与 Cody Gray https://stackoverflow.com/a/4326046/4342139 发表在已接受答案中的文章有关。我会直接在那里发表评论,但我对此没有声誉。

      如果您像我一样并遵循 Cody Gray 的回答中的文章,那么要隐藏滚动条,您将使用内面板和外面板。这不是最佳解决方案,坦率地说是“奇怪和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 似乎并没有伤害它(似乎根本不起作用,但也许我错过了一些东西)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-18
        • 2017-02-16
        • 2015-02-21
        • 1970-01-01
        • 1970-01-01
        • 2013-08-06
        • 2010-10-18
        相关资源
        最近更新 更多