preferred size abhängig von Fenstergröße berechnen

hupfdule

Top Contributor
Hallo,

ich möchte die preferredSize einer Komponente abhängig von der Fenstergröße berechnen, in der sich die Komponente befindet. Dazu habe ich getPreferredSize() überschrieben

Java:
    @Override
    public Dimension getPreferredSize(){
      final Dimension prefSize= super.getPreferredSize();

      //calculate new preferred size based on the current preferred size
      prefSize.setSize(this.getWidth(), this.getWidth() / PREF_RATIO);

      return prefSize;
    }

Wie zu sehen ist, beziehe ich mich hier einfach auf die aktuelle preferred size und berechne daraus die neue gewünschte (wichtig ist halt, dass das Seitenverhältnis korrekt bleibt). Bei langsamem manuellem Vergrößern/Verkleinern des Fensters klappt das auch halbwegs. Macht man das zu schnell oder benutzt gar Maximize/Unmaximze des Windowmanagers, dann klappts halt nicht mehr, da die preferredSize der Komponente abgefragt wird, bevor die Änderung der Fenstergröße stattfindet. Zu dem Zeitpunkt kenn ich natürlich nur die alte Größe.

Was gibt es denn für sinnvolle Wege, mein Ziel zu erreichen, dass ich die preferredSize immer abhängig von der endgültigen Fenstergröße mache?
 
Zuletzt bearbeitet:
Sollte das nicht eher ein LayoutManager übernehmen? Z. B. FormLayout hat Möglichkeiten, die Größe dynamisch zu verändern und gleichzeitig auch minimale oder maximale Größem mit anzugeben.
 
Es geht mir ja eben nicht um minimale und maximale Größen, sondern um das Seitenverhältnis der Komponente (was wiederum abhängig von deren Inhalt ist). Der LayoutManager kann es nicht wissen, er soll sich auf die preferredSize der Komponente beziehen. Und diese will ich ja verändern.
 
