gpt4 book ai didi

c# - 如何在自动滚动设置为 false 的情况下使用可滚动控件

转载 作者:太空狗 更新时间:2023-10-29 20:31:31 25 4
gpt4 key购买 nike

我有一个自定义控件,可以在自定义绘制的文档 Canvas 上进行缩放。

我尝试使用 AutoScroll,但结果并不令人满意。当我将 AutoScrollPosition 和 AutoScrollMinSize 背对背设置(以任何顺序)时,它会强制绘制并在每次缩放更改时引起抖动。我认为这是因为当我修改这两个属性时它调用的是 Update 而不是 Invalidate。

我现在手动设置 Horizo​​ntalScroll 和 VerticalScroll 属性,并将 AutoScroll 设置为 false,就像每次缩放级别或客户端大小发生变化时一样:

int canvasWidth = (int)Math.Ceiling(Image.Width * Zoom) + PageMargins.Horizontal;
int canvasHeight = (int)Math.Ceiling(Image.Height * Zoom) + PageMargins.Vertical;

HorizontalScroll.Maximum = canvasWidth;
HorizontalScroll.LargeChange = ClientSize.Width;

VerticalScroll.Maximum = canvasHeight;
VerticalScroll.LargeChange = ClientSize.Height;

if (canvasWidth > ClientSize.Width)
{
HorizontalScroll.Visible = true;
}
else
{
HorizontalScroll.Visible = false;
HorizontalScroll.Value = 0;
}

if (canvasHeight > ClientSize.Height)
{
VerticalScroll.Visible = true;
}
else
{
VerticalScroll.Visible = false;
VerticalScroll.Value = 0;
}

int focusX = (int)Math.Floor((FocusPoint.X * Zoom) + PageMargins.Left);
int focusY = (int)Math.Floor((FocusPoint.Y * Zoom) + PageMargins.Top);

focusX = focusX - ClientSize.Width / 2;
focusY = focusY - ClientSize.Height / 2;

if (focusX < 0)
focusX = 0;
if (focusX > canvasWidth - ClientSize.Width)
focusX = canvasWidth - ClientSize.Width;

if (focusY < 0)
focusY = 0;
if (focusY > canvasHeight - ClientSize.Height)
focusY = canvasHeight - ClientSize.Height;

if (HorizontalScroll.Visible)
HorizontalScroll.Value = focusX;

if (VerticalScroll.Visible)
VerticalScroll.Value = focusY;

在这种情况下,FocusPoint 是一个 PointF 结构,它保存用户关注的位图中的坐标(例如,当他们用鼠标滚轮放大时,他们关注的是当前鼠标当时的地点)。此功能在大多数情况下都有效。

不起作用的是滚动条。如果用户试图通过单击任一滚动条手动滚动,它们都会返回到 0。我没有在我的代码中的其他任何地方设置它们。我尝试在 OnScroll() 方法中编写以下内容:

if (se.ScrollOrientation == ScrollOrientation.VerticalScroll)
{
VerticalScroll.Value = se.NewValue;
}
else
{
HorizontalScroll.Value = se.NewValue;
}

Invalidate();

但这会导致一些非常不稳定的行为,包括轻弹和滚动出界。

我应该如何编写 OnScroll 的代码?我已经尝试了 base.OnScroll,但是当 AutoScroll 设置为 false 时它没有做任何事情。

最佳答案

我最终通过创建 3 个子控件实现了我自己的自定义滚动:HScrollBar、VScrollBar 和 Panel。

我像这样隐藏 ClientSize 和 ClientRectangle:

public new Rectangle ClientRectangle
{
get
{
return new Rectangle(new Point(0, 0), ClientSize);
}
}

public new Size ClientSize
{
get
{
return new Size(
base.ClientSize.Width - VScrollBar.Width,
base.ClientSize.Height - HScrollBar.Height
);
}
}

布局在 OnClientSizeChanged 中完成:

protected override void OnClientSizeChanged(EventArgs e)
{
base.OnClientSizeChanged(e);

HScrollBar.Location = new Point(0, base.ClientSize.Height - HScrollBar.Height);
HScrollBar.Width = base.ClientSize.Width - VScrollBar.Width;

VScrollBar.Location = new Point(base.ClientSize.Width - VScrollBar.Width, 0);
VScrollBar.Height = base.ClientSize.Height - HScrollBar.Height;

cornerPanel.Size = new Size(VScrollBar.Width, HScrollBar.Height);
cornerPanel.Location = new Point(base.ClientSize.Width - cornerPanel.Width, base.ClientSize.Height - cornerPanel.Height);
}

每个 ScrollBar 都订阅了它们的 Scroll 事件:

private void ScrollBar_Scroll(object sender, ScrollEventArgs e)
{
OnScroll(e);
}

最后我们可以允许 MouseWheel 事件通过以下方式滚动:

protected override void OnMouseWheel(MouseEventArgs e)
{
int xOldValue = VScrollBar.Value;

if (e.Delta > 0)
{
VScrollBar.Value = (int)Math.Max(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), 0);
OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll));
}
else
{
VScrollBar.Value = (int)Math.Min(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), VScrollBar.Maximum - (VScrollBar.LargeChange - 1));
OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll));
}
}

对于自定义绘画,您将使用以下语句:

e.Graphics.TranslateTransform(-HScrollBar.Value, -VScrollBar.Value);

这在使用 AutoScroll 时完美无缺。

关于c# - 如何在自动滚动设置为 false 的情况下使用可滚动控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10286265/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com