Swing setLocation Aufruf in JApplets 20 mal langsamer als in JFrames

javimka

Top Contributor
Mir ist etwas seltsames aufgefallen, für das ich keine Erklärung finde. Ich habe eine Klasse TimerPanel, die von JPanel erbt. Darin fliegen 1000 ganz billige Bälle umher, die von JComponent erben. Die neue Position dieser Bälle, wird mit setLocation(x,y) gesetzt. Mit System.nanoTime() werden die Zeiten, die die setLocation Aufrufe benötigen gemessen und anschliessend angezeigt.

Wenn ich das Panel nun in ein JFrame lege, dauern die Aufrufe von setLocation bei mir 3 ms. Wenn ich das gleiche Panel in ein JApplet lege, dauert es 60 ms, also 20 Mal mehr. Wieso?

Folgendes Programm kann als Applikation mit einem JFrame oder als JApplet gestartet werden. In beiden Fällen, wird eine Instanz von TimerPanel erstellt und in den jeweiligen Container gelegt.
Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JApplet;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class TimerApplet extends JApplet {

	// setup frame
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				JFrame frame = new JFrame("Performance Test Frame");
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.add(new TimerPanel());
				frame.pack();
				frame.setLocationRelativeTo(null);
				frame.setVisible(true);
			}
		});
	}

	// setup applet
	public void init() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				getContentPane().add(new TimerPanel());
				setSize(getPreferredSize());
			}
		});
	}
	
	/**
	 * Panel für die Bälle, das auch die Zeit misst
	 */
	private static class TimerPanel extends JPanel {

		private static final int MAX_SPEED = 250; // pixel per second
		private static final int INIT_BALLS = 1000;
		private static final int INIT_DELAY = 20; // in ms

		// step time
		private long locdt; // meassured in ns
		
		private int n;
		private ArrayList<Ball> balls;
		
		public TimerPanel() {
			// setup panel
			setLayout(null);
			setBackground(Color.WHITE);
			setSize(600,400);
			setPreferredSize(new Dimension(600,400));
			
			// init balls
			balls = new ArrayList<Ball>();
			addRandomBalls(INIT_BALLS);
			
			// init timer
			new Timer(INIT_DELAY,new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					step(INIT_DELAY);
					repaint();
				}
			}).start();
		}
		
		public void paint(Graphics g) {
			super.paint(g);
			g.setColor(Color.RED);
			g.drawString("Bälle: "+n,0,12);
			g.drawString("Bälle: "+n,1,12);
			g.drawString("setLocation: "+locdt/1000000+" ms",0,24);
			g.drawString("setLocation: "+locdt/1000000+" ms",1,24);
		}

		/**
		 * Bewege alle Bälle so weit, wie sie in der Zeit dt kommen. Summiere
		 * dabei die benötigte Zeit für die setLocation Aufrufe auf
		 * @param dt - wie viele Millisekunden sich die Bälle bewegt haben
		 */
		private void step(long dt) {
			locdt = 0; // reset time
			for (Ball ball:balls) {

				locdt += ball.step(dt); // sum time for setLocation calls
				
				// collision with border handling
				if (ball.vx<0 && ball.getX()<0) ball.vx = -ball.vx;
				if (ball.vy<0 && ball.getY()<0) ball.vy = -ball.vy;
				if (ball.vx>0 && ball.getX()+ball.size>=getWidth()) ball.vx = -ball.vx;
				if (ball.vy>0 && ball.getY()+ball.size>=getHeight()) ball.vy = -ball.vy;
			}
		}
		
		/**
		 * Füge m Bälle hinzu
		 */
		public void addRandomBalls(int m) {
			Random rand = new Random();
			for (int i=0;i<m;i++) {
				Ball ball = new Ball(rand.nextInt(600),
						rand.nextInt(400),
						rand.nextInt(MAX_SPEED*2)-MAX_SPEED,
						rand.nextInt(MAX_SPEED*2)-MAX_SPEED,
						rand.nextInt(20)+4,
						new Color(rand.nextInt(256*256*256)));
				balls.add(ball);
				add(ball);
			}
			n += m;
		}
	}
	
	/**
	 * Klasse für die Bälle
	 */
	private static class Ball extends JComponent {

		private float x, y;
		private float vx, vy;
		private int size;
		private Color col;
		
		public Ball(int x, int y, float vx, float vy, int size, Color col) {
			this.x = x;
			this.y = y;
			this.vx = vx;
			this.vy = vy;
			this.size = size;
			this.col = col;
			setLocation(x, y);
			setSize(size,size);
		}
		
		/**
		 * Bewege dich soweit, wie du in dt kommst und gibt die benötigte Zeit
		 * für setLocation zurück
		 * @param dt - wie viele Millisekunden der Ball gekommen ist
		 * @return - Zeit für den setLocation Aufruf
		 */
		private long step(long dt) {
			x = x+vx*dt/1000;
			y = y+vy*dt/1000;
			
			int xx = (int) Math.round(x);
			int yy = (int) Math.round(y);
			// meassure time for setLocation
			long t0 = System.nanoTime();
			setLocation(xx,yy);
			return System.nanoTime()-t0; // time for setLocation
		}
		
		public void paintComponent(Graphics g) {
			g.setColor(col);
			g.fillOval(0,0,size,size);
		}
	}
}
Das KSKB ist leider etwas gross geworden.

