Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.

[JAVA] Button-Array krijgt foutieve waarde

Pagina: 1
Acties:

  • Teeno
  • Registratie: Juni 2007
  • Laatst online: 16-11 19:19
Misschien een wat ongelukkige titel, maar kon er zo even snel niets beters van maken.

Ik ben nu wat aan het experimenteren met Arrays van Swing objecten, om zo een dynamische applicatie te kunnen maken, en hierbij stuit ik op het volgende probleem.

Ik heb een button-array gemaakt en een private integer die dus het aantal objecten bepaalt (dat is de enige waarde die bepaald wordt door de gebruiker)
Hierna maak ik de buttons aan in een JPanel

Java:
1
2
3
4
for (i = 0; i < aantal_patches; i++) {
            button[i] = new JButton("Start " + (i + 1));
            buttonPanel.add(button[i]);
        }


aantal_patches heeft een waarde van 5, en ik krijg ook keurig netjes 5 JButtons in mijn panel met allen Start 1 t/m 5.

Nu wil ik aan deze buttons een Actionlistener hangen, zodat er ook nog iets mee gedaan kan worden. Dat heb ik op deze manier gedaan.

Java:
1
2
3
4
5
6
7
8
for (i = 0; i < aantal_patches; i++) {
            button[i].addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    System.out.println("Knop " + i + " aangeklikt");
                }
            });
        }


Wat ik begrijp is dat de waarde van i pas bepaald wordt nadat op de knop is geklikt. Omdat ik bij elke button "Knop 5 aangeklikt" krijg.

Kan ik op een manier de waarde van i binnen de actionlistener definiëren? Ik zat zelf te denken aan een integer-array die dan weer gevuld wordt, maar ik zou graag een reactie van jullie expertise afwachten voor ik me onnodig in bochten ga wringen.

  • Marcj
  • Registratie: November 2000
  • Laatst online: 15:34
Dit kan niet direct op de manier die je nu wilt. Wat je kunt doen is de source ophalen van deze action. Dit doe je door e.getSource() aan te roepen. Deze source is dan een van jouw JButton objecten. Door te zoeken welke JButton in jouw array gelijk is aan de deze source, kun je het nummer bepalen.

edit:

Wacht, ze hebben elk hun eigen ActionListener! Dan kun je wel een lokale final variabele aanmaken, welke wel meegenomen wordt in een anoniem object.

Java:
1
2
3
4
5
6
7
8
for (i = 0; i < aantal_patches; i++) { 
    final int nr = i;
    button[i].addActionListener(new ActionListener() { 
       public void actionPerformed(ActionEvent e) { 
           System.out.println("Knop " + nr + " aangeklikt"); 
       } 
    }); 
}

[ Voor 40% gewijzigd door Marcj op 04-08-2008 21:40 ]


  • Teeno
  • Registratie: Juni 2007
  • Laatst online: 16-11 19:19
Oke dan, hiermee is het inderdaad gelukt. Heb deze code toegepast

Java:
1
2
3
4
5
for (int i = 0; i < aantal_patches; i++) {
                        if (e.getSource() == button[i]) {
                            source = i;
                        }
                    }

source krijgt nu inderdaad het goede nummer

bedankt voor de tip!

--edit--
Ik zie nu jouw edit pas.. dat werkt inderdaad ook.. weer wat geleerd ;)

[ Voor 10% gewijzigd door Teeno op 04-08-2008 21:42 ]


  • Marcj
  • Registratie: November 2000
  • Laatst online: 15:34
Met die oplossing volsta je ook door slechts één ActionListener aan te maken en deze aan elke JButton te hangen. Anders is er nog een snellere oplossing (zie mijn edit boven).

  • Teeno
  • Registratie: Juni 2007
  • Laatst online: 16-11 19:19
Marcj schreef op maandag 04 augustus 2008 @ 21:42:
Met die oplossing volsta je ook door slechts één ActionListener aan te maken en deze aan elke JButton te hangen. Anders is er nog een snellere oplossing (zie mijn edit boven).
Het werkt dus allebei.. wat raad je aan op gebied van performance, is een ActionListener voor élke JButton dan geen overkill?

  • maxjuh
  • Registratie: November 2004
  • Laatst online: 19-03 15:04
Is inderdaad echt overkill 5 ActionListeners. Is ook veel netter om één ActionListener te gebruiken.

  • Marcj
  • Registratie: November 2000
  • Laatst online: 15:34
Met één ActionListener gebruik je iets minder geheugen (als is het maar 16 bytes per stuk) en iets meer processorkracht (je moet de array doorlopen). Met de ander is het andersom. Tja, het blijven micro-optimalisaties.

Wat bijvoorbeeld ook in het voorbeeld van Sun zelf gebeurt is dat ze het omliggende object de ActionListener laten implementeren. Dit scheelt gewoon het aanmaken van nieuwe objecten en dan kun je gewoon het volgende doen:

Java:
1
2
3
for (i = 0; i < aantal_patches; i++) {  
    button[i].addActionListener(this);  
}


---
Wat ik zelf een goede regel vind om aan te houden is wanneer er meerdere objecten zijn die hetzelfde moeten doen bij zo'n action, om dan maar één object te hebben. Als je voor elk object een andere methode moet hebben is het makkelijk om meerdere anonieme objecten aan te maken, anders krijg je zo'n lange if-else constructie.

[ Voor 20% gewijzigd door Marcj op 04-08-2008 21:53 ]


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 16:12

Robtimus

me Robtimus no like you

Marcj schreef op maandag 04 augustus 2008 @ 21:51:
Wat bijvoorbeeld ook in het voorbeeld van Sun zelf gebeurt is dat ze het omliggende object de ActionListener laten implementeren. Dit scheelt gewoon het aanmaken van nieuwe objecten en dan kun je gewoon het volgende doen:

Java:
1
2
3
for (i = 0; i < aantal_patches; i++) {  
    button[i].addActionListener(this);  
}
Maar dat is toch wel zo slecht vanuit een OO perspectief. Immers, je frame wordt opeens een action listener, die je daardoor ook kan gebruiken voor controls in andere classes. Het maakt me niet uit hoeveel efficienter het is, dat is een oplossing die ik echt nooit zal gebruiken.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Marcj
  • Registratie: November 2000
  • Laatst online: 15:34
IceManX schreef op maandag 04 augustus 2008 @ 22:18:
[...]

Maar dat is toch wel zo slecht vanuit een OO perspectief. Immers, je frame wordt opeens een action listener, die je daardoor ook kan gebruiken voor controls in andere classes. Het maakt me niet uit hoeveel efficienter het is, dat is een oplossing die ik echt nooit zal gebruiken.
Ik zou het ook in een losse controller doen, zodat je iets meer het MVC model aanhoudt. Sun geeft hierbij ook niet altijd het goede voorbeeld ;)
Pagina: 1