# Probleme mit JViewport.setViewPosition(Point)...



## maystorm (10. Mrz 2007)

Bin auf ein Problem mit der Methode *getViewport().setViewPosition(Point)* der Klasse *JScrollPane* gestoßen.

Gegeben sei folgendes Code-Fragment:


```
private JScrollPane scrollPane;
private int x, y;
  :
  :
Point p1 = new Point(x, y);
System.out.println("Before setViewPosition: " + p1);
scrollPane.getViewport().setViewPosition(p1);

Point p2 = scrollPane.getViewport().getViewPosition();
System.out.println("After getViewPosition : " + p2);
```

Sollten in diesem Code-Snippet nicht p1 und p2 identische Koordinaten enthalten, sollte also getViewPosition() nicht denselben Point zurückliefern, den setViewPosition(Point) gesetzt hat? In der Applikation, an der ich gerade progge, kommt es hin und wieder vor, dass dies nicht der Fall ist. Manchmal sind p1 und p2 gleich, manchmal nicht. Hier z.B. die Ausgaben nach zweimaligem Durchlaufen der Codezeilen:


```
Before setViewPosition: java.awt.Point[x=999807,y=999827]
After getViewPosition : java.awt.Point[x=999807,y=999827]

Before setViewPosition: java.awt.Point[x=1999614,y=1999654]
After getViewPosition : java.awt.Point[x=1999226,y=1999307]
```

Wie man sieht, stimmen p1 und p2 beim ersten Mal überein, bei zweiten Mal nicht (das äußerst sich natürlich beim Laufen der Anwendung durch falsche Darstellung des in der JScrollPane enthaltenen JComponents).

Wer kennt sich hier aus? Sind weitere Details nötig?

TIA!

[EDIT] Titel geändert (war: Kann man sich auf setViewPosition(Point) verlassen?)


----------



## Wildcard (11. Mrz 2007)

wtf?  :shock: 
Das ist ja riesig...
Sollte sich herausstellen das der 'before' Wert immer größer als der 'after' Wert ist (sofern beide unterschiedlich sind), so liegt der Verdacht nahe das der 'before' Wert größer als die ViewPort-View ist.


----------



## maystorm (11. Mrz 2007)

Wildcard hat gesagt.:
			
		

> wtf?  :shock:
> Das ist ja riesig...


Jo, handelt sich um eine Umsetzung von Conway's "Game of Life". Das Spielfeld ist so implementiert, dass es prinzipiell unendlich groß sein kann,  wobei ich z.Zt. Höhe und Breite  auf 1 Mio. x 1 Mio. Felder begrenzt habe. Sollte reichen, denke ich... :wink:



			
				Wildcard hat gesagt.:
			
		

> Sollte sich herausstellen das der 'before' Wert immer größer als der 'after' Wert ist (sofern beide unterschiedlich sind), so liegt der Verdacht nahe das der 'before' Wert größer als die ViewPort-View ist.


Bin mir jetzt nicht so ganz sicher, was du mit der Größe der "Viewport-View" meinst. Was mich vor allem ins Schleudern bringt, ist, dass das Problem nicht konsistent auftritt. Ich habe hier mal insgesamt sechs Durchläufe durch das Code-Fragment dokumentiert:


```
Before setViewPosition: p1 = java.awt.Point[x=3806,y=3826]
After getViewPosition : p2 = java.awt.Point[x=3806,y=3826]

Before setViewPosition: p1 = java.awt.Point[x=1903,y=1913]
After getViewPosition : p2 = java.awt.Point[x=1903,y=1913]

Before setViewPosition: p1 = java.awt.Point[x=951,y=956]
After getViewPosition : p2 = java.awt.Point[x=951,y=956]

Before setViewPosition: p1 = java.awt.Point[x=1902,y=1912]  // Nur hier läuft's
After getViewPosition : p2 = java.awt.Point[x=1224,y=1305]  // schief!

Before setViewPosition: p1 = java.awt.Point[x=2448,y=2610]
After getViewPosition : p2 = java.awt.Point[x=2448,y=2610]

Before setViewPosition: p1 = java.awt.Point[x=4896,y=5220]
After getViewPosition : p2 = java.awt.Point[x=4896,y=5220]
```

Dieser Code wird übrigens ausgeführt, wenn der Anwender das Spielfeld zoomt, also die Pixel-Größe ändert, mit der die einzelnen Life Cells angezeigt werden.

Es wird dreimal herausgezoomt (Zeilen 2 bis 9), und anschließend dreimal wieder hineingezoomt (Zeilen 11 bis 18). Komisch ist, dass nur das erste Hineinzoomen (Zeile 11 + 12) nicht korrekt klappt, nachfolgend dann allerdings schon.

Ich hab schon mittlerweile keine Haare mehr auf'm Kopp vor lauter Haareraufen.  :shock:


----------



## maystorm (11. Mrz 2007)

Hier übigens mal ein Screenshot vom Programm in Aktion. Läuft schon recht anständig und vor allem performant. Was noch fehlt, sind das Einlesen und Speichern von Patterns, das freie Definieren eigener Regeln sowie kosmetisches Finetuning. Und halt das korrekt Zooming...  :cry: 




(Klicken für größeres Bild)


