如何在绘画事件之前静态绘制线条?

How to draw lines statically before paint event?

我正在创建一个频谱分析仪,我想将其网格化。我的光谱将绘制在 windows 表单应用程序的面板上。当我在 panel_Paint 函数内绘制线条时,它与面板的绘制事件相关联,它每秒重绘 2048/48000 次,因为它是一个实时 FFT 频谱,FFT 大小为 2048,采样率为 48000。这是我的在 paint 函数中画线的方式:

private void panel1_Paint(object sender, PaintEventArgs e)
{
       for (int i = 0; i < panel1.Width; i+= panel1.Width / 20)
            {
                for (int j = 0; j < panel1.Height; j+= panel1.Height / 20)
                {
                    g.DrawLine(Pens.Black, i, j, i, panel1.Height + j);
                    g.DrawLine(Pens.Black, i, j, panel1.Width + i, j);
                }
            }
}

这是线后的频谱:

我喜欢频谱的外观,但在计算时没有时间在等待重新绘制线条时处理频谱。

注意:上图是频谱的即时(单个 fft 块)屏幕截图。正如我上面提到的,在执行实时应用程序时,频谱不可读。

任何帮助将不胜感激,提前致谢。

制作带有图形的实时应用程序并非易事。几点:

  1. 以 2048 Hz 绘画对观看者没有用,屏幕通常以 60 Hz 刷新,因为我们的眼睛无法观察到更快的变化。
  2. 绘制事件旨在一次绘制所有内容,因此网格线和 FFT 图。
  3. 您可以通过调用 Control.Invalidate() 来触发绘画事件,或者在这种情况下 Control.Refresh() 可能会带来更愉快的刷新。参见:https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.invalidate
  4. 可能需要将收集信号和计算 FFT 频谱的代码移动到后台线程,这样您可以更好地控制其时序并可以不间断地处理数据。

因此组织应用程序的可能方式如下:

有很多关于如何从后台线程与前台线程(如处理绘制事件的线程)进行通信的信息。所以我不打算在这里重复。但如果做得好,它会使您的应用程序 运行 流畅且响应迅速。

将多个 FFT 块组合成一个图形绘制是一项挑战。因此,首先,通过例如丢弃除最新块以外的所有块来保持该部分简单。然后在其他一切正常的情况下改进这部分的设计。

也从设置为 20 Hz 左右的油漆计时器开始,然后从那里增加它。因为图形系统可能不喜欢很多绘画动作。

原来我用错了这个工作的工具,在处理实时数据时,你应该在显示它之前进行非常快的计算。当涉及到显示时,双缓冲父显示工具就像“魔术”一样工作。

正如我在上面的问题中提到的,我在绘制频谱时在窗体上使用了面板,当我移除面板并将整个窗体更改为 UserControl 时,我能够进行双缓冲,这是我做不到的。 t在面板上做,整个问题就解决了。

当DoubleBuffered 属性设置为true时,当前绘图数据在绘制到要绘图的表面之前被写入第二个缓冲区,那么这个第二个缓冲区中的数据是快速写入将要绘制的内存中。瞧!防止闪烁。

UserControl 的加载函数中的代码:

this.DoubleBuffered = true;