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();
}
Related
I have a 2d array of LEDButton : Button.
I want to find out the index [x,y] of each buttons the user clicks.
I am new to Windows Forms and not used to working outside of a console so these GUI objects are very unfamiliar to me.
private void Form1_Load(object sender, EventArgs e)
{
LEDButton[,] leds = new LEDButton[11, 11];
for (int x = 0; x < leds.GetUpperBound(0); x++)
{
listBox1.Items.Add("x = " + x);
for (int y = 0; y < leds.GetUpperBound(1); y++)
{
leds[x, y] = new LEDButton()
{
Name = String.Format("Button{0}{1}", x, y),
TabIndex = 40 * x + y,
Location = new Point(40 * y + 50, 40 * x + 50)
};
leds[x, y].pointx = x;
leds[x, y].pointy = y;
}
}
// add buttons to controls
for (int x = 0; x < leds.GetUpperBound(0); x++)
{
for (int y = 0; y < leds.GetUpperBound(1); y++)
{
Controls.Add(leds[x, y]);
leds[x, y].Click += Form1_Click;
}
}
public class LEDButton : Button
{
public const int LEDWidth = 20;
public const int LEDHeight = 20;
public int pointx = 0;
public int pointy = 0;
public LEDButton()
{
BackColor = Color.FromArgb(0, 64, 0);
ForeColor = Color.Black;
FlatStyle = FlatStyle.Flat;
Size = new Size(LEDWidth, LEDHeight);
UseVisualStyleBackColor = false;
this.Click += LEDButton_Click; //throws error
}
}
I think I found my answer with the help of Lars.
Code should be
private void Form1_Click(object? sender, EventArgs e)
{
LEDButton btn = sender as LEDButton;
listBox2.Items.Add(btn.Name);
}
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);
}
}
}
Hello the code below works perfectly but i was wondering on how i could implement code that once The row of balls cant fit in the picture box in the first row it creates a new row below that row and so on.
{
//calculate the number of rows
int ballRows = HEIGHT / (SIZE + GAP);
// sets the seed posion in the picturebox
Rectangle recCircle = new Rectangle(LEFT, TOP,SIZE,SIZE);
Graphics paper = pictureBoxBowl.CreateGraphics();
Pen pen1 = new Pen(Color.Gray, 2);
// variable for amount of balls
int ballAmount = 0;
try
{
//changes text value to interger
ballAmount = int.Parse(textBoxNumSeeds.Text);
}
catch (Exception ex)
{
//tells user of error and clears and focuses the textbox
MessageBox.Show("invalid numeric input try again");
textBoxNumSeeds.Clear();
textBoxNumSeeds.Focus();
return;
}
//makes y position for the circle rows
int yPos = TOP;
int xPos = LEFT;
//creates new row under previous row
for (int cols = 0; cols < ballAmount; cols++)
{
SolidBrush SeedColour = null;
int randBallCol = rand.Next(40) + 1;
//if random ball colour is between 1 - 100 then set to blue
if (randBallCol >= 1 && randBallCol <= 100)
{
SeedColour = new SolidBrush(Color.Gray);
}
//changes new circle location by changing y position and adding gap and radius to it
recCircle.Location = new Point(xPos, yPos);
//displays the circles based on recCircle dimensions
paper.FillEllipse(SeedColour, recCircle);
paper.DrawEllipse(pen1, recCircle);
//updates the xposition of the columns
xPos = xPos + SIZE + GAP;
}
You did not specify what platform you are using, but let's assume WinForms for simplicity.
You need to reset the yPos when the next ball x-Position will be outside the size of the paper rectangle.
something like this just below the line where you update the x position right at the bottom.
int xNext = xPos + SIZE + GAP;
if (xNext > e.ClipRectangle.Width)
{
yPos = yPos + SIZE;
xPos = 0;
}
However its better to use the Paint event.
I set up a small WinForms app and it looks like this.
public partial class Form1 : Form
{
int HEIGHT = 5;
int SIZE = 10;
int GAP = 2;
int LEFT = 0;
int TOP = 0;
Rectangle _recCircle;
int ballAmount = 0;
Random _rand;
public Form1()
{
InitializeComponent();
_recCircle = new Rectangle(LEFT, TOP, SIZE, SIZE);
_rand = new Random(1);
}
private void button1_Click(object sender, EventArgs e)
{
try
{
//changes text value to interger
ballAmount = int.Parse(textBoxNumSeeds.Text);
}
catch (Exception ex)
{
//tells user of error and clears and focuses the textbox
MessageBox.Show("invalid numeric input try again");
textBoxNumSeeds.Clear();
textBoxNumSeeds.Focus();
return;
}
pictureBoxBowl.Invalidate();
}
private void pictureBoxBowl_Paint(object sender, PaintEventArgs e)
{
//makes y position for the circle rows
int yPos = TOP;
int xPos = LEFT;
int xNext = 0;
//creates new row under previous row
for (int cols = 0; cols < ballAmount; cols++)
{
SolidBrush SeedColour = null;
SeedColour = new SolidBrush(Color.FromArgb(_rand.Next(255), _rand.Next(255), _rand.Next(255)));
//changes new circle location by changing y position and adding gap and radius to it
_recCircle.Location = new Point(xPos, yPos);
//displays the circles based on recCircle dimensions
e.Graphics.FillEllipse(SeedColour, _recCircle);
e.Graphics.DrawEllipse(new Pen(SeedColour), _recCircle);
//updates the xposition of the columns
xPos = xPos + SIZE + GAP;
//test if a new row is required
xNext = xPos + SIZE + GAP;
if (xNext > e.ClipRectangle.Width)
{
yPos = yPos + SIZE;
xPos = 0;
}
}
}
}
and gives you this result.
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.
I want create a control that draws a table in panel . My code is:
public class PanelZ : System.Windows.Forms.Panel
{
public static void Draw()
{
Panel p = new Panel();
p.Width = 200;
p.Height = 200;
Graphics g = p.CreateGraphics();
Pen mypen = new Pen(Brushes.Black, 1);
Font myfont = new Font("tahoma", 10);
int lines = 9;
float x = 0;
float y = 0;
float xSpace = p.Width / lines;
float yspace = p.Height / lines;
for (int i = 0; i < lines + 1; i++)
{
g.DrawLine(mypen, x, y, x, p.Height);
x += xSpace;
}
x = 0f;
for (int i = 0; i < lines + 1; i++)
{
g.DrawLine(mypen, x, y, p.Width, y);
y += yspace;
}
}
..but it dosen't draw a table; so what should I do?
This will work. But the numbers ought to be properties, as should the pen and then some.. Also: Properties ought to start with an uppercase letter.
public class PanelZ : System.Windows.Forms.Panel
{
public PanelZ() // a constructor
{
Width = 200;
Height = 200;
DoubleBuffered = true;
lines = 9;
}
public int lines { get; set; } // a property
protected override void OnPaint(PaintEventArgs e) // the paint event
{
base.OnPaint(e);
Graphics g = e.Graphics;
Pen mypen = new Pen(Brushes.Black, 1);
Font myfont = new Font("tahoma", 10);
float x = 0;
float y = 0;
float xSpace = Width / lines;
float yspace = Height / lines;
for (int i = 0; i < lines + 1; i++)
{
g.DrawLine(mypen, x, y, x, Height);
x += xSpace;
}
for (int i = 0; i < lines + 1; i++)
{
g.DrawLine(mypen, 0, y, Width, y);
y += yspace;
}
}
}
At work in VS:
Note that this only colors pixels. There is no useful grid there, just pixels with color.. So, if you actually want to use the Font you define you will have to calculate the coodordinates and the bounding boxes.