.NET表单的平滑滚动

5

您好,我正在使用.NET中的表单,并在运行时动态添加了许多链接标签,将这些链接标签添加到面板并将该面板添加到窗体中。当链接标签的数量增加时,窗体会自动添加一个垂直滚动条......

现在,当我使用该自动滚动条向下滚动时,窗体在滚动时不会更新其视图,只有当我停止滚动时,窗体才会刷新...

此外,当它刷新时看起来很糟糕... 我可以看到它如何缓慢绘制....

有人之前遇到过这个问题吗?

我尝试在滚动事件处理程序中使用form.refresh(),但似乎没有帮助...

有任何线索吗?

4个回答

6

将这段代码放入你的类中(UserControl、Panel等),那么它就能通过拖动滑块来工作。

private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;

protected override void WndProc (ref Message m)
{
    if ((m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL)
    && (((int)m.WParam & 0xFFFF) == 5))
    {
        // Change SB_THUMBTRACK to SB_THUMBPOSITION
        m.WParam = (IntPtr)(((int)m.WParam & ~0xFFFF) | 4);
    }
base.WndProc (ref m);
}

先生,您真是位绅士。这个问题一直困扰着我 :) - Martin
1
你能否对这里的操作添加更多详细信息?我试图从这里进行跟踪 -> https://learn.microsoft.com/en-us/windows/win32/controls/wm-vscroll - eri0o
我不知道,它是从某个地方找来的。 - CharlesW

6

如果您不想使用WinAPI调用,可以这样做:

// Add event handler to an existing panel
MyPanel.Scroll += new EventHandler(MyPanelScroll_Handler);

// Enables immediate scrolling of contents
private void MyPanelScroll_Handler(System.Object sender, System.Windows.Forms.ScrollEventArgs e)
{
    Panel p = sender As Panel;
    if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll) {
        p.HorizontalScroll.Value = e.NewValue;
    } else if (e.ScrollOrientation == ScrollOrientation.VerticalScroll) {
        p.VerticalScroll.Value = e.NewValue;
    }
}

2
尝试将表单的DoubleBuffered属性设置为True。
更新:实际上,由于您的控件位于表单上的面板上,所以这可能不起作用。内置的Panel控件没有公开的DoubleBuffered属性,因此要做的方法是向项目中添加一个名为DBPanel的用户控件,并更改代码,使其从Panel而不是UserControl继承(在添加后可以在CS文件中手动更改)。当您添加用户控件时,代码将如下所示:
public partial class DBPanel : UserControl
{
    public DBPanel()
    {
        InitializeComponent();
    }
}

将其编辑为以下内容(将UserControl更改为Panel并在构造函数中添加“this.DoubleBuffered = true;”行):

public partial class DBPanel : Panel
{
    public DBPanel()
    {
        InitializeComponent();
        this.DoubleBuffered = true;
    }
}

当您构建项目时,编译器会在以“this.AutoScaleMode ...”开头的行上报错。删除此行并重新构建。

现在,您可以在表单上使用DBPanel控件来替换常规面板,这应该解决您的闪烁问题。

更新2:很抱歉,我没有仔细阅读您的问题。您是对的,直到您松开滚动条的拇指,面板才会重新绘制自己。我认为要实现这种效果,您只需要创建自己的UserControl。

基本上,您只需将一个VScrollBar停靠在右侧的UserControl与AutoScroll = false的Panel停靠在左侧占据其余空间。随着您移动拇指,VScrollBar的滚动和ValueChanged事件会触发,因此在向内部Panel添加大量LinkLabel后,您可以使用这些事件来更改Panel的顶部位置,从而实现您正在寻找的动态滚动效果。

令人恼火的是,面板默认情况下不起作用,甚至没有启用它的设置。


我尝试了完全相同的事情 public partial class CustomPanel : Panel { public CustomPanel() { InitializeComponent(); this.DoubleBuffered = true; this.AutoSize = true; this.AutoSizeMode = AutoSizeMode.GrowAndShrink; } 没有起作用... 表单/面板只有在我释放鼠标按钮后才会更新,并且在滚动条上单击并向下滚动时不会更新。 - FatDaemon

0

最简单的方法是在滚动事件期间刷新面板。


private void panel1_Scroll(object sender, ScrollEventArgs e)
{
        panel1.Refresh();
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接