Ja, das Problem ist wohl (wie du schon angedeutet hast) dass die PreferredSize erst dann richtig berechnet werden kann, wenn sie schon berechnet wurde - das Layout "hinkt immer einen Größenänderungsschritt hinterher". Das merkt man teilweise auch bei anderen LayoutManagern (auch den schon vorhandenen, FlowLayout z.B.)
Du solltest ggf. trotzdem mal überlegen, ob das nicht mit einem LayoutManager gemacht werden kann: Ich hatte mal ein "AspectLayout" zusammengehackt ( http://www.java-forum.org/awt-swing-swt/89781-maximale-quadratische-groesse.html#post568106 ), was sich erstmal nur auf EINE Component bezieht. Wenn das für mehrere funktionieren soll, wird's natürlich schwierig (bis "unmöglich", d.h. man muss ggf. Kompromisse finden), aber vielleicht kann man ja das "Aspect Ratio" und ggf. irgendwelche "weights" (für die Kompromisse) in den Layout-Constraints unterbringen - sofern es nicht schon einen RICHTIGEN LayoutManager gibt, der das alles kann (es gibt so viele, ich hab' da nicht so den Überblick - mehr als Box, Border und Grid braucht man ja kaum 😉 )
 
Noch so ein Gedanke: Die Komponenten kriegen ja einen Resize-Event. Diesen könnte man abfangen und die Preferred-Size auf die kleinere Seitenlänge setzen:

Java:
    public void componentResized(ComponentEvent e) {
        //hier die entsprechende Logik einbauen.            
    }

Könnte aber auch sein, dass das immer wieder aufgerufen wird und hängt.
 
Falls ich das richtig verstanden habe, geht es nicht um relative Größen zu anderen Components, sondern wirklich NUR um das Seitenverhältnis EINER Component.
 
Hallo,

die Componente sollte ihre Container "kennen", wenn sie ihre preferredSize in Abhängigkeit von ihrem Container setzen soll:
Java:
import java.awt.Color;
import java.awt.Dimension;

import javax.swing.JComponent;
import javax.swing.JPanel;

public class RatioComponent extends JPanel {

	private double PREF_RATIO = 4.0 / 3.0;
	private JComponent container;

	// hier lernt sie ihren Container kennen
	public RatioComponent(JComponent container) {
		// dass man was sieht :-)
		this.setBackground(Color.MAGENTA);
		this.container = container;
	}

	@Override
	public Dimension getPreferredSize() {
		Dimension result;

		// nur zur Sicherheit oder für GUI-Builder
		if (container != null) {
			if (container.getWidth() > container.getHeight()) {
				result =
						new Dimension(container.getHeight(),
								(int) (container.getHeight() / PREF_RATIO));
			}
			else {
				result =
						new Dimension(container.getWidth(),
								(int) (container.getWidth() / PREF_RATIO));
			}
		}
		else
			result = new Dimension(300, 200);
		return result;
	}
}

Grüße
Momolin
 
Falls ich das richtig verstanden habe, geht es nicht um relative Größen zu anderen Components, sondern wirklich NUR um das Seitenverhältnis EINER Component.

Korrekt, daher wird mir ein vorgefertigter LayoutManager da nicht helfen.


Du solltest ggf. trotzdem mal überlegen, ob das nicht mit einem LayoutManager gemacht werden kann: Ich hatte mal ein "AspectLayout" zusammengehackt (http://www.java-forum.org/awt-swing-swt/89781-maximale-quadratische-groesse.html#post568106), was sich erstmal nur auf EINE Component bezieht.

Das fänd ich eigentlich etwas viel für meinen Zweck, scheint aber ein guter Ansatzpunkt zu sein. Sollte ich mal überlegen, ob ich das nutze.

Noch so ein Gedanke: Die Komponenten kriegen ja einen Resize-Event. Diesen könnte man abfangen und die Preferred-Size auf die kleinere Seitenlänge setzen:

Stimmt. Daran hatte ich nicht gedacht. So funktioniert es auch. Und es ergibt keine Endlosschleife. 🙂
Da das so gut funktioniert, werde ich diesen Weg dem eigenen LayoutManager vorziehen.

Vielen Dank euch beiden!
 
Hallo,

Stimmt. Daran hatte ich nicht gedacht. So funktioniert es auch. Und es ergibt keine Endlosschleife. 🙂
Da das so gut funktioniert, werde ich diesen Weg dem eigenen LayoutManager vorziehen.
Vielen Dank euch beiden!

es gibt zwar keine Endlosschleife, aber sehr schnell eine winzige Componente. Mit jedem "kleiner machen der Dimension" löst man ja das ResizeEvent aus und macht dann die Componente wieder kleiner - solange bis sie nicht mehr da ist.
 
es gibt zwar keine Endlosschleife, aber sehr schnell eine winzige Componente. Mit jedem "kleiner machen der Dimension" löst man ja das ResizeEvent aus und macht dann die Componente wieder kleiner - solange bis sie nicht mehr da ist.

Nein, passiert nicht. Ich wüsste auch gar nicht wieso. Das Problem wäre höchstens, wenn das Setzen der Dimension wiederum einen resize-Event auslösen würde, was offensichtlich nicht der Fall ist.

So habe ich jetzt umgesetzt:
Java:
    this.addComponentListener(new ComponentAdapter() {
          @Override
          public void componentResized(ComponentEvent e) {
              final Dimension d= getPreferredSize();
              setSize(d);
              revalidate();            
          }
        });

    @Override
    public Dimension getPreferredSize(){
      final Dimension prefSize= super.getPreferredSize();
 
      //calculate new preferred size based on the current preferred size
      prefSize.setSize(this.getWidth(), this.getWidth() / PREF_RATIO);
 
      return prefSize;
    }

Zu deiner Idee mit der RatioComponent: Ich habe es nicht ausprobiert, aber mir scheint das genau das selbe Problem zu sein, wie bei der Lösung in meinem ersten Post (also ohne das resize-Event zu beachten). Ich bin immer eine Größenänderung hinterher.
 
Naja, es ist ewas hakelig, man müßte sich da schon nochmal SEHR genau Gedanken drüber machen, aber... Durch das 'validate' wird das Layout neu angestoßen. Dadurch händert sich vielleicht (vielleicht auch nicht) die Größe der Component. Dadurch wird die PreferredSize geändert und das validate aufgerufen...
Da kann schon was schiefgehen. Ich hatte, als das vorgeschlagen wurde, auch gleich irgendwelche "Race Conditions" im Hinterkopf, GANZ grob: Dass er irgendein Aspect-Ratio hat, durch das er die Component 100 Pixel breit macht, dann die oben angedeutete Kette durchläuft und dabei die Component 99 Pixel breit macht, dann wieder die Kette durchläuft und sie wieder 100 breit macht.......
Es KANN sein, dass dieser Fall (bei dir, oder allgemein) nicht auftreten kann, aber das sollte man wirklich genau durchdenken...
 

Zurück
Oben