How to draw from Buffered Graphics into Graphics provided by PaintEventArgs .NET

问题描述 投票:0回答:0

我需要在自定义控件的 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 中我可以从缓冲区复制足够的内容以擦除光标然后绘制一个新的。这是我原来的帖子的基础。

另外 - 我不知道如何以简洁明了的方式陈述这些问题!对不起,冗长的补充。

.net bufferedimage drawrectangle onpaint double-buffering
© www.soinside.com 2019 - 2024. All rights reserved.