setText bei JLabel

MonsterBit

Mitglied
Moin,

also mein Problem ist folgendes:

Ich brauche für mein Programm ein Countdown der auf einer GUI angezeigt wird.
Dafür habe ich eine Klasse CountdownLabel, die die Klasse JLabel erweitert. CountdownLabel hat eine Methode
Code:
start(final int stunden)
die ich von einer anderen Klasse aufrufen möchte. Soweit so gut...

In der Methode
Code:
start()
wird ein neuer Thread gestartet der die Sekunden runterzählt und dann über
Code:
setText(time)
die Zeit aktualisiert.

Wenn ich jetzt von der anderen Klasse den Countdown starte, wird zwar der Thread ausgeführt aber es wird nicht die Zeit auf dem Label aktuallisiert. Das erkenne ich daran, das ich nebenbei mir die aktuelle Zeit mit
Code:
System.out.println(time);
ausgebe.

Und jetzt kommt das interessante:
Wenn ich jedoch
Code:
start();
im Konstruktor meiner CountdownLabel-Klasse aufrufe, funktionierts einfandfrei...???:L

Das ganze sieht ungefähr so aus:
Java:
public class CountdownLabel extends JLabel {
         public CountdownLabel() {
         //....
         start(6);  //<--- Im Konstruktor funktioniert es
         }

         public void start(final int stunden) {
              new Thread() {
                public void run() {
                   //... 
                   
                   setText(time);

              }
         }
         
}

Hab ich jedoch meine andere Klasse, womit ich auch den Countdown starten will, gehts nicht:
Java:
public class Main {
         //...
         CountdownLabel cl = new CountdownLabel();
         cl.start(6);  
}

Kann mir einer sagen, wieso setText(); nur funktioniert wenn ich start(); im Konstruktor der eigenen Klasse aufrufe und warum nicht, wenn ich den Countdown von einer anderen Klasse aus starten will?

MonsterBit
 
Ließ dir mal Infos zu Multithreading und Swing durch. Und warum man keinen Thread im Konstruktor einer nicht-finalisierten Klasse starten sollte. Und warum man "start()" von einen neuen Thread aufrufen kann.
 
> Und warum man keinen Thread im Konstruktor einer nicht-finalisierten Klasse starten sollte.

das wäre mir persönlich auch neu,
unspezifisch irgendwas zu lesen scheint mir nicht zielführend, gibts genauere Infos/ Links?

ich vermute einen einfachen Grund:
die Main-Klasse erzeugt ein zweites Label-Objekt, dort läuft der Thread 1A, setText() usw. wird aufgerufen,
nur interessiert das niemanden, das erste Label welches in der GUI sichtbar ist bleibt unverändert

bei Konstruktor-Aufruf läufts vielleicht in beiden Labels
> Das erkenne ich daran, das ich nebenbei mir die aktuelle Zeit mit System.out.println(time); ausgebe.
hmm, zwei Ausgaben wären doch auffällig, na möglich bleibt es noch je nach Umständen
 
Zuletzt bearbeitet von einem Moderator:
Da fehlt ein
Code:
.run()
-Aufruf auf das Thread-Object.
Zumindest in deinem Beispiel...
So kann nie was passieren.
 
Von FindBugs:

Code:
Constructor invokes Thread.start()
The constructor starts a thread. This is likely to be wrong if the class is ever extended/subclassed, since the thread will be started before the subclass constructor is started.
 
Ok, nochmal zur Klärung.

Der Thread startet. Im Beispiel habe ich ein .start(); hinter der Klammer vergessen. Ausedem weis ich das der Thread startet, weil der Countdown ja in der Console angezeigt wird. D.h. ich hab setText(time), und darunter System.out.println(time) nur um zu gucken ob überhaupt was passiert. Aber wie gesagt, in der Konsole läuft der Countdown.

Wenn 2 Labelobjekte erzeugt werden, was kann ich dann tun?
Ich versteh nicht, wo der unterschied ist, ob ich start() in einer anderen Klasse aufrufe oder im Konstruktor der eigenen Klasse. Ich ändere ja nichts an der Methode start()...

@Volvagia: Das verstehe ich nicht ganz.... Ich will ja auch nicht, das der Konstruktor den Thread in start() startet. Aber nur so funktioniert es... rufe ich start() von einer anderen Klasse auf, gehts nicht. Oder vielleicht versteh ich nicht ganz was du meinst...
 
Zuletzt bearbeitet:
Wenn 2 Labelobjekte erzeugt werden, was kann ich dann tun?
Ich versteh nicht, wo der unterschied ist, ob ich start() in einer anderen Klasse aufrufe oder im Konstruktor der eigenen Klasse. Ich ändere ja nichts an der Methode start()...

Wärst nicht der erste, der ausversehen ein zweites Objekt erzeugt und an diesem Methoden aufruft und sich wundert, das sich am anderen Objekt nichts tut.

Entscheidend ist, dass Du start() an dem Label aufrufst, das auch tatsächlich in Deiner GUI verbaut ist.
Mehr kann man da ohne Code nicht dazu sagen.
 
Ok, dann komm hier der Code:
Java:
public class CountdownLabel extends JLabel{

