【发布时间】:2011-04-09 13:49:18
【问题描述】:
我是 C# 新手,并尝试通过编写一些简单的应用程序来学习以熟悉语法和 .NET 库。我最近接的一个小项目是极地时钟like the one found here。
我早期注意到的一个问题是应用程序会不断“闪烁”,这确实与演示无关,因此我在网上阅读了有关如何实现双缓冲区的信息,它消除了这个问题,但可能会或可能会与问题无关。这是我的onPaint 方法;它由定时器控制每 33ms (~30 FPS) 调用一次。应用程序的大部分其余部分只是用于拖动应用程序(因为它是无框架且具有透明背景)、双击退出等的处理程序。
protected override void OnPaint(PaintEventArgs e) {
DateTime now = DateTime.Now;
float secondAngle = now.Second / 60F;
secondAngle += (now.Millisecond / 1000F) * (1F / 60F);
float minuteAngle = now.Minute / 60F;
minuteAngle += secondAngle / 60F;
float hourAngle = now.Hour / 24F;
hourAngle += minuteAngle / 60F;
float dayOfYearAngle = now.DayOfYear / (365F + (now.Year % 4 == 0 ? 1F : 0F));
dayOfYearAngle += hourAngle / 24F;
float dayOfWeekAngle = (float)(now.DayOfWeek + 1) / 7F;
dayOfWeekAngle += hourAngle / 24F;
float dayOfMonthAngle = (float)now.Day / (float)DateTime.DaysInMonth(now.Year, now.Month);
dayOfMonthAngle += hourAngle / 24F;
float monthAngle = now.Month / 12F;
monthAngle += dayOfMonthAngle / (float)DateTime.DaysInMonth(now.Year, now.Month);
float currentPos = brushWidth / 2F;
float[] angles = {
secondAngle, minuteAngle,
hourAngle, dayOfYearAngle,
dayOfWeekAngle, dayOfMonthAngle,
monthAngle
};
SolidBrush DateInfo = new SolidBrush(Color.Black);
SolidBrush background = new SolidBrush(Color.Gray);
Pen lineColor = new Pen(Color.Blue, brushWidth);
Font DateFont = new Font("Arial", 12);
if (_backBuffer == null) {
_backBuffer = new Bitmap(this.Width, this.Height);
}
Graphics g = Graphics.FromImage(_backBuffer);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
try {
g.Clear(Color.White);
if (_mouseIsOver) {
g.FillEllipse(background, new Rectangle(0, 0, this.Width, this.Height));
}
foreach (float angle in angles) {
g.DrawArc(
lineColor,
currentPos, currentPos,
this.Height - currentPos * 2, this.Width - currentPos * 2,
startAngle, angle * 360F
);
currentPos += brushWidth + spaceStep;
}
// Text - Seconds
g.DrawString(String.Format("{0:D2} s", now.Second), DateFont, DateInfo, new PointF(115F, 0F));
g.DrawString(String.Format("{0:D2} m", now.Minute), DateFont, DateInfo, new PointF(115F, 20F));
g.DrawString(String.Format("{0:D2} h", now.Hour), DateFont, DateInfo, new PointF(115F, 40F));
g.DrawString(String.Format("{0:D3}", now.DayOfYear), DateFont, DateInfo, new PointF(115F, 60F));
g.DrawString(now.ToString("ddd"), DateFont, DateInfo, new PointF(115F, 80F));
g.DrawString(String.Format("{0:D2} d", now.Day), DateFont, DateInfo, new PointF(115F, 100F));
g.DrawString(now.ToString("MMM"), DateFont, DateInfo, new PointF(115F, 120F));
g.DrawString(now.ToString("yyyy"), DateFont, DateInfo, new PointF(115F, 140F));
e.Graphics.DrawImageUnscaled(_backBuffer, 0, 0);
}
finally {
g.Dispose();
DateInfo.Dispose();
background.Dispose();
DateFont.Dispose();
lineColor.Dispose();
}
//base.OnPaint(e);
}
protected override void OnPaintBackground(PaintEventArgs e) {
//base.OnPaintBackground(e);
}
protected override void OnResize(EventArgs e) {
if (_backBuffer != null) {
_backBuffer.Dispose();
_backBuffer = null;
}
base.OnResize(e);
}
我认为通过在方法结束时处理所有东西我会很安全,但这似乎没有帮助。此外,运行时和 OutOfMemoryException 之间的间隔不是恒定的;一旦它只发生在几秒钟内,但通常需要一两分钟。下面是一些类范围的变量声明。
private Bitmap _backBuffer;
private float startAngle = -91F;
private float brushWidth = 14;
private float spaceStep = 6;
还有一个屏幕截图(编辑:屏幕截图链接到存在一些代码的视图):
(来源:ggot.org)
编辑:堆栈跟踪!
System.OutOfMemoryException: Out of memory.
at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawArc(Pen pen, Single x, Single y, Single width, Single height, Single startAngle, Single sweepAngle)
at PolarClock.clockActual.OnPaint(PaintEventArgs e) in C:\Redacted\PolarClock\clockActual.cs:line 111
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
似乎与上次崩溃的同一行,循环内的主要drawArc。
【问题讨论】:
-
请裁剪您的屏幕截图,使其不超过必要的大小。
-
@Gabe:完成;我使用较大的截图来显示一些额外的代码,所以我将新截图作为旧截图的链接。
-
根据msdn.microsoft.com/en-us/library/…中的cmets,当弧i小于2像素或3.5扫描度时,drawArc中存在错误。
-
我刚刚添加了 1.5 扫描度的规定,因为崩溃似乎发生在极小的值上,例如 0.02;我们会看看这是怎么回事
-
提供的代码没有任何泄漏,在我的机器上运行稳定。
标签: c# gdi+ out-of-memory paint onpaint