Swing JViewport Problem

Bastler

Mitglied
Heyho,
ich bin grad dabei ein Spiel zu basteln. Es besitzt eine Klasse (extend JComponent) für die Map, deren Größe in ihrem Konstruktor festgelegt wird.
Im JFrame Konstruktor wird ein JViewport erstellt, und ihm die Map als View übergeben.
Ich habe einen KeyListener mit eingebaut, der per setViewPosition(...) die Map scrollen sollte.

Das Problem ist, dass er die Map zwar scrollt, jedoch die neu aufgetauchten Bereiche der Map nicht zeichnet.
Mir ist beim Debugversuch aufgefallen, dass die Größe der Map immer der Größe des Viewports angepasst wird, sodass es logischerweise beim scrollen nichts mehr zu zeichnen gibt Oo...
Ich habe es auch mit einem ScrollPane versucht. Bei dem sind die Scrollbalken dann so groß, dass ebenfalls kein Scrollen mehr möglich ist (selber Grund).

Egal ob ich die Größe der Map vor dem zufügen zum Viewport einstelle, oder hinterher, oder per setViewSize, wird beim laden des Programms immer wieder der Viewportgröße angepasst.

Gibt es da einen einfachen Fehler/Grund, oder etwas das ich beachten muss, damit das nicht passiert?

Java:
public class Frame extends JFrame implements KeyListener{
	Welt welt; // die Map, die grad im Fenster angezeigt wird, evtl. auch für
				// Kampfmodi etc. verwenden
	Bottom bottom; // die Leiste unter der Map, für Buttons, Icons etc.
	JViewport VP;
	JScrollPane ScP;

	public Frame(String title) {
		super(title);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Programm wird beendet
														// wenn Fenster
														// geschlossen wird

		// Karte
		welt = new Welt(50, 50);

		// Objekt für die Anzeige des Kartenausschnitts
		VP = new JViewport();
		VP.setView(welt);
		VP.add(welt);
		VP.setPreferredSize(new java.awt.Dimension(700, 700));
		//VP.setViewSize(new java.awt.Dimension(1750, 1750));
		System.out.println(VP.getViewSize());
		
		//VP.setAutoscrolls(true);
		//VP.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);

		// Bottomleiste
		bottom = new Bottom();

		// zweigeteilter Fensterinhalt
		JSplitPane SP = new JSplitPane(JSplitPane.VERTICAL_SPLIT, VP, bottom);
		SP.setBorder(null);
		SP.setResizeWeight(1.0); // beim Vergrößern wird nur die Welt vergrößert
		SP.setOneTouchExpandable(false);
		SP.setDividerSize(0);

		//setMap(welt);
		setContentPane(VP);
		addKeyListener(this);

		pack();
		validate();
		setVisible(true);
		System.out.println(VP.getViewSize());
		System.out.println(welt.getSize());
	}...

class Welt extends JComponent implements Karte{

	private Feld[][] _Spielfeld;
	private int _hoehe;
	private int _breite;

	/**
	 * Constructor for objects of class Welt
	 */
	public Welt() {
		_hoehe = 10;
		_breite = 10;
		setPreferredSize(new Dimension(35 * _breite, 35 * _hoehe));
		setSize(35 * _breite, 35 * _hoehe);
		_Spielfeld = new Feld[_breite][_hoehe];
		
		for (int i = 0; i < _breite; i++) {
			for (int j = 0; j < _hoehe; j++) {
				_Spielfeld[i][j] = new Feld();
			}
		}
	}

	/**
	 * konstruktor für beliebig große welten
	 */
	public Welt(int x, int y) {
		_hoehe = x;
		_breite = y;
		setSize(35 * _breite, 35 * _hoehe);
		_Spielfeld = new Feld[_breite][_hoehe];

		for (int i = 0; i < _breite; i++) {
			for (int j = 0; j < _hoehe; j++) {
				_Spielfeld[i][j] = new Feld();
			}
		}
		for (int k = 0; k < 6; k++) {
			_Spielfeld[k][0].setTerrain(new Berg());
			_Spielfeld[k][1].setTerrain(new Berg());
			_Spielfeld[k][2].setTerrain(new Wald());
			_Spielfeld[k][3].setTerrain(new Wald());
			_Spielfeld[k][19].setTerrain(new Wald());
		}
	}

	public void paint(Graphics g) {
		for (int i = 0; i < _breite; i++) {
			for (int j = 0; j < _hoehe; j++) {
				java.awt.Graphics2D g2d = (Graphics2D) g;
				_Spielfeld[i][j].paint(i, j, g2d);
			}
		}
	}...
 
Zuletzt bearbeitet:
Ich habe noch ein bisschen weiter probiert.
Auch durch setViewPosition wird die Größe der Karte wieder auf die des Viewports gesetzt.
Wenn ich danach per setViewSize die Sollgröße der Map wiederherstelle, resett er die ViewPosition dafür wieder...
Aber das passiert nicht direkt nach dem setViewSize, sondern mit einiger Verzögerung, (per System.out getestet) also wahrscheinlich durch das Neuzeichnen.
Hier nochmal der Debug-Code des Frames, falls es jemand selber sehen will:
Java:
public class Frame extends JFrame implements KeyListener{
	Welt welt; // die Map, die grad im Fenster angezeigt wird, evtl. auch für
				// Kampfmodi etc. verwenden
	Bottom bottom; // die Leiste unter der Map, für Buttons, Icons etc.
	JViewport VP;
	JScrollPane ScP;