    private String stunde, minute, sekunde;    

    public CountdownLabel() {

        stunde  = "00:";
        minute  = "00:";
        sekunde = "00";   

        try {
            //Schriftart laden
            InputStream fin = this.getClass().getResourceAsStream("digital-7.ttf");
            Font font = Font.createFont (Font.PLAIN, fin).deriveFont(48f);

            setFont(font);
            setForeground(Color.gray);
            setPreferredSize(new Dimension(150, 45));
            } catch(FontFormatException ex) {

            } catch(IOException ex) {

            }

       setText(stunde+minute+sekunde);
       //start(6); So würde es gehen...       
    }  

     public void start(final int stunde) {

        new Thread() {
            public void run() {

                System.out.println("blöa");

                //Anzahl der Stunden in Sekunden umrechnen
                int stunden = stunde;
                int minuten = 60;
                int sekunden = 60;

                //Anfangsanzeige
                String dStunde = stunden+":";
                String dMinute = "00:";
                String dSekunde = "00";               
                System.out.println("blöa");

                try {
                    sleep(1000);

                    //Überall eins abziehen, da schonm eine sekunde vergangen ist
                    stunden--;
                    minuten--;
                    sekunden--;

                    while(true) {
                        //Sekunde warten
                        sleep(1000);

                        if(sekunden > 0) {
                            sekunden--;

                            dStunde = stunden+":";
                            dMinute = minuten+":";
                            dSekunde = sekunden+"";

                            setText(dStunde+dMinute+dSekunde);
                            System.out.println(dStunde+dMinute+dSekunde);

                        } else {
                            minuten--;
                            sekunden = 59;
                            System.out.println(dStunde+dMinute+dSekunde);
                        }

                        if(minuten < 0) {
                            stunden--;
                            minuten = 59;
                            sekunden = 59;
                            System.out.println(dStunde+dMinute+dSekunde);
                        }

                        if(stunden < 0) {
                            setText("Fertig");
                            break;
                        }
                    }

                } catch (InterruptedException ex) {
                    Logger.getLogger(JukeBox.class.getName()).log(Level.SEVERE, null, ex);
                }

            }
        }.start();
    }
}

EDIT: Ich hab den Fehler jetzt gefunden... war ein ganz dummer. Ich hatte wohl 2 CountdownLabel. einmal cl1 und cl2. ich wollte, dass cl1 startet hab aber cl2.start(6); geschrieben....😳
 
Zuletzt bearbeitet:
Meinte eigentlich den Code in dem das CountdownLabel verwendet wird ;-)

laut Deiner wird der Thread ja gestartet - daher sollte dieser funktioneren.
 
Works for me:
Java:
  CountdownLabel l = new CountdownLabel();
  l.start(2);
  jPanel2.add(l, gbc);

Alternativ:
Java:
  CountdownLabel l = new CountdownLabel();
  l.start(2);
  jPanel2.add(l, gbc);

Angepasste Stellen:
[JAVA=16]
public CountdownLabel() {

stunde = "00:";
minute = "00:";
sekunde = "00";

// try {
// //Schriftart laden
// InputStream fin = this.getClass().getResourceAsStream("digital-7.ttf");
// Font font = Font.createFont (Font.PLAIN, fin).deriveFont(48f);
//
// setFont(font);
setForeground(Color.gray);
setPreferredSize(new Dimension(150, 45));
// } catch(FontFormatException ex) {
//
// } catch(IOException ex) {
//
// }

setText(stunde+minute+sekunde);
}
[/code]

[JAVA=98]
} catch (InterruptedException ex) {
//Logger.getLogger(JukeBox.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
[/code]
 
bisschen redundant inzwischen, aber da schon getippt:

@MonsterBit
der Code sagt nichts darüber aus,
- wer alles CountdownLabel-Objekte erzeugt (ob 1 oder mehrere kannst du gut mit einer Ausgabe im Konstruktor prüfen)
- welche(s) davon wenn überhaupt in die GUI eingefügt wird, da allein könne 375 Dinge schief gehen
- wer wann an welchen dieser Objekte start() aufruft
usw.
also die Aufrufer bzw. der Restcode sind genauso wichtig

edit:
@Ariol

Works for me: + Alternativ: sind gleich? 😉
 
Danker, war aber ein anderer Fehler
... war ein ganz dummer. Ich hatte wohl 2 CountdownLabel. einmal cl1 und cl2. ich wollte, dass cl1 startet hab aber cl2.start(6); geschrieben....😳
 
Sagte ja ;-)
Wärst nicht der erste, ...

Da Du den Threadcode gepostest hast, hier noch eine kleine Anregung:
Java:
	new Thread(new Runnable() {
		public void run() {
			long time = stunde*3600;
			while(time>=0) {
				String timeString = String.format("%02d:%02d:%02d", time/3600, time/60%60, time%60);
				System.out.println(timeString);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				time--;
			}
			System.out.println("Countdown beemdet!");
		}
	}).start();
 
Vielen Dank!

Ich hab mir schon die ganze Zeit über gedacht, das meine Lösung für einen Countdown etwas sehr "improvisiert" war. Deiner hingegen ist viel besser🙂
 

Neue Themen


Zurück
Oben