10 Replies - 665 Views - Last Post: 05 February 2012 - 01:49 PM Rate Topic: -----

Topic Sponsor:

#1 civicdude95  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 40
  • Joined: 18-January 12

Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 07:40 AM

Hey guys, I think this is the right place for this, but if not then please move it accordingly. I am making a level editor for my Xna game using winforms and C#. I want to display the images (tiles) available to use in a grid layout on the form. For example, I have a tabControl that I want to house a bunch of PictureBox(es) which are the pictures of the tiles. Whenever I click on one of the PictureBoxes, that tile is selected for use in the editor.

Right now my current method of doing this is to have a listbox with the names of the tiles listed and when the listBox_SelectedIndexChanged() method is called, I set one PictureBox to display the image. Here is some code so that hopefully this will make more sense.

private void textureListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (textureListBox.SelectedItem != null)
            {
                texturePreviewBox1.Image = previewDict[textureListBox.SelectedItem as string];
            }
        }


The previewDict[] is a simple dictionary with <string, Image> for the <key, value>. Whenever I add a texture to the editor, I run this code for the previewDict[].

private void addTextureButton_Click(object sender, EventArgs e)
{
    openFileDialog1.Filter = "PNG Image|*.png|JPG Image|*.jpg|TGA Image|*.tga";
    openFileDialog1.InitialDirectory = contentPathTextBox.Text;

    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        string filename = openFileDialog1.FileName;

        Texture2D texture = Texture2D.FromStream(GraphicsDevice, File.OpenRead(filename));
        Image image = Image.FromFile(filename);

        filename = filename.Replace(contentPathTextBox.Text + "\\", "");
        filename = filename.Remove(filename.LastIndexOf("."));

        textureListBox.Items.Add(filename);
        textureDict.Add(filename, texture);
        previewDict.Add(filename, image);

        // THIS IS MY CURRENT TEST CODE TO GET A PICTURE BOX DYNAMICALLY
        // CREATED ON THE FORM
        PictureBox box = new PictureBox();
        box.Image = image;
        box.BorderStyle = BorderStyle.Fixed3D;
        box.Location = new System.Drawing.Point(6, 6);

        box.Width = Engine.TileWidth;
        box.Height = Engine.TileHeight;
        tileTab.Controls.Add(box);
    }
}


As you can see, I'm using a textureDict and a previewDict for each image. Until now they have been completely separate things because I only had one PictureBox for the previewImage and the method of texture selection was based on choosing an item in the listBox. My goal is to change the method of texture selection to simply having a grid of loaded textures (PictureBoxes with the image of the texture) and the image that I click on is the image I currently have selected to draw with.

Does anyone have a suggestion on how to do this? I've spent way too much time on this lately and I would like for this feature to be done so I can get back to the engine for the game.

Thanks guys!

Is This A Good Question/Topic? 0
  • +

Replies To: Winforms PictureBox in my Level Editor

#2 tlhIn`toq  Icon User is online

  • WillMyCodeWork = !FailedWhenYouTriedIt;
  • member icon

Reputation: 3290
  • View blog
  • Posts: 6,896
  • Joined: 02-June 10

Re: Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 07:46 AM

Objects. This is OOP after all.

Instead of having your program trying to track and synchronize everything in lists what about making a UserControl, that has the picturebox, a label, the textureDict and previewDict... etc. etc.

Wrap all the functionality into a single control. Let it handle everything internally. Then you can make as many instances of that UserControl as you like and lay them out on a FlowLayoutPanel or something similar.

When you click on the UserControl it can do its thing, then raise a custom event saying "I've been clicked, this is my TextureSelectedArgs" and those args contain .Image, .Texture, .Thumbail, etc.

These should help:

Quick and easy custom events
Bulding an application - Part 1
Building an application - Part 2
Was This Post Helpful? 2
  • +
  • -

#3 civicdude95  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 40
  • Joined: 18-January 12

Re: Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 08:35 AM

