none
Steuerelement mit Arrays und Ereignisse RRS feed

  • Frage

  • Hallo.

    Ich habe zu Laufzeit ein Array mit PictureBoxen erstellt. Nennen wir sie mal Bild[x,x].

    Wie rufe ich für diese jetzt z.B. das Ereigniss Click ab? Auf:

    private void Bild_MouseClick(object sender, EventArgs e)
            {
                MessageBox.Show("teste");
            }

    erfolgt keine Reaktion bei einem Mausklick auf die PicturBox.

    Kann jemand helden?

    Danke
    Jan

     

     

    Sonntag, 26. Juni 2011 00:51

Antworten

  • Hallo Jan,

    verpasse den Bäumen Namen.

    Jedes Steuerelement hat eine Name Eigenschaft - die ansonsten vom Designer genutzt wird.

    Baum[1,1] = new PictureBox();
    Baum[1, 1].Name = "Baum 1, 1";
    
    Baum[1,2] = new PictureBox();
    Baum[1, 2].Name = "Baum 1, 2";
    

    Beachte dass ich jedesmal eine neue PictureBox erstelle, denn sonst kannst Du sie nicht unterscheiden.
    Du kannst ihnen jedoch die gleiche Grafik über die Image-Eigenschaft zuweisen.

    Und den Namen kannst Du später verwenden und aus Holgers Code wird:

    private void OnBaumClick(object sender, EventArgs e) {
     var angeklickterBaum = sender as PictureBox;
     if (angeklickterBaum != null) 
     { 
        //mehr Code
        Console.WriteLine("Baum geklickt: " + angeklickterBaum.Name);
      }
    
    Eine weitere Variante wäre der Einsatz der Tag Eigenschaft, wo Du beliebiges hinterlegen kannst -
    z. B. die Baumart ;-)

    Gruß Elmar

    Freitag, 1. Juli 2011 14:11
    Beantworter

