Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Winforms:如何在不使控件无效的情况下在控件上绘制线条_C#_Winforms_Paint_Invalidation - Fatal编程技术网

C# Winforms:如何在不使控件无效的情况下在控件上绘制线条

C# Winforms:如何在不使控件无效的情况下在控件上绘制线条,c#,winforms,paint,invalidation,C#,Winforms,Paint,Invalidation,我有一门课画音频波形。我正在用OnPaint函数绘制它。现在我需要画一条线,显示我们当前在波形上的位置。我可以计算位置,但当我试图绘制它时,我需要调用Invalidate(),这迫使表单重新绘制所有波形图数据(很多点) 有没有办法在这个元素上放置一些透明元素,然后只对该元素调用Invalidate()?我试着用图片盒,但没有成功 //main form private void timer100ms_Tick(object sender, EventArgs e)

我有一门课画音频波形。我正在用OnPaint函数绘制它。现在我需要画一条线,显示我们当前在波形上的位置。我可以计算位置,但当我试图绘制它时,我需要调用Invalidate(),这迫使表单重新绘制所有波形图数据(很多点)

有没有办法在这个元素上放置一些透明元素,然后只对该元素调用Invalidate()?我试着用图片盒,但没有成功

//main form    
private void timer100ms_Tick(object sender, EventArgs e)
            {
                customWaveViewer1.currentPosition = (int)((stream.Position / (float)stream.Length) * customWaveViewer1.Width);
                customWaveViewer1.overlayLabel.Invalidate(false);
            }

   //drawing function in my class
   private void overlayLabelInvalidate(object sender, PaintEventArgs e)
        {
            Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0));
            e.Graphics.DrawLine(pen, currentPosition, 0, currentPosition, this.Height);
        }

  //constructor
  public CustomWaveViewer()
        {
            InitializeComponent();
            this.DoubleBuffered = true;

            this.PenColor = Color.DodgerBlue;
            this.PenWidth = 1;

            overlayLabel = new PictureBox();
            overlayLabel.Size = new System.Drawing.Size(this.Width, this.Height);
            overlayLabel.Location = new Point(this.Left, this.Top);
            overlayLabel.Visible = true;
            overlayLabel.BackColor=Color.FromArgb(0,0,0,0);
            overlayLabel.Paint += new System.Windows.Forms.PaintEventHandler(this.overlayLabelInvalidate);
            Controls.Add(overlayLabel);
        }

事实上你所说的并不完全正确。 在painteventargs中,有一个矩形指示需要重新绘制的窗口的一小部分。 另外,当您使表单失效时,不一定需要使整个表单失效。 在您的情况下,您可能希望仅使指示您在波形中的位置的标记的新旧位置无效。 因此,在绘制方法的算法中,要使其高效,只绘制窗口中真正需要重新绘制的部分,并跳过不需要重新绘制的部分,这实际上取决于您。 这真的能带来巨大的不同

要使其看起来更专业,请启用双缓冲。 无需匆忙处理您自己拥有的整个图像的位图,这正是双缓冲的全部内容,表单可以为您完成

我抄录了以下摘录自

BeginPaint使用信息填充PAINTSTRUCT结构,例如要更新的窗口部分的尺寸以及指示是否已绘制窗口背景的标志。应用程序可以使用此信息优化绘图。例如,它可以使用rcPaint成员指定的更新区域的尺寸,将图形仅限于窗口中需要更新的部分如果应用程序有非常简单的输出,它可以忽略更新区域并在整个窗口中绘制,依靠系统放弃(剪裁)任何不需要的输出。因为系统剪裁延伸到剪裁区域之外的图形,所以只有更新区域中的图形可见

在这种情况下,没有简单的输出,建议考虑到这一点。 我并不是说创建位图不起作用。我是说,优化绘图逻辑同样可以解决这个问题


以上信息仍然有效,因为windows窗体是在旧的win32 api之上构建的。

是的,您可以这样做,但需要确保覆盖控件位于底部控件内:
overlycontrol.Parent=bottomControl:
您能解释一下代码中的内容吗?CustomWaveViewer:是形式还是类?还是:如果重画波浪很昂贵,请考虑绘制成位图!好的,我将尝试在位图中绘制。如果您已经作为CustomWaveViewer类的子类创建OverlyLabel,请将其位置设置为点(0,0)!您可以在其他线程中提前准备下一个位图。。但最初的想法也应该行得通。恕我不敢苟同。父级通常至少会重新绘制内存中的所有内容,即使使用“优化无效”命令,也不会发送所有像素。在本例中,我猜绘图是昂贵的部分,而不是将内存位图转储到图形设备。绘制位图并不比绘制在表面上更困难或更麻烦。至于双缓冲:在他的代码中,它是开启的。他一直在思考
Paint
事件如何可能将自身限制为只调用那些
Drawxxx
的更改无效区域?!因此,它必须完全通过。如果这意味着十万个电话都必须完成。-之后,一小部分可能就是更新屏幕所需的全部内容,但那就太晚了。。!自己动手画代码肯定比画位图更麻烦。另外,如果需要的话,您还可以使用多个内核。我已经实现了一些类似这样的复杂形式,我可以告诉您这是一个不同的世界。我甚至调用了scrollwindowex,这在windows窗体中是不可用的。仅在窗口中绘制无效部分的问题是一个众所周知的问题。我描述它的方式是最佳实践。这一切都取决于你采用的算法。我有有效的方法来获取需要重新绘制的对象,这些对象与需要重新绘制的窗口的一小部分相交。Win api有scrollwindow和出于某种原因复制部分窗口的方法,以完全避免复杂的绘制逻辑。