Creating numerous PictureBoxes by code - only one is visible - c#

I am trying to draw lots of instances of an image using the following code:
PictureBox[] sprites = new PictureBox[100];
private void Game_Load(object sender, EventArgs e)
{
PictureBox mainSprite = new PictureBox();
Bitmap img = new Bitmap(SpriteTest.Properties.Resources.Image); //Load a png image
mainSprite.Size = new Size(16, 16);
mainSprite.Image = img;
for(var i = 0; i < sprites.Length; i++)
{
sprites[i] = mainSprite;
//Keeping it simple for now with a single row of sprites
sprites[i].Location = new Point(i * 16, 8);
}
Game.ActiveForm.Controls.AddRange(sprites);
}
When it comes to running the code, only the last image is shown. While debugging the code, everything seems to be working as expected. I can also verify that the location is in fact being updated.
I have also tried adding the controls differently using the following code in the for loop (with no luck);
this.Controls.Add(sprites[i]);
I have had this problem many times, especially when I tried to create many GroupBoxes in a similar fashion. For the hours that I searched online as I tried to find a solution, nothing has ever fixed it.

You're only actually creating one instance of PictureBox:
PictureBox mainSprite = new PictureBox();
...
for(var i = 0; i < sprites.Length; i++)
{
sprites[i] = mainSprite;
Your array will have lots of reference to the same object. You should create a new PictureBox on each iteration of the loop:
for(var i = 0; i < sprites.Length; i++)
{
PictureBox mainSprite = new PictureBox();
mainSprite.Size = new Size(16, 16);
mainSprite.Image = img;
sprites[i] = mainSprite;
...
}

Related

Converting windows Form to windows Metro Form

i have written a desktop app in normal windows form, it worked fine. Later i tried to convert it to Metro form because of its modern look. With minor change in control names i used most of the code from old normal form. But the form resizing function block throwing "System.NullReferenceException" while starting the app. But after commenting the resizing event it works fine.
private void Form1_Load(object sender, EventArgs e)
{
defaultSize = this.Size;
panel4Size = new Rectangle[] { new Rectangle(panel4.Location.X, panel4.Location.Y, panel4.Width, panel4.Height), new Rectangle(qusNo.Location.X, qusNo.Location.Y, qusNo.Width, qusNo.Height), new Rectangle(element1.Location.X, element1.Location.Y, element1.Width, element1.Height), new Rectangle(element2.Location.X, element2.Location.Y, element2.Width, element2.Height), new Rectangle(operation.Location.X, operation.Location.Y, operation.Width, operation.Height), new Rectangle(line.Location.X, line.Location.Y, line.Width, line.Height), new Rectangle(nextQus.Location.X, nextQus.Location.Y, nextQus.Width, nextQus.Height), new Rectangle(flp1.Location.X, flp1.Location.Y, flp1.Width, flp1.Height), new Rectangle(flp2.Location.X, flp2.Location.Y, flp2.Width, flp2.Height), new Rectangle(opt1.Location.X, opt1.Location.Y, opt1.Width, opt1.Height), new Rectangle(opt2.Location.X, opt2.Location.Y, opt2.Width, opt2.Height), new Rectangle(opt3.Location.X, opt3.Location.Y, opt3.Width, opt3.Height), new Rectangle(opt4.Location.X, opt4.Location.Y, opt4.Width, opt4.Height), new Rectangle(opt5.Location.X, opt5.Location.Y, opt5.Width, opt5.Height), new Rectangle(opt6.Location.X, opt6.Location.Y, opt6.Width, opt6.Height), new Rectangle(dopt1.Location.X, dopt1.Location.Y, dopt1.Width, dopt1.Height), new Rectangle(dopt2.Location.X, dopt2.Location.Y, dopt2.Width, dopt2.Height), new Rectangle(dopt3.Location.X, dopt3.Location.Y, dopt3.Width, dopt3.Height), new Rectangle(dopt4.Location.X, dopt4.Location.Y, dopt4.Width, dopt4.Height), new Rectangle(dopt5.Location.X, dopt5.Location.Y, dopt5.Width, dopt5.Height), new Rectangle(dopt6.Location.X, dopt6.Location.Y, dopt6.Width, dopt6.Height), new Rectangle(LaBackBt.Location.X, LaBackBt.Location.Y, LaBackBt.Width, LaBackBt.Height), new Rectangle(LaFinishBt.Location.X, LaFinishBt.Location.Y, LaFinishBt.Width, LaFinishBt.Height), new Rectangle(results.Location.X, results.Location.Y, results.Width, results.Height) };
panel2Size = new Rectangle[] { new Rectangle(panel2.Location.X, panel2.Location.Y, panel2.Width, panel2.Height), new Rectangle(Easy.Location.X, Easy.Location.Y, Easy.Width, Easy.Height), new Rectangle(Hard.Location.X, Hard.Location.Y, Hard.Width, Hard.Height), new Rectangle(MdBackBt.Location.X, MdBackBt.Location.Y, MdBackBt.Width, MdBackBt.Height), new Rectangle(eelem1.Location.X, eelem1.Location.Y, eelem1.Width, eelem1.Height), new Rectangle(eelem2.Location.X, eelem2.Location.Y, eelem2.Width, eelem2.Height), new Rectangle(eelem3.Location.X, eelem3.Location.Y, eelem3.Width, eelem3.Height), new Rectangle(eelem4.Location.X, eelem4.Location.Y, eelem4.Width, eelem4.Height), new Rectangle(eelem5.Location.X, eelem5.Location.Y, eelem5.Width, eelem5.Height), new Rectangle(flp3.Location.X, flp3.Location.Y, flp3.Width, flp3.Height), new Rectangle(flp4.Location.X, flp4.Location.Y, flp4.Width, flp4.Height), new Rectangle(flp5.Location.X, flp5.Location.Y, flp5.Width, flp5.Height), new Rectangle(flp6.Location.X, flp6.Location.Y, flp6.Width, flp6.Height) };
panel1Size = new Rectangle[] { new Rectangle(panel1.Location.X, panel1.Location.Y, panel1.Width, panel1.Height), new Rectangle(label1.Location.X, label1.Location.Y, label1.Width, label1.Height), new Rectangle(listView3.Location.X, listView3.Location.Y, listView3.Width, listView3.Height), new Rectangle(HmAdd.Location.X, HmAdd.Location.Y, HmAdd.Width, HmAdd.Height), new Rectangle(HmSub.Location.X, HmSub.Location.Y, HmSub.Width, HmSub.Height), new Rectangle(HmMul.Location.X, HmMul.Location.Y, HmMul.Width, HmMul.Height), new Rectangle(HmDiv.Location.X, HmDiv.Location.Y, HmDiv.Width, HmDiv.Height) };
}
private void reziseChildControl()
{
Control[] controlP4 = new Control[] { panel4, qusNo, element1, element2, operation, line, nextQus, flp1, flp2, opt1, opt2, opt3, opt4, opt5, opt6, dopt1, dopt2, dopt3, dopt4, dopt5, dopt6, LaBackBt, LaFinishBt, results };
Control[] controlP2 = new Control[] { panel2, Easy, Hard, MdBackBt, eelem1, eelem2, eelem3, eelem4, eelem5, flp3, flp4, flp5, flp6 };
Control[] controlP1 = new Control[] { panel1, label1, listView3, HmAdd, HmSub, HmMul, HmDiv};
for (int j = 0; j < controlP4.Length; j++)
{
resizeControls(panel4Size[j], controlP4[j]);
}
for (int j = 0; j < controlP2.Length; j++)
{
resizeControls(panel2Size[j], controlP2[j]);
}
for (int j = 0; j < controlP1.Length; j++)
{
resizeControls(panel1Size[j], controlP1[j]);
}
}
private void Form1_Resize(object sender, EventArgs e)
{
reziseChildControl();
}
private void resizeControls(Rectangle originalContrl, Control control)
{
float xRatio = (float)(this.Width) / (float)(defaultSize.Width);
float yRatio = (float)(this.Height) / (float)(defaultSize.Height);
int newX = (int)(originalContrl.X * xRatio);
int newY = (int)(originalContrl.Y * yRatio);
int newWidth = (int)(originalContrl.Width * xRatio);
int newHeight = (int)(originalContrl.Height * yRatio);
control.Location = new Point(newX, newY);
control.Size = new Size(newWidth, newHeight);
}
}
Update: The NullReferenceException throwing because the Form1_Resize event occurs before Form1_Load event. Form1_Resize event shouldn't be called before i change the layout of window(by dragging or maximize the window size). But Resize event calling automatically at starting of the app before Form1 completely laading. On checking the Form1 property i could not find relevant property which could be the reason for calling resize event while starting. Tried selecting different values for the form1 layout properties, nothing much changes except WindowState propety. Even with different values for WindowState property the Resize event calling at starting.
its easy to see what value is going null with debugger that is the problem when you create your panelsize don't set whit any start value that going null, to
see these complete guide and examples for build metro style app
https://msdn.microsoft.com/en-us/library/windows/apps/br211380
hope that helps !!!
Added a simple condition statement to resizing code. It worked fine after that. But didn't able to figure it out exactly what caused calling form_resize event at starting. May be its add in in metro framework but not sure.
Thanks

