How to create an array with pictureboxes in Windows Forms (C#) - c#

I am fairly new to C# and I can't figure out how to create an array with visible picture boxes inside the cs file. In this example I want to create 200 picture boxes 10x20 to create an grid for a tetris game. This is my code, I can't get any of the pictures to show but the code runs just fine.
Image[] blockImage = {
TetrisSlutprojekt.Properties.Resources.TileEmpty,
TetrisSlutprojekt.Properties.Resources.TileCyan,
TetrisSlutprojekt.Properties.Resources.TileBlue,
TetrisSlutprojekt.Properties.Resources.TileRed,
TetrisSlutprojekt.Properties.Resources.TileGreen,
TetrisSlutprojekt.Properties.Resources.TileOrange,
TetrisSlutprojekt.Properties.Resources.TilePurple,
TetrisSlutprojekt.Properties.Resources.TileYellow
};
PictureBox[] blockBoxes = new PictureBox[200];
private void CreateBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i] = new System.Windows.Forms.PictureBox();
blockBoxes[i].Name = "pbBox" + i;
blockBoxes[i].Size = new Size(30, 30);
blockBoxes[i].Visible = true;
}
}
private void PlaceBoxes()
{
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < columns; x++)
{
blockBoxes[y].Top = y * blockWidth;
blockBoxes[x].Left = x * blockWidth;
}
}
}
private void FillBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i].Image = blockImage[4];
}
}

Add them to the Form:
private void CreateBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i] = new System.Windows.Forms.PictureBox();
blockBoxes[i].Name = "pbBox" + i;
blockBoxes[i].Size = new Size(30, 30);
blockBoxes[i].Visible = true;
this.Controls.Add(blockBoxes[i]); // <--- HERE
}
}

Related

How can I access to my Grid table from my private method

