Text in Komponenten anpassen

Ich hab ein kleines Programm, welches im Moment mit dem BorderLayout arbeitet. Es besteht im Moment aus 3 Komponenten:

  • North (Kategorie und Punkte)
  • Center (Spielbereich)
  • South (Statistiken)

Im Northbereich ist wiederum ein Panel, welches ebenfalls das BorderLayout hat, wobei dort die Kategorie im Centerbereich und die Punkte im EAST- Bereich sind (Beides JLabel). So weit, so gut,… alles funktioniert.

Nun kann der Anwender verschiedene Schriftarten, Größen etc. in einem extra Bereich einstellen. Das heißt, es kann passieren, dass die Überschrift, wenn es zum Beispiel ein „Satz“ ist, mit „…“ abgekürzt wird, da er nicht mehr in das Label passt.

Nun bin ich mal meine Möglichkeiten durchgegangen und bin mir nicht so sicher, welche ich davon auswählen sollte oder ob es vll. noch eine ganz andere gibt.

A: Ich prüfe, ob die Labelgröße für den Text reicht und ändere dann die Größe des Fonts runter, bis es passt.

B: Ich prüfe erst und zeichne den Text dann selber mit z.b. einem Umbruch und kleinerer Schrift.

Wie würdet ihr sowas regeln, wäre dankbar für jede Hilfe :slight_smile:

ps. das prüfen der Größe mache ich bisher übrigens mit: http://docs.oracle.com/javase/tutorial/2d/text/measuringtext.html

Probier mal ein revalidate() auf dein Panel

Soooo tut mir leid war etwas beschäftigt,… nun ich hab mal ein kleines Beispiel geschrieben um meine Probleme evtl. besser zu erklären. (Es ist noch eins dazu gekommen)

