Probleme mit repaint()

epytir

Mitglied
Hallo Community,
ich habe mittlerweile seit Wochen Probleme mit repaint() ich habe schon X seiten gegoogelt und nichts hat geholfen.
Zu meinem Problem ich versuche mich an einer Anwendung die automatisch einen Graphen von Punkt zu Punkt verbindet also nicht alle auf einmal sondern als Animation....
Ich Speicher die Punkte die verbunden werden sollen in ein Point Array und daraus soll dann paintcomponent sich die Koordinaten für die Verbindung raussuchen das sieht dann so aus :
Java:
			 for(int i = 0;i<towns.getPointsDrawable() ; i++)
			 {
					 x1 = (int)towns.getLinesPosition(i, 0).getX();
					 y1 = (int)towns.getLinesPosition(i,0).getY();
					 x2 = (int)towns.getLinesPosition(i,1).getX();
					 y2 = (int)towns.getLinesPosition(i,1).getY();	 
					 g.drawLine(x1, y1, x2, y2);
			 }
getPointsDrawable steht für wie weit er im Array gehen kann also wieviele Punkte im Array gespeichert sind damit es keine Zugriffsfehler gibt.
Leider passiert rein garnichts wenn ich repaint() aufrufe nachdem ich einen Punkte hinzugefügt habe. Wenn er fertig ist und alle Punkte im Koordinatensystem verbunden sind gibt er den gesammten Graphen korrekt aus aber ich will ja das er das Stück für Stück macht ;( ;(
Habe es schon mit einem Thread versucht der jede halbe Sekunde repaint aufruft seiner ohne Erfolg...
Ich habe alles zum Zeichnen in der paintComponent Methode und rufe am Anfang immer super.paintComponent auf damit meine Buttons nicht verschwinden.(Nur als Info 🙂 )
Achso und ich habe mal ein System.out in der paintcomponent gemacht es ist so das diese erst am Ende aufgerufen wird und dann gleich so oft wie es Wege gibt also wenn ich 5 Wege zeichne dann führt er am Ende 5 mal direkt hintereinander paintComponent aus anstatt das in gewissen abständen zu tun.
Meine Init und run Methoden sehen so aus :
Java:
public void init() 
{ 
     clockThread= new Thread(this); 
     clockThread.start(); 
}


public void run() 
{ 

	System.out.println("TEdt");
     while (true) 
     { 
    	repaint();
          try 
          { 
               clockThread.sleep(500); 
          } 
          catch (InterruptedException e) 
          { 
               System.out.println(e); 
           } 

     } 
}
Und das ganze ist ausgelagert also meine Main ist in einer anderen Klasse die PaintKlasse wird als Jpanel in der Main benutzt der Kopf der paint Klasse ist :
Java:
public class PaintPanel extends JPanel implements Runnable{
Hoffe jemand kann mit helfen bin am verzweifeln
Gruß Epytir
 
Zuletzt bearbeitet von einem Moderator:
Übershreib mal die update() Methode. Und zwar so:

[Java] public void update(Graphics g) {
paint(g);

}
[/Java]
 
Zuletzt bearbeitet:
Danke schon mal für die Antwort hat leider nichts gebracht ich habe mal getestet das Programm ruft alle 500 Millisekunden repaint auf. Sobald ich das zeichnen starte wartet er bis alles gezeichnet ist und repainted erst dann... sehr doof.

Ich habe in meiner Methode zum zeichnen einen Sleep Thread eingebaut da sonnst der Computer in milisekunden alle Punkte ausgeben würde und genau bei diesem Sleep schläft auch der repaint ein kann ich das irgendwie verhindern ?
 
Ist ja lustig 🙂 Genau die gleiche Anwendung habe ich vor ein paar Tagen programmiert.
Beim mir läuft es, allerdings bin ich mit der Umsetzung nicht zufrieden und möchte es optimieren.

Aber hier mal mein zusammengeschnittener Code, mit dem ich eine wunderbare Kurve zeichne.

Java:
package fuerforum;

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import static javax.swing.JFrame.EXIT_ON_CLOSE;

public class Main extends JComponent implements Runnable {

	static int wert;
	Integer[] aktuell;

	public Main() {

		aktuell = new Integer[900];
		for (int i = 0; i < 900; i++) {
			aktuell[i] = 0;
		}
	}

	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(1024, 600);
		Main system = new Main();
		frame.setContentPane(system);
		new Thread(system).start();
		frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
		frame.setVisible(true);

		JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 15);
		slider.setBounds(450, 450, 200, 200);
		slider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				wert = ((JSlider) e.getSource()).getValue();
			}
		});
		frame.add(slider);

	}

	@Override
	public void run() {
		while (true) {

			long t = System.currentTimeMillis();

			for (int i = 0; i < 900; i++) {
				if (i > 0)
					aktuell[i - 1] = aktuell[i];
			}
			aktuell[899] = 360 - wert;

			this.validate();
			this.repaint();

			long d = t - System.currentTimeMillis();
			int wait = 10 - (int) d;
			if (wait > 0)
				try {
					Thread.sleep(wait);
				} catch (InterruptedException e) {
				}

		}
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.setColor(Color.white);
		g.fillRect(46, 40, 904, 360);
		g.setColor(Color.black);
		for (int i = 1; i < 900; i++) {
			g.drawLine(i + 46, aktuell[i - 1] + 40, i + 46, aktuell[i] + 40);
		}
	}
}