I started yesterday a new proyect in c# with WPF. My first time with it.
I'm trying to do the tictactoe game with graphical interface so i create the grid and i use bottons to change the state (it's not finish yet).
Here is the declaration of the class:
public partial class juego : Window
{
private juego tab;
public juego( int size)
{
InitializeComponent();
this.tab = CreateDynamicWPFGrid(size);
}
Here is the method that created the grid.
public juego CreateDynamicWPFGrid(int size)
{
Grid DynamicGrid = new Grid();
DynamicGrid.Name = "GridTablero";
DynamicGrid.Width = 400;
DynamicGrid.HorizontalAlignment = HorizontalAlignment.Left;
DynamicGrid.VerticalAlignment = VerticalAlignment.Top;
DynamicGrid.ShowGridLines = true;
DynamicGrid.Background = new SolidColorBrush(Colors.LightSteelBlue);
for (int i = 0; i < size; i++)
{
ColumnDefinition gridCol1 = new ColumnDefinition();
DynamicGrid.ColumnDefinitions.Add(gridCol1);
RowDefinition gridRow1 = new RowDefinition();
gridRow1.Height = new GridLength(45);
DynamicGrid.RowDefinitions.Add(gridRow1);
}
for (int fila = 0; fila < DynamicGrid.RowDefinitions.Count; fila++)
{
for (int columna = 0; columna < DynamicGrid.RowDefinitions.Count; columna++)
{
System.Windows.Controls.Button newBtn = new Button();
newBtn.Content = fila.ToString() + "_" + columna.ToString();
newBtn.Name = "Button" + fila.ToString() + "_" + columna.ToString();
newBtn.SetValue(Grid.ColumnProperty, columna);
newBtn.SetValue(Grid.RowProperty, fila);
newBtn.Click += new RoutedEventHandler(button_Click);
DynamicGrid.Children.Add(newBtn);
}
}
tablero.Content = DynamicGrid;
return tablero;
}
So the thing is that i want to iterate over the grid and then, count the buttons which content means if they are X, O or white.
I tried to use in my private method something like tab.Content but i really don't have any idea.
Anyways, i would like to know if this it is even possible.
After all, i come up with a solution by myselft.
So, i changed some lines in the class.
public partial class juego : Window
{
private ArrayList jugadores;
public juego(ArrayList jugadores, int size)
{
InitializeComponent();
tablero.Content = CreateDynamicWPFGrid(size);
}
Then i changed the return from the CreateDynamicWPFGrid:
return dynamicGrid;
And then, one method that i call when i click on buttons.
Grid boardValidar = tablero.Content as Grid;
Button[,] botones = new Button[boardValidar.ColumnDefinitions.Count, boardValidar.ColumnDefinitions.Count];
var buttons = boardValidar.Children.Cast<Button>();
for (int i = 0; i < boardValidar.ColumnDefinitions.Count; i++)
{
for (int j = 0; j < boardValidar.RowDefinitions.Count; j++)
{
botones[i, j] = buttons.Where(x => Grid.GetRow(x) == j && Grid.GetColumn(x) == i).FirstOrDefault();
}
}
So, i cast the grid and then, i do the same with all the buttons.
After this i use the linq to put in the array and that's all.
I know my code it's no the best but i got what i wanted.

creating a tablelayoutpanel of pictureboxes takes a long time

I'm creating this tablelayoutpanel of picture boxes (66x66 pixels) and while on one PC it is taking less then a second to finish, it takes about 8 seconds on another pc (with the same capabilities...).
I have to create the graphics on run time as I know only on run time which images I need to place.
This is the function:
private void InitializeDrawerCells(int cabinetPartID, int drawerID)
{
PictureBox pb;
try
{
tblDrawerCells.RowStyles.Clear();
tblDrawerCells.ColumnStyles.Clear();
tblDrawerCells.Controls.Clear();
tblDrawerCells.RowCount = 12;
tblDrawerCells.ColumnCount = 16;
for (int i = 0; i < tblDrawerCells.RowCount; i++)
{
RowStyle style = new RowStyle
{
SizeType = SizeType.Absolute,
Height = tblDrawerCells.Height / tblDrawerCells.RowCount
};
tblDrawerCells.RowStyles.Add(style);
}
for (int i = 0; i < tblDrawerCells.ColumnCount; i++)
{
ColumnStyle style = new ColumnStyle
{
SizeType = SizeType.Absolute,
Width = tblDrawerCells.Width / tblDrawerCells.ColumnCount
};
tblDrawerCells.ColumnStyles.Add(style);
}
for (int i = 0; i < tblDrawerCells.ColumnCount; i++)
{
for (int j = 0; j < tblDrawerCells.RowCount; j++)
{
pb = new PictureBox();
if (_DrawerType == eDrawerType.Regular)
{
if (Scenraio == OpenCabinetScenario.Maintenance)
{
if (NarcoticsCabinetManager.CabinetParts[_CurrentCabPartID].Drawers[_DrawerNumber - 1].DrawerType == eDrawerType.Regular)
pb.BackgroundImage = ImageOn[tblDrawerCells.RowCount - j - 1][i];
else
pb.BackgroundImage = ImageReturnOff;
}
else
pb.BackgroundImage = ImageOff;
}
else
pb.BackgroundImage = global::NarcoticsStorageSystem2.Properties.Resources._11x6_Cells;
pb.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
// pb.Dock = System.Windows.Forms.DockStyle.Fill;
pb.Location = new System.Drawing.Point(0, 0);
pb.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
if (_DrawerType == eDrawerType.Regular)
pb.Size = new System.Drawing.Size(66, 66);
else if (_DrawerType == eDrawerType.Return)
pb.Size = new System.Drawing.Size(198, 66);
// if (_Scenraio == OpenCabinetScenario.FillItems)
// {
pb.Click += new System.EventHandler(this.pbCell_Click);
// }
pb.TabStop = false;
pb.Tag = new Tuple<int, int, int, int>(_DrawerNumber, tblDrawerCells.RowCount - j, i + 1, (int)ImageType.Off);
tblDrawerCells.Controls.Add(pb, i, j);
}
}
}
catch (Exception ex)
{
//add ex to log...
}
finally
{
}
}
Any ideas?

How to generate a Checkboxes grid with Array?

Does somebody know how to programmatically generate a grid of checkboxes like this using a 2D Array?
for (int x = 0; x < numberOfRows; x++)
{
for (int y = 0; y < numberOfColumns; y++)
{
int index = x * numberOfColumns + y;
var checkbox = new CheckBox();
checkbox.Location = new Point(20 * x, 20*y);
this.Controls.Add(checkbox);
}
}
Give this a go. You need to initialise a dictionary, as shown here at the top, to allow for the GetCheckBoxAtPosition function to work.
private Dictionary<Point, CheckBox> checkBoxes;
private Dictionary<Point,CheckBox> GenerateCheckBoxes(Form form, int width, int height, int padding) {
Dictionary<Point, CheckBox> checkboxes = new Dictionary<Point, CheckBox>();
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
CheckBox checkBox = new CheckBox();
Point location = new Point(x*(15+padding), y*(15+padding));
//Formatting
checkBox.Location = location;
checkBox.Text = string.Empty;
checkBox.Size = new Size(15,15);
//Custom behaviour
checkBox.Click += CheckBox_Click;
form.Controls.Add(checkBox);
checkboxes.Add(new Point(x, y), checkBox);
}
}
return checkboxes;
}
private void CheckBox_Click(object sender, EventArgs e)
{
CheckBox clicked = (CheckBox)sender;
}
private CheckBox GetCheckBoxAtPosition(int x, int y) {
return checkBoxes[new Point(x, y)];
}
You could use a List of Lists, like this:
private List<List<CheckBox>> CheckBoxes = new List<List<CheckBox>>();
private void button1_Click(object sender, EventArgs e)
{
int numberOfRows = 5;
int numberOfColumns = 10;
CheckBoxes.Clear();
for (int y = 0; y < numberOfRows; y++)
{
List<CheckBox> row = new List<CheckBox>();
CheckBoxes.Add(row);
for (int x = 0; x < numberOfColumns; x++)
{
var checkbox = new CheckBox();
checkbox.Text = "";
checkbox.AutoSize = true;
checkbox.Location = new Point(20 * x, 20 * y);
row.Add(checkbox);
this.Controls.Add(checkbox);
}
}
}
Then you could access a particular one with:
CheckBoxes[0][3].Checked = true;
I just found the Answer the Problem was the Autosize without Autosize=true some Checkboxes will not be visible
CheckBox[,] c = new CheckBox[2, 2];
for (int i = 0; i < c.GetLength(0); i++)
{
for (int j = 0; j < c.GetLength(1); j++)
{
c[i, j] = new CheckBox();
c[i, j].Location = new Point(i*20, j* 20);
c[i, j].AutoSize = true;
//c[i, j].Height = 10;
//c[i, j].Width = 10;
this.Controls.Add(c[i, j]);
}
}