Das Applet kann man auch hier im Browser starten oder downloaden und als Applikation (jar) starten. TimerApplet Informationen und Download
Hier wird auch noch die Zeit, die für das Zeichnen benötigt wird angezeigt und man kann Bälle hinzufügen oder entfernen.

Wieso bringt ein Panel in einem JApplet nicht dieselbe Leistung, wie in einem JFrame?
 

javimka

Top Contributor
Viele Ideen scheint es leider nicht zu geben. Oder ist das KSKB zu gross/kompliziert? Musste leider etwas gross sein, weil der Effekt bei wenigen Bewegungen nicht zu sehen ist. Ich finde jedenfalls, es sieht cool aus, es sich anzusehen ist es allemal wert ;)

Ich habe selbst noch etwas nachgeforscht, aber nicht mehr viel herausgefunden. Weil setLocation sowieso setBounds(x,y,widht,height) aufruft, habe ich es gleich dadurch ersetzt, der Effekt bleibt der Gleiche. Dann habe ich einige Methoden, die setBounds benutzt analysiert, z.B. getTreeLock(), konnte bei denen aber kein anderes Verhalten für Applets und Frames finden. Übrig geblieben sind noch einige, die nicht sichtbar sind, deren Zeitbedarf ich also nicht genau messen kann und an einer solchen muss es wohl liege :(
Es könnten mixOnReshaping(), reshapeNativePeer(…), notifyNewBounds(…) oder repaintParentIfNeeded(…) sein.

Ich fines es jedenfalls seltsam.
 

javimka

Top Contributor
Wahrscheinlich als JFrame oder? Dann hast du einen schnellen Rechner :D
Aber wenn du es als JApplet startest, ist es wahrscheinlich langsamer.
 
U

user124

Gast
zu meiner schande muss ich zugeben das ich in meinem javabuch noch nicht so weit bin als das ich mit dem begriff japplet was anfangen könnte :/ sry
 

Marco13

Top Contributor
Hmja, der Unterschied ist schon ziemlich deutlich. (Abgesehen davon, dass ich - wie schon in anderen Threads zur genüge breitgetreten habe - nicht viel davon halte, einen Sprite von "JComponent" erben zu lassen - und der Unterschied, der entsteht, wenn man Ball mal NICHT von JComponent erben läßt, und die Gesamtzeit von TimerPanel#step bei 10000 Bällen mißt, ist ein weiterer Grund ;) ).

Die Ursache... naja ... ist schwer zu sagen.... setLocation landet irgendwann bei "Component#reshape...", man könnte mal schauen, wo von dort aus Applets anders behandelt werden als JFrames....
 

javimka

Top Contributor
Mit der breitgetretenen Diskussion meinst wahrscheinlich diesesn Thread hier http://www.java-forum.org/awt-swing-swt/75096-schichten-jpanel.html ^^

Die Sprites habe ich von JComponent erben lassen, weil es einen gewissen Komfort bringt, konnta ja nicht ahnen, dass dass setLocation()/move()/setBounds()/reshape() dann so lange dauert. Naja, jetzt wissen wir es :)
Aber eine simple Erklärung/Lösung gibt es in dem Fall nicht.

Habe es jetzt umgeschrieben, ohne JComponent, das war in diesem Beispiel jetzt auch ganz einfach. Die Methode step läuft nun in JFrames und Applets sehr schnell ab, meistens unter einer ms, was natürlich hervorragend ist.

Vielen Dank für alle Antworten
 

javimka

Top Contributor
Naja, ohne hierarchyBoundsListener und vetoableChangeSupport ist mein Sprite schon nicht mehr das Sprite, das es einmal war :lol:
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
H RPG Programmieren, label.setLocation funktioniert nicht AWT, Swing, JavaFX & SWT 7
C Swing Komponente mit setLocation auf JPanel funktioniert nicht AWT, Swing, JavaFX & SWT 3
B JLabel mittels Timer und setLocation verschieben AWT, Swing, JavaFX & SWT 3
H Y-Position mit get-/setLocation() unter Linux/Enlightement16 inkonsistent AWT, Swing, JavaFX & SWT 3
J JFrame.setLocation() AWT, Swing, JavaFX & SWT 19
W Swing Problem: setLocation und setBounds werden ignoriert... AWT, Swing, JavaFX & SWT 3
N rechtsklick und popup setlocation AWT, Swing, JavaFX & SWT 2
J JLabel setLocation AWT, Swing, JavaFX & SWT 4
K setSize und setLocation geht nicht AWT, Swing, JavaFX & SWT 8
C setLocation() beim JDialog AWT, Swing, JavaFX & SWT 2
Juelin JavaFX Netbeans Aufruf Funktion aus Scenebuilder AWT, Swing, JavaFX & SWT 8
G Gui updated beim zweiten Aufruf nicht mehr AWT, Swing, JavaFX & SWT 15
T SWT: Aufruf des Top-Dialogfensters und sperre des Hintergrundes AWT, Swing, JavaFX & SWT 2
C Swing Aufruf der Funktion (die ein Dialog anzeigt) über Symbol anzeigen lassen AWT, Swing, JavaFX & SWT 4
N Aufruf einer anderen Klasse durch Button ActionListener AWT, Swing, JavaFX & SWT 2
P GUI Aufruf AWT, Swing, JavaFX & SWT 2
MiMa Übergeben von Paramter bei FXML Aufruf? AWT, Swing, JavaFX & SWT 8
C Nach Aufruf von anderer Klasse streikt Grafik AWT, Swing, JavaFX & SWT 1
D Swing keine JLabel-Aktualisierung bei "externem" Aufruf durch Helferklasse AWT, Swing, JavaFX & SWT 10
D JLabel bei Aufruf neue Zeile AWT, Swing, JavaFX & SWT 5
M Swing Vorgehen beim Aufruf der Klassen/Methoden AWT, Swing, JavaFX & SWT 7
S 2D-Grafik repaint()-Aufruf. Und nichts geschieht. AWT, Swing, JavaFX & SWT 5
F 2D-Grafik Grafikproblem nach Aufruf von JColorChooser-Dialog AWT, Swing, JavaFX & SWT 6
D Swing JOptionPane verschwindet beim 2. Aufruf einfach so?? AWT, Swing, JavaFX & SWT 2
A Swing JFileChooser - Größenänderung nach Aufruf von showOpenDialog() AWT, Swing, JavaFX & SWT 15
Ernesto95 AnimationLoop - Problem bei Aufruf von repaint AWT, Swing, JavaFX & SWT 6
W Funktionen, sowie aufruf einiger Komponenten AWT, Swing, JavaFX & SWT 4
X Swing Panel Extra Klasse & Aufruf über Button AWT, Swing, JavaFX & SWT 18
P JPanel-Aufruf funktioniert nicht AWT, Swing, JavaFX & SWT 5
K Swing setPreferredWidth für JTable funktioniert nur beim ersten Aufruf!? AWT, Swing, JavaFX & SWT 8
P EDT Problem? Kein Aufruf der repaint Methode AWT, Swing, JavaFX & SWT 6
X Alte Frame-Größe beim wiederholten Aufruf AWT, Swing, JavaFX & SWT 5
D Aufruf neuer Klasse ohne Erzeugung eines neuen Fensters AWT, Swing, JavaFX & SWT 3
C Unterschiedlicher Aufruf der paint() Methode ? (AWT/Swing) AWT, Swing, JavaFX & SWT 2
C SWT SWT Dialogfenster blitzen bei deren Aufruf AWT, Swing, JavaFX & SWT 2
P seltsame Performance Probleme bei 2 Guis abhängig vom Aufruf AWT, Swing, JavaFX & SWT 8
JFeel-x repaint für Aufruf von paintComponent-Klasse ungeeignet? AWT, Swing, JavaFX & SWT 11
Dragonfire ZoomImage flackert -> Fehler: repaint-Aufruf [gelöst] AWT, Swing, JavaFX & SWT 5
D Container des JFrame zeichnet sich nicht bei Aufruf von paintAll AWT, Swing, JavaFX & SWT 9
S NullPointerException bei Aufruf von updateUI() beim JFrame AWT, Swing, JavaFX & SWT 12
A preferredLayoutSize aufruf erzwingen AWT, Swing, JavaFX & SWT 4
D JTab <--> JPanel aufruf per Button AWT, Swing, JavaFX & SWT 2
G Keine Anzeige von Grafik bei externem paintComponent-Aufruf AWT, Swing, JavaFX & SWT 2
M Problem mit erneutem Aufruf AWT, Swing, JavaFX & SWT 4
K g.DrawImage unter paintComponent klappt nur beim 1. Aufruf AWT, Swing, JavaFX & SWT 3
G ActionListener und Methoden-Aufruf aus anderen Klassen AWT, Swing, JavaFX & SWT 3
G NullPointerException bei Aufruf von JTabbedPane.getSelectedI AWT, Swing, JavaFX & SWT 7
P AWT: Expliziter repaint-Aufruf AWT, Swing, JavaFX & SWT 2
H doppelter Aufruf von selectionListener für JList AWT, Swing, JavaFX & SWT 4
J Aufruf externer Quellen aus java AWT, Swing, JavaFX & SWT 3
F fertige JApplets in Desktop Application einbinden AWT, Swing, JavaFX & SWT 4

Ähnliche Java Themen

Neue Themen


Oben