Aktualisierung von jLabel in jFrames

PetBe

Mitglied
Hi Leute,

ich würde gerne ein von eiem jLabel in einem jFrame angezeigtes Bild (ImageIcon) verändern, wenn ein Button gedrückt wurde. Dazu habe ich folgende Klasse:
Code:
    class StartButtonListener implements ActionListener{
       public void actionPerformed (ActionEvent ae) {
           int i=0;
           while (i<5) {
               pictureLabel1.setIcon(icon1);
              
              
              System.out.println("i" + i);
               
               try{
                   Thread.sleep(1200);
               }
               
               catch (Exception ex) {
                   
               }
               
               pictureLabel1.setIcon(icon2);
           
               i++;
           }//
           
       }
       
   }

Beim Ablauf ist es so, dass sich das Bild nur einmal ändert und zwar nach dem letzten Durchlauf von i. Ich würde gerne, dass sich das Bild bei jedem Durlauf von i ändert. Ich habe es mit "pictureLabel1.repaint()" und "c.repaint()" (C ist der Container) probiert. Das zeigt aber keinerlei Wirkung. Wie bekomme ich das jLabel aktualisiert?
 
Du rufst Thread.sleep(int ms) auf dem EDT auf. Das legt deine GUI schlafen und wird damit auch nicht aktualisiert.

Nutz lieber (bspw.) einen javax.swing.Timer
Hier mal eine kleine SSCCE anhand eines einfachen Farbwechsels (funktioniert mit Bildern genauso):

Java:
ActionListener blinkListener = new ActionListener(){
    int count = 0;
    @Override
    public void actionPerformed(ActionEvent e){
        label.setForeground(count % 2 == 0 ? Color.RED : Color.BLUE);

        if(++count > 5)
            ((Timer)e.getSource()).stop();

    }
};

btn.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e){
        new Timer(600, blinkListener).start();
    }
});
 
Ich habe jetzt eine separate Thread Klasse erstellt, die folgendermaßen aussieht:
Code:
package game;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

public class JLabelChangerThread extends Thread{
   
    JLabel label;
    ImageIcon icon1 = new ImageIcon(("src/game/pictures/Bild 1.PNG"));
    ImageIcon icon2 = new ImageIcon(("src/game/pictures/Bild 2.PNG"));
    ImageIcon icon3 = new ImageIcon(("src/game/pictures/Bild 3.PNG"));
   
    public JLabelChangerThread (String name, JLabel label) {
        super(name);
        this.label=label;
       
    }

   
    public void run() {
        for (int i =0; i<5; i++) {
            label.setIcon(icon1);
           
            try {
               
                this.sleep(200);
           
            }
           
            catch (Exception ex) {
               
            }
            label.setIcon(icon2);
           
            try {
               
                this.sleep(200);
               
                }
               
                catch (Exception ex) {
                   
                }
           
           
           
            label.setIcon(icon3);
           
            }
    }
   
}

In meiner Hauptklasse rufe ich den Thread mittels einer ActionListener Klasse auf:
Code:
class StartButtonListener implements ActionListener{
        public void actionPerformed (ActionEvent ae) {
            JLabelChangerThread thread1 = new JLabelChangerThread ("jLabel_1" , pictureLabel1);
            thread1.run();
           
        }
       
    }

Leider ändert sich am Verhalten nichts. Ich sage doch jetzt hier expliziet, dass dieser Thread (this.sleep(200)) unterbrochen werden soll; nicht der Thread für die GUI.
 
Ich sage doch jetzt hier expliziet, dass dieser Thread (this.sleep(200)) unterbrochen werden soll; nicht der Thread für die GUI.
Nein. Wenn du dir die Java-Doc anschaust wirst du sehen, dass die Methode public static void sleep(long millis) den aktuellen Thread schlafen legt. Welches der aktuelle Thread ist kann man so nicht beurteil.

Wie oben schon beschrieben solltest du Animationen o.ä. mit schon existierenden Klassen wie javax.swing.Timer erstellen.
 
Der Fehler war - wie es Flown gesagt hat - dass ich run() anstatt start() verwendet habe. Mit start() funktioniert alles, so wie es sein sollte 🙂 Vielen Dank dafür.

Das mit der Timer Klasse verstehe ich nicht ganz anhand des Beispiels von Robat. Wofür ist der Timer gedacht bzw. welchen Vorteil bietet er gegenüber meiner (jetzt funktionierenden) Implementierung? Und was macht der Konstruktor:"new Timer(600, blinkListener)". In der Klasse Timer finde ich einen Konstruktor mit (int, ActionListener) nicht (https://docs.oracle.com/javase/7/docs/api/java/util/Timer.html)
 
Hi Leute,

ich bins wieder und habe eine Frage. Ich habe folgende Klasse zur ständigen Aktualisierung von 3 jLabel (mit Aktualisierung meine ich, dass das Image auf den JLabel ständig per Zufall geändert wird):
Java:
ackage game;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

public class JLabelChangerThread extends Thread{
   
    boolean stop;
    int waitingTime;
    JLabel label;
    ImageIcon [] icons = new ImageIcon[6] ;
   
   
    public JLabelChangerThread (String name, JLabel label) {
        super(name);
        this.label=label;
        stop=false;
        waitingTime=800;
       
           icons[0] = new ImageIcon(("src/game/pictures/Bild 1.PNG"));
         icons[1] = new ImageIcon(("src/game/pictures/Bild 2.PNG"));
         icons[2] = new ImageIcon(("src/game/pictures/Bild 3.PNG"));
         icons[3] = new ImageIcon(("src/game/pictures/Bild 4.PNG"));
         icons[4] = new ImageIcon(("src/game/pictures/Bild 5.PNG"));
         icons[5] = new ImageIcon(("src/game/pictures/Bild 6.PNG"));
       
    }

   
    public void run() {
        while(!stop) {
           
            int zufallszahl = (int) (Math.random() * 6 ) ;
            label.setIcon(icons[zufallszahl]);
           
            try {
               
                this.sleep(waitingTime);
           
            }
           
            catch (Exception ex) {
               
            }
           
           
           
            }
    }
   
    public void decreaseWaitingTime() {
        this.waitingTime = waitingTime/2;
    }
   
    public void stopTheThread() {
        this.stop=true;
    }
   
}
Das funktioniert auch soweit ganz gut. Nur ist mir aufgefallen, dass die Aktualisierung manchmal "stockt" d.h. dass bei den jLabels manchmal ein Bild länger angezeigt wird als es sollte (und somit die Aktualisierung langsamer ist). Hat jemand eine Idee, woran das liegen könnte?
 

Neue Themen


Zurück
Oben