cycled pictureboxes - c#

I need to work with much pictureboxes in one cycle. How can i do this? I tryed this :
for (int i = 1; i <= 10; i++)
{
PictureBox[] pb = new PictureBox[i];
pb[i].Image = global::Ippodrom.Properties.Resources.horse;
}
But it crashes with:
An unhandled exception of type 'System.IndexOutOfRangeException' occurred in Ippodrom.exe
Additional information: Index was outside the bounds of the array.
What shall I do?
UPD: I need to change the picture in created picturebox, not to create a new picturebox.

You need to loop through your existing pictureboxes on your form.
This procedure assumes you have the pictureboxes on the form and not in another container, like a panel. If so, adjust this code accordingly:
foreach (PictureBox pb in this.Controls.OfType<PictureBox>()) {
pb.Image = global::Ippodrom.Properties.Resources.horse;
}

What you want is to create an array of 10 PictureBox and initialize each of them.
What you have done is to create 10 arrays, each of size N, where N is [1..10].
Start by creating an array:
PictureBox[] pb = new PictureBox[10];
Now you have an array of 10 PixtureBox references. Each of them holds the value 'null'.
for (int i = 0; i < 10; i++) // C# arrays are zero-indexed, not one
{
// Create a new PictureBox and assign it to the array
pb[i] = new PictureBox();
// Assign an image to this new PictureBox
pb[i].Image = global::Ippodrom.Properties.Resources.horse;
}
The IndexOutOfRangeException occurs because you used a one-based index instead of zero, but the code was flawed to begin with, so it's not relevant.

If you create the Array of PictureBox you don't create any instances. You only declare "space" to hold the References to the Instances.
I guess what you're trying to do is this (but I might be wrong)
PictureBox[] pb = new PictureBox[10]; // creates space for 10 elements, first one is 0
for(int i = 0; i < 10; i++) { // from 0..9
pb[i] = new PictureBox(); // we create the actual thing
pb[i].Image = global::Ippodrom.Properties.Resources.horse;
}
It's probably a lot easier to use a List here
IList<PictureBox> pb = new List<PictureBox>();
for(int i = 0; i < 10; i++) { // if you want exactly 10
var theBox = new PictureBox();
theBox.Image = global::Ippodrom.Properties.Resources.horse;
pb.add(theBox);
}
if you want to change them
IList<PictureBox> pb = new List<PictureBox>() { pictureBox1 /* etc */ };
foreach(PictureBox p in pb) {
p.Image = global::Ippodrom.Properties.Resources.horse;
}
If you want every Picturebox in the Control go with the by LarsTech :)

Related

Adding a control to another control which is created at runtime

I am trying to add a picturebox control to a panel which is created at runtime.
It is for a chess game I am working on. I want to add a picture box to each panel , an assigning the image to the control later. Here is what I have so far:
//Sets the number of rows on the chess board
for (int i = 0; i < 8; i++)
{
//Set the number of columns on the board
for (int j = 0; j < 8; j++)
{
ChessSquare sq = new ChessSquare(((char)(65 + i)).ToString(), 7- j);
sq.Color = (i + (j % 2)) % 2 == 0 ? Color.Black : Color.White;
Panel p = new Panel()
{
Size = new Size(blockSize, blockSize),
BackColor = sq.Color,
Tag = sq,
Location = new Point(blockSize * i + 15, blockSize * j + 15),
BackgroundImageLayout = ImageLayout.Stretch
};
p.MouseEnter += new EventHandler(squareMouseEnter);
p.MouseLeave += new EventHandler(squareMouseLeave);
p.Click += new EventHandler(squareMouseClick);
chessBoardPanels[i, j] = p;
groupBox1.Controls.Add(p);
}
}
//SetUp Board
SetUpBoad Setup = new SetUpBoad();
SetUpBoad(chessBoardPanels);
Since you already put the Panels into the panel-array (?)
chessBoardPanels[i, j] = p;
You can add the PictureBoxes either now or later..:
PictureBox pb = new PictureBox ();
pb.Size = ..
pb.BackColor = Color.Transparent;
chessBoardPanels[i,j].Controls.Add(pb);
To access them later you can cast their first Control to PictureBox:
PictureBox pb = (PictureBox)chessBoardPanels[i,j].Controls[0];
pb.Image = aQueenImage;
If you want to add a PictureBox only where a piece is you need to do checks:
if (chessBoardPanels[i,j].Controls.Count > 0)
{
PictureBox pb = (PictureBox)chessBoardPanels[i,j].Controls[0];
pb.Image = aQueenImage;
}
To move a piece from <i1,j1> to <i2, j2> you do as expected:
chessBoardPanels[i1,j1].Controls[0].Parent = chessBoardPanels[i2,j2];
I notice that you are hooking up mouse events. If you want to use them to move the pieces, remember that transparency will not work for overlapping controls in Winforms and so while a piece-Box is crossing Panels it will not have working tranparency around the Image.
While the pBox is nested in a Panel all is well but to move it you would have to first make it a child of the parent of those panels and only add it to the target Panel upon MouseUp; the coordinate corrections can be solved but the tranparency, if you need it, will be a bigger problem..
The usual advice it to consider drawing at least those board squares and maybe even the pieces onto a base board-Panel (or board-PictureBox)

