Foreach loop to create 100 buttons, painting all buttons at same time as to prevent flicker

后端 未结 2 1525
夕颜
夕颜 2021-01-03 09:03

In my minesweeper game I need to dynamically create controls in order to shift between easy - medium - hard. Let\'s say for the sake of the question hard consists of 100 but

相关标签:
2条回答
  • 2021-01-03 09:28

    Sadly, WinForms does not like to have too many controls, especially when you get into the hundreds. You can never have each control paint at the same time since each control will send its own paint message to windows.

    I think the best way to approach a game board like MineSweeper is to just use one control and draw the grid of buttons.

    Simple Mine class:

    public class Mine {
      public Rectangle Bounds { get; set; }
      public bool IsBomb { get; set; }
      public bool IsRevealed { get; set; }
    }
    

    Then create a new control where you inherit from the Panel control and set the DoubleBuffered property to prevent any flicker:

    public class MineSweeperControl : Panel {
      private int columns = 16;
      private int rows = 12;
      private Mine[,] mines;
    
      public MineSweeperControl() {
        this.DoubleBuffered = true;
        this.ResizeRedraw = true;
    
        // initialize mine field:
        mines = new Mine[columns, rows];
        for (int y = 0; y < rows; ++y) {
          for (int x = 0; x < columns; ++x) {
            mines[x, y] = new Mine();
          }
        }
      }
    
      // adjust each column and row to fit entire client area:
      protected override void OnResize(EventArgs e) {
        int top = 0;
        for (int y = 0; y < rows; ++y) {
          int left = 0;
          int height = (this.ClientSize.Height - top) / (rows - y);
          for (int x = 0; x < columns; ++x) {
            int width = (this.ClientSize.Width - left) / (columns - x);
            mines[x, y].Bounds = new Rectangle(left, top, width, height);
            left += width;
          }
          top += height;
        }
        base.OnResize(e);
      }
    
      protected override void OnPaint(PaintEventArgs e) {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        for (int y = 0; y < rows; ++y) {
          for (int x = 0; x < columns; ++x) {
            if (mines[x, y].IsRevealed) {
              e.Graphics.FillRectangle(Brushes.DarkGray, mines[x, y].Bounds);
            } else {
              ControlPaint.DrawButton(e.Graphics, mines[x, y].Bounds, 
                                      ButtonState.Normal);
            }
          }
        }
        base.OnPaint(e);
      }
    
      // determine which button the user pressed:
      protected override void OnMouseDown(MouseEventArgs e) {
        for (int y = 0; y < rows; ++y) {
          for (int x = 0; x < columns; ++x) {
            if (mines[x, y].Bounds.Contains(e.Location)) {
              mines[x, y].IsRevealed = true;
              this.Invalidate();
              MessageBox.Show(
                string.Format("You pressed on button ({0}, {1})",
                x.ToString(), y.ToString())
              );
            }
          }
        }
        base.OnMouseDown(e);
      }
    }
    

    enter image description here

    0 讨论(0)
  • 2021-01-03 09:30

    hide minesPanel, paint your buttons, show minesPanel?

    0 讨论(0)
提交回复
热议问题