Display text from file in a picture box

I would like to ask, how would you print text from a file directly into a pictureBox. Currently, my program is supposed to do that, but it fails, and I think the reason is, that I force the containerBox to the front of the program. The pictureboxes itself are black as of right now, but that is for testing purposes.
Code:
for (int i = 0; i < fileitems.Length; i++)
{
containerBox.Add(new PictureBox());
//PictureBox pBox = new PictureBox();
containerBox[i].Name = "cb" + i;
containerBox[i].Location = new Point(Convert.ToInt32(b*0.05), curB);
containerBox[i].Size = new Size(Convert.ToInt32(b*0.9),Convert.ToInt32(a/5));
containerBox[i].BackColor = Color.Black;
containerBox[i].Dock = DockStyle.Left;
containerBox[i].Anchor = AnchorStyles.None;
//containerBox[i].Paint += PBox_Paint;
j = containerBox[i].CreateGraphics();
using (Font test1 = new Font("Arial", 14))
{
j.DrawString(fileitems[i],test1,Brushes.Blue,new Point(2,2));
}
//this.Controls.Add(containerBox[i]);
//containerBox.Add(pBox);
this.Controls.Add(containerBox[i]);
containerBox[i].BringToFront();
curB = Convert.ToInt32(containerBox[i].Location.Y+(a/5)+25);
}
As you can see, I tried making it so, that I can paint, but then I can't access the file or read the data. Below you see the code in the paint event
Code:
private void PBox_Paint(object sender, PaintEventArgs e)
{
/*
using (Font test1 = new Font("Arial", 14))
{
e.Graphics.DrawString("test", test1, Brushes.Blue, new Point(3, 3));
}*/
}
How can I read the text from the file, then print it to the left side in the picturebox?

