[英]c# - Form "lags" after button being pressed
我对我制作的游戏进行了扩展,当您按下“搜索像素”时,它会自动按下一个按钮,但每次按下按钮时,无论成功还是失败,应用程序的内存都会增加大约 30 兆字节。 从 4.5 MB 开始,然后一旦单击按钮,它就会上升到 33.3 MB,这里是代码
{
public Form1()
{
InitializeComponent();
}
private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
private const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
[DllImport("user32.dll")]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, uint dwExtraInf);
[DllImport("user32.dll")]
private static extern bool SetCursorPos(int x, int y);
private void OnButtonSearchPixelClick(object sender, EventArgs e)
{
// 01. get hex value from input field
string inputHexColorCode = textBox1.Text;
SearchPixel(inputHexColorCode);
}
private bool SearchPixel(string hexcode)
{
// Take an image from the screen
// Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); // Create an empty bitmap with the size of the current screen
Bitmap bitmap = new Bitmap(SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height); // Create an empty bitmap with the size of all connected screen
Graphics graphics = Graphics.FromImage(bitmap as System.Drawing.Image); // Create a new graphics objects that can capture the screen
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size); // Screenshot moment → screen content to graphics object
Color desiredPixelColor = ColorTranslator.FromHtml(hexcode);
// Go one to the right and then check from top to bottom every pixel (next round -> go one to right and go down again)
for (int x = 0; x < SystemInformation.VirtualScreen.Width; x++)
{
for (int y = 0; y < SystemInformation.VirtualScreen.Height; y++)
{
// Get the current pixels color
Color currentPixelColor = bitmap.GetPixel(1550, 412);
// Finally compare the pixels hex color and the desired hex color (if they match, we found a pixel)
if (desiredPixelColor == currentPixelColor)
{
DoubleClickAtPosition(1387, 414);
return true;
}
}
}
return false;
}
private void DoubleClickAtPosition(int posX, int posY)
{
SetCursorPos(posX, posY);
Click();
Thread.Sleep(250);
Click();
}
private new void Click()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
}
}
此代码来自我观看的视频。 如果您需要我做任何事情,例如发布视频或发布任何其他代码,请告诉我,我真的需要帮助。 我还想说,我对 C# 编码真的很陌生。
Windows 窗体使用单线程单元模型。 这意味着 Windows 窗体中的所有内容,从呈现到处理 Windows 消息(如鼠标和键盘事件),都发生在单个线程中。
您可能已经注意到,在所有 WinForms 应用程序中,您都可以在Program.cs
看到[STAThreadAttribute]
。 “STA”代表“单线程公寓”。
因为 WinForms 在单线程单元中运行,所以您在 WinForms STA 线程中运行的任何密集代码都会阻止 WinForms 呈现您的表单并处理其鼠标和键盘事件,因为它一次只能做一件事。
此处的解决方案是在 WinForms STA 线程的单独线程中运行您的密集SearchPixel()
函数。
有很多方法可以实现这一点,例如BackgroundWorker
或 hard Thread
。 然而,最简单,最容易被接受的方法是使用一个Task
后自动推迟到一个线程池。
这就像更改代码一样简单:
private void OnButtonSearchPixelClick(object sender, EventArgs e)
{
// 01. get hex value from input field
string inputHexColorCode = textBox1.Text;
Task.Run(() => {
SearchPixel(inputHexColorCode);
});
}
由于您的代码将在 WinForms 的 STA 线程以外的线程中运行,因此在不执行调用的情况下无法与 WinForms 正在使用的任何对象进行交互。
例如:
Task.Run(() => {
label1.Text = "Test";
});
将导致InvalidOperationException
,因为您正在尝试访问 WinForms 希望只能在其单线程单元中访问的对象。
您必须告诉 STA 线程调用一个操作,这将导致代码在 STA 线程中运行。 像这样:
Task.Run(() => {
//Code in here will run in a thread pool
this.Invoke((Action)delegate {
//Code in here will run in the STA thread
label1.Text = "Test";
});
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.