I am looking to create a dynamic grid of picture boxes that will be generated once the user enters their desired number of rows and columns.
e.g. If user enters 3x3, 9 total picture boxes will be created in a grid like form.
Currently, my code will create all the desired picture boxes, but it will indent the first one in each new column creating an awkward shaped grid.
int rows = Convert.ToInt32(txtRow.Text);
int columns = Convert.ToInt32(txtColumn.Text);
// coordinates to place first box in the grid
int x = 211;
int y = 136;
int totalBoxes = rows * columns;
List<PictureBox> pictureBoxList = new List<PictureBox>();
for (int i = 0; i < totalBoxes; i++)
{
while (i < rows)
{
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = new Size(70, 60),
Location = new Point(x, y),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
this.Controls.Add(picture);
pictureBoxList.Add(picture);
y = y + 59;
break;
}
while (i < columns)
{
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = new Size(70, 60),
Location = new Point(x, y),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
this.Controls.Add(picture);
pictureBoxList.Add(picture);
x = x + 67;
break;
}
}
you can set picturebox locations like this:
PictureBox picture = new PictureBox
{
Location = new Point(i%columns * desiredWidth, i/columns * desiredHeight),
....
};
for example as picturebox size is (70,60), with a 5 pixel more space between you may like it as new Point(i%columns * 75, i/columns * 65) //desiredWidth=75, desiredHeight=65
You may also give it an start Indent too:
Location = new Point(x+ i%columns * desiredWidth,y+ i/columns * desiredHeight);
I would do it like:
int w=75, h = 65;
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = new Size(70, 60),
Location = new Point(x + i%columns * w, y + i/columns * h),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
You can use on cycle from 0 up to total picture box numbers, as you started in your code. In this case you should calculate position of each box, as Ashkan Mobayen Khiabani show you, like this:
// size of the boxes
Size size = new Size(70, 60);
int totalBoxes = rows * columns;
List<PictureBox> pictureBoxList = new List<PictureBox>();
for (int i = 0; i < totalBoxes; i++)
{
int curentColumn = i % columns;
int currentRow = i / columns;
int curentX = x + curentColumn * size.Width;
int curentY = y + currentRow * size.Height;
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = size,
Location = new Point(curentX, curentY),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
this.Controls.Add(picture);
pictureBoxList.Add(picture);
}
However, you can also use two nested loops. First goes trough all the rows and second through all the columns, like this:
// size of the boxes
Size size = new Size(70, 60);
int totalBoxes = rows * columns;
List<PictureBox> pictureBoxList = new List<PictureBox>();
for (int row = 0; row < rows; row++)
{
int curentY = y + row * size.Height;
for (int col = 0; col < columns; col++)
{
int curentX = x + col * size.Width;
PictureBox picture = new PictureBox
{
Name = "pictureBox" + (row + col),
Size = size,
Location = new Point(curentX, curentY),
BorderStyle = BorderStyle.Fixed3D,
SizeMode = PictureBoxSizeMode.Zoom,
Visible = true
};
this.Controls.Add(picture);
pictureBoxList.Add(picture);
}
}
I personally prefer the nested loops way as it easier to read :)
From performance point of view both approaches should be the same.
Related
I want to make a tiles based scrolling game in Visual Studio C# using forms. I know its not the best platform for this but those are set parameters. I suppose the easiest way to think of the end program is like pokemon 2d top down world scrolling.
I can create a 2d array of picture boxes and allocated images to them based on a text 2d array of tile ids. I can scroll the picture boxes and when they reach a certain place, jump back to the original location and display a shifted tile.
My issue is adding controls, it only adds a column rather than the full grid. I have tried using tables but with the same problem.
Has anyone done this type of large world scroller using VSC# and forms? Are there any tutorials or suggestions? Thanks.
EDIT - Code added'
public Form1()
{
InitializeComponent();
TableLayoutPanel wholescreen = new TableLayoutPanel();
wholescreen.Location = new System.Drawing.Point(0,0);
wholescreen.Size = new System.Drawing.Size(200,200);
wholescreen.RowCount = 2;
wholescreen.ColumnCount = 2;
Controls.Add(wholescreen);
PictureBox item = new PictureBox();
item.Size = new System.Drawing.Size(50, 50);
item.ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
for (int x = 0; x < 2; x++)
{
for (int y = 0; y < 2; y++)
{
item.Left = x * 50;
item.Top = y * 50;
wholescreen.Controls.Add(item,x,y);
}
}
}
'
another way i tried....'
int WIDTH = 3;
int HEIGHT = 3;
PictureBox[] grid = new PictureBox[9];
//PictureBox[,] grid = new PictureBox[3, 3];
//int[,] level1 = new int[2, 2] { { 1, 2 }, { 3, 4 } };
int playerx = 0;
public Form1()
{
InitializeComponent();
int y = 0;
int x = 0;
for (int cntr = 0; cntr < HEIGHT*WIDTH; cntr++)
{
if ((cntr % HEIGHT) == 0)
{
x++;
y = 0;
}
grid[cntr] = new PictureBox();
grid[cntr].Left = x * 50;
grid[cntr].Top = y * 50;
grid[cntr].ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
Controls.Add(grid[cntr]);
}
}
'
I think you are just creating one square and moving it around. Try...
private void Method2()
{
TableLayoutPanel wholescreen = new TableLayoutPanel();
wholescreen.BackColor = Color.AliceBlue;
wholescreen.Location = new System.Drawing.Point(0, 0);
wholescreen.Size = new System.Drawing.Size(200, 200);
wholescreen.RowCount = 2;
wholescreen.ColumnCount = 2;
Controls.Add(wholescreen);
PictureBox item;
// item.ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
for (int x = 0; x < 2; x++)
{
for (int y = 0; y < 2; y++)
{
item = new PictureBox();
item.Size = new System.Drawing.Size(50, 50);
item.BackColor = Color.Blue;
//item.Left = 0;
//item.Top = 0;
wholescreen.Controls.Add(item, x, y);
}
}
}
I'm beginner in programming and I want to create a little "game" with Panels.
(Later maybe I'll change for PictureBox, but for now it's OK)
Code:
private void Form1_Load(object sender, EventArgs e)
{
int size = 20;
int quantity = 10;
Random rnd = new Random();
for (int y = 0; y < quantity; y++)
{
for (int x = 0; x < quantity; x++)
{
Color randomColor = Color.FromArgb(
rnd.Next(256), rnd.Next(256), rnd.Next(256)
);
Panel panel = new Panel
{
Size = new Size(size, size),
Location = new Point(x * size, y * size),
BorderStyle = BorderStyle.FixedSingle,
BackColor = randomColor
};
Controls.Add(panel);
//panel.Click += Panel_Click;
}
}
}
I have two questions:
How can I set 5 pixel distance to each Panel from each other?
Should I place these panel creation in the constructor? I see people prefer that.
You have to include additional 5 pixels padding into Location:
...
int padding = 5;
...
Location = new Point(x * (size + padding), y * (size + padding))
...
Let's extract a method:
private void CreateGameField() {
int size = 20;
int padding = 5;
int quantity = 10;
Random rnd = new Random();
for (int y = 0; y < quantity; ++y)
for (int x = 0; x < quantity; ++x)
new Panel() {
Size = new Size(size, size),
Location = new Point(x * (size + padding), y * (size + padding)),
BorderStyle = BorderStyle.FixedSingle,
BackColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256)),
Parent = this, // instead of Controls.Add(panel);
};
}
Then
private void Form1_Load(object sender, EventArgs e) {
CreateGameField();
}
FromLoad event handler is a good place to create the game field; if you want you can place CreateGameField() in the constructor, but put it after InitializeComponent():
public Form1() {
InitializeComponent();
CreateGameField();
}
I have a grid that is being overlayed an image. A user will input the total image length and width in meters. They will also input the size of the columns and rows they want.
For example the image is 143 meters long and 216 meters wide, and they want the grid cells to be 10 meters wide by 15 meters high.
So I would need 14 equal width cells and 1 cell that is 30% the width of the previous 14. I am adding the columns through a loop
numColumns = Convert.ToInt32(Math.Ceiling(143 / 10));
numRows = Convert.ToInt32(Math.Ceiling(216 / 15));
for(int i = 0; i < numColumns + 1; i++)
{
ColumnDefinition col = new ColumnDefinition();
if(i == 0)
{
col.Width = new GridLength(gridHeaderOffset);
}
else if(i < numColumns)
{
col.Width = new GridLength(1,GridUnitType.Auto);
}
else
{
col.Width = new GridLength(Math.Round( (143 % 10), 2), GridUnitType.Star);
}
grid.ColumnDefinitions.Add(col);
}
Problem is some where in the 2nd last line.
public MainWindow()
{
InitializeComponent();
SetupGrid(143);
}
private void SetupGrid(double width)
{
LayoutRoot.ShowGridLines = true;
int numColumns = Convert.ToInt32(width / 10);
double remainder = width % 10;
//create whole columns
for (int i = 0; i < numColumns; i++)
{
ColumnDefinition col = new ColumnDefinition();
col.Width = new GridLength(10, GridUnitType.Star);
LayoutRoot.ColumnDefinitions.Add(col);
//adding a textblock just so show the placement
TextBlock t = new TextBlock();
t.HorizontalAlignment = HorizontalAlignment.Center;
t.Text = i.ToString();
LayoutRoot.Children.Add(t);
Grid.SetColumn(t, i);
}
//create remainder
ColumnDefinition colr = new ColumnDefinition();
colr.Width = new GridLength(remainder, GridUnitType.Star);
LayoutRoot.ColumnDefinitions.Add(colr);
//adding a textblock just so show the placement
TextBlock t2 = new TextBlock();
t2.HorizontalAlignment = HorizontalAlignment.Center;
t2.Text = remainder.ToString();
LayoutRoot.Children.Add(t2);
Grid.SetColumn(t2, numColumns + 1);
}
I have created an array of black labels and have displayed them on a picture box. Unfortunately, I am not able to line them up directly at each intersection of the black lines. How can I do this?
InitializeComponent();
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
// create 361 labels, set their properties
for (int i = 0; i < 361; i++)
{
board[i] = new Label();
board[i].Parent = pictureBox1;
board[i].Location = new Point(x, y);
board[i].Name = "label" + i;
board[i].Text = "0";
board[i].BackColor = Color.Black;
//set size of labels
board[i].Size = new Size(31,31);
}
// set the position of the label
foreach (Label i in board)
{
//set distance between labels
if (x >= 1024)
{
x = pictureBox1.Location.X;
y += 52;
}
else
{
x += 52;
}
this.Controls.Add(i);
i.BringToFront();
i.Location = new Point(x, y);
}
as far as i have understand your question, and saw your code.
you are creating labels at same
Location(x,y) where x = 100 and y = 0
in the next loop
foreach (Label i in board)
{
if (x >= 1024)
{
x = 0;
y += i.Height + 55;
}
else if (y >= 1024)
{
y = 0;
x += i.Width + 55;
}
}
None of your condition will become true, because your x = 100 and y = 0
so location will remain same and all labels will be at same location
if you want to display a chess grid see this method
Chess Grid in Winforms
if you want to display labels on intersection of lines then lets modify your Code
x = PictureBox1.Location.X + 55;
y = pictureBox1.Location.Y + 55;
for (int i = 0; i < 361; i++)
{
board[i] = new Label();
board[i].Parent = pictureBox1;
board[i].Location = new Point(x,y);
board[i].Name = "label" + i;
board[i].Text = "0";
board[i].BackColor = Color.Black;
board[i].Size = new Size(55,55); //Define size of label according to your choice
if(x >= 1024)
{
x = PictureBox1.Location.X + 55; //Start position
y += 55; // Step to next line
}
else
x += 55; //jump to next horizontal box
}
I hope this helps
I need to draw a user defined number of grids using C# WPF. My code works but is overly long if the maximum allowed number of grids is large - is there a more concise way?
The following code shows how 1 grid is currently drawn on gridCanvas (a WPF Grid Control) - it is repeated for each additional grid that may be needed.
private void DrawInvGrid(int[,] initialPosn)
{
PathFigure myPathFigure1 = new PathFigure();
GeometryGroup myGeometryGroup1 = new GeometryGroup();
LineSegment myLineSegment1 = new LineSegment();
PathSegmentCollection myPathSegmentCollection1 = new PathSegmentCollection();
PathFigureCollection myPathFigureCollection1 = new PathFigureCollection();
// repeat declarations for each grid
int gridx = 5;
int gridy = 5;
int gridsize = 11;
// create grid 1
for (int z = 0; z < 5; z++)
{
int startpt_1x = (initialPosn[0, 0] - 5);
int startpt_1y = (initialPosn[0, 1] - 5);
for (int i = 0; i <= gridx; i++)
{
myPathFigure1 = new PathFigure();
myPathSegmentCollection1 = new PathSegmentCollection();
myPathFigure1.StartPoint = new System.Windows.Point(startpt_1x +
(i * gridsize), startpt_1y);
myLineSegment1 = new LineSegment();
myLineSegment1.Point = new System.Windows.Point(startpt_1x + (i * gridsize),
startpt_1y + gridy * gridsize);
myPathSegmentCollection1.Add(myLineSegment1);
myPathFigure1.Segments = myPathSegmentCollection1;
myPathFigureCollection1.Add(myPathFigure1);
xgridpos1.Add(startpt_1x + (i * gridsize));
}
for (int i = 0; i <= gridy; i++)
{
myPathFigure1 = new PathFigure();
myPathSegmentCollection1 = new PathSegmentCollection();
myPathFigure1.StartPoint = new System.Windows.Point(startpt_1x, startpt_1y +
(i * gridsize));
myLineSegment1 = new LineSegment();
myLineSegment1.Point = new System.Windows.Point(startpt_1x + gridx *
ridsize, startpt_1y + (i * gridsize));
myPathSegmentCollection1.Add(myLineSegment1);
myPathFigure1.Segments = myPathSegmentCollection1;
myPathFigureCollection1.Add(myPathFigure1);
ygridpos1.Add(startpt_1y + (i * gridsize));
}
}
// repeat grid creation loop for each grid
// display grid 1
gridCanvas.Children.Clear();
PathGeometry myPathGeometry1 = new PathGeometry();
myPathGeometry1.Figures = myPathFigureCollection1;
myPath1.Stroke = System.Windows.Media.Brushes.Green;
myPath1.StrokeThickness = 1;
myPath1.ToolTip = gridname;
myPath1.Data = myPathGeometry1;
gridCanvas.Children.Add(myPath1);
// repeat display routine for each grid
}
All grids are identical in any particular run - only the position of the grid (defined by int[,] initialPosn) varies from grid to grid. Any suggestions on more efficient alternatives appreciated.
Extract the repetitive code into a method that takes only those values that change (the position in your case) as parameters.