C# Picturebox not loading that is added in code - c#

I have a procedure which draws in the player picture box, as below:
public static PictureBox drawPlayer(Engine.Tile location, Image looks)
{
PictureBox player = new PictureBox();
player.Location = location.img.Location;
player.BackColor = Color.Yellow;
player.Size = new Size(50, 50);
player.Name = "Player";
player.Visible = true;
player.BringToFront();
return player;
}
However, it is not working, it is called as such:
t.Controls.Add(drawPlayer(location, image));
Any help with this would be great or an answer as to why this doesn't work, I have temporarily set the colour of the box to yellow just to make it really stand out when it does finally decide to load.
Thanks,
Laurence

You need to use player.BringToFront(); after the control has been added into the form, as it does not exist on the form when you call this in the method that is making the PictureBox.

Related

changing image to gif after event

i have created a game, and im trying to get the image of the enemies once they have been shot to chnage to a explosion gif before they dissapear but i cant seem to get it to work, you can see the code below where it is meant to change to gif but when you pay the gamethe nemies just dissapear without the gif showing
lasers.RemoveAll(laser => laser.isDisposed);
foreach (Laser laser in lasers)
{
laser.MoveLaser(this);
foreach (Invader ship in invaders)
{
if (laser.laser.Bounds.IntersectsWith(ship.ship.Bounds))
{
laser.isDisposed = true;
laser.laser.Dispose();
ship.ship.Image = SpaceInvaders.Properties.Resources.explosionGIF1;
ship.isDisposed = true;
ship.ship.Dispose();
score = score + 2; //adds 2 points to players score if enemy is hit
lblScore.Text = score.ToString(); //updates the score label
As #jimi explained
Well, you set an Image to the property of an object, then dispose of the object that should show it. Btw, don't try to set [object].isDisposed = true;, it's read-only. Just dipose of an object when needed. Btw2, you need to assign Properties.Resources.[Some Image] to a reusable Image object: right now you're generating a new Image each time.
You're disposing the ship and with that the image.
An example solution would be to create a new GIF object that self-disposes after it has been played once. When the ship is destroyed, a new GIF object is created in the same place the ship was.

How to make new GameObject with multiple siblings follow its parent objects layout rules?

The button click function attached to to a button will create new gameObjects and first one will be child of reference gameObject, the second one will be child of first one. The referenced object has vertical layout group attached but the created child is not following the order.
Here is the code that created new objects:
public void CreateTextButtonClick(GameObject panel)
{
string text = "hello..";
Debug.Log("Hey starting of this..");
//Create Canvas Text and make it child of the Canvas
GameObject txtObj = new GameObject("myText");
txtObj.transform.SetParent(panel.transform, false);
//image
GameObject back = new GameObject("image");
back.transform.SetParent(txtObj.transform, false);
Image i = back.AddComponent<Image>();
//text
GameObject pan = new GameObject("text");
pan.transform.SetParent(txtObj.transform, false);
//Attach Text,RectTransform, an put Font to it
Text txt = pan.AddComponent<Text>();
txt.text = text;
Font arialFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
txt.font = arialFont;
txt.lineSpacing = 1;
txt.color = Color.blue;
Debug.Log("Hey its done..");
}
Here the child appears at the same place while it is expected to be from top to bottom order.
Heres the screenshot while not in play mode:
Here's the screenshot while in play mode and after two button clicks the object appeared on scrollViews panel but in unexpected way:
dragging this will reveal the object.
And also objects with no child follows that layout rule.
How can that object be in a order that shows one after another also in properly within the view port?
Thanks.
Update:
With multiline strings, with [Soragge]'s given code this will happen with height checkboxes checked :
with height checkboxes not checked:
Can this be made dynamic with more objects added?
Probably your new objects are missing the RectTransform. Try this:
GameObject txtObj = new GameObject("myText", typeof(RectTransform));
And if you want them to show starting from top, uncheck both Height checkboxes at the Layout Component.
Edit:
If you want the content to fit the text, keep the Height checkboxes checked and add the ContentSizeFitter component to the Content game object with Vertical Fit set to Preferred Size. The txtObj must also have a layout group attached. This should do the trick:
public void CreateTextButtonClick(GameObject panel)
{
string text = "hello..";
Debug.Log("Hey starting of this..");
//Create Canvas Text and make it child of the Canvas
GameObject txtObj = new GameObject("myText", typeof(RectTransform));
txtObj.transform.SetParent(panel.transform, false);
HorizontalLayoutGroup layoutgroup = txtObj.AddComponent<HorizontalLayoutGroup>();
layoutgroup.childAlignment = TextAnchor.MiddleCenter;
layoutgroup.childControlWidth = false;
//image
GameObject back = new GameObject("image");
back.transform.SetParent(txtObj.transform, false);
back.AddComponent<LayoutElement>().ignoreLayout = true;
Image i = back.AddComponent<Image>();
RectTransform imageRectTransform = back.GetComponent<RectTransform>();
imageRectTransform.anchorMin = Vector2.zero;
imageRectTransform.anchorMax = Vector2.one;
imageRectTransform.sizeDelta = Vector2.zero;
//text
GameObject pan = new GameObject("text");
pan.transform.SetParent(txtObj.transform, false);
//Attach Text,RectTransform, an put Font to it
Text txt = pan.AddComponent<Text>();
txt.text = text;
Font arialFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
txt.font = arialFont;
txt.lineSpacing = 1;
txt.color = Color.blue;
Debug.Log("Hey its done..");
}

Basic tile map in winforms

I am making a program where you bassicly move from tile to tile in windows forms.
So in order to do that, I wanted to use panels each panel has a tag. To detect collision.
So I have an image of my map. and I divided into multiple tiles. However now I have to drag 900 tiles onto panels.
This isn't very effective in 2 ways. First loading 900 textures isn't really a smart idea. Also it would take ages. So i wanted to use a spritesheet or tilemap. But how would I do that in winforms. I believe I have seen some people use a grid view or whatever. However im not sure how to do what I want to do.
What would be the best solution?
Thanks in advance!
For any serious gaming project WinForms is not the best platform. Either WPF or XNA or Unity are able to deliver high performance use of DirectX.
But since you want to do it in Winforms here is a way to do it.
It creates a whopping number of 900 PictureBoxes and loads each with a fraction of an source image:
private void Form1_Load(object sender, EventArgs e)
{
int tileWidth = 30;
int tileHeight = 30;
int tileRows = 30;
int tileCols = 30;
using (Bitmap sourceBmp = new Bitmap("D:\\900x900.jpg"))
{
Size s = new Size(tileWidth, tileHeight);
Rectangle destRect = new Rectangle(Point.Empty, s);
for (int row = 0; row < tileRows; row++)
for (int col = 0; col < tileCols; col++)
{
PictureBox p = new PictureBox();
p.Size = s;
Point loc = new Point(tileWidth * col, tileHeight * row);
Rectangle srcRect = new Rectangle(loc, s);
Bitmap tile = new Bitmap(tileWidth, tileHeight);
Graphics G = Graphics.FromImage(tile);
G.DrawImage(sourceBmp, destRect, srcRect, GraphicsUnit.Pixel);
p.Image = tile;
p.Location = loc;
p.Tag = loc;
p.Name = String.Format("Col={0:00}-Row={1:00}", col, row);
// p.MouseDown += p_MouseDown;
// p.MouseUp += p_MouseUp;
// p.MouseMove += p_MouseMove;
this.Controls.Add(p);
}
}
}
When I tried it I was a bit worried about perfomance, but..
This takes under 1 second to load on my machine.
Starting the programm adds 10MB to VS memory usage. That is like nothing.
For a fun project this will do; for best performance one might use Panels but these will have to be filled and refilled in the Paint event. This solution saves you the hassle and since you don't change the tile picture all the time this works well enough.
Pleae note: I have added a Name and a Tag to each PictureBox, so you can later refer to it. These both contain info about the original position of the Picturebox. The Name looks like this: Col=23-Row=02 and the Tag is the original Location object.
Also: Dynamically added controls take a little extra to script since you can't create their method bodies in the designer. Instead you add them like above. In doing so Intellisense and the Tab key are your best friends..
I have added three event handlers for a few mouse events. When you uncomment them you will have to add the methods like e.g. this:
void p_MouseMove(object sender, MouseEventArgs e)
{
throw new NotImplementedException();
}
But maybe you want to use other events to play like Drag&Drop or keyboard events..
There are two ways to refer to these tiles. Maybe you want to try and/or use both of them: You can loop over the form's controls with a
foreach (Control ctl in this.Controls)
{ if (ctl is PictureBox ) this.Text = ((PictureBox)ctl).Name ; }
It tests for the right type and then casts to PictureBox. As an example it displays the name of the tile in the window title.
Or you can have a variable and set it in the MouseDown event:
PictureBox currentTile;
void p_MouseDown(object sender, MouseEventArgs e)
{
currentTile = (PictureBox ) sender;
}

Window won't draw my Sprite when releasing Mouse Button

I am new to SFML and I am just playing around with an example at the moment. I try to draw a sprite where I last clicked my mouse in a window. But some reason the event fires and no sprite is drawn. I can't really figure out why.
I've been looking around in the Documentation but I don't seem to do anything wrong. Help me pretty please? :3
The event is called OnMouseLeftClick and I am trying to draw the mouseLeftClickSprite object. I have removed the bits of code that doesn't matter like the OnMouseMoved event and the OnClose event. They have nothing to do with this.
using System;
using SFML.Audio;
using SFML.Graphics;
using SFML.Window;
namespace SFMLExample
{
class Program
{
static Text xMouseCoord;
static Text yMouseCoord;
static Text statusMsg;
static float mouseX, mouseY;
static Texture mouseLeftClickTexture;
static Sprite mouseLeftClickSprite;
static void OnMouseLeftClick(object sender, EventArgs e)
{
if (Mouse.IsButtonPressed(Mouse.Button.Left))
{
statusMsg.DisplayedString = "Console: OnMouseLeftClick() Fired";
RenderWindow window = (RenderWindow)sender;
mouseLeftClickSprite.Position = new Vector2f(mouseX, mouseY);
window.Draw(mouseLeftClickSprite);
}
}
static void Main(string[] args)
{
mouseX = 0.0f;
mouseY = 0.0f;
// Create the main window
RenderWindow window = new RenderWindow(new VideoMode(800, 600), "SFML Window");
window.Closed += new EventHandler(OnClose);
window.MouseMoved += new EventHandler<MouseMoveEventArgs>(OnMouseMoved);
window.MouseButtonPressed += new EventHandler<MouseButtonEventArgs>(OnMouseLeftClick);
// Load a sprite to display
Texture texture = new Texture("cute_image.jpg");
Sprite sprite = new Sprite(texture);
mouseLeftClickTexture = new Texture("GM106.png");
mouseLeftClickSprite = new Sprite(mouseLeftClickTexture);
// Create a graphical string to display
Font font = new Font("arial.ttf");
Text text = new Text("Hello SFML.Net", font);
xMouseCoord = new Text("Mouse X: ", font);
yMouseCoord = new Text("Mouse Y: ", font);
statusMsg = new Text("Console: ", font);
// Play some Music
//Music music = new Music("nice_music.mp3");
//music.Play();
// Start the game loop
while (window.IsOpen())
{
// Process events
window.DispatchEvents();
// Clear screen
window.Clear();
sprite.Scale = new Vector2f(1.0f, 1.0f);
sprite.Position = new Vector2f(window.Size.X / 2, window.Size.Y / 2);
// Draw the sprite
window.Draw(sprite);
// Draw the strings
xMouseCoord.Position = new Vector2f(text.Position.X, text.Position.Y + 30);
yMouseCoord.Position = new Vector2f(xMouseCoord.Position.X, xMouseCoord.Position.Y + 30);
statusMsg.Position = new Vector2f(yMouseCoord.Position.X, yMouseCoord.Position.Y + 30);
window.Draw(text);
window.Draw(xMouseCoord);
window.Draw(yMouseCoord);
window.Draw(statusMsg);
// Update the window
window.Display();
}
}
}
}
Added this bit below for some clarification
static void OnMouseMoved(object sender, EventArgs e)
{
RenderWindow window = (RenderWindow)sender;
Vector2i vector = window.InternalGetMousePosition();
mouseX = vector.X;
mouseY = vector.Y;
xMouseCoord.DisplayedString = "Mouse X: " + mouseX;
yMouseCoord.DisplayedString = "Mouse Y: " + mouseY;
statusMsg.DisplayedString = "Console: ";
}
You only draw your sprite once. With approximately 60 frames per second, you might see it blink... or not. If you need it to stay permanent, you need to remember the point in your main program and then draw a sprite at that point every time your draw the other things.
You may want to look into game programming patterns. Normally, you have three big blocks that are repeated endlessly: you get user input, you act on user input, you draw the result.
In pseudo code:
while(isRunning)
{
HandleUserInput();
ChangeWorld():
Render();
}
That way, you can check yourself if what you do is correct. For example, in your scenario you would have drawn something while handling user input. Not good.
The events are dispatched and evaluated inside the so-called window.DispatchEvents(). When you click on your window, the event will be fired and your sprite will be drawn.
The thing is that you are calling window.Clear() after it, so you can not see the result. As nvoigt said, you must render everything at each frame, that is to say at each turn of your loop. This is why one uses Clear() method from Window, to clear the result of the previous frame.
What you could do is remember the position of the mouse when the event is fired or directly set the position of the sprite according to it. Then draw your sprite along with your text etc. If you don't want it to be displayed before any click of the mouse, just put its coordinates at a point outside the window so it will not be drawn.

A PictureBox Problem

I have a problem:
I have 3 picture boxes with 3 different images as in Image
what can i set to pictureBox3 so both images look same.....
EDITED:
I want to move pictureBox3 on pictureBox2,
So there is no Option to merge them to single image
Make sure the image in pictureBox3 is transparent. Set the BackColor to transparent. In code, set the Parent property of the pictureBox3 to be pictureBox2. Adjust the Location coordinates of pictureBox3 since they will be relative to the coordinates of pictureBox2 once you've changed the Parent.
private void Form1_Load(object sender, EventArgs e)
{
pictureBox3.Parent = pictureBox2;
pictureBox3.Location =
new Point(
pictureBox3.Location.X
- pictureBox2.Location.X,
pictureBox3.Location.Y
- pictureBox2.Location.Y);
}
In designer you will not see the transparency, but at runtime you will.
Update
In the image, the left side shows the designer view, the right side is the runtime version.
Another update
I really don't understand how it would be possible that this doesn't work for you. I suppose there must be something we are doing different. I'll describe the exact steps to take to create a working sample. If you follow the exact same steps, I wonder if we'll get the same results or not. Next steps describe what to do and use two images I found on the net.
Using Visual Studio 2008, create a New Project using template Windows Forms Application. Make sure the project is targeted at the .NET Framework 3.5.
Set the Size of the Form to 457;483.
Drag a PictureBox control onto the form. Set its Location to 0;0 and its Size to 449;449.
Click the ellipsis besides its Image property, click the Import... button and import the image at http://a.dryicons.com/files/graphics_previews/retro_blue_background.jpg (just type the URL in the File name text box and click Open). Then click OK to use the image.
Drag another PictureBox onto the form, set its Location to 0;0 and its Size to 256;256. Also set its BackColor property to Transparent.
Using the same method as described above, import image http://www.axdn.com/redist/axiw_i.png which is a transparent image.
Now place the following code in the form's OnLoad event handler:
private void Form1_Load(object sender, EventArgs e)
{
pictureBox2.Parent = pictureBox1;
}
That's it! If I run this program I get a transparent image on top of another image.
I'll add another example that according to the updated requirement allows for moving image3.
To get it working, put an image with transparency in Resources\transp.png
This uses the same image for all three images, but you can simply replace transparentImg for image1 and image2 to suitable images.
Once the demo is started the middle image can be dragged-dropped around the form.
public partial class Form1 : Form
{
private readonly Image transparentImg; // The transparent image
private bool isMoving = false; // true while dragging the image
private Point movingPicturePosition = new Point(80, 20); // the position of the moving image
private Point offset; // mouse position inside the moving image while dragging
public Form1()
{
InitializeComponent();
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(0, 0);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(231, 235);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
this.pictureBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseDown);
this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseMove);
this.pictureBox1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseUp);
this.Controls.Add(this.pictureBox1);
transparentImg = Image.FromFile("..\\..\\Resources\\transp.png");
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.DrawImageUnscaled(transparentImg, new Point(20, 20)); // image1
g.DrawImageUnscaled(transparentImg, new Point(140, 20)); // image2
g.DrawImageUnscaled(transparentImg, movingPicturePosition); // image3
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
var r = new Rectangle(movingPicturePosition, transparentImg.Size);
if (r.Contains(e.Location))
{
isMoving = true;
offset = new Point(movingPicturePosition.X - e.X, movingPicturePosition.Y - e.Y);
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isMoving)
{
movingPicturePosition = e.Location;
movingPicturePosition.Offset(offset);
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
isMoving = false;
}
}
This code will do the trick:
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
g.DrawImage(pictureBox2.Image,
(int)((pictureBox1.Image.Width - pictureBox2.Image.Width) / 2),
(int)((pictureBox1.Image.Height - pictureBox2.Image.Height) / 2));
g.Save();
pictureBox1.Refresh();
}
It will draw the image from pictureBox2 on the existing image of pictureBox1.
For starters, set the BackColor property of PictureBox3 to Transparent. This should work in almost all cases.
You should also use an image with a transparent background instead of white so you do not have the white borders around your purple circle. (Recommended image format: PNG)
Update
Following the replies I got, it appears setting the BackColor to Transparent doesn't work. In that case, it's best you handle the Paint event of the PictureBox and do the painting of the new image yourself as Albin suggested.
You might do some hack by overriding OnPaint and stuff, example here.
But I'd recommend to merge the pictures in pictureBox2 and 3 into a single image before displaying them in a single pictureBox.

Categories

Resources