Button auf Null-Layout immer im Viewport

Hidiho,

ich befürchte ich bin in die verhängnisvollen Mühlen des Null-Layouts geraten.

Folgende Situation:
In einem JScrollPane sitzt ein JPanel mit Null-Layout. Auf diesem JPanel sitzen 2 Buttons links oben fürs Zoomen.
Wird der Viewport durch Scrollen verändert, sollen die Buttons ihre Position anpassen, sodass sie im neuen Viewport wieder links oben positioniert sind.
Dazu hab ich am Viewport des Scrollpane das Panel als ChangeListener registriert und immer wenn dieser aufgerufen wird, setze ich die Position der Buttons in Abhängigkeit des Rechtecks des Viewport neu, sodass sie für den Benutzer “die gleiche Position” beibehalten.

In der Praxis kommt es aber zu einem usnchönen Nebeneffekt. Während des Scrollens und somit beim Neupositionieren der Buttons “springen” die Buttons. Wird das Scrollen beendet haben sie die gewünschte Position. Nur während des Scrollens ist dieser Effekt leider zu erkennen.

Ich schätze mal das ganze hat mit dem Null-Layout und dem Neuzeichnen der Buttons zu tun. Gibts ne Möglichkeit das zu verhindern?

Hier ein KSKB:

import java.awt.Dimension;
import java.awt.Rectangle;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


public class Test extends JPanel implements ChangeListener{
	public static void main(String[] args){
		JFrame frame = new JFrame("test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		Test panel = new Test();
		JScrollPane scrollpane = new JScrollPane(panel);
		((JViewport) scrollpane.getViewport()).addChangeListener(panel);
		frame.add(scrollpane);
		
		frame.setSize(200, 200);
		frame.setVisible(true);
	}

	private JButton zoomIn;
	private JButton zoomOut;
	
	public Test(){
		
		setLayout(null);
		zoomIn = new JButton("+");
		zoomIn.setBounds(5, 10, 20, 20);
		zoomOut = new JButton("-");
		zoomOut.setBounds(5, 30, 20, 20);
		add(zoomIn);
		add(zoomOut);
		setSize(400, 400);
		setPreferredSize(new Dimension(400, 400));
		
	}
	
	@Override
	public void stateChanged(ChangeEvent e) {
		JViewport viewport = (JViewport) getParent();
		Rectangle viewRect = viewport.getViewRect();
		zoomIn.setBounds(viewRect.x + 5, viewRect.y + 10, 20, 20);
		zoomOut.setBounds(viewRect.x + 5, viewRect.y + 30, 20, 20);		
	}
}

wie du schon selbst erkannt hast -> nutze nicht das NullLayout

Setz doch die Buttons über das ScrollPane, dann bleiben die Buttons immer an der gleichen Stelle und du brauchst dich um so was nicht zu kümmern… Oder ist es unbedingt erforderlich, dass diese Buttons auf dem scrollbaren JPanel sitzen?

Da die Buttons nicht zur scrollable Komponent gehören, würde ich sie ebenfalls über dem JScrollPane anzeigen. (z.B. auf der GlassPane des Frames, falls diese nicht anderweitig benötigt wird)

Wenn ich die auf dem ScrollPane Null-Layout setze und die Buttons so hinzufüge, muss ich mich aber auch um das JPanel auf dem Scrollpane kümmern (Größe setzen etc), oder?

Die Idee mit dem GlassPane hört sich gut an. Bin mir aber nicht sicher, wie das funktionieren soll. Das GlassPane liegt doch komplett über dem Frame?! Das heißt das JPanel (auf dem später noch Komponenten hinzukommen und auf dem noch mit MouseListener hantiert werden soll, ist doch dann gar nicht mehr erreichbar oder?

Ich würde auch komplett auf das Null-Layout verzichten. Mit Buttons über das ScrollPane setzen meinte ich nicht auf das ScrollPane drauf, sondern oberhalb (ausserhalb, z.B. in den NORTH-Bereich des BorderLayouts des Frames) des ScrollPanes… Und dann ganz einfach das JPanel dem ScrollPane hinzufügen.

Die Möglichkeit hab ich natürlich auch durchgespielt, da ich in dem Frame allerdings nur Malen bzw. Animationen abspielen lassen will, habe ich mich aber dagegen entschieden. Die einziegen UI-Elemente sind eben die beiden Buttons zum Zoomen.

Hab mir grade das GlassPane näher angeschaut. Bei meinen ersten Tests scheints genau das zu sein, was ich brauche. Ich versuchs mal in mein Projekt zu intergrieren

edit:
Mitm GlassPane hats wunderbar funktioniert.
Danke für eure Antworten