Möge es dir helfen 🙂
 
Leider hat diese Lösung bei mir nicht funktioniert ...
Ich habe eine Klasse für das Panel und die Main in einer anderen Klasse das sollte zwar eigentlich trotzdem gehen aber geht irgendwie nicht ....
Achso und mein Graph entsteht durch eine rekursive Methode also ein Array das jede Sekunde einen neuen Punkt dazu bekommt und das soll eigentlich gezeichnet werden leider bisher ohne Erfolg.
Danke aber schonmal für den Versuch habe verschiedene Abwandlungen deines Codes versucht leider ohne Erfolg.
Gruß Epytir
 
Rufst du das zeichnen der Punkte den auch in der while Schleife auf ? den sonst werden die 5 ja alle gezeichnet und du machst halt nur alle 500 ms ein repaint, was dir ja auch nichts bringt dann.
du müsstest ja vor dem repaint in der while schleife punkt für punkt dazu bringen, also pro while durchlauf einen punkt mehr. das was du gepostet hast sieht mir aktuell nicht so aus
 
Ich hatte das so gelöst das es eine Methode getPointsDrawable gibt in dieser steht wie viele Punkte gezeichnet werden können mit jedem Schleifendurchlauf wird diese um eins erhöht und in der Schleife wird ein repaint aufgerufen bzw hatte auch mal eine Pause von 1 Sek in der Schleife. Leider wird trotzdem erst am Ende der Schleife gezeichnet.

Die Pause die ich hatte hat leider das gesamte Programm angehalten gibt es eine Funktion die nur die Methode anhällt damit repaint in ruhe zeichnen kann ?
In meiner Schleife wird immer am Ende die Methode
Code:
MainWindowGui.Dorepaint();[\Code]
Diese ist so implementiert :
[Code]	
	public static void Dorepaint() {	
		panel_drawArea.validate();
		panel_drawArea.repaint();
	}
	[\Code]
