我需要在自定义控件的 OnPaint 覆盖期间将缓冲区中的一部分图形内容绘制到屏幕上,但只熟悉使用 .Render 来绘制整个内容。
我使用这样的代码来创建缓冲区。
private BufferedGraphicsContext context;
private BufferedGraphics grafx;
context = BufferedGraphicsManager.Current;
grafx = context.Allocate(CreateGraphics(), DisplayRectangle);
在各种事件中,事物被吸引到缓冲区。然后...
protected override void OnPaint(PaintEventArgs e)
{
grafx.Render(e.Graphics);
}
这会使用整个缓冲区填充控件——这是应该的。有时,我只想将buffer grafx.Graphics的一部分内容绘制到e.Graphics中。喜欢 dest Rect <- src Rect or something.
有什么想法吗?
------------ 以下部分添加于 4/4/2023 以回应评论
所以我的项目有两个自定义控件:一个是带有一些自定义功能的轨迹栏,另一个是显示光标的音频波形查看器(水平方向位图条上的垂直线)。之所以称为 PictureZoomer,是因为下面的波浪最终会出现放大版本。轨迹栏完全由其 OnPaint() 中的几何命令自行绘制。波形查看器创建一个覆盖整个控件表面的图形缓冲区。打开一首歌曲时,会创建一个波形位图并将其绘制到缓冲区。播放音乐时,计时器会定期更新歌曲播放位置,包括更改轨迹栏 .Value 以及波形查看器 .Position(绘制光标的位置)。我还可以通过选择轨迹栏“thumb”并四处移动来更改播放位置。控件的绘制方式使轨迹栏拇指似乎作为一个单元附着在波形光标上。
tldr;问题是:光标移动处理太慢,即使我适度快速拖动拇指,视觉上光标和跟踪拇指也会“断开连接”。查看器的 OnPaint() 使用 .Render() 在光标位置更改时将整个缓冲区渲染到屏幕,然后在顶部绘制光标。我希望 OnPaint() 只重新绘制足够的缓冲区以“擦除”光标的先前位置,然后在一个新的、稍微移动的位置再次绘制它。
查看器类开始于...
public partial class PictureZoomer : Control
{ // PRIVATE VARIABLES
BufferedGraphicsContext myContext = BufferedGraphicsManager.Current;
BufferedGraphics myBuffer; // used to self-manage double buffer graphics
private Rectangle topFrame = new Rectangle();
在我的属性部分有...
private int _position = 0;
public int Position
{
get => _position;
set
{
if ((value != _position) && (value >= 0) && (value <= PictureWidth))
{
/*if (value > _position) // moving right
Invalidate(new Rectangle(Gutter + _position - 2, topFrame.Top, value - _position + 2, topFrame.Height));
else // moving left
Invalidate(new Rectangle(Gutter + value - 2, topFrame.Top, _position - value + 2, topFrame.Height));*/
_position = value;
Invalidate();
}
}
}
还有...
protected override void OnPaint(PaintEventArgs pe)
{
myBuffer.Render();
pe.Graphics.DrawLine(new Pen(SystemColors.Highlight, 2), Gutter + Position, topFrame.Top, Gutter + Position, topFrame.Bottom);
}
最后,当移动拇指时,轨迹栏 (slider1) 发出一个事件,该事件在表单中处理...
private void slider1_ValueChanging(object sender, EventArgs e)
{
toolTip1.SetToolTip(slider1, FormatTime(Convert.ToInt32(slider1.Value)));
pzmWaveViewer.Position = Convert.ToInt32(slider1.Value * Convert.ToSingle(pzmWaveViewer.PictureWidth) / (slider1.ValueMax - slider1.ValueMin));
}
在 _position 属性中,我目前 Invalidate() 整个事情。您可以看到我之前试图使光标周围无效的尝试 - “有效”但后来我无法将光标绘制到剪辑区域之外的新位置。我在渲染后尝试了 .ResetClip() 但似乎失败了(回复:我在下面的第二条评论)。在显示的代码中,我扩展了无效区域以包括新的光标位置,这有效但并不理想 - 并且仍然阻止我在 clipRegion 之外绘制,因此我无法添加制表位指示器之类的东西,我需要这些在某个时候。
所以我最近的想法是避免无效并设置一些标志,以便在 OnPaint 中我可以从缓冲区复制足够的内容以擦除光标然后绘制一个新的。这是我原来的帖子的基础。
另外 - 我不知道如何以简洁明了的方式陈述这些问题!对不起,冗长的补充。