Displaying pictureBox array

I would like to display 13 pictureBox, however, it ends up with only the last one visible.
So I was wondering if I did it in a wrong way.
The following code get image from resources folder.
var testP = new PictureBox();
for (int i = 0; i < 13; i++)
{
testP.Width = 65;
testP.Height = 80;
testP.BorderStyle = BorderStyle.None;
testP.SizeMode = PictureBoxSizeMode.StretchImage;
test[i] = getImage(testP, testPTemp[i]);
}
The following code is trying to display 13 pictureBox with shifting location.
These two codes segments should be able to perform the action.
test = new PictureBox[13];
for (var i = 0; i < 13; i++)
{
test[i].Image = (Image)Properties.Resources.ResourceManager.GetObject("_" + testTemp[i]);
test[i].Left = 330;
test[i].Top = 500;
test[i].Location = new Point(test[i].Location.X + 0 * displayShift, test[i].Location.Y);
this.Controls.Add(test[i]);
}
Here is the getImage()
private PictureBox getImage(PictureBox pB, string i) // Get image based on the for loop number (i)
{
pB.Image = (Image)Properties.Resources.ResourceManager.GetObject("_" + i); // Get the embedded image
pB.SizeMode = PictureBoxSizeMode.StretchImage;
return pB;
}
I'm pretty sure there are all PictureBox Controls but they have all the same location so they are lying above each other. That's why only the last one is visible to you.
I think you should replace the 0 with the i variable.
test[i].Location = new Point(test[i].Location.X + i * displayShift, test[i].Location.Y); this.Controls.Add(test[i]);
It's hard to tell the exact problem based off the code you've provided. One possible issue could be that when you are creating the PictureBoxes you only create a single instance before the for loop and then fill the array with references to that instance. Another possibility is that when you're calculating the X position of the controls, you're multiplying by 0 which will always result in 0 (meaning all the controls are at location 330).
Below is code that will achieve basically what you're trying but without all your code I can't give you a more specific example.
In Your Class
const int PICTURE_WIDTH = 65;
const int PICTURE_HEIGHT = 85;
Inside You Function
//Loop through each image
for(int i = 0; i < testTemp[i].length; i++)
{
//Create a picture box
PictureBox pictureBox = new PictureBox();
pictureBox.BorderStyle = BorderStyle.None;
pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
//Load the image date
pictureBox.Image = (Image)Properties.Resources.ResourceManager.GetObject("_" + testTemp[i]);
//Set it's size
pictureBox.Size = new Size(PICTURE_WIDTH, PICTURE_HEIGHT);
//Position the picture at (330,500) with a left offset of how many images we've gone through so far
pictureBox.Location = new Point(330 + (i * PICTURE_WIDTH), 500);
//Add the picture box to the list of controls
this.Controls.Add(pictureBox);
}
If you need to keep a list of the picture boxes, just create a new list before the loop and add each pictureBox to the list inside the loop. If the control/window you're adding these PictureBoxes to needs to scroll left or right to see all the images set the AutoScroll property to true.

Grid child is already another visual or the root of a compositionTarget

