"Vergrößern" eines Labels wird vom Layout nicht erkannt

Hallöchen,

ich habe ein JLabel dass sich selbst einen runden Rahmen zeichnet, quasi ein rundes JLabel. Über einen JSpinner vergrößere bzw. verkleinere ich die “Dicke” des Kreises.
Wie man auf den Beispielbildern sehen kann, führt eine Vergrößerung des runden Rahmens dazu, dass der neue dickere Rahmen nicht mehr ganz angezeigt wird, da das Label offenbar keinen Platz mehr im Layout hat.
Das runde JLabel befindet sich in einem JPanel mit standarmäßigem FlowLayout und dieses JPanel wiederum in einem JPanel mit CardLayout.

Die Vergrößerung des Kreises realisier ich, indem ich dem JLabel die neue Dicke übergebe, mit diesem Wert wird ein BasicStroke initialisiert und der wiederum wird in paintBorder vom Graphics2D Objekt gesetzt, mit dem auch der Kreis gezeichnet wird.

Ich hab schon versucht mit höheren Werten für den Rahmen, auch die zurückgegebene preferredSize vom Label zu vergrößern, aber das führt dazu, dass das Label ein bisschen springt, da es durch die neue Größe wohl eine neue Position bekommt im Panel bekommt.

Ich hätte aber gerne, dass sich der Rahmen vergrößern lässt, und das JLabel seine Position beibehält, nur eben den dickeren Kreis zeichnet.

Ohne code kann man da nicht viel dazu sagen, ausser hast du revalidate am Container gemacht?

Hab ein kurzes KSKB zusammengebastelt.

public class Preview {
	public static void main(String[] args){
		new Preview();
	}
	
	
	private JPanel previewPanel;
	private JSpinner spinner;
	private RoundedJLabel rjl;
	public Preview(){
		JFrame frame = new JFrame("KSKB");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLayout(new FlowLayout());
		
		previewPanel = new JPanel();
		Dimension d = new Dimension(150, 150);
		previewPanel.setPreferredSize(d);
		previewPanel.setMinimumSize(d);
		previewPanel.setMaximumSize(d);
		previewPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
		CardLayout cl = new CardLayout();
		previewPanel.setLayout(cl);
		
		JPanel panel = new JPanel();
		ImageIcon imageLabel = new ImageIcon(new ImageIcon("union.png").getImage().
				getScaledInstance(100, 100, Image.SCALE_SMOOTH));
		rjl = new RoundedJLabel(imageLabel);
		rjl.setBackground(Color.RED);
		panel.add(rjl,"label");
		cl.show(previewPanel, "label");
		
		previewPanel.add(panel);
		frame.add(previewPanel, BorderLayout.CENTER);
		
		SpinnerModel spinnerModel = new SpinnerNumberModel(1, 1, 7, 1);
		spinner = new JSpinner(spinnerModel);
		spinner.addChangeListener(new ChangeListener(){
			
			@Override
			public void stateChanged(ChangeEvent e){
				rjl.setBorderWidth(((SpinnerNumberModel) spinner.getModel()).
						getNumber().intValue());
				JPanel parent = (JPanel) rjl.getParent();
				parent.validate();
				parent.revalidate();
			}
		});
		
		frame.add(spinner, BorderLayout.PAGE_END);
		
		frame.pack();
		frame.setVisible(true);
	}
}





class RoundedJLabel extends JLabel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Shape shape;
	private int index;
	private BasicStroke stroke;
	//private int borderWidth;

	
	public RoundedJLabel(Icon icon){
		super(icon);
		init();
	}
		
	public void init(){
		stroke = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);

		Dimension size = getPreferredSize();
		size.width = size.height = Math.max(size.width, size.height);
		setPreferredSize(size);
	}
	
	
	public void setBorderWidth(int width){
		stroke = new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
		
		repaint();
	}
	
	@Override
	public void paint(Graphics g){
		g.setColor(this.getParent().getBackground());
		g.fillRect(0, 0, getSize().width, getSize().height);
		super.paint(g);
	}

	@Override
	protected void paintComponent(Graphics g) {
		g.setColor(getBackground());
		g.fillOval(0, 0, getSize().width, getSize().height);
		super.paintComponent(g);
	}

	@Override
	protected void paintBorder(Graphics g) {
		g.setColor(getForeground());
		Graphics2D graph = (Graphics2D) g;
		graph.setStroke(stroke);
		graph.drawOval(0, 0, getSize().width, getSize().height);
	}

	@Override
	public boolean contains(int x, int y) {
		if (shape == null || !shape.getBounds().equals(getBounds())) {
			shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());
		}
		return shape.contains(x, y);
	}
}

validate() und revalidate() hab ich versucht, leider ohne Erfolg.
Was mir noch aufgefallen ist: Obwohl ich die Größe vom JPanel previewPanel von Hand setze, nimmt das darin enthaltende JPanel (das auch das Label enthält) keine mittige Position darin ein. Kommt mir auch grade komisch vor.
Aber seht selbst.

edit:
Ich denke ich hab die Ursache gefunden. Durch die größere Kreisdicke will meine JLabel-Klasse irgendwann über ihre Größe hinausmalen, da sie im Grunde immer noch rechtecking ist, ich sie aber nur kreiförmig bemale. Das heißt ich müsste die Größe neu berechnen und setzen.
Sowas hab ich vorher auch schon versucht, dann kommts nämlich wieder zu dem Effekt, dass das JPanel (das das JLabel beinhaltet) nicht mittig in auf dem previewPanel liegt und es so aussieht als würde das JLabel beim vergrößern ein bisschen “springen”

Hab mir nicht genau angeschaut, wie Du die Komponenten inneinander verschachtelst, aber es sieht so aus, dass die Bild Komponente in einem FlowLayout liegt. Hier ist die PreferredSize ganz wichtig und da Du selbst zeichnest musst der Komponene bzw. muss die Komponente dem LayoutManager auch die korrekte PreferredSize mitteilen.

löschen, ich sollte schlafen gehen

Ich würde sagen, du solltest nicht von JLabel sondern von JComponent erben und die paintComponent Methode ganz selber machen. Dann kannst du gleich in der paintComponent deinen Rand Zeichnen und bei einer Änderung der Rahmendicke die Größenberechnung richtig machen. Ich glaube, wenn du deinem Label eine größere Preferred Size gibst, sieht der Border davon nichts. Daher, der paintComponent Bereich wird vergrößert und der Border wieder abgeschnitten.
Anstatt der super Aufrufe, zeichne es lieber gleich selber.

[QUOTE=bERt0r]Ich würde sagen, du solltest nicht von JLabel sondern von JComponent erben und die paintComponent Methode ganz selber machen. Dann kannst du gleich in der paintComponent deinen Rand Zeichnen und bei einer Änderung der Rahmendicke die Größenberechnung richtig machen. Ich glaube, wenn du deinem Label eine größere Preferred Size gibst, sieht der Border davon nichts. Daher, der paintComponent Bereich wird vergrößert und der Border wieder abgeschnitten.
Anstatt der super Aufrufe, zeichne es lieber gleich selber.[/QUOTE]

Interessante Idee, werde ich mal in Erwägung ziehen

Was mir noch eingefallen ist:

        g.fillRect(0, 0, getSize().width, getSize().height);```

Das da oben kannst du dir auch sparen wenn du die Komponente setOpaque(false) machst (wie JLabel es von Haus aus ist).