repaint() klappt anders als vorgestellt

D

Dickmann123

Gast
Hi,

ich habe ein kleines Problem mit folgender Methode. Das Ergebnis, was ich haben will, stimmt zwar, jedoch möchte ich, dass bei jedem Schritt das JLabel "random_label" neu zu sehen ist. Sprich es soll von oben nach unten wandern, und ich möchte es sehen. Dazu habe ich an entsprechnender Stelle das repaint() eingefügt.

Die Methode wird aufgerufen durch Klick auf einen Button. Ergebnis ist wie gesagt das gewünschte, nur ich sehe eben nicht den "zeitlichen Verlauf", also das repaint() in der Schleife.

Ich würde mich über eine Antwort sehr freuen :)

Java:
public void roll(){
		wait = 50;
		compare = 0;
		random_position = 37;
		random_label.setLocation(5, random_position);
		random_label.setVisible(true);
		left_panel.repaint();
		random = (int)(Math.random()*(counter*10-counter*5)+counter*5);
		for (int i = 0; i < random; i++){
			random_position = random_position + 30;
			if (compare == counter){
				random_position = 37;
				compare = 0;
			}
			random_label.setLocation(5, random_position);
			left_panel.repaint();
			compare++;
			wait(wait);
		}
	}
 
D

Dickmann123

Gast
Oha, danke für die Antwort :)

Was kann ich denn gegen eine solche Blockade machen? Aus deiner Verlinkung werde ich jetzt nicht ganz so schlau. Bin leider auch nicht so der Java-Pro.
 

xehpuk

Top Contributor
Swing/AWT ist auch kein Anfängerthema. Wenn man es richtig machen will, muss man ein wenig Zeit reinstecken.
Ich kann dir eine Kurzfassung von dem geben, was dich im Tutorial erwartet:

Für das Zeichnen der Oberfläche ist der EDT (Event Dispatch Thread) zuständig. Führt dieser gerade anderweitigen Code aus, kann er die Oberfläche nicht mehr zeichnen, weil er eben beschäftigt ist. Deine Methode
Code:
roll()
wird wohl im EDT ausgeführt.* Erst wenn dieser mit der Methode fertig ist, kann er die Oberfläche wieder zeichnen, also aktualisieren. Daher siehst du bis zum Ende der Methode keine Änderungen, die Oberfläche wirkt eingefroren.

*Der Code in AWT-Listenern wird im EDT ausgeführt. Ich nehme an, dass deine Methode durch einen Klick auf einen Button ausgeführt wird, also von einem [JAPI]ActionListener[/JAPI] aufgerufen wird.
Ob ein Code gerade im EDT ausgeführt wird, kannst du auch über [JAPI]SwingUtilities#isEventDispatchThread()[/JAPI] herausfinden.

Um diese Blockierung des EDT zu verhindern, lagert man lang andauernde Methoden in andere Threads aus. Eine Erleichterung dieser Aufgabe erhält man durch den [JAPI]SwingWorker[/JAPI]. Dieser stellt passende Methoden bereit.

Wenn man Code, welcher die Oberfläche verändert, in einen Thread auslagert, muss man darauf achten, dass diese Änderungen wiederum im EDT ausgeführt werden, da es sonst zu den üblichen Problemen der Nebenläufigkeit (bspw. Race Condition) kommen kann. Um dies zu bewerkstelligen, gibt es dieses Konstrukt:
Java:
SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        // hier die Oberfläche verändern
    }
});
Dieses ruft man in dem Code auf, der in einem anderen Thread läuft. Ein Beispiel aus deinem Code, der in dieser
Code:
run()
ausgeführt werden müsste, wäre
Code:
random_label.setLocation(5, random_position);
.

Das wird jetzt bestimmt nicht alle Fragen geklärt haben oder eher noch mehr erzeugt haben. Daher würde ich dir wirklich raten, dich intensiv mit Nebenläufigkeit in Java und speziell Nebenläufigkeit in Swing (bereits oben verlinkt) auseinanderzusetzen.
 
Zuletzt bearbeitet:
D

Dickmann123

Gast
Okay, vielen Dank für die Antworten!! :)

Ich werde mich damit mal ein wenig beschäftigen.

