我有一个绘制音频波形的课程。我在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);
}
答案 0 :(得分:0)
实际上你所说的并不完全正确。 在painteventargs中有一个矩形,表示需要重新绘制窗口的一小部分。 此外,当您无效时,您不一定需要使整个表单无效。 在您的情况下,您可能只想使标记的旧位置和新位置无效,以指示您在波形中的位置。 所以在你的paint方法的算法中,你真的应该让它变得高效,并且只绘制真正需要重新绘制的窗口部分,并跳过不需要重新绘制的部分。 它真的可以产生巨大的差异。
为了让它看起来更专业,请设置双缓冲。 无需使用您自己拥有的整个图像的位图,这就是双缓冲的全部内容,而且表单可以为您完成。
我复制了以下https://msdn.microsoft.com/en-us/library/windows/desktop/dd145137(v=vs.85).aspx
的摘录BeginPaint使用诸如要更新的窗口部分的尺寸之类的信息以及指示是否已绘制窗口背景的标志来填充PAINTSTRUCT结构。应用程序可以使用此信息来优化绘图。例如,它可以使用由rcPaint成员指定的更新区域的维度来限制绘制到仅需要更新的窗口部分。 如果应用程序输出非常简单,它可以忽略更新区域并在整个窗口中绘图,依靠系统丢弃(剪辑)任何不需要的输出。因为系统剪辑延伸到外部的绘图剪切区域,只有更新区域中的图形可见。
在这种情况下,没有简单的输出,建议考虑到这一点。 我不是说创建位图不起作用。我说优化绘图逻辑也可以解决它。
上面的信息仍然存在,因为Windows窗体构建在旧的win32 api之上。