Multiply images boxes

I have a simple form with 10 picture boxes like: pictureBox1, pictureBox2, pictureBox3...
And I have a folder with 10 images like: image1, image2, image3...
Now I am smart enough to know that I don't want to hard code pictureBox1.ImageLocation = image1, pictureBox2.ImageLocation = image2... Rather, I need to create some kind of loop or array that will populate my picture boxes with their respective images, but I am not smart enough to figure out how.
Something like:
for (int i = 0; i < 10; i++)
{
pictureBox[i].ImageLocation = image[i];
}
Eventually, I was hoping this project would scale dynamically, if I have a file with say 12 images, the program will simply create 12 picture boxes and load the images. A little help would be great.
What you have there would roughty work though I would suggest a list.
List<PictureBox> pictureBoxes = new List<PictureBox>();
List<Image> images = new List<Image>();
//code to populate your lists
for (int i = 0; i < pictureBoxes.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
If you want to make sure you have enough images for your PictureBox list you could check ahead of time:
if (images.Count >= pictureBoxes.Count)
{
for (int i = 0; i < pictureBoxes.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
}
...or fill out as many as you can before running out of images.
for (int i = 0; i < pictureBoxes.Count && i < images.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
EDIT:
So if you want to use strings to set the location of the images instead you can do that. Check this out:
List<PictureBox> pictureBoxes = new List<PictureBox>();
List<string> imageLocations = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
PictureBox PB1 = new PictureBox();
PB1.Location = new Point(0, 0);
PB1.Size = new Size(144, 197);
Controls.Add(PB1);
PictureBox PB2 = new PictureBox();
PB2.Location = new Point(145, 0);
PB2.Size = new Size(327, 250);
Controls.Add(PB2);
pictureBoxes.Add(PB1);
pictureBoxes.Add(PB2);
imageLocations.Add(#"C:\PicExample\image1.jpg");
imageLocations.Add(#"C:\PicExample\image2.jpg");
for (int i = 0; i < pictureBoxes.Count && i < imageLocations.Count; i++)
{
pictureBoxes[i].ImageLocation = imageLocations[i];
}
}
EDIT for Iteratively Creating PictureBoxe List:
If you want to not have to worry about hard-coding your list (and your picture boxes will be the same size) you could do something like this:
for (int i = 0; i < HoweverManyPictureBoxesYouWant; i++)
{
PictureBox PB = new PictureBox();
PB.Name = "PB" + i.ToString();
PB.Location = new Point(250 * i, 0); //Edit this as you see fit for location, i'm just putting them in a row
PB.Size = new Size(250, 250);
PB.ImageLocation = #"C:\PicExample\image" + i.ToString() + ".jpg";
Controls.Add(PB);
pictureBoxes.Add(PB); //You only need to do this if you want the PB's in a list for other reasons than setting the image location
}

Adding graphics to components created at runtime

For anybody that can help me out here I'd be very grateful!
I've got a very small app which creates several panels at runtime with a for LOOP. At the moment the number of panels to be created is derived from a value entered in a textbox, but will ultimately be determined by an integer read from a database
Each panel has a Label which is created in the same loop
My problem is that I want to draw 120 lines in each panel as it is created (in each iteration of the FOR loop), and I'm doing this with a nested WHILE loop
I can get everything to work fine, the panels are creating along with the Label titles, but for some reason I can't get the lines to draw
It's all in one method for testing, can anybody help me?
The code I currently have is as follows:
public void CreatePanels()
{
int PanelPosX = 50;
int PanelPosY = 500;
int LabelPosX = 10;
int LabelPosY = 10;
for (int i = 0; i < (Convert.ToInt32(textBox2.Text)); i++)
{
Panel pnlOverview = new Panel();
pnlOverview.Name = "InspectorPanel" + i.ToString();
pnlOverview.Text = "Inspector Panel " + i.ToString();
pnlOverview.Location = new Point(PanelPosX, PanelPosY);
pnlOverview.Size = new Size(974, 136);
pnlOverview.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
Controls.Add(pnlOverview);
PanelPosY += 170;
Label lblInspectorName = new Label();
lblInspectorName.Name = "InspectorName" + i.ToString();
lblInspectorName.Text = " Inspector " + i.ToString();
lblInspectorName.Width = 100;
lblInspectorName.Height = 13;
lblInspectorName.Location = new Point(LabelPosX, LabelPosY);
lblInspectorName.Size = new Size(974, 136);
pnlOverview.Controls.Add(lblInspectorName);
// Draw the Overview Chart
int x = 10;
int y = 0;
Pen OVTable = new Pen(Color.Black, 0);
while (y < 120)
{
Graphics mp = pnlOverview.CreateGraphics();
mp.DrawLine(OVTable, x, 40, x, 100);
y++;
x += 8;
}
}
return;
}
Thanks
Ivan
You might need to create an empty Image and draw into it and then add it to the Panel. The other option would be to Derive from Panel and override the OnPaint method, at which point you would draw your chart.
Perhaps there is a C# Chart component that would effect this for you.
Here's a link to a MSDN reference on rendering custom controls, which is what you are pursuing.

Add picture boxes dynamically in row

I am trying to show images in a row..For this I am trying to add picture boxes dynamically. Image location is stored in databses. my code is as
int iCtr = 0;
for (int i = 0; i < dt.Rows.Count; i++)
{
PictureBox picture = new PictureBox
{
Name = "pictureBox"+i,
Size = new Size(316, 320),
Location = new Point(1, iCtr * 1100 + 1),
Visible = true
};
// string fname = dt.Rows[2]["FileName"].ToString();
picture.ImageLocation = dt.Rows[i]["FileName"].ToString();
//#"..\Images\80knhk00003.jpg";
pnlDisplayImage.Controls.Add(picture);
iCtr++;
}
where dt is datable.
with this I can see only last image but not all images. Even last image is very small and complete image is not shown.(i.e. I can view only one corner of actual image).
How can I give size to image so that it can be viewed completely?
And how can I display images in row?
Please help
Thanks
Can you try something like this? To get the scaling, see PictureBoxSizeMode.
List<PictureBox> pictureBoxList = new List<PictureBox>();
for (int i = 0; i < dt.Rows.Count; i++)
{
PictureBox picture = new PictureBox
{
Name = "pictureBox" + i,
Size = new Size(316, 320),
Location = new Point(i * 316, 1),
BorderStyle = BorderStyle.FixedSingle,
SizeMode = PictureBoxSizeMode.Zoom
};
picture.ImageLocation = dt.Rows[i]["FileName"].ToString();
pictureBoxList.Add(picture);
}
foreach (PictureBox p in pictureBoxList)
{
pnlDisplayImage.Controls.Add(p);
}
instead of Image property, set the BackGroundImage property to your picture location, and then set the BackGroundImageLayout to the value "Stretch" then you will see full image.

Categories