Bis hierhin auf auf jeden Fall schonmal danke :)
 
D

Dickmann123

Gast
Muss ich, um dein Konstrukt umzusetzen, eine neue Klasse anlegen und dafür einen neuen Thread anlegen? Oder reicht es eine Methode dafür bereitzustellen, weil wenn ich es direkt in meine Methode einfüge funktioniert es nicht.
 
S

SlaterB

Gast
"Um diese Blockierung des EDT zu verhindern, lagert man lang andauernde Methoden in andere Threads aus."

du brauchst irgendein Thread-Objekt zunächst, das kann man auch anonym erzeugen bzw. ein anonymes Runnable übergeben,
hast du schonmal einen Thread laufen lassen?

SwingUtilities.invokeLater() wird erst später noch interessant

> weil wenn ich es direkt in meine Methode einfüge funktioniert es nicht.

hier kann man raten, was du wo wie gemacht hast und kommt wahrscheinlich doch nicht auf deine Variante,
besser immer Code posten,
in jedem Post alle 5 Min. vielleicht zuviel, jetzt nach mindestens einem Tag Pause und Vorschlag einer bedeutenden Änderung nicht falsch
 
D

Dickmann123

Gast
Okay, dann mach ich das mal:

Versuch eben war

Java:
public void roll(){
		wait = 50;
		compare = 0;
		random_position = 37;
		random_label.setLocation(5, random_position);
		random_label.setVisible(true);
		left_panel.repaint();
		random = (int)(Math.random()*(counter*10-counter*5)+counter*5);
		for (int i = 0; i < random; i++){
			random_position = random_position + 30;
			if (compare == counter){
				random_position = 37;
				compare = 0;
			}
			SwingUtilities.invokeLater(new Runnable() {
			    @Override
			    public void run() {
			    	System.out.println(javax.swing.SwingUtilities.isEventDispatchThread());
					random_label.setLocation(5, random_position);
			    }
			});
		
			left_panel.repaint();
			compare++;
			wait(wait);
			//gui.wait = gui.wait + 10;
		}
	}
[/Java]

Mein ActionListener ist übrigens in einer Extra-Klassen:

[code=Java]
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Roll_action implements ActionListener{

	GUI gui;
	
	public Roll_action(GUI Gui){
		gui = Gui;
	}
	
	public void actionPerformed(ActionEvent e) {
		gui.roll();
	}
}

Könnte ich nicht in diese Klasse (mit dem ActionListener) eine Background Task einfügen, wie hier beschrieben: Simple Background Tasks (The Java™ Tutorials > Creating a GUI With JFC/Swing > Concurrency in Swing)
 
S

SlaterB

Gast
SwingWorker geht genauso wie Thread, ja,
man muss es nur machen, bisher ist beides nicht vorhanden,
die actionPerformed()-Methode macht bisher die Arbeit, ruft die Methode roll() auf, ist erst fertig, wenn roll() abgearbeitet ist

Ziel muss es sein, eine nebenläufige Ausführung allein mit dem start-Kommando zu initialisieren und dann sofort
den ActionListener zu beenden, roll() wird erst später/ parallel ausgeführt

in dem Link steht gar nicht wie der SwingWorker gestartet wird,
hier ein Beispiel
Albert Attard: Practical Example of Swing Worker
execute() ziemlich weit unten,
wobei dort nicht aus einem Listener gestartet, sondern die ganze Zeit läuft, nicht ganz passend

für den Anfang mag es einfacher sein, erstmal Threads kennenzulernen,
aber wenn du zu SwingWorker schon was weißt/ noch beim Lesen bist, dann auch gut
 
D

Dickmann123

Gast
Also meinst du soll ich meinen Actionlistener in einem extra Thread ausführen, ohne den BackgroundWorker bzw. invoke?
 
S

SlaterB

Gast
du kannst den ActionListener nicht beeinflussen, der wird bei einem Button registriert und das war und ist genau alles an Einstellmöglichkeiten,
der AWT-Thread führt den ActionListener aus, soweit die festen Fakten,

die einzige Entscheidung ist, nochmal wiederholt, ob der ActionListener alles selber macht und solange die GUI blockiert wird,
oder ob jemand anders das nebenläufig macht, frisch gestartet vom ActionListener, vielleicht auch schon lange laufend und nur informiert
 
