![](/img/trans.png)
[英]Parameter Not Valid Error on Button_Click (C#, VisualStudio, WinForms)
[英]'parameter is not valid' C# winforms graphics error
我正在嘗試使用winforms在C#中創建一個游戲,其中形狀隨機出現,您必須盡快單擊形狀(一次一個)。
創建形狀后,會啟動一個計時器,該計時器會計算您單擊該形狀所花費的時間,然后單擊該形狀后,該形狀將被刪除。 我在刪除形狀部分時遇到問題。 我有計時器,我讓它等待計時器停止,但是每當我嘗試刪除形狀時,我都會在該行收到以下錯誤: g.clear(Color.black)
。
System.ArgumentException:“參數無效。”
完整的錯誤跟蹤是:
System.ArgumentException
HResult=0x80070057
Message=Parameter is not valid.
Source=System.Drawing
StackTrace:
at System.Drawing.Graphics.Clear(Color color)
at NumbersGame.ShapesRound.<ShapesWindow_Paint>d__9.MoveNext() in
C:\Users\Matthew\Desktop\AHProject\NumbersGame\NumbersGame\ShapesRound.cs:line 92
這是我所有的游戲代碼:
namespace NumbersGame
{
public partial class ShapesRound : UserControl
{
public ShapesRound()
{
InitializeComponent();
}
public bool GameStarted = false;
public GraphicsPath path;
public Rectangle currentShape = new Rectangle();
Stopwatch timer = new Stopwatch();
public bool timerIsRunning = false;
public bool ShapeClicked(Point location)
{
bool clicked = false;
if (currentShape.Contains(location))
{
clicked = true;
}
return clicked;
}
private void ShapesRound_Load(object sender, EventArgs e)
{
path = new GraphicsPath();
nameBox.Text = "Matthew";
// nameBox.Text = Welcome.name;
scoreBox.Text = Welcome.totalScore.ToString();
}
private void ShapesRound_MouseDown(object sender, MouseEventArgs e)
{
if (ShapeClicked(e.Location))
{
// MessageBox.Show("CLICKED");
//end timer
timer.Stop();
var timeP = timer.ElapsedMilliseconds / 1000;
// MessageBox.Show(timeP.ToString() + " SECONDS");
}
}
private async void ShapesWindow_Paint(object sender, PaintEventArgs e)
{
if (GameStarted == false) { return; } //if the game hasnt started (ie the start button has not been clicked), do nothing
else
{
using (Graphics g = e.Graphics)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
currentShape = new Rectangle(10, 100, 75, 75); //assign coordinates to the global CurrentShape variable
g.FillEllipse(new SolidBrush(Color.Black), currentShape);
//INVALID PAARAM?//fill the currentshape on screen
//start a timer
timer.Start(); //start a timer
while (timer.IsRunning) //while the timer is running (ie shape isnt clicked) wait
{
await Task.Delay(500);
}
g.Clear(Color.Black);
// currentShape = null;
// MessageBox.Show("DELETING");
var bckCol = ShapesWindow.BackColor;
// e.Graphics.FillEllipse(new SolidBrush(bckCol), currentShape);
// e.Graphics.Clear(Color.Black); //INVALID PAARAM?
ShapesWindow.Refresh();
}
}
}
private void StartButton_Click(object sender, EventArgs e)
{
GameStarted = true;
ShapesWindow.Paint += new PaintEventHandler(ShapesWindow_Paint);
ShapesWindow.Refresh();
}
}
}
如果我理解正確,您正在繪制一個形狀。 然后,當單擊該形狀時,您要刪除該形狀並繪制一個新形狀,然后重復該過程。
如果我是對的,那就顛倒你的邏輯。 現在,您正在繪制一個形狀,等待,然后嘗試清除。 但你可以先清除,然后繪制形狀。 這樣,當您檢測到點擊時,您只需觸發刷新。
private void ShapesRound_MouseDown(object sender, MouseEventArgs e)
{
if (ShapeClicked(e.Location))
{
// MessageBox.Show("CLICKED");
//end timer
timer.Stop();
var timeP = timer.ElapsedMilliseconds / 1000;
// MessageBox.Show(timeP.ToString() + " SECONDS");
ShapesWindow.Refresh();
}
}
private async void ShapesWindow_Paint(object sender, PaintEventArgs e)
{
if (GameStarted == false) { return; } //if the game hasnt started (ie the start button has not been clicked), do nothing
else
{
using (Graphics g = e.Graphics)
{
g.Clear(Color.Black);
g.SmoothingMode = SmoothingMode.AntiAlias;
currentShape = new Rectangle(10, 100, 75, 75); //assign coordinates to the global CurrentShape variable
g.FillEllipse(new SolidBrush(Color.Black), currentShape);
//start a timer
timer.Start(); //start a timer
}
}
}
如果您不想繪制新形狀,則聲明一個bool
值,告訴它不要繪制新形狀。 每當您不想繪制新值時設置它,並在清除后在您的繪制事件中檢查它,例如:
...
g.Clear(Color.Black);
if (dontDrawNewShape) return;
...
這並不是對您最初問題的真正答案,而是對您的評論的回答:
也許我在這里遺漏了一些東西。 我正在嘗試繪制 object,基本上是在單擊最后一個 object 時。 這涉及刪除第一個 object,並在單擊舊的時繪制一個新的。 您如何建議我 go 這樣做? 以非“argh”誘導方式。
正如 rene 和 Flydog57 指出的那樣,您的方法非常不標准。 與其從您所在的位置開始,不如讓我擴展他們的評論並解釋構建 Windows Forms 應用程序的標准方法,就像您要構建的應用程序一樣。
Paint
事件僅用於一次刷新控件或其中的一部分。 如果發生會影響控件外觀的事情,請從導致 state 更改的任何事件處理程序調用Invalidate()
並信任 Windows 在方便時通過 Paint 事件通知您的控件。 注意: Invalidate()
不會像Refresh()
那樣導致同步繪制(這通常是過分熱心的); 當 Windows 完成處理更高優先級的消息(如鼠標移動)時,它會排隊重繪。Paint
處理程序中傳遞的Graphics
object 僅適用於一次重繪。 一旦您從該處理程序返回,或者像在您的代碼中那樣,您開始一個新的重繪(就像您對Refresh
所做的那樣,使您的Paint
處理程序遞歸,這是它如此引人入勝的一部分),它就會變得無效。Paint
事件處理程序中繪制的內容不是持久的。 也就是說,如果有東西遮擋了 window,或者您將其拖到屏幕外,或者發生其他任何事情導致分配給您的控件的視頻 memory 無效,那么 Windows 之前發生的任何事情都會觸發Paint
事件以觸發您重繪事件。 這是您希望在成員變量中跟蹤 state 的另一個原因 - 當其 state 未更改時,可能會要求您的控件重新繪制自身。 您不能依靠視頻 memory 來准確表示過去繪制的內容。System.Windows.Forms.Timer
作為成員變量,注冊一個Tick
處理程序,然后Start()
計時器。 Tick
處理程序應適當更新控件的持久 state 並調用Invalidate()
。 如果計時器用於一次性操作,則Stop()
它。Click
或MouseDown
事件並針對您用於持久化 state 的成員變量進行測試。 如果您最后繪制的形狀是Rectangle
,則將該Rectangle
保存在成員變量中,並根據該Rectangle
測試EventArgs
中的鼠標位置。 如果是時候繪制不同的形狀,請創建一個新的持久 object 來表示新形狀並調用Invalidate()
。如果您對此一般大綱有任何疑問,請告訴我,我會相應地更新我的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.