我知道Winforms不是为大量图形使用而设计的,但我不知道C#以外的任何东西,所以多年来我使用C#和Visual Studio创建了各种程序,这些程序将事情推向了Visual Studio / Winforms限制的边缘。
Example view of the program in question
该程序读取摇滚乐队格式的文件,并像音乐播放器一样播放它们,其附加功能是利用摇滚乐队文件中的附加信息,如图表,专辑艺术和歌词来完成体验。一切都很好。绘图是在图形上完成的,所有这些,没有图像被加载和移动(我发现这是较慢的)。
每个图形示例都伴随着我在这里找到的以下代码:
graphics.SmoothingMode = SmoothingMode.HighSpeed;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
我被引导相信这会有助于表现。
所有的绘制都是基于一个以60 Hz(16 ms)运行的计时器,因此每秒60次,它会在屏幕上绘制所有内容。这对所有的事情都有效,除了歌词。我可以有歌词在静态模式或卡拉OK模式没有问题。但是如果我把它们设置为与声乐音符一起滚动(在上面的图像中,底部的蓝色音符,歌词应该与这些音符对齐并与它们一起沿着),除非你暂停,否则不可能阅读它们,那么它是非常清晰的。我试过将计时器的刷新率从1 ms调整到500 ms,但行为没有改变。歌词难以辨认。
这是滚动歌词的相关代码:
private void DrawLyricsScrolling(IEnumerable<Lyric> lyrics, Control label, Color color, Graphics graphics)
{
if (!openSideWindow.Checked || PlayingSong == null || btnPlayPause.Tag.ToString() == "play" || !doScrollingLyrics)
return;
var time = GetCorrectedTime();
label.Text = "";
graphics.SmoothingMode = SmoothingMode.HighSpeed;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
using (var pen = new SolidBrush(MediaPlayer.Visible ? picVisuals.BackColor : LabelBackgroundColor))
{
graphics.FillRectangle(pen, label.ClientRectangle);
}
foreach (var lyric in lyrics.TakeWhile(lyric => lyric.LyricStart <= time + PlaybackWindow).Where(lyric => !(lyric.LyricStart + (PlaybackWindow * 2) < time)))
{
var left = (int)(((lyric.LyricStart - time) / PlaybackWindow) * label.Width);
TextRenderer.DrawText(graphics,lyric.LyricText,label.Font,new Point(left, 0),color);
}
}
我希望你能指出我可能做错了什么,或者我可能完全错过了什么,以提高性能,如果可能的话,在Winforms的范围内。我在这个程序中有超过6,000行独特的代码,所以我不希望更改为WPF或其他语言或环境。它可以在C# / Winforms中得到改进,或者保持这种方式。
谢谢你,谢谢
编辑:
https://i.imgur.com/vZrpT5F.png
如果我禁用所有其他渲染,只有滚动歌词,他们仍然滚动滞后,不容易阅读。这张截图是用软件自己的F12截图功能拍摄的。它停止了动作,看起来很完美。如果我用Print Screen截图,同样的事情。我想我不能复制录制视频的模糊/滞后。
我在某个地方发现了使用foreach比使用List慢得多的评论。所以我把密码改成
for (var i = 0; i < lyrics.Count(); i++)
{
if (lyrics[i].LyricStart < time) continue;
if (lyrics[i].LyricStart > time + PlaybackWindow) return;
var left = (int)(((lyrics[i].LyricStart - time) / PlaybackWindow) * label.Width);
TextRenderer.DrawText(graphics, lyrics[i].LyricText, label.Font, new Point(left, 0), color);
}
在行为上没有区别。此外,有人建议使用周期性计时器,但这是在.NET 6+上,这个程序是在4.8.1上,所以我没有访问周期性计时器。将继续努力。
2条答案
按热度按时间gpfsuwkq1#
我们在这里可以看到一些东西
从这段代码和你所展示的图像中,我理解的是,你是:
1/循环歌词,逐字逐句,直到当前时间窗口为止
2/然后你删除那些太早/应该滚动到非视图
3/然后你把这些话,一个接一个地
无论是LinQ还是逐字渲染都不是很高效,尤其是每秒渲染60次。我的建议是:一次性渲染整个(或几分钟的)歌词,并“滑动”整个渲染文本句子
mpgws1up2#
您可以尝试使用EmguCV,它是OpenCV(用C++编写的机器视觉库)的C# .net Package 器,其中包括内置的在图像上绘制文本/形状的函数。
NuGet的库是:如果Emgu.CV.runtime.windows这与你有关,请发表评论,我会在这个问题上再加几个指针。