	public Frame(String title) {
		super(title);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Programm wird beendet
														// wenn Fenster
														// geschlossen wird

		// Karte
		welt = new Welt(50, 50);

		// Objekt für die Anzeige des Kartenausschnitts
		VP = new JViewport();
		VP.setView(welt);
		VP.add(welt);
		VP.setPreferredSize(new java.awt.Dimension(700, 700));
		//VP.setViewSize(new java.awt.Dimension(1750, 1750));
		System.out.println(VP.getViewSize());
		
		//VP.setAutoscrolls(true);
		//VP.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);

		// Bottomleiste
		bottom = new Bottom();

		// zweigeteilter Fensterinhalt
		JSplitPane SP = new JSplitPane(JSplitPane.VERTICAL_SPLIT, VP, bottom);
		SP.setBorder(null);
		SP.setResizeWeight(1.0); // beim Vergrößern wird nur die Welt vergrößert
		SP.setOneTouchExpandable(false);
		SP.setDividerSize(0);

		//setMap(welt);
		setContentPane(VP);
		addKeyListener(this);

		pack();
		validate();
		setVisible(true);
		System.out.println(VP.getViewSize());
		VP.setViewSize(new java.awt.Dimension(1750, 1750));
		repaint();
		VP.setViewSize(new java.awt.Dimension(1750, 1750));
		System.out.println(VP.getViewSize());
		
	}
	
	public void setMap(Welt w) {
		welt = w;
		VP.setView(w);
		w.repaint();
	}

	public void keyPressed(KeyEvent e) {
		int k = e.getKeyCode();
		if (k==37) {
			VP.setViewPosition(new Point(VP.getViewPosition().x-35,VP.getViewPosition().y));
			System.out.println(VP.getViewSize());
			VP.setViewSize(new java.awt.Dimension(1750, 1750));
			System.out.println(VP.getViewSize());
			System.out.println(VP.getViewPosition());
			//welt.repaint(10,-VP.getViewPosition().x,-VP.getViewPosition().y,VP.getExtentSize().width, VP.getExtentSize().height);
		}
		if (k==38) {
			VP.setViewPosition(new Point(VP.getViewPosition().x,VP.getViewPosition().y-35));
			System.out.println(VP.getViewSize());
			VP.setViewSize(new java.awt.Dimension(1750, 1750));
			System.out.println(VP.getViewSize());
			System.out.println(VP.getViewPosition());
			//VP.repaint(10,0,0,VP.getExtentSize().width, VP.getExtentSize().height);
		}
		if (k==39) {
			VP.setViewPosition(new Point(VP.getViewPosition().x+35,VP.getViewPosition().y));
			System.out.println(VP.getViewSize());
			VP.setViewSize(new java.awt.Dimension(1750, 1750));
			System.out.println(VP.getViewSize());
			System.out.println(VP.getViewPosition());
			//VP.repaint(10,0,0,VP.getExtentSize().width, VP.getExtentSize().height);
		}
		if (k==40) {
			VP.setViewPosition(new Point(VP.getViewPosition().x,VP.getViewPosition().y+35));
			System.out.println(VP.getViewSize());
			VP.setViewSize(new java.awt.Dimension(1750, 1750));
			System.out.println(VP.getViewSize());
			System.out.println(VP.getViewPosition());
			//VP.repaint(10,0,0,VP.getExtentSize().width, VP.getExtentSize().height);
		}
	}

	public void keyReleased(KeyEvent e) {}

	public void keyTyped(KeyEvent e) {}
}
 
Du solltest auf keinen Fall deine Klasse so benennen, wie die Klassen aus dem JDK.
Das kann zu Problemen führen.

Warum benutzt du eigentlich keine JScrollPane?
 
Wie erwähnt habe ich es auch mit einem ScrollPane probiert, aber das Problem ist dasselbe und außerdem wollte ich keine Scrollbalken dabei haben. Ich finde sowieso, dass das ScrollPane nur unnötiger Ballast gegenüber einem einfachen Viewport ist...wenn es wenigstens funktionieren würde^^.

Aber das mit dem Klassennamen ist ne gute Idee, habe ich garnicht dran gedacht, dass das zu Problemen führen könnte.
Ich schau mal ob das was bringt.

€: Ok, es hat leider nichts an der Problematik geändert.
 
Zuletzt bearbeitet:
Ok, ich habe es gerade selber gelöst. Ich habe nur in einem der Konstruktoren das "setPreferredSize" eingebaut, jedoch den anderen benutzt.
Ich verstehe zwar nicht, wieso ein setPreferredSize nötig ist, wenn setSize stattdessen verwendet wurde, aber nun weiß ich, DASS es so ist 😉.
Trotzdem danke für die Antwort.
 

Neue Themen


Zurück
Oben