簡體   English   中英

'參數無效' C# 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 應用程序的標准方法,就像您要構建的應用程序一樣。

  1. 在控件的成員變量中跟蹤控件的“狀態”(哪些對象可見等)。
  2. Paint事件僅用於一次刷新控件或其中的一部分。 如果發生會影響控件外觀的事情,請從導致 state 更改的任何事件處理程序調用Invalidate()並信任 Windows 在方便時通過 Paint 事件通知您的控件。 注意: Invalidate()不會像Refresh()那樣導致同步繪制(這通常是過分熱心的); 當 Windows 完成處理更高優先級的消息(如鼠標移動)時,它會排隊重繪。
  3. 請記住,您在Paint處理程序中傳遞的Graphics object 僅適用於一次重繪。 一旦您從該處理程序返回,或者像在您的代碼中那樣,您開始一個新的重繪(就像您對Refresh所做的那樣,使您的Paint處理程序遞歸,這是它如此引人入勝的一部分),它就會變得無效。
  4. 請記住,您在Paint事件處理程序中繪制的內容不是持久的。 也就是說,如果有東西遮擋了 window,或者您將其拖到屏幕外,或者發生其他任何事情導致分配給您的控件的視頻 memory 無效,那么 Windows 之前發生的任何事情都會觸發Paint事件以觸發您重繪事件。 這是您希望在成員變量中跟蹤 state 的另一個原因 - 當其 state 未更改時,可能會要求您的控件重新繪制自身。 您不能依靠視頻 memory 來准確表示過去繪制的內容。
  5. 如果需要動畫或在經過一段時間后發生某些事情,請創建一個System.Windows.Forms.Timer作為成員變量,注冊一個Tick處理程序,然后Start()計時器。 Tick處理程序應適當更新控件的持久 state 並調用Invalidate() 如果計時器用於一次性操作,則Stop()它。
  6. 對於您繪制的形狀的命中測試,處理控件的ClickMouseDown事件並針對您用於持久化 state 的成員變量進行測試。 如果您最后繪制的形狀是Rectangle ,則將該Rectangle保存在成員變量中,並根據該Rectangle測試EventArgs中的鼠標位置。 如果是時候繪制不同的形狀,請創建一個新的持久 object 來表示新形狀並調用Invalidate()

如果您對此一般大綱有任何疑問,請告訴我,我會相應地更新我的答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM