C# Getting pictureboxes from Struct - c#

I want to get the object that created in struct. Showing the codes will explain it better though.
private void Obstacle()
{
obstacle_pos_x = obstacle_random_x.Next(1000);
obstacle_pos_y = obstacle_random_y.Next(700);
picture = new PictureBox
{
Name = "pictureBox" + obstacle_numb,
Size = new Size(32, 32),
Location = new Point(obstacle_pos_x,obstacle_pos_y),
BackColor = Color.Black,
};
this.Controls.Add(picture);
}
This is the struct inside of Obstacle method. As you can see this method creates pictureboxes and I want to pull them into KeyPressEvents. Like, if I press W, all the pictureboxes that created by struct has to move -10(y axis).
else if (e.KeyCode == Keys.W)
{
y -= chrspeed;
obstacle_numb++;
Obstacle();
for (int i = 0; i <= obstacle_numb; i++)
{
}
}
Well this the event. But it just creates pictureboxes. For loop is empty, because I couldn't figure out what to do. I simply want to do something like that,
picture+obstacle_numb.Location = new Point(x,y); (I need this picture+obstacle_numb combination.)
But also know that it is imposible. foreach came up to my mind but I don't know how to use it. Maybe something like this can work if fixed.
foreach(PictureBox objects from picture) //It doesn't work too.
I'm stuck right now and waiting for your help. Thanks in advance.

The easiest would be to iterate all the child controls that are of type PictureBox:
...
foreach (var pict in this.Controls.OfType<PictureBox>())
{
// pict is now a Picturebox, you can access all its properties as you have constructed it
// the name was constructed that way: Name = "pictureBox" + obstacle_numb,
if (pict.Name != "pictureBox1")
{
pict.Location = new Point(pict.X, pict.Y-10);
}
}

Related

Dynamically display an array of PictureBoxes - Performance issue

I'd like to display coverarts for each album of an MP3 library, a bit like Itunes does (at a later stage, i'd like to click one any of these coverarts to display the list of songs).
I have a form with a panel panel1 and here is the loop i'm using :
int i = 0;
int perCol = 4;
int disBetWeen = 15;
int width = 250;
int height = 250;
foreach(var alb in mp2)
{
myPicBox.Add(new PictureBox());
myPicBox[i].SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
myPicBox[i].Location = new System.Drawing.Point(disBetWeen + (disBetWeen * (i % perCol) +(width * (i % perCol))),
disBetWeen + (disBetWeen * (i / perCol))+ (height * (i / perCol)));
myPicBox[i].Name = "pictureBox" + i;
myPicBox[i].Size = new System.Drawing.Size(width, height);
myPicBox[i].ImageLocation = #"C:/Users/Utilisateur/Music/label.jpg";
panel1.Controls.Add(myPicBox[i]);
i++;
}
I'm using the same picture per picturebox for convenience, but i'll use the coverart embedded in each mp3 file eventually.
It's working fine with an abstract of the library (around 50), but i have several thousands of albums. I tried and as expected, it takes a long time to load and i cannot really scroll afterward.
Is there any way to load only what's displayed ? and then how to assess what is displayed with the scrollbars.
Thanks
Winforms really isn't suited to this sort of thing... Using standard controls, you'd probably need to either provision all the image boxes up front and load images in as they become visible, or manage some overflow placeholder for the appropriate length so the scrollbars work.
Assuming Winforms is your only option, I'd suggest you look into creating a custom control with a scroll bar and manually driving the OnPaint event.
That would allow you to keep a cache of images in memory to draw the current view [and a few either side], while giving you total control over when they're loaded/unloaded [well, as "total" as you can get in a managed language - you may still need tune garbage collection]
To get into some details....
Create a new control
namespace SO61574511 {
// Let's inherit from Panel so we can take advantage of scrolling for free
public class ImageScroller : Panel {
// Some numbers to allow us to calculate layout
private const int BitmapWidth = 100;
private const int BitmapSpacing = 10;
// imageCache will keep the images in memory. Ideally we should unload images we're not using, but that's a problem for the reader
private Bitmap[] imageCache;
public ImageScroller() {
//How many images to put in the cache? If you don't know up-front, use a list instead of an array
imageCache = new Bitmap[100];
//Take advantage of Winforms scrolling
this.AutoScroll = true;
this.AutoScrollMinSize = new Size((BitmapWidth + BitmapSpacing) * imageCache.Length, this.Height);
}
protected override void OnPaint(PaintEventArgs e) {
// Let Winforms paint its bits (like the scroll bar)
base.OnPaint(e);
// Translate whatever _we_ paint by the position of the scrollbar
e.Graphics.TranslateTransform(this.AutoScrollPosition.X,
this.AutoScrollPosition.Y);
// Use this to decide which images are out of sight and can be unloaded
var current_scroll_position = this.HorizontalScroll.Value;
// Loop through the images you want to show (probably not all of them, just those close to the view area)
for (int i = 0; i < imageCache.Length; i++) {
e.Graphics.DrawImage(GetImage(i), new PointF(i * (BitmapSpacing + BitmapWidth), 0));
}
}
//You won't need a random, just for my demo colours below
private Random rnd = new Random();
private Bitmap GetImage(int id) {
// This method is responsible for getting an image.
// If it's already in the cache, use it, otherwise load it
if (imageCache[id] == null) {
//Do something here to load an image into the cache
imageCache[id] = new Bitmap(100, 100);
// For demo purposes, I'll flood fill a random colour
using (var gfx = Graphics.FromImage(imageCache[id])) {
gfx.Clear(Color.FromArgb(255, rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255)));
}
}
return imageCache[id];
}
}
}
And Load it into your form, docking to fill the screen....
public Form1() {
InitializeComponent();
this.Controls.Add(new ImageScroller {
Dock = DockStyle.Fill
});
}
You can see it in action here: https://www.youtube.com/watch?v=ftr3v6pLnqA (excuse the mouse trails, I captured area outside the window)

controlling a spawned picturebox

I am trying to make a little game coded in c#, the game involves moving enemies.
These enemies are spawned in using the following code, this code is used multiple times to spawn multiple enemies.
private void EventHandler(Action<object, EventArgs> spawnBox)
{
Random randomPlek = new Random();
int xPlek;
xPlek = randomPlek.Next(1000, 1100);
int yPlek;
yPlek = (randomPlek.Next(0, 8)) * 100;
var picture = new PictureBox
{
Name = "pictureBoxLM",
Size = new Size(150, 100),
SizeMode = PictureBoxSizeMode.StretchImage,
BackColor = Color.Transparent,
Location = new Point(xPlek, yPlek),
Image = Leeuwenmier,
};
this.Controls.Add(picture);
}
The problem is that when trying to make them move or collide, Visual Studio can't find the name and gives an error. This is the code i used for collision:
if(PbMier.Bounds.IntersectsWith(pictureBoxLM.Bounds))
{
// some actions
}
How can I call the spawned picturebox in the code without getting an error?
WinForms controls have names, but that doesn't mean you can access them using that name as a C# identifier.
Your PictureBox only has a named reference within EventHandler(), namely picture, but once control leaves that method that reference goes out of scope.
You need to find the controls again, or find another way to reference the generated controls.
So either:
var allPictureBoxes = this.Controls.Find("PictureBoxLM");
foreach (var pictureBox in allPictureBoxes)
{
// ...
}
Or put this on your form:
List<PictureBox> pictureBoxList = new List<PictureBox>();
And then in the EventHandler();
this.Controls.Add(picture);
pictureBoxList.Add(picture);
After which you can use this for your collision detection:
foreach (var pictureBox in pictureBoxList)
{
// ...
}

When PictureBox location property is changed the old image is still shown

