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 buttons.
This is how I'm creating them:
this.SuspendLayout(); //Creating so many things that I assume it would be faster to suspend and resume.
foreach (string i in playingField)
{
Button button = new Button();
button.Name = i;
button.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
button.Margin = new Padding(0);
button.TabIndex = 0;
button.Location = new System.Drawing.Point(3, 3);
button.Size = new System.Drawing.Size(25, 25);
button.BackgroundImage = blockImage; //##//
button.MouseDown += new System.Windows.Forms.MouseEventHandler(this.GetUnderSide);
button.UseVisualStyleBackColor = false;
minesPanel.Controls.Add(button); //Adding the controls to the container
}
this.ResumeLayout(); //Refer to above. Correct me if I'm wrong please.
As you can see I'm creating all of the controls through a for loop, and then adding them. It results in each button being painted once at a time. I also tried name.Controls.AddRange(arrayButtons)
and it still resulted in the same problem. Individual painting.
What I need is a way to create all items, and then paint them ALL after, like painting a single bitmap with DoubleBuffered
, but alas, that doesn't work either.
Furthermore, I have tried this:
protected override CreateParams CreateParams
{
get
{
// Activate double buffering at the form level. All child controls will be double buffered as well.
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return cp;
}
}
Which kind of works. It only works on application startup. However, given that I will be changing grid sizes and adding more controls at runtime, it is not a viable option.
I've been told it's as easy as using the methods in the Graphics
class. Problem is, I don't know where to start.
If anyone could provide some help on getting all my controls to be painted at the same time, that would be great.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With