----------



## maystorm (12. Mrz 2007)

Da ich einfach nicht weiterkomme, habe ich hier ein kleines Testprogramm erstellt und würde mich freuen, wenn sich das jemand einmal anschauen könnte:


```
// TestSetViewPosition.java

import java.awt.*;
import javax.swing.*;

public class TestSetViewPosition
{
  private static int x = 10000, y = 10000;
  private static JPanel drawPane;
  private static JScrollPane scrollPane;

  public static void main(String[] args)
  {
    drawPane = new JPanel();
    drawPane.setPreferredSize(new Dimension(x, y));
    scrollPane = new JScrollPane(drawPane);
    
    JFrame appFrame = new JFrame("TestSetViewportPosition");
    appFrame.setLayout(new BorderLayout());
    appFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    appFrame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    appFrame.setBounds(200, 100, 600, 400);
    appFrame.setVisible(true);
    
    zoom(true);      // drawPane verkleinern
    zoom(false);      // und dreimal vergrößern
    zoom(false);
    zoom(false);
    
    System.exit(0);
  }
  
  // Verkleinert die drawPane um den Faktor 2, wenn 'shrink' gleich true,
  // ansonsten vergrößert um den Faktor 2
  static void zoom(boolean shrink)
  {
    x = shrink ? x / 2 : x * 2;
    y = shrink ? y / 2 : y * 2;

    drawPane.setPreferredSize(new Dimension(x, y));
    Dimension size = drawPane.getPreferredSize();
    System.out.println("getPreferredSize: size =  " + size);

    Point p1 = new Point(x/2, y/2);
    System.out.println("Before setViewPosition: p1 = " + p1);
    scrollPane.getViewport().setViewPosition(p1);

    Point p2 = scrollPane.getViewport().getViewPosition();
    System.out.println("After setViewPosition:  p2 = " + p2 + "\n");

    drawPane.revalidate();
  }
}
```

Es wird also zunächst ein JPanel mit Namen 'drawPane' mit den Ausmaßen 1000x1000 Pixeln in eine JScrollPane eingebettet. Anschließend wird drawPane einmal verkleinert und dreimal hintereinander vergrößert, und zwar in der Mehode 'zoom(boolean)' durch Halbieren bzw. Verdoppeln der Breite (x) und Höhe (y) mit setPreferredSize(). Die ViewPosition wird danach auf die Mitte der drawPane gesetzt durch die Koordinaten x/2 und y/2.

Es werden jeweils die relevanten Informationen bzgl. PreferredSize sowie der ViewPosition vor und nach Aufruf von setViewPosition() ausgegeben.

Erstaunlicherweise bekomme ich bei verschiedenen Testdurchläufen unterschiedliche Resultate! Hier sind einmal zwei solcher Durchläufe dokumentiert:


```
getPreferredSize: size =  java.awt.Dimension[width=5000,height=5000]
Before setViewPosition: p1 = java.awt.Point[x=2500,y=2500]
After setViewPosition:  p2 = java.awt.Point[x=2500,y=2500]

getPreferredSize: size =  java.awt.Dimension[width=10000,height=10000]
Before setViewPosition: p1 = java.awt.Point[x=5000,y=5000]
After setViewPosition:  p2 = java.awt.Point[x=5000,y=5000]

getPreferredSize: size =  java.awt.Dimension[width=20000,height=20000]
Before setViewPosition: p1 = java.awt.Point[x=10000,y=10000]
After setViewPosition:  p2 = java.awt.Point[x=9428,y=9648]

getPreferredSize: size =  java.awt.Dimension[width=40000,height=40000]
Before setViewPosition: p1 = java.awt.Point[x=20000,y=20000]
After setViewPosition:  p2 = java.awt.Point[x=20000,y=20000]
```

Hier sind p1 und p2 nur beim zweiten Vergrößern unterschiedlich.


```
getPreferredSize: size =  java.awt.Dimension[width=5000,height=5000]
Before setViewPosition: p1 = java.awt.Point[x=2500,y=2500]
After setViewPosition:  p2 = java.awt.Point[x=2500,y=2500]

getPreferredSize: size =  java.awt.Dimension[width=10000,height=10000]
Before setViewPosition: p1 = java.awt.Point[x=5000,y=5000]
After setViewPosition:  p2 = java.awt.Point[x=4424,y=4642]

getPreferredSize: size =  java.awt.Dimension[width=20000,height=20000]
Before setViewPosition: p1 = java.awt.Point[x=10000,y=10000]
After setViewPosition:  p2 = java.awt.Point[x=9424,y=9642]

getPreferredSize: size =  java.awt.Dimension[width=40000,height=40000]
Before setViewPosition: p1 = java.awt.Point[x=20000,y=20000]
After setViewPosition:  p2 = java.awt.Point[x=19424,y=19642]
```

Hier sind p1 und p2 sogar bei allen drei Vergößerungen unterschiedlich! Es scheint sporadisch zu sein, wann das Vergrößern klappt und wann nicht. Beim Verkleinern habe ich bisher keine Probleme festgestellt.

Kann hier jemand sich das mal angucken?

Tausendfachen Dank im voraus!

[EDIT]: Tippfehler in der Ausgabe korrigiert.


----------

