我有一个Windows窗体,上面有一些数字(当前只有一个数字),并定期刷新它们(数字是随机生成的)。更新过程在应用程序的另一个线程中进行,以便窗体可以接收到用户点击按钮、调整窗口大小等事件。
主方法:
class Program {
static void Main(string[] args) {
Form o = new Overlay();
Application.Run(o);
}
}
表单类:
public partial class Overlay : Form {
Graphics g;
Drawer drawer;
public Overlay() {
InitializeComponent();
TopMost = true;
TransparencyKey = Color.Black;
BackColor = TransparencyKey;
CheckForIllegalCrossThreadCalls = false;
g = CreateGraphics();
drawer = new Drawer();
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
Thread upd = new Thread(mainLoop);
upd.Start();
}
void mainLoop() {
while (true) {
NetCoreEx.Geometry.Rectangle r;
GetWindowRect(Handle, out r);
Refresh();
drawer.Update(g, new Rectangle(r.Left, r.Top, r.Width, r.Height));
}
}
抽屉:
class Drawer {
Font font;
public Drawer() {
string workingDir = Environment.CurrentDirectory;
string projDir = Directory.GetParent(workingDir).Parent.FullName;
PrivateFontCollection collection = new PrivateFontCollection();
collection.AddFontFile(projDir + "\\Resources\\Athelas-Regular.ttf");
FontFamily fontFamily = new FontFamily("Athelas", collection);
font = new Font(fontFamily, 16);
}
public void Update(Graphics g, Rectangle rect) {
string stats = new Random().NextDouble().ToString();
g.DrawString(stats, font, Brushes.Aqua, rect.Width / 2, (int)(rect.Height * 0.75));
}
}
这段代码看起来很简单,但是由于某些原因,在正常运行5-10秒后应用程序突然崩溃,在DrawString方法上抛出System.AccessViolationException异常...堆栈跟踪:
at System.Drawing.SafeNativeMethods.Gdip.GdipDrawString(HandleRef graphics, String textString, Int32 length, HandleRef font, GPRECTF& layoutRect, HandleRef stringFormat, HandleRef brush)
at System.Drawing.Graphics.DrawString(String s, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format)
at System.Drawing.Graphics.DrawString(String s, Font font, Brush brush, Single x, Single y)
at OverlayStatistics.Scripts.Drawer.Update(Graphics g, Rectangle rect) in C:\Users\Гриша\source\repos\OverlayStatistics\Scripts\Drawer.cs:line 30
at OverlayStatistics.Overlay.mainLoop() in C:\Users\Гриша\source\repos\OverlayStatistics\Scripts\Overlay.cs:line 50
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
我已经花了很多时间进行调试,但仍然不知道我做错了什么,请帮忙吗?
control.CreateGraphics
!永远不要尝试缓存Graphics
对象!您可以使用Graphics g = Graphics.FromImage(bmp)
将其绘制到Bitmap bmp
中,或者在控件的“Paint”事件中使用e.Graphics
参数。 - TaWInvoke()
,不要禁用CheckForIllegalCrossThreadCalls
,它存在有其原因。 - Charliefaceprotected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Rectangle r = e.ClipRectangle; drawer.Update(e.Graphics, new Rectangle(r.Left, r.Top, r.Width, r.Height)); }
在计时器/线程循环中使用Refresh()
仍然会出现相同的错误。 - Fizz Areh