Hey thanks for the reply! I was starting to lean in the direction of at least using a custom control, so this should hopefully solve my problem. I'll read over those pages you suggested and let you know how it goes.
Was This Post Helpful? 0
  • +
  • -

#4 Kilorn  Icon User is online

  • XNArchitect
  • member icon



Reputation: 988
  • View blog
  • Posts: 3,036
  • Joined: 03-May 10

Re: Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 09:06 AM

If those somehow don't help, I'd suggest watching Nick Gravelyn's XNA Tile Editor Tutorial series on Youtube. It's 94 videos averaging around 9 minutes each. Unfortunately it's for a slightly older version of XNA, but it's easy enough to modify the code to use XNA 4.0.
Was This Post Helpful? 0
  • +
  • -

#5 tlhIn`toq  Icon User is online

  • WillMyCodeWork = !FailedWhenYouTriedIt;
  • member icon

Reputation: 3290
  • View blog
  • Posts: 6,896
  • Joined: 02-June 10

Re: Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 09:09 AM

94 videos? Holly sheep dip Batman. That's dedication!
Was This Post Helpful? 1
  • +
  • -

#6 Kilorn  Icon User is online

  • XNArchitect
  • member icon



Reputation: 988
  • View blog
  • Posts: 3,036
  • Joined: 03-May 10

Re: Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 09:11 AM

It's worth every second if you've got the time, but yea 94 videos is kind of difficult to get through as it seems overwhelming at first.
Was This Post Helpful? 0
  • +
  • -

#7 civicdude95  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 40
  • Joined: 18-January 12

Re: Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 09:15 AM

Lol, I actually watch those religiously, and his method is actually the method I currently use (the listBox selection method). I've combed through his videos more than a few times and keep hoping one day he'll either pick it back up or remake them or do a new series.

Actually, I reference and link to his YouTube playlist occasionally on my blog ;)

This post has been edited by civicdude95: 02 February 2012 - 09:17 AM

Was This Post Helpful? 0
  • +
  • -

#8 RexGrammer  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 152
  • View blog
  • Posts: 664
  • Joined: 27-October 11

Re: Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 09:45 AM

I'm sorry for not watching them before asking but are they (the videos) meant for complete programming beginners or just showing you how to specialize in XNA?

Is it really that hard so that you need (94 x 9 = 846min = 846 / 60 h =) 14h to learn how to make a tile editor? Just out of curiosity's sake.
Was This Post Helpful? 0
  • +
  • -

#9 Kilorn  Icon User is online

  • XNArchitect
  • member icon



Reputation: 988
  • View blog
  • Posts: 3,036
  • Joined: 03-May 10

Re: Winforms PictureBox in my Level Editor

Posted 02 February 2012 - 09:51 AM

It's not that difficult. He goes over not just how to create the tile editor, but goes into detail on how to import the data for tile maps from xml files and even shows in depth how to utilize it in a game that you create throughout the series.
Was This Post Helpful? 0
  • +
  • -

#10 civicdude95  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 40
  • Joined: 18-January 12

Re: Winforms PictureBox in my Level Editor

Posted 03 February 2012 - 09:45 AM