D

Dickmann123

Gast
Danke Leute es geht! :)

Habs jetzt über nen Thread gelöst:

Java:
public class roll_thread extends Thread {
	
	GUI gui;
	
	public roll_thread(GUI Gui){
		gui = Gui;
	}
	
	public void run() {
		gui.wait = 50;
		gui.compare = 1;
		gui.random_position = 37;
		gui.random_label.setLocation(5, gui.random_position);
		gui.random_label.setVisible(true);
		gui.left_panel.repaint();
		wait(gui.wait);
		gui.random = (int)(Math.random()*(gui.counter*10-gui.counter*5)+gui.counter*5);
		for (int i = 0; i < gui.random; i++){
			gui.random_position = gui.random_position + 30;
			if (gui.compare == gui.counter){
				gui.random_position = 37;
				gui.compare = 0;
			}
			gui.random_label.setLocation(5, gui.random_position);
			gui.left_panel.repaint();
			gui.compare++;
			gui.wait = gui.wait + (int)15/gui.counter;
			wait(gui.wait);
		    }
		for (int i = 0; i < 4; i ++){
			wait(300);
			gui.random_label.setVisible(false);
			wait(300);
			gui.random_label.setVisible(true);
		}
	}
	
	private void wait(int time){
		try{
		     Thread.sleep(time);
		}catch(InterruptedException e){}
	}
}

Vielen Dank nochmal :)
 
D

Dickmann123

Gast
Eine Frage hab ich aber noch:

Moment passiert jedes Mal wenn ich den Button drücke folgendes:

Java:
		roll_thread rthread = new roll_thread(gui);
		rthread.start();

Dabei wird ja jedes Mal ein neues Objekt vom Typ thread angelegt. Was passiert nachdem rthread.start(); fertig abgearbeitet ist? Terminiert dann der Thread oder bleibt er und ich habe mit mehrfachem drücken des Buttons einen immer voller werdenden Speicher? Sprich muss ich noch etwas einfügen, um den Thread nach Abarbeitung zu löschen?
 
S

SlaterB

Gast
der Thread terminiert, wenn die run-Methode beendet wird,

ein Thread ist eine teure Sache, würde mich nicht wundern wenn intern tausende Objekte angelegt werden,
aber das muss dich nicht jucken, schon gar nicht in GUIs, jede Bewegung mit der Maus gibt dem Programm Leerlauf für Mio. an Objekte
(Erzeugen, Verarbeiten, Aufräumen als Arbeitsaufwand, Platz zum Speichern ist natürlich immer eine andere Frage),
so erzeugt man ihn richtig und der Speicher wird durchaus wieder freigegeben

durchaus denkbar dass mehrere gleichzeitig laufen, ohne Terminierung werden es immer mehr usw.,
aber selbst dann musst du schon viel klicken,
vielleicht geht deine Maus kaputt bevor der Speicher voll ist um wie immer blumenreich paar Dimensionen zu übertreiben

natürlich sollte man immer beobachten und drauf achten, dass nichts schief läuft
 
Zuletzt bearbeitet von einem Moderator:

André Uhres

Top Contributor
Wir sollten die Animation allerdings noch "thread-safe" machen, sonst gibt die Anzeige möglicherweise irgendwann den Geist auf.

Swing-Event-Handler Code läuft auf einem speziellen Thread, der als Event Dispatch Thread bekannt ist. Der meiste Code, der Swing-Methoden aufruft, läuft auch auf diesem Thread. Dies ist notwendig, denn die meisten Swing-Komponenten-Methoden sind nicht "thread-safe" sind: Aufrufe von mehreren Threads bewirken Risiken von Thread Störungen oder Speicher Konsistenzfehler. Einige Swing-Komponenten-Methoden sind als "thread-safe" in der API-Spezifikation bezeichnet, diese können sicher von jedem Thread aufgerufen werden. Alle anderen Swing-Komponenten Methoden müssen vom Event Dispatch Thread aufgerufen werden. Programme, die diese Regel ignorieren können zwar die meiste Zeit funktionieren, sind aber abhängig von unvorhersehbaren Fehlern, die schwer zu reproduzieren sind.