I have a pictureBox in another pictureBox. I try to create an imitation of flying plane on a map. I made a simple loop to do this task. The code:
for (var i = 0; i < 23; i++)
{
Fuel -= 1;
Changed(i);
}
private void Changed(int a)
{
Thread.Sleep(350);
pbPlane1.Location = new Point(525-(25*a), 235);
pbPlane1.Refresh();
}
So in this case the plane image is moving as I want but the old images are shown aswell, and I don't want it. I have tried a couple of things but with no results. What is wrong with my code?
Instead of refreshing the plane image, you need to refresh the map image.
The code should be as follows:
private void Changed(int a)
{
Thread.Sleep(350);
pbPlane1.Location = new Point(525-(25*a), 235);
pbMap1.Refresh(); // refresh the background picturebox
}

How can I update/redraw a Microsoft Powerpacks canvas in C#?

I have a method which finds relationships between two objects, if it exists, I would like to draw two Lineshapes to the link. I have started to implement the first lineshape, however whenever I test the code the lines persist. I have tried multiple methods (as you can see) and these do not refresh the canvas for the new lines to be drawn.
private void DrawRelationshipLines()
{
_canvas = new ShapeContainer {Parent = panelCredentialsVisualisation};
//These methods below do not redraw the canvas
_canvas.Shapes.Remove(_tableinfoLine);
_canvas.Shapes.Clear();
_canvas.Refresh();
_canvas.Update();
//
List<string> relationships = lvSelectedTableInfoCredentialsIntersection.GetAllRelationships();
if (relationships.Capacity == 0)
return;
foreach (string context in relationships)
{
Label contextLabelName = GetLabelByName(context);
_tableinfoLine = new LineShape
{
Parent = _canvas,
BorderWidth = 2,
BorderColor = Color.BlueViolet,
StartPoint = new Point(lblselectedTableinfo.Right, lblselectedTableinfo.Top + 10),
EndPoint = new Point(contextLabelName.Left, contextLabelName.Top + 10)
};
}
The code works fine in searching for relationships and drawing them, however I'd like to be able to clear the canvas before drawing a different relationship, is this possible?
Thanks if anyone can help.
Moving _canvas = new ShapeContainer {Parent = panelCredentialsVisualisation}; outside of the method made this work. Seems like initializing a new ShapeContainer each time was causing issues.

How to use BringToFront(); properly?

So I've been working on a little game project called economy, and I've ran into a little problem. What I want is to draw a stick man on the screen when someone hires a new employee, I do this by creating a new picture box, and assigning the stick man image to it. However because I needed to do this over and over again (so that they could have unlimited employees) I had it create a new object each time.
To remove the stick men, when someone fired them, I added a new picture box over the old stick men that is just white, so it looks as if they disappear. However for some reason BringToFront(); does not appear to work with it, and so I can't get the white picture to be drawn over the stick men.
If someone could tell me why it is not working, or a way to reference the original stickmen pictureboxe's to change their image, that would be fantastic.
public void Hire_Worker_Click(object sender, EventArgs e)
{
workers++;
money -= 10000;
PictureBox WPB = new PictureBox();
//Set location and size of new picturebox
WPB.Image = Economy.Properties.Resources.Worker;
WPB.Width = 68;
WPB.Height = 118;
WPB.Location = new Point(workerx,400);
workerx += 68;
Controls.Add(WPB);
}
public void Fire_Worker_Click(object sender, EventArgs e)
{
if (workers > 1)
{
clickfire++;
workers--;
money -= 100;
if (clickfire == 1)
{
workerx -= 68;
}
PictureBox WWPB = new PictureBox();
//Set location and size of picturebox
WWPB.BringToFront();
WWPB.Image = Economy.Properties.Resources.whiteworker;
WWPB.Width = 68;
WWPB.Height = 118;
WWPB.Location = new Point(workerx, 375);
workerx -= 68;
Controls.Add(WWPB);
}
}
BringToFront only works when the control is already in the parent, so move that line:
Controls.Add(WWPB);
WWPB.BringToFront();

Categories