Hey tlhIn`toq, I read over your posts and thought I had a pretty good understanding of custom events/controls, but I just couldn't get it through my head last night how to use this in my editor. Here's what I've tried based on your posts
public class TextureSelectArgs : EventArgs
{
    // Texture2D for saving the textures for the Xna engine
    private Texture2D texture;

    // Image for the custom PictureBox UserControl's display
    private Image image;

    // Filename for saving/loading the texture from a file.
    private string filename;

    public Texture2D Texture { get; set; }
    public Image Image { get; set; }
    public string Filename { get; set; }

    public TextureSelectArgs(Texture2D tex, Image i, string file)
    {
        texture = tex;
        image = i;
        filename = file;
    }
}


This part makes sense to me, I have to supply the custom EventArgs with the things that I will need when an event is raised (texture, image, and filename). The next part, the custom UserControl, is where it starts to go downhill for me. I think this is how my UserControl should go, but I'm not positive. And after this UserControl part I have an idea of what to do in Form1.cs, but again I'm not too sure.
public partial class PreviewPictureBox : UserControl
{
    // Needs a PictureBox to fill the entire control
    // (added on the designer)

    public PreviewPictureBox()
    {
        InitializeComponent();
    }

    // HERE'S WHERE I'M NOT TOO SURE
    public event EventHandler<TextureSelectArgs> TextureSelected;

    public void RaiseTextureSelected(
        /*DO I SEND IN A TEXTURE, IMAGE, AND FILENAME?*/
        Texture2D texture,
        Image image,
        string filename)
    {
       EventHandler<TextureSelectArgs> handler = TextureSelected;
       if (handler != null)
       {
           handler(this, new TextureSelectArgs(texture, image, filename));
       } 
    }

    // IS THIS CLASS WHERE I TIE IN MY ACTION?
    private void pictureBox1_Click(object sender, TextureSelectArgs ts)
    {
        // DO SOMETHING. NOT SURE WHAT TO DO HERE
    }
}


One big question about the PreviewPictureBox control is when and where do I set the control's image to be the image that the TextureSelectArgs uses?

The idea that I have is to dynamically create these PreviewPictureBoxes as I need them. So then in Form1.cs it should go something like this?
public partial class Form1 : Form
{
    Texture2D texture;
    Image image;
    string filename;

    public Form1()
    {
        InitializeComponent();
    }

    public void Load()
    {                               // DON'T WORRY ABOUT THIS PART, I'M TYPING THIS FROM 
                                    // MEMORY AND SOME OF IT IS XNA SPECIFIC
        texture = Texture2D.FromStream(GraphicsDevice, File.ReadOpen("myTexture.png"));
        image = .... // A GOOD IMAGE
        filename = // WHATEVER THE FILENAME WAS IN AN OPENFILEDIALOG

        // ASSUME I HAVE A FLOWLAYOUTPANEL CALLED flPanel
        flPanel.Add(new PreviewPictureBox());
        // THIS IS WHAT I WANT TO DO, BUT I DON'T KNOW HOW TO GET
        // THE TEXTURE, IMAGE, AND FILENAME ACTUALLY INTO THE OBJECT
        // THAT I'VE JUST DYNAMICALLY CREATED.
    }

    private void previewPictureBox1_TextureSelected(object sender, TextureSelectArgs ts)
    {
        // AGAIN, I'M NOT SURE WHAT TO DO HERE BECAUSE MY PreviewPictureBox OBJECT WAS
        // CREATED DYNAMICALLY.
    }
}


I hope I'm making some sense and if you have any suggestions on what to do here I'm wide open to hearing them. Events have never been my strong point. I know that somewhere in Form1.cs I'm supposed to subscribe to the TextureSelected event, right? Any ideas are most welcome.
Was This Post Helpful? 0
  • +
  • -

#11 civicdude95  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 40
  • Joined: 18-January 12

Re: Winforms PictureBox in my Level Editor

Posted 05 February 2012 - 01:49 PM

Great news! I was finally able to figure this one out and get it to work just like it is supposed to. I was on the right track to begin with, but I needed to modify the way I was handling the click event. At first, I was having trouble getting an
public event EventHandler<TextureSelectedArgs> TextureSelectedHandler;

to work right, which sent me to the interwebs studying up on delegates. I then came up with the
public delegate void PreviewBoxClickHandler(object sender, TextureSelectedArgs t);

delegate, which I was hoping would give me the correct EventHandler to use for my custom event.

I then tied in my pictureBox_Click method to use the TextureSelected() method, which fired the TextureSelectEvent event. The only other piece of this UserControl that I needed was a way to tell from the outside if anyone was subscribed to this event.
public bool IsTextureSelectEventSubbed { get { return (TextureSelectEvent != null); } }

Here is the code that I now have for my PreviewImageBox custom UserControl.

using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Xna.Framework.Graphics;

namespace JumpEditor
{
    public delegate void PreviewBoxClickHandler(object sender, TextureSelectedArgs t);

    public partial class PreviewImageBox : UserControl
    {
        public Texture2D Texture { get; set; }
        public Image Image { get; set; }
        public string Filename { get; set; }

        public event PreviewBoxClickHandler TextureSelectEvent;
        public bool IsTextureSelectEventSubbed { get { return (TextureSelectEvent != null); } } 

        public PreviewImageBox(Texture2D texture, Image image, string filename)
        {
            InitializeComponent();
            pictureBox.Image = image;

            Texture = texture;
            Image = image;
            Filename = filename;
        }
        
        private void pictureBox_Click(object sender, EventArgs e)
        {
            TextureSelected(new TextureSelectedArgs(Texture, Image, Filename));
        }

        public void TextureSelected(TextureSelectedArgs t)
        {
            PreviewBoxClickHandler handler = TextureSelectEvent;
            if (handler != null)
            {
                handler(this, t);
            }
        }
    }
}



Moving on to my form1.cs class, I needed a way to tie this new event and user control into my main form. I decided to use an "Add Texture" button for this, making use of its Click event. Here is my method of using my new custom method with its own custom event arguments.

// WE WILL USE THESE VARIABLES TO KEEP TRACK OF THE CURRENTLY
// SELECTED TILE IMAGE AND FILENAME FOR THAT TILE.
private Texture2D currentTexture;
private string currentTextureName;



private void addTextureButton_Click(object sender, EventArgs e)
{
    openFileDialog1.Filter = "PNG Image|*.png|JPG Image|*.jpg|TGA Image|*.tga";
    openFileDialog1.InitialDirectory = contentPathTextBox.Text;

    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        foreach (string filename in openFileDialog1.FileNames)
        {
            string file = filename;

            Texture2D texture = Texture2D.FromStream(GraphicsDevice, File.OpenRead(file));
            Image image = Image.FromFile(file);

            file = file.Replace(contentPathTextBox.Text + "\\", "");
            file = file.Remove(file.LastIndexOf("."));

            // RIGHT HERE IS WHERE I DYNAMICALLY ADD A NEW PREVIEWBOX TO THE FLOWPANEL
            tileFlowPanel.Controls.Add(new PreviewImageBox(texture, image, file));
        }
        SetPreviewImageEvents();
    }
}

// THIS METHOD LOOPS THROUGH ALL PREVIEWIMAGEBOXES IN THE TILEFLOWPANEL.CONTROLS 
// COLLECTION AND IF NOONE IS SUBSCRIBED TO THEM, WE CREATE A NEW SUBSCRIPTION, 
// CALLING THE p_TextureSelectEvent method
private void SetPreviewImageEvents()
{
    foreach (PreviewImageBox p in tileFlowPanel.Controls)
    {
        if (p.IsTextureSelectEventSubbed == false)
            p.TextureSelectEvent += new PreviewBoxClickHandler(p_TextureSelectEvent);
    }
}

// HERE IS WHERE WE KEEP TRACK OF THE CURRENTLY SELECTED TEXTURE AND FILENAME,
// WHICH WILL ALLOW US TO DRAW WITH THE CURRENT TEXTURE AND ADD THE FILENAME
// TO OUR OUTPUT FILE.
void p_TextureSelectEvent(object sender, TextureSelectedArgs t)
{
    currentTexture = t.Texture;
    currentTextureName = t.Filename;
}



So far, this is working like a charm. I still have a few optimization things I can do (i.e. put the currentTexture and currentTextureName into a private class in form1), but the basic functionality is in place. And that's what I was going for to begin with. I know I can optimize this method later.

I want to thank you guys for your help and suggestions. tlhIn`toq, thanks for pointing me to your tutorials, they definitely helped get the ball rolling for me. Using this method, I was able to get rid of the textureDictionary and the previewImageDictionary all together.

I plan on writing this up as a tutorial on my blog, so I will make a post about that on this site when I get it finished.

Thanks again guys!

This post has been edited by civicdude95: 05 February 2012 - 01:52 PM

Was This Post Helpful? 1
  • +
  • -

Page 1 of 1