Es ist nützlich, den Code, der auf dem Event Dispatch Thread läuft, als eine Reihe von kurzen Aufgaben zu sehen. Die meisten Aufgaben sind Aufrufe von Event-Handling Methoden, wie ActionListener.actionPerformed. Andere Aufgaben können durch die Anwendung mit invokeLater (oder invokeAndWait) geplant werden:

Java:
import javax.swing.SwingUtilities;

public class RollThread extends Thread
{

   private Gui gui;

   public RollThread(final Gui Gui)
   {
      gui = Gui;
   }

   @Override
   public void run()
   {
      gui.setWait(50);
      gui.setCompare(1);
      gui.setRandomPosition(37);
      SwingUtilities.invokeLater(new Runnable()
      {

         @Override
         public void run()
         {
            gui.getRandomLabel().setLocation(5, gui.getRandomPosition());
            gui.getRandomLabel().setVisible(true);
         }
      });
      wait(gui.getWait());
      gui.setRandom((int) (Math.random() * (gui.getCounter() * 10 - gui.getCounter() * 5) + gui.getCounter() * 5));
      for (int i = 0; i < gui.getRandom(); i++)
      {
         gui.setRandomPosition(gui.getRandomPosition() + 30);
         if (gui.getCompare() == gui.getCounter())
         {
            gui.setRandomPosition(37);
            gui.setCompare(0);
         }
         SwingUtilities.invokeLater(new Runnable()
         {

            @Override
            public void run()
            {
               gui.getRandomLabel().setLocation(5, gui.getRandomPosition());
            }
         });
         gui.setCompare(gui.getCompare() + 1);
         gui.setWait(gui.getWait() + 15 / gui.getCounter());
         wait(gui.getWait());
      }
      for (int i = 0; i < 4; i++)
      {
         wait(300);
         SwingUtilities.invokeLater(new Runnable()
         {

            @Override
            public void run()
            {
               gui.getRandomLabel().setVisible(false);
            }
         });
         wait(300);
         SwingUtilities.invokeLater(new Runnable()
         {

            @Override
            public void run()
            {
               gui.getRandomLabel().setVisible(true);
            }
         });
      }
   }

   private void wait(final int time)
   {
      try
      {
         Thread.sleep(time);
      } catch (InterruptedException e)
      {
      }
   }
}

Gruß,
André
 
D

Dickmann123

Gast
Okay gut :)

