gpt4 book ai didi

c# - 使用带有固定位置文本的 ScrollableControl 的自定义控件

转载 作者:行者123 更新时间:2023-11-30 15:58:31 24 4
gpt4 key购买 nike

我正在构建将用于显示图 block map 的自定义用户控件,我选择 ScrollableControl 作为基类,因为我希望在我的控件中有滚动条。

我已经成功创建了负责仅绘制所需元素的绘制逻辑。

现在我正在尝试添加始终在同一位置可见的静态文本(在我的例子中是左上角带有红色文本的白色框):

enter image description here

这在上面的 gif 上看不清楚,但是当我使用鼠标或滚动条滚动时,那个白框闪烁并跳动了一下。

我的问题是我应该如何更改我的代码以在该可滚动内容之上具有可滚动内容和固定位置内容?

ScrollableControl 是基类的好选择吗?

下面是我的代码:

class TestControl : ScrollableControl
{
private int _tileWidth = 40;
private int _tileHeight = 40;
private int _tilesX = 20;
private int _tilesY = 20;

public TestControl()
{
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles();
ResizeRedraw = true;
AutoScrollMinSize = new Size(_tilesX * _tileWidth, _tilesY * _tileHeight);

Scroll += (sender, args) => { Invalidate(); };
}

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(new SolidBrush(BackColor), ClientRectangle);
e.Graphics.TranslateTransform(AutoScrollPosition.X, AutoScrollPosition.Y);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

var offsetX = (AutoScrollPosition.X * -1) / _tileWidth;
var offsetY = (AutoScrollPosition.Y * -1) / _tileHeight;

var visibleX = Width / _tileWidth + 2;
var visibleY = Height / _tileHeight + 2;

var x = Math.Min(visibleX + offsetX, _tilesX);
var y = Math.Min(visibleY + offsetY, _tilesY);

for (var i = offsetX; i < x; i++)
{
for (var j = offsetY; j < y; j++)
{
e.Graphics.FillRectangle(Brushes.Beige, new Rectangle(i*_tileWidth, j*_tileHeight, _tileWidth, _tileHeight));
e.Graphics.DrawString(string.Format("{0}:{1}", i, j), Font, Brushes.Black, new Rectangle(i * _tileWidth, j * _tileHeight, _tileWidth, _tileHeight));
}
}

using (var p = new Pen(Color.Black))
{
for (var i = offsetX + 1; i < x; i++)
{
e.Graphics.DrawLine(p, i*_tileWidth, 0, i*_tileWidth, y*_tileHeight);
}

for (var i = offsetY + 1; i < y; i++)
{
e.Graphics.DrawLine(p, 0, i*_tileHeight, x*_tileWidth, i*_tileHeight);
}
}

e.Graphics.FillRectangle(Brushes.White, AutoScrollPosition.X * -1, AutoScrollPosition.Y * -1, 35, 14);
e.Graphics.DrawString("TEST", DefaultFont, new SolidBrush(Color.Red), AutoScrollPosition.X * -1, AutoScrollPosition.Y * -1);
}
}

编辑:
我搜索了一下,发现具有类似功能的 UserControl - https://www.codeproject.com/Articles/16009/A-Much-Easier-to-Use-ListView在 control 的作者博客上阅读了更多内容之后 http://objectlistview.sourceforge.net/cs/blog1.html#blog-overlays我发现他正在使用位于控件顶部的透明表单。我真的很想避免这种情况,但仍然在我的控制之上覆盖。

最佳答案

您正在与名为“拖动时显示窗口内容”的 Windows 系统选项作斗争。默认情况下始终打开,this web page显示如何将其关闭。

解决了问题,但它不是您可以依赖的东西,因为它会影响所有应用程序中的所有 可滚动窗口。要求用户为你关闭它是不现实的,用户喜欢这个选项,所以他们会忽略你。他们没有提供针对特定窗口将其关闭的选项,这是一个非常重大的疏忽。在信息亭应用程序中这是一个不错的解决方案。

简而言之,该选项的工作方式是 Windows 本身使用 ScrollWindowEx() 滚动窗口内容。 winapi函数。使用窗口内容的 bitblt 来移动像素,并且只为滚动显示的窗口部分生成绘制请求。通常只有几行像素,所以完成得非常快。问题是,bitblt 也会移动固定像素。重绘将它们移回。非常明显,人眼对这样的运动非常敏感,这有助于避免成为过去百万年的狮子午餐。

您必须去除 ScrollWindowsEx() 的刺痛,防止它移动像素,即使您无法阻止它被调用。这需要一把沉重的大锤,LockWindowUpdate() .您将在 this post 中找到代码.

using System.Runtime.InteropServices;
...

protected override void OnScroll(ScrollEventArgs e) {
if (e.Type == ScrollEventType.First) {
LockWindowUpdate(this.Handle);
}
else {
LockWindowUpdate(IntPtr.Zero);
this.Update();
if (e.Type != ScrollEventType.Last) LockWindowUpdate(this.Handle);
}
}

[DllImport("user32.dll", SetLastError = true)]
private static extern bool LockWindowUpdate(IntPtr hWnd);

不太漂亮,使用单独的 Label 控件应该开始听起来很有吸引力。

关于c# - 使用带有固定位置文本的 ScrollableControl 的自定义控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43208630/

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