My Windows Forms buttons are not displaying as I want

I have a Windows Forms application and I'm trying to add buttons to mimic a calculator.
public class myform : Form
{
public myform()
{
//setting size of form
this.Text = "Calculator";
this.Height = 600;
this.Width = 400;
//creating buttons from 0-9
Button[] b = new Button[10];
int x = 0;
int y = 0;
string ch;
for (int i = 0; i < b.Length; i++)
{
ch = Convert.ToString(i);
x = 0;
y = y + 50;
b[i] = new Button();
b[i].Height = 40;
b[i].Width = 40;
b[i].Text = ch;
for (int j = 0; j < 3; j++)
{
x = x + 50;
b[i].Location = new Point(x, y);
}
}
for (int i = 0; i < b.Length; i++)
{
this.Controls.Add(b[i]);
}
}
}
here is the form class in which i am creating the object of myform class described above.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
myform mf = new myform();
mf.Show();
}
}
The problem seems to be that you always set the x value to x = x + 150; I suggest you change your x value to x = (i%3) * 50; and your y to y= (i/3) *50;
that should provide you with a nice array of buttons.
ch = Convert.ToString(i);
x = (i%3)*50;
y = (i/3)*50;
b[i] = new Button();
b[i].Height = 40;
b[i].Width = 40;
b[i].Text = ch;
b[i].Location = new Point(x, y);
Will be your new loop body.

C# Form does not refresh