Vielen vielen Dank für eure Hilfe. Das mit dem Thread-safe hab ich jetzt auch übernommen.
Ihr wart eine super Hilfe, nochmal Dankeschön :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Repaint mittels Button richtig aufrufen klappt nicht AWT, Swing, JavaFX & SWT 1
D Repaint Funktioniert nicht AWT, Swing, JavaFX & SWT 2
D JUNG Repaint function does not work AWT, Swing, JavaFX & SWT 2
E repaint Probleme AWT, Swing, JavaFX & SWT 13
G listener repaint() - verschiedene Darstellung AWT, Swing, JavaFX & SWT 24
ExceptionOfExpectation Textdarstellung auf einem Canvas mit Hilfe von repaint(); AWT, Swing, JavaFX & SWT 6
J actionperformed wird nicht aufgerufen/ repaint() AWT, Swing, JavaFX & SWT 6
L Swing repaint() ruft paintComponent(g1d) nicht auf AWT, Swing, JavaFX & SWT 12
G Repaint wird nicht durchgeführt AWT, Swing, JavaFX & SWT 8
I Swing Verhindern, dass repaint() kaskadiert AWT, Swing, JavaFX & SWT 6
ms_cikar Update swingUtilities Repaint in der Schleife AWT, Swing, JavaFX & SWT 3
T Swing Probleme mit repaint() bzw. JScrollPane AWT, Swing, JavaFX & SWT 7
N Swing JButtons werden nach repaint() doppelt dargestellt AWT, Swing, JavaFX & SWT 12
K Methode repaint() AWT, Swing, JavaFX & SWT 1
B Swing Wann brauche ich repaint() ? AWT, Swing, JavaFX & SWT 1
javampir Swing repaint in JavaFX Anwendung AWT, Swing, JavaFX & SWT 3
A repaint(); AWT, Swing, JavaFX & SWT 9
J Swing ungewünschter Nebeneffekt bei der repaint() Methode AWT, Swing, JavaFX & SWT 3
A Problem: repaint() - Schleife AWT, Swing, JavaFX & SWT 3
S 2D-Grafik repaint()-Aufruf. Und nichts geschieht. AWT, Swing, JavaFX & SWT 5
Joew0815 JDialog repaint() funktioniert nicht wie gewünscht. AWT, Swing, JavaFX & SWT 2
P JPanel und Repaint AWT, Swing, JavaFX & SWT 5
J JavaFX Automatisches Neuzeichnen ("Repaint") abstellen. AWT, Swing, JavaFX & SWT 10
F JTable Repaint Issue AWT, Swing, JavaFX & SWT 1
N Observer: update ruft nicht repaint auf AWT, Swing, JavaFX & SWT 0
C Repaint() funktioniert nicht in TabbedPanel AWT, Swing, JavaFX & SWT 5
S JList repaint AWT, Swing, JavaFX & SWT 1
L NullpointerException und Probleme mit repaint() AWT, Swing, JavaFX & SWT 11
B Repaint auf JFrame, JLabel und ImageIcon AWT, Swing, JavaFX & SWT 4
K 2D-Grafik Paint - Wie binde ich repaint ein? AWT, Swing, JavaFX & SWT 8
R Repaint() in Schleifen, Threads AWT, Swing, JavaFX & SWT 13
B Swing Repaint Problem - mal wieder AWT, Swing, JavaFX & SWT 5
P 2D-Grafik Gezielter Repaint einzelner Frames in Java-Game AWT, Swing, JavaFX & SWT 6
javampir Bei repaint nix los AWT, Swing, JavaFX & SWT 2
B Swing repaint() AWT, Swing, JavaFX & SWT 3
Ernesto95 AnimationLoop - Problem bei Aufruf von repaint AWT, Swing, JavaFX & SWT 6
P 2D-Grafik repaint(); steigender RAM Verbauch AWT, Swing, JavaFX & SWT 6
Y KeyListener, GUI Thread, repaint AWT, Swing, JavaFX & SWT 7
S Applet Repaint AWT, Swing, JavaFX & SWT 3
M Programm hängt sich auf nachdem repaint() benutzt wurde AWT, Swing, JavaFX & SWT 2
R Swing Grafikfehler bei repaint AWT, Swing, JavaFX & SWT 2
N repaint() blockieren AWT, Swing, JavaFX & SWT 6
K canvas zeig nach repaint nichts an AWT, Swing, JavaFX & SWT 8
M Repaint() AWT, Swing, JavaFX & SWT 14
J Swing repaint, repaint, repaint AWT, Swing, JavaFX & SWT 8
M Applet repaint() verlangsamen AWT, Swing, JavaFX & SWT 7
R paintComponent malt bei repaint() Rahmen um Panel AWT, Swing, JavaFX & SWT 7
P EDT Problem? Kein Aufruf der repaint Methode AWT, Swing, JavaFX & SWT 6
V Applet JApplet Flackern durch Repaint AWT, Swing, JavaFX & SWT 11
kodela Problem mit repaint() AWT, Swing, JavaFX & SWT 3
N Swing Funktion repaint() updated nicht AWT, Swing, JavaFX & SWT 5
F repaint reagiert nicht AWT, Swing, JavaFX & SWT 8
S AWT Probleme mit repaint() AWT, Swing, JavaFX & SWT 2
D Repaint()? Oder was??? AWT, Swing, JavaFX & SWT 5
M Eine nicht korrekte Darstellung bei repaint() warum? AWT, Swing, JavaFX & SWT 4
T 2D-Grafik Kreis "von Hand" zeichnen -> jedesmal repaint()? AWT, Swing, JavaFX & SWT 6
R validate(), repaint funktionieren nicht! AWT, Swing, JavaFX & SWT 7
B AWT Canvas überdeckt nach repaint() JComboBox-Optionen AWT, Swing, JavaFX & SWT 2
B Swing verschachteltes GUI: repaint() ändert mehr als nur gewünschte Component AWT, Swing, JavaFX & SWT 4
S validate(), invalidate(), repaint(),... Was kommt wann? AWT, Swing, JavaFX & SWT 5
M 2D-Grafik repaint() löscht altes Bild nicht AWT, Swing, JavaFX & SWT 2
J repaint() nicht richtig? AWT, Swing, JavaFX & SWT 6
R repaint erzwingen AWT, Swing, JavaFX & SWT 3
Zettelkasten repaint() von anderen Klassen aufrufen AWT, Swing, JavaFX & SWT 4
H repaint()-Problem - 50% CPU-Auslastung AWT, Swing, JavaFX & SWT 4
P repaint während Thread läuft AWT, Swing, JavaFX & SWT 9
D Repaint Frage, Design Frage AWT, Swing, JavaFX & SWT 2
N Swing MainWindow(JFrame) aktualisieren(neuzeichnen) repaint AWT, Swing, JavaFX & SWT 4
T repaint() Problem AWT, Swing, JavaFX & SWT 2
A 2D-Grafik Repaint - Alternative? AWT, Swing, JavaFX & SWT 3
C JLabel, JTextArea, JScrollPane. repaint(); ? AWT, Swing, JavaFX & SWT 6
N Swing repaint() funktioniert nicht AWT, Swing, JavaFX & SWT 5
T Swing repaint funktioniert nur manchmal? AWT, Swing, JavaFX & SWT 6
K Jpanel repaint problem (Fullscreen) AWT, Swing, JavaFX & SWT 5
V Swing Bei repaint() tut sich nichts AWT, Swing, JavaFX & SWT 7
G ColorReader, bei Fadenkreuz zeichnen mit repaint() flackern AWT, Swing, JavaFX & SWT 19
I Canvas Repaint Probleme AWT, Swing, JavaFX & SWT 2
D Swing Actionlistener verhindert repaint?! AWT, Swing, JavaFX & SWT 2
S JLabel repaint AWT, Swing, JavaFX & SWT 8
C Swing Linux mag mein Swing-repaint() nicht... AWT, Swing, JavaFX & SWT 7
J Swing paintComponent() - repaint() - BufferedImage anzeigen AWT, Swing, JavaFX & SWT 5
Luk10 repaint() auch in anderen Klassen! AWT, Swing, JavaFX & SWT 6
A repaint() zu langsam, bitte um alternativen AWT, Swing, JavaFX & SWT 5
T Überlappende Transparenz und repaint() AWT, Swing, JavaFX & SWT 10
E EINFACHE Verständnisfrage zu repaint(), paintComponent(), usw. AWT, Swing, JavaFX & SWT 16
O Girdbag Formatierung nach repaint verloren AWT, Swing, JavaFX & SWT 2
E Swing - repaint() AWT, Swing, JavaFX & SWT 6
T Image wird nicht angezeigt?! - MediaTracker/repaint AWT, Swing, JavaFX & SWT 9
E AWT Problem mit Repaint (in Loop oder Timer) AWT, Swing, JavaFX & SWT 3
O Exception bei repaint AWT, Swing, JavaFX & SWT 3
D Fragen zu Swing, paintComponent() und repaint AWT, Swing, JavaFX & SWT 6
Dit_ Zeilenmarkierung verschwindet nach repaint() AWT, Swing, JavaFX & SWT 12
A Swing Infinite repaint loop unterbrechen AWT, Swing, JavaFX & SWT 7
hdi Swing EDT macht kein repaint() AWT, Swing, JavaFX & SWT 2
F "Verrutschen" von Komponenten bei repaint() AWT, Swing, JavaFX & SWT 9
Junker Fensterinhalt vor ausführen von repaint komplett löschen. AWT, Swing, JavaFX & SWT 2
T Fenster wird trotz repaint() und revalidate() nicht sofort neu gezeichnet AWT, Swing, JavaFX & SWT 6
E Graphics2D: altes Objekt löschen, wenn repaint aufgerufen wird AWT, Swing, JavaFX & SWT 7
J Swing Verständnis-Problem repaint(int x,int y,int width,int height) AWT, Swing, JavaFX & SWT 3
C Frame repaint hat keine Wirkung AWT, Swing, JavaFX & SWT 6

Ähnliche Java Themen

Neue Themen


Oben