I want in set all images from list to grid. But I have problem with adding second image in grid with Children.Add.
Here is my example:
List<Image> images = new List<Image>(8);
images.AddRange(Enumerable.Repeat(new Image(), 8));//8 empty images
Then setting images:
foreach (var image in images)
{
BitmapImage b = new BitmapImage();
b.BeginInit();
b.UriSource = new Uri("path");
b.EndInit();
image.Source = b;
image.Width = 50;
image.Height = 50;
}
Then in one function call like this:
private void put_images()
{
int i = 0;
foreach (var image in images)
{
Grid.SetRow(image, i);
Grid.SetColumn(image, i);
LayoutRoot.Children.Add(image);//here is error
i++;
}
}
I got runtime error: Additional information: Specified Visual is already a child of another Visual or the root of a CompositionTarget.
I don't understand why, because I got 8 different images, and I don't know how to fix that problem.
The problem is the code where you create the images.
images.AddRange(Enumerable.Repeat(new Image(), 8));
This is one image object, with 8 references in the collection.
The documentation of Enumerable.Repeat says:
element
Type: TResult
The value to be repeated.
The value of new Image() is the reference to that Image.
Which means you have 8 references to the same object in the collection.
You can easily verify that by comparing the first with the second entry in the list.
images[0] == images[1] //=true
A solution would be to use a for loop to instantiate the images.
for(int i = 0; i < 8; i++) images.Add(new Image());
It's seems the problem is the creating images.
Now I don't create 8 empty images, but I create Image, and then add in list. Now it's work:
for(int i = 0; i < 8; i++)
{
Image a = new Image();
BitmapImage b = new BitmapImage();
b.BeginInit();
b.UriSource = new Uri("path");
b.EndInit();
a.Source = b;
a.Width = 50;
a.Height = 50;
images.Add(a);
}

Adding objects during run time?

Background
I have a tab which is made active if there is more than one record returned from a query on my database.
For each record returned I would like a set of labels created and placed on the tab. For example if there are 8 records I would like 8 labels created.
Question
My loop only creates one label, even though my count is showing I have 8 records? Not sure why?
How do you create labels in a loop 8 times and not have them draw in the same location 8 times? I would them to appear in a horizontal list. Pretty sure the way I have coded the solution ,they will all be drawn in the same place?
Code
for (int i = 1; i <= rowCount; i++)
{
// Create objects
LinkLabel Linklabel1 = new LinkLabel();
Linklabel1.Text += ds.Tables[0].Rows[0]["code"].ToString();
Linklabel1.Location = new Point(10, 50);
Linklabel1.Height = 40;
Linklabel1.Width = 100;
tabControl1.TabPages[0].Controls.Add(Linklabel1);
}
Try something like this out:
for (int i = 0; i < rowCount; i++)
{
// Create objects
LinkLabel Linklabel1 = new LinkLabel();
Linklabel1.Text = ds.Tables[0].Rows[i]["code"].ToString();
Linklabel1.Height = 40;
Linklabel1.Width = 100;
Linklabel1.Location = new Point((i + 1) * 10 + (i * Linklabel1.Width), 50);
tabControl1.TabPages[0].Controls.Add(Linklabel1);
}
If you don't want to explicitly position them by setting the Location() property, consider putting a FlowLayoutPanel on the TabPage and added the controls to that instead. Then they will positioned automatically for you.

C# how to slide a panel

This code is just changing location, not sliding.
I am using this at the moment:
for (int i = 740; i == 740; i++)
{
panel2.Location = new Point(panel2.Location.X - i, panel2.Location.Y);
}
How can I slide the panel slowly?
Now, as I stated in my comment you really need to use float values, so you really need to draw it. However, the current implementation only makes a single iteration. The current loop could have been translated into this:
panel2.Location = new Point(panel2.Location.X - 740, panel2.Location.Y);
Consider a loop like this to slide it out:
for (int i = -(panel2.Width); i < 0; i++)
{
panel2.Location = new Point(i, panel2.Location.Y);
}
That algorithm is assuming that you've set the Location to the - of it's width (e.g. -740x) so that it's simply not visible on the screen. The reverse would hide it.
This will still be a little choppy, but it won't just hide it like your current code.
If you are just going to slide the panel try to do this
Try this code:
Panel panelArray = new Panel[];
Panel panel2 = panelArray[0];
for (int i = 0; i <= 100; i++)
{
panel2.Location = new Point(panel2.Location.X - i, panel2.Location.Y);
System.Threading.Thread.Sleep(10);
}

Categories

Resources