I have a problem with my program (Minesweeper game)
this is my Board class (mines board)
class Board
{
private Cell[,] MinesBoard;
private int maxrow, maxcol;
private int numOfMines;
public bool isLose;
private List<Point> MinesLocation;
private Random rnd;
private List<Point> randomPoint;
public delegate void OnClickEventHandler(object sender, CellClickEventArgs e);
public event OnClickEventHandler OnCellClick;
public int NumOfMines
{
get { return numOfMines; }
}
public int Column
{
get { return maxcol; }
}
public int Row
{
get { return maxrow; }
}
private void GetRandomPoints(int maxr, int maxc)
{
Point t = new Point();
t.X = rnd.Next(0, maxr);
t.Y = rnd.Next(0, maxc);
if (!randomPoint.Contains(t))
randomPoint.Add(t);
}
public Board(int _row, int _col, int _mines)
{
isLose = false;
maxrow = _row;
maxcol = _col;
numOfMines = _mines;
rnd = new Random(DateTime.Now.Ticks.GetHashCode());
randomPoint = new List<Point>();
MinesBoard = new Cell[_row, _col];
MinesLocation = new List<Point>();
for (int i = 0; i < maxrow; ++i)
for (int j = 0; j < maxcol; ++j)
{
MinesBoard[i, j] = new Cell();
//MinesBoard[i, j].button = new Button();
//MinesBoard[i, j].IsMine = false;
//MinesBoard[i, j].IsOpen = false;
//MinesBoard[i, j].MineAround = 0;
}
for (int i = 0; i < numOfMines; ++i)
GetRandomPoints(maxrow, maxcol);
foreach (Point p in randomPoint)
{
if (MinesBoard[p.X, p.Y].IsMine == false)
{
MinesBoard[p.X, p.Y].IsMine = true;
MinesLocation.Add(p);
}
}
}
public void DrawBoard(Form frm)
{
int id = 0;
for (int i = 0; i < maxrow; ++i)
for (int j = 0; j < maxcol; ++j)
{
frm.Controls.Remove(MinesBoard[i, j].button);
MinesBoard[i, j].button.Name = "btnCell" + id.ToString();
++id;
MinesBoard[i, j].button.Size = new Size(25, 25);
MinesBoard[i, j].button.Location = new Point(j * 25, 60 + i * 25);
//MinesBoard[i, j].button.FlatStyle = FlatStyle.Flat;
//CellClickEventArgs args = new CellClickEventArgs(new Point(i, j));
MinesBoard[i, j].button.Click += new System.EventHandler(CellClick);
MinesBoard[i, j].button.MouseDown += new MouseEventHandler(CellMouseDown);
//=========
MinesBoard[i, j].button.Tag = new Point(i, j);
//MinesBoard[i, j].button.Tag = MinesBoard[i, j].button;
//=========
if (MinesBoard[i, j].IsMine)
MinesBoard[i, j].button.Text = "z";
else
MinesBoard[i, j].button.Text = "";
frm.Controls.Add(MinesBoard[i, j].button);
}
}
when I change number of mines, it doesn't change correctly. But the rows and columns is OK
this is my Form1 class
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
private Board board;
private void frmMain_Load(object sender, EventArgs e)
{
board = new Board(8, 10, 15);
board.DrawBoard(this);
}
private void optionToolStripMenuItem_Click(object sender, EventArgs e)
{
frmOption option = new frmOption(board.Row, board.Column, board.NumOfMines);
if (option.ShowDialog() == DialogResult.OK)
{
board = new Board(option.Rows, option.Columns, option.Mines);
this.Size = new Size(board.Column * 25 + 5, board.Row * 25 + 88);
board.DrawBoard(this);
}
}
here is the picture:
8x10 15 mines
5x5 5 mines
when I set number of mines is 5, but it shows only 3 (1 z letter is 1 mine)
could you give me any solutions, thank you very much.!!!
When you click on the tool strip menu item, you're creating a new board, which will cause the old buttons to stay on the form (resize the form to see all of the old buttons). You will notice, that the mines are placed on the same buttons as before. This is caused by the old buttons staying in front of the new ones. Therefore, you need to clear the old board before creating a new one. Example:
public void Clear(Form frm)
{
for (int i = 0; i < maxrow; ++i)
{
for (int j = 0; j < maxcol; ++j)
{
frm.Controls.Remove(MinesBoard[i, j].button);
}
}
}
Call this directly before creating the new board:
private void optionToolStripMenuItem_Click(object sender, EventArgs e)
{
if (board != null)
{
board.Clear(this);
}
board = new Board(5, 5, 5);
this.Size = new Size(board.Column * 25 + 5, board.Row * 25 + 88);
board.DrawBoard(this);
}
Be sure to fix the bug mentioned by #AndersJH as well :)
I hope I don't misunderstand the question here. But the method GetRandomPoints does not guarantee to add a point to the list of random points. If the point exists, it will not be added.
I would suggest something like this:
while(randomPoint.Count < numOfMines)
{ GetRandomPoints(maxrow, maxcol); }

Categories