Alle Antworten

  • Du musst den Clicked Eventhandler halt für jedes deiner Objekte anbinden.

    Wenn du dynamisch ein obj vom Typ PictureBox erzeugst, musste halt

    obj.MouseClicked+=new MouseClickedEventHandler(...)

    manuell einbauen. Das geht dann nicht vom Designer aus.

    Sonntag, 26. Juni 2011 06:52
  • Hallo Jan,

    Tamlocar hat Recht, Du mußt für jede neue PictureBox-Instanz das entsprechende Ereignis abonnieren. Hier ein Beispiel, dass ein multidimensionales PictureBox-Array in ein TableLayoutPanel einliest und dabei für jedes PictureBox-Control einen OnClick-Handler hinzufügt:

    using System;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    using System.IO;
    
    namespace WindowsFormsApplication1
    {
     public partial class Form1 : Form
     {
      Button buttonFillLayoutPanel;
      TableLayoutPanel imagesLayoutPanel;
    
      public Form1()
      {
       InitializeComponent();
    
       // Controls hinzufügen
       imagesLayoutPanel = new TableLayoutPanel { Dock = DockStyle.Fill };
       buttonFillLayoutPanel = new Button { Text = "Bilddateien einlesen", Dock = DockStyle.Top };
       buttonFillLayoutPanel.Click += OnButtonFillLayoutPanelClick;
       Controls.AddRange(new Control[] {imagesLayoutPanel, buttonFillLayoutPanel});
      }
    
      void OnButtonFillLayoutPanelClick(object sender, EventArgs e)
      {
       // Image-Dateipfade ermitteln
       string imagePath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
       string[] imageFiles = Directory.GetFiles(imagePath, "*.jpg", SearchOption.AllDirectories);
       int imageCount = imageFiles.Length;
    
       if (imageCount == 0)
        return;
    
       // Für Testzwecke Anzahl der Imagedateien auf 20 begrenzen
       if (imageCount > 20)
       {
        Array.Resize(ref imageFiles, 20);
        imageCount = 20;
       }
    
       // Zeilen- und Spaltenanzahl berechnen
       int rowCount = imageCount == 1 ? 1 : imageCount % 2 == 0 ? imageCount / 2 : (imageCount / 2) + 1;
       int columnCount = 2;
    
       // Evtl. vorhandene PictureBoxControls vom OnPictureBoxClick-Ereignishandler lösen
       var pictureBoxQuery = from p in imagesLayoutPanel.Controls.OfType<PictureBox>() select p;
    
       foreach (var pictureBox in pictureBoxQuery)
        pictureBox.Click -= OnPictureBoxClick;
    
       // TableLayoutPanel neu initialisieren und dimensionieren
       imagesLayoutPanel.RowStyles.Clear();
       imagesLayoutPanel.Controls.Clear();
       imagesLayoutPanel.RowCount = rowCount;
       imagesLayoutPanel.ColumnCount = columnCount;
       imagesLayoutPanel.AutoScroll = true;
    
       // Image-Dateien zum PictureBox[] bzw. zum TableLayoutPanel hinzufügen
       // OnClick-Ereignis abonnieren.
       PictureBox[,] pictureBoxArray = new PictureBox[rowCount, columnCount];
       int imageIndex = 0;
    
       for (int rowIndex = 0; rowIndex < pictureBoxArray.GetLength(0); rowIndex++)
       {
        for (int columnIndex = 0; columnIndex < pictureBoxArray.GetLength(1); columnIndex++)
        {
         Image image = Image.FromFile(imageFiles[imageIndex]);
         PictureBox pictureBox = new PictureBox { Image = image, Tag = imageFiles[imageIndex], SizeMode = PictureBoxSizeMode.Zoom };
         pictureBox.Click += OnPictureBoxClick;
         pictureBoxArray[rowIndex, columnIndex] = pictureBox;
         imagesLayoutPanel.Controls.Add(pictureBox, columnIndex, rowIndex);
         imageIndex++;
        }
       }
      }
    
      void OnPictureBoxClick(object sender, EventArgs e)
      {
       // Gespeicherten Dateinamen anzeigen
       PictureBox pictureBoxClicked = sender as PictureBox;
    
       if(pictureBoxClicked != null)
       {
        Image image = pictureBoxClicked.Image;
    
        if (image != null && pictureBoxClicked.Tag != null && pictureBoxClicked.Tag.GetType() == typeof(string))
        {
         MessageBox.Show((string)pictureBoxClicked.Tag);
        }
       }
      }
     }
    }
    
    

    Für einfache Informationen reicht die Behandlung von Control.Click. Möchtest Du erweiterte Maus-Informationen oder soll das Ereignis nicht auch durch die Eingabetaste ausgelöst werden können, kannst Du (seit .NET 2.0) Control.MouseClick verwenden.

    Gruß
    Marcel

    Sonntag, 26. Juni 2011 07:16
    Moderator
  • Hallo Y.,

    man geht die PictureBox'en einfach normal (zum Beispiel in einer for-Schleife) durch und subscribed (pro PictureBox) das Click-Ereignis.
    Hier ein Beispiel: 

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Collections.Generic;
    
    namespace SteuerelementArrayDemo
    {
     public partial class Form1 : Form
     {
      const int anzahlBildBoxen = 10;
      const int höhePictureBox = 50;
      const int breitePictureBox = 50;
      Color geradeFarbe = Color.Green;
      Color ungeradeFarbe = Color.Red;
      TextBox txtInfo = new TextBox();
      PictureBox[] pictureBoxen;
    
      public Form1()
      {
       InitializeComponent();
      }
    
      private void Form1_Load(object sender, EventArgs e)
      {
       pictureBoxen = DemoBildBoxenFüllen();
       foreach (PictureBox box in pictureBoxen)
        box.Click += new EventHandler(box_Click);
       InformationsTextBoxZufügen();
      }
    
      private PictureBox[] DemoBildBoxenFüllen()
      {
       FlowLayoutPanel flp = new FlowLayoutPanel();
       flp.WrapContents = true; flp.Dock = DockStyle.Fill;
       List<PictureBox> boxen = new List<PictureBox>();
       for (int i = 0; i < anzahlBildBoxen; i++)
       {
        PictureBox box = new PictureBox();
        box.Width = breitePictureBox; box.Height = höhePictureBox;
        box.BackColor = (i % 2 == 0) ? geradeFarbe :ungeradeFarbe;
        box.Name = "box" + (i+1);
        boxen.Add(box); flp.Controls.Add(box);
       }
       Controls.Add(flp);
       return boxen.ToArray();
      }
    
      void box_Click(object sender, EventArgs e)
      {
       Control ctl = sender as Control;
       if (ctl == null) return;
       txtInfo.AppendText("Geklickt auf: " + ctl.Name + "\r\n");
      }
    
      private void InformationsTextBoxZufügen()
      {
       txtInfo.Dock = DockStyle.Bottom;
       txtInfo.Multiline = true;
       txtInfo.Height = 100;
       txtInfo.ScrollBars = ScrollBars.Both;
       Controls.Add(txtInfo);
      }
     }
    }
    


    ciao Frank

    Sonntag, 26. Juni 2011 07:36
  • Hallo zusammen.

    Ich war ein paar Tage unterwegs, daher erst jetzt die Antwort.

    Danke für die Hilfe... Nun kann ich ja weiter machen.

    *winke*

    Jan

    Mittwoch, 29. Juni 2011 15:21
  • Und weiter geht es.

    Ich muss dazu sagen, dass ich relativer Anfänger bin und mich schwer tue ein Buch von A bis Z durch zu abreiten da ich doch schon einiges weis und mir dann der Anfang in den Büchern immer auf die Nerven geht :-/ Bitte daher nicht übel nehmen ...

    Ich habe mit

            public PictureBox[,] Baum= new PictureBox[3,10];
            public PictureBox pbxBaum = new PictureBox();

    zwei neue Pictureboxen zur Laufzeit erstellt und dann mit

            pbxBaum.MouseHover += OnBaumMouseHover;
            pbxBaum.Click += OnBaumClick;

    die Ereignisse zugeortnet und abschliessend dann per

            Baum[1,1] = pbxBaum;
            Baum[2,1] = pbxBaum;

    zwei neue PictureBoxen Baum[,] erstellet.

    auf die Ereignisse reagiere ich mit

            private void OnBaumClick(object sender, EventArgs e)
            {
                MessageBox.Show("geklickt");
            }
            private void OnBaumMouseHover(object sender, EventArgs e)
            {
                txtBox1.Text = "MouseHover";
            }

    Nun möchte ich aber in den Ereinissen wissen welcher "Baum" das Ereigniss ausgelöst hat. Um z.B. nach einem Click auf einen der Bäume "Du hast Baum Nr.: " + BaumNummer + " geklickt" über die MessageBox auszugeben.

    Danke für die Hilfe

    Jan

     

    Freitag, 1. Juli 2011 11:51
  • Hallo Yawahoo,

    bitte beginne bei einer neuen Frage einen neuen Thread.

    Bei Windows Forms erhälst du den Sender des Events über den Parameter "sender" eines jeden Events. Du musst "sender" nur noch in den richtigen Datentypen casten, und schon hast du das Objekt das den Event gefeuert hat.

    private void OnBaumClick(object sender, EventArgs e) {
      PicutreBox angeklickterBaum = sender as PictureBox;
      if(angeklickterBaum != null) { //war cast erfolgreich?
        ... //mehr Code
      }
    }
    

    Viele Grüße
    Holger M. Rößler


    Kaum macht man es richtig, schon funktioniert es
    Freitag, 1. Juli 2011 12:30
  • Hallo Holger.

    Das nächste mal schreibe ich eine neue Frage in einen neuen Thread :)

    Nun aber zu Deiner Antwort. Ich kann Dir nämlich nicht ganz folgen. Wie kann ich in Deinem Code unterscheiden ob der sender Baum[1,1] oder Baum[2,1] ist?

    Gruß
    Jan

     

    Freitag, 1. Juli 2011 13:24
  • Hallo Jan und Holger,

    Ich beziehe mich jetzt auf den weiter oben von mir geposteten Code (wobei ich zusätzlich das PictureBox-Array zum Feld promotet habe):

    void OnPictureBoxClick(object sender, EventArgs e)
    {
      PictureBox pictureBoxClicked = sender as PictureBox;
    
      if (pictureBoxClicked != null) {
        for (int rowIndex = 0; rowIndex < pictureBoxArray.GetLength(0); rowIndex++) {
          for (int columnIndex = 0; columnIndex < pictureBoxArray.GetLength(1); columnIndex++) {
            if(pictureBoxArray[rowIndex, columnIndex] == pictureBoxClicked) {
              MessageBox.Show(String.Format("{0},{1}", rowIndex, columnIndex ));
              return;
            }
          }
        }
      }
    }
    


    Im Prinzip eine einfache Suche im Array, die auf manigfaltige Weise gestaltet und optimiert werden kann.

    P.S. Im obigen Beispiel werden (nur zur Beruhigung) nicht die PictureBox-Inhalte miteinander verglichen, sondern die im Array gespeicherten Referenzen werden mit der übergebenen pictureBoxClicked-Referenz verglichen.

    5 ways for equality check in .net .. why? and which to use?
    http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/84e2a419-f82a-494e-8723-ef01284d2cbc#a15a0a55-8616-4f7c-b4be-ef05b1b578bf

    Gruß
    Marcel

    Freitag, 1. Juli 2011 13:50
    Moderator
  • Hallo Jan,

    verpasse den Bäumen Namen.

    Jedes Steuerelement hat eine Name Eigenschaft - die ansonsten vom Designer genutzt wird.

    Baum[1,1] = new PictureBox();
    Baum[1, 1].Name = "Baum 1, 1";
    
    Baum[1,2] = new PictureBox();
    Baum[1, 2].Name = "Baum 1, 2";
    

    Beachte dass ich jedesmal eine neue PictureBox erstelle, denn sonst kannst Du sie nicht unterscheiden.
    Du kannst ihnen jedoch die gleiche Grafik über die Image-Eigenschaft zuweisen.

    Und den Namen kannst Du später verwenden und aus Holgers Code wird:

    private void OnBaumClick(object sender, EventArgs e) {
     var angeklickterBaum = sender as PictureBox;
     if (angeklickterBaum != null) 
     { 
        //mehr Code
        Console.WriteLine("Baum geklickt: " + angeklickterBaum.Name);
      }
    
    Eine weitere Variante wäre der Einsatz der Tag Eigenschaft, wo Du beliebiges hinterlegen kannst -
    z. B. die Baumart ;-)

    Gruß Elmar

    Freitag, 1. Juli 2011 14:11
    Beantworter
  • Hallo Jan,

    • ... Nun möchte ich aber in den Ereignissen wissen welcher "Baum" das Ereigniss ausgelöst hat.

    ja, das ist aber u.a. bereits in meinem ersten Posting beispielhaft gezeigt, also eben beispielsweise über den Namen der PictureBox (in meinem Codebeispiel: "ctl.Name"). Wenn Du auf eine PictureBox klickst, kommt ja die Meldung, auf welche Box geklickt wurde.


    ciao Frank


    Freitag, 1. Juli 2011 15:06
  • Hallo.

    Danke soweit, das habe ich jetzt hin...

    LG

    Jan

     

    Samstag, 2. Juli 2011 23:41