Hier erstmal der Code:

	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(500, 500);
		frame.add(createNorthPanel(), BorderLayout.NORTH);
		frame.add(createCenterPanel(), BorderLayout.CENTER);
		frame.add(createSouthPanel(), BorderLayout.SOUTH);
		frame.setVisible(true);
		
	}

	public static JPanel createNorthPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		JLabel lbl = new JLabel("Der Titel wird nun nicht mehr ganz angezeigt");
		Font f = lbl.getFont();
		lbl.setFont(f.deriveFont(50.0f));
		panel.add(lbl,BorderLayout.CENTER);

		panel.add(new JLabel("Anderes Panel"),BorderLayout.EAST);
		return panel;
	}

	public static JPanel createSouthPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new FlowLayout());
		for(int i = 0; i < 10 ; i++){
			panel.add(new JLabel("TEXT TEXT " + i));
		}
		return panel;
	}
	
	public static JPanel createCenterPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		panel.add(new JLabel("CenterPanelNorth"),BorderLayout.NORTH);
		panel.add(new JLabel("CenterPanelCenter"),BorderLayout.CENTER);
		panel.add(new JLabel("CenterPanelEast"),BorderLayout.EAST);
		return panel;
	}

}```

Problem1 ("Überschrift im NorthPanel"):

Oben habe ich ja meine Überschrift drin. Diese Überschrift kann in einem gesonderten Bereich festgelegt werden und auch ihre Schriftgröße bestimmt werden. Nun will ich, dass wenn die Überschrift z.b. nicht ganz passt, dass ich die Größe bis zu einem bestimmten Limit automatisch runtersetzt wird. Die Frage ist nur, wie ich das am Besten mache oder ob es dafür schon etwas fertiges gibt. 

Problem2 ("Flowlayout im SouthPanel"):

Normal sollte ein Umbruch im Southpanel stattfinden, wenn die Label nicht mehr in die Zeile passen, leider wird dieser nicht mehr durchgeführt, daher gehe ich mal davon aus, dass es daran liegt, dass sich das Flowlayout in einem anderen Layout/Panel befindet. Ich weiß dazu gabs mal nen Thread im alten Forum aber leider finde ich den nicht mehr.  

€DIT: Problem 2 ist behoben (Ich pack den Beitrag mal in den Spoiler, wir wollen ja keine Werbung fürs alte Forum machen :P, der Beitrag war von The_S ):

Extended-Flowlayout
[spoiler]
Hier eine kleine Überarbeitung des FlowLayouts:

Das ExtendedFlowLayout gibt seine Höhe nicht wie das normale FlowLayout immer mit der Höhe der größten Component an, sondern gibt die reale Höhe zurück, falls nicht alle Components in eine Zeile passen.

```public class ExtendedFlowLayout extends FlowLayout {
 
    private static final long serialVersionUID = 1L;
   
    public ExtendedFlowLayout() {
        super();
    }
 
    public ExtendedFlowLayout(int arg0, int arg1, int arg2) {
        super(arg0, arg1, arg2);
    }
 
    public ExtendedFlowLayout(int arg0) {
        super(arg0);
    }
 
    public Dimension preferredLayoutSize(Container target) {
       
        synchronized (target.getTreeLock()) {
            int width = 0;
            int height = 0;
            Dimension dim = new Dimension(0, 0);
            Insets insets = target.getInsets();
            int nmembers = target.getComponentCount();
            boolean firstVisibleComponent = true;
            for (int i = 0 ; i < nmembers ; i++) {
                Component m = target.getComponent(i);
                if (m.isVisible()) {
                    Dimension d = m.getPreferredSize();
                    if (firstVisibleComponent) {
                        firstVisibleComponent = false;
                        width = d.width;
                        height = d.height;
                    }
                    else {
                        if (width + d.width > target.getWidth() - insets.left - insets.right - getHgap() * 2) {
                            dim.height += height + getVgap();
                            dim.width = Math.max(dim.width, width);
                            width = d.width;
                            height = d.height;
                        }
                        else {
                            width += d.width + getHgap();
                            height = Math.max(d.height, height);
                        }
                    }
                }
            }
            dim.height += height + getVgap() * 2 + insets.top + insets.bottom;
            dim.width = Math.max(dim.width, width) + getHgap() * 2 + insets.left + insets.right;
            return dim;
        }
    }
   
    public Dimension minimumLayoutSize(Container target) {
       
        synchronized (target.getTreeLock()) {
            int width = 0;
            int height = 0;
            Dimension dim = new Dimension(0, 0);
            Insets insets = target.getInsets();
            int nmembers = target.getComponentCount();
            boolean firstVisibleComponent = true;
            for (int i = 0 ; i < nmembers ; i++) {
                Component m = target.getComponent(i);
                if (m.isVisible()) {
                    Dimension d = m.getMinimumSize();
                    if (firstVisibleComponent) {
                        firstVisibleComponent = false;
                        width = d.width;
                        height = d.height;
                    }
                    else {
                        if (width + d.width > target.getWidth() - insets.left - insets.right - getHgap() * 2) {
                            dim.height += height + getVgap();
                            dim.width = Math.max(dim.width, width);
                            width = d.width;
                            height = d.height;
                        }
                        else {
                            width += d.width + getHgap();
                            height = Math.max(d.height, height);
                        }
                    }
                }
            }
            dim.height += height + getVgap() * 2 + insets.top + insets.bottom;
            dim.width = Math.max(dim.width, width) + getHgap() * 2 + insets.left + insets.right;
            return dim;
        }
    }
}```

``` public static void main(String[] args) {
       
        JFrame frame = new JFrame("ExtendedFlowLayout vs. FlowLayout");
        JPanel normalFlow = new JPanel();
        JPanel extendedFlow = new JPanel();
        JLabel n1 = new JLabel("Das ist ein Label mit viel Text (FL)");
        JLabel n2 = new JLabel("Das ist noch ein Label mit viel Text (FL)");
        JLabel n3 = new JLabel("Und das ist ein drittes Label mit viel Text (FL)");
        JLabel e1 = new JLabel("Das ist ein Label mit viel Text (EFL)");
        JLabel e2 = new JLabel("Das ist noch ein Label mit viel Text (EFL)");
        JLabel e3 = new JLabel("Und das ist ein drittes Label mit viel Text (EFL)");
       
        n1.setBackground(Color.YELLOW);
        e1.setBackground(Color.YELLOW);
        n2.setBackground(Color.RED);
        e2.setBackground(Color.RED);
        n3.setBackground(Color.GREEN);
        e3.setBackground(Color.GREEN);
 
        n1.setOpaque(true);
        n2.setOpaque(true);
        n3.setOpaque(true);
        e1.setOpaque(true);
        e2.setOpaque(true);
        e3.setOpaque(true);
       
        frame.setLayout(new BorderLayout());
        normalFlow.setLayout(new FlowLayout(FlowLayout.LEFT));
        extendedFlow.setLayout(new ExtendedFlowLayout(ExtendedFlowLayout.LEFT));
       
        frame.add(normalFlow, BorderLayout.NORTH);
        frame.add(extendedFlow, BorderLayout.SOUTH);
        frame.add(new JLabel("Platzhalter"), BorderLayout.CENTER);
       
        normalFlow.add(n1);
        normalFlow.add(n2);
        normalFlow.add(n3);
       
        extendedFlow.add(e1);
        extendedFlow.add(e2);
        extendedFlow.add(e3);
       
        frame.setSize(450, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }```

[/spoiler]


Ich hoffe ich konnte nun ein bisschen besser darlegen, was ich will :)

Schönes WE noch ;)

Zum 2.: Da hab’ ich mir auch schon eine Watsch’n geholt, aber: http://www.java-blog-buch.de/dflowlayout-mit-zeilenumbruch/ :slight_smile:

Zum 1.: Da geht es jetzt „nur noch“ darum, dass man den Text in einem Label über die Änderng der Schriftgröße automatisch so verkleinert, dass er immer reinpasst (also nie die „…“ erscheinen)? Da hatte ich auch schonmal überlegt. Schon den Punkt zu bestimmen, wo die „…“ erscheinen, ist IMHO frickelig, und bei meinen Überlegungen für eine automatische Anpassung bin ich nicht über ~„irgendwas mit einer binären Suche“ hinausgekommen… Falls jemand dafür eine elegante Lösung hat, würde mich die auch interessieren. Wenn nicht, versuch’ ich vielleicht bei Gelegenheit mal, da was zu basteln…

#1 Dürfte mit Hilfe der Klasse FontMetrics hinzukriegen sein. Es sei denn, du willst sowieso, dass alle Komponenten größer werden wenn sich das Fenster vergrößert, dann wärs auch möglich die paintComponent von deinem ContentPane zu überschreiben und dirt einen Zoom einzufügen.

Mein Mantra zu diesem Thema: Fonts sind immer kacke.

Insbesondere gäbe es, um das Ziel eines “Bereichsfüllenden Schriftzuges” zu erreichen, mindestens 3 Ansätze:

  1. Man setzt einen Font mit passender Size. Da ist die Schwierigkeit, dass man ggf. etliche Fonts erstellen und für jeden einzelnen die Größe des Textes messen müßte, um den Font mit der richtigen Größe zu finden - die dann aber ggf. sehr ungenau wäre.
  2. Man verwandelt den Text in ein Shape (über GlyphVector & Co) und skaliert das dann einfach passend
  3. Man verwendet Graphics2D#scale mit einer Skalierung, durch die bei einem “normalen g#drawString-Aufruf” der Text in der richtigen Größe rauskommt. Ich hatte mal einen Test gemacht (den ich bei Gelegenheit nochmal raussuchen kann), der zeigte, dass letzteres ggf. nicht möglich ist. Text wird auf sehr spezielle Art gerendert, und dort traten Effekte auf, die man oberflächlich betrachtet als “Renderfehler” bezeichnen könnte (aber vielleicht waren es gar keine - siehe Mantra).

Am vielversprechendsten erscheint mir Spontan Ansatz Nummer 2, aber das ist erstmal nur ein Gefühl…