leider funktioniert das nicht .. :(
 
Du zeichnest mit deiner For Schleife auch erst alle Punkte und machst dann ein repaint oder ?
eigentlich müsstest du das repaint ja mit in die schleife nehmen.

das mit dem stoppen des programms kannst du über Threads bzw Timer verhindern.

z.B. so
Java:
        TimerTask task = new TimerTask()
        {
            @Override
            public void run()
            {
                system.repaint();
            }
        };
        Timer timer = new Timer();
        timer.schedule(task, 0, 10);
startet den Timer sofort und wiederholt alle 10ms das was im run() steht.
Könnte bei dir jetzt auch das erstellen der ersten 5 punkte + repaint sein.
system ist die das Objekt (Klasse mit extends JComponent in meinen Fall) was du neu zeichnen willst.
In system muss dann auch das
Java:
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
usw.. drin stehen.

aber probiere vielleicht erst mal dein repaint in der for schleife aus und nehm in die for schleife ein
Java:
try { Thread.sleep(100); } catch (InterruptedException e) {  }
mit rein, nur um zu testen ob er dann alle 100ms einen punkt dazu zeichnet
 
Zuletzt bearbeitet:
Die Pause hat leider auch nichts genutzt er macht zwar Pause rapainted aber vorher nicht .
Habe jetzt extra die draw Area global gemacht um direkt repaint anzusprechen leider auch ohne Erfolg.
Er führt repaint in der Schleife nicht aus erst wenn alle Punkte fertig sind führt er repaint aus. Habe das mit Sys outs getestet er kommt zwar immer in die Schleife aber ignoriert das repaint am ende. In meiner paintComponent Methode ist auch ein Sys.out und das gibt immer nur am Ende der Schleife einmal aus anstatt mit jedem Durchgang.
Java:
MainWindowGui.panel_drawArea.repaint();
try { Thread.sleep(100); } catch (InterruptedException e) {  }

Das komische ist das sogar der Timer während der Schleife stehen geblieben ist auch hier kein Sys.out mehr erst nach der Schleife 🙁
Da der Code der Schleife nicht mir gehört darf ich ihn nicht posten aber das sind nur 2 for Schleifen und ein return nichts das so ein Verhalten erklären würde 🙁
Wenn paintComponent überhaupt mal in der Schleife ausgeführt werden würde denk ich das dass alle Probleme löst ...
Danke schonmal für die bisherige Hilfe ist echt super 🙂
 
Du legst den Thread schlafen der "repaint"en soll daher wird auch nichts neu gezeichnet! 😉
Der Code in "repaint" wird zwar ausgeführt aber durch dein Sleep danach wird der eigentliche "Zeichner" blockiert.
 
Kapsel' doch die "Rekursionsmethode" in einen eigenen Thread.
Generell sollte man Datenmodell, (Geschäfts-)logik und Anzeige möglichst weitgehend getrennt halten.
 
Letztlich ahbe ich eine nicht ganz so elegante Lösung gefunden, aber da es mir nicht auf Performance ankommt ist das ok 😀

Hier mal meine Lösung falls es irgendwann mal jemand braucht

Java:
paintpanel.paint(paintpanel.getGraphics());
try{Thread.sleep(100);} catch InterruptedException e{}

Es aktualisiert das Gesammte Frame, da ich auf diesem Frame nur zeichne und auf einem anderen Frame meine Buttons sind und vereinzelt auch Wege verschwinden ist diese Lösung sehr gut für mich, da alle nicht mehr aktuellen Wege verschwinden. Man sollte auf jedenfall eine Zeit einbauen sonnst flackert das Frame in einer zu schnellen Schleife.
Gruß Epytir
 
Zuletzt bearbeitet:
Ich kenne natürlich nicht genau dein Programm aber ich zeichne mit dem Swing Timer da gibt es kein Flackern oder einfrierende Fenster.
Hier mal eine kleines Programm das nichts macht außer einen Graphen zu zeichenen von Links nach Rechts ohne Flackern Ruckeln oder dergleichen.


Java:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;


public class Graphen extends JFrame {

	private JPanel contentPane;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Graphen frame = new Graphen();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	private List<Point> points=new ArrayList<Point>();
	private Timer timer;
	private int x=0;
	/**
	 * Create the frame.
	 */
	public Graphen() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 700, 400);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		GraphLabel graphLabel=new GraphLabel();
		add(graphLabel,BorderLayout.CENTER);
		
		JButton btn=new JButton("Start");
		add(btn, BorderLayout.SOUTH);
		btn.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				x=0;
				timer.start();
			}
		});
		
		timer=new Timer(10, new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				
				x++;
				repaint();
				if(x==500)
				timer.stop();
			}
		});
		
		points.add(new Point(0,0));
		points.add(new Point(100,100));
		points.add(new Point(200,120));
		points.add(new Point(300,300));
		points.add(new Point(400,310));
	}
	public class GraphLabel extends JLabel{
		
		@Override
		protected void paintComponent(Graphics g) {
			Graphics2D g2d=(Graphics2D) g;
			g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
			for(int i=0;i<points.size()-1;i++){
				g2d.drawLine(points.get(i).x, points.get(i).y, points.get(i+1).x, points.get(i+1).y);
			}
			g2d.setColor(getBackground());
			g2d.fillRect(x, 0	, getWidth(), getHeight());
		}
	}

}
 
Wahlweise kann zu Glättung des Graphen noch das Antialiasing eingeschaltet werden.
Java:
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 

Zurück
Oben