Forum: PC-Programmierung java Schriftgröße an Komponente anpassen


von Vlad T. (vlad_tepesch)


Lesenswert?

hi,
vielleicht hat ja von euch jemand nen Plan:

Ich benutze einen Layout-Manager, der die Komponenten mit der 
Fenstergröße skaliert.
Ich möchte auch die Schriftgröße entsprechend mitskalieren.

Hat da jemand eine Idee?
Was mir einfällt, wäre, dass man sich auf das Resize-Event registriert 
und dann von Hand die Größen anpasst, aber das erscheint mir arg 
umständlich.

Geht das nicht auch irgendwe automatisch?


Gruß,
Vlad

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Wenn die Komponente (welche überhaupt) das nicht von sich aus 
unterstützt so musst du dich selbst darum kümmern.
Ist es den überhaupt wünschenswert das sich die Schrift mitsamt der 
Komponente vergrößert? Was soll passieren wenn zwar die Höhe/Größe der 
Schrift sich anpasst aber aufgrund der Textmenge die Breite nicht mehr 
passt?

von Vlad T. (vlad_tepesch)


Lesenswert?

das ganze sollte natürlich so funtkionieren, dass die Boundingbox der 
Schrift komplett in der Komponente liegt, was anderes macht meiner 
Meinung nach auch gar keinen Sinn.

Die schrift soll also so groß wie möglich sein, ohne über die Ränder zu 
laufen.

Konkret handelt es sich um JButton und JSpinner

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Bei einem JSpinner kannst du einen eigenen Editor implementieren:
http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JSpinner.html
> The editor is created by the JSpinner's constructor and can be
> changed with the editor property. The JSpinner's editor stays
> in sync with the model by listening for ChangeEvents.

Bei einem Button, könntest du AbstractButton oder JButton erweitern und 
Kontrolle über die paintComponent Methode übernehmen.

Hört sich etwas komplizierter an, ist aber eigentlich ganz einfach.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

So könnte z.B. ein read only Editor für einen JSpinner dann aussehen 
(vorgehen ist für einen JButton ähnlich)
1
package test;
2
import java.awt.Color;
3
import java.awt.Dimension;
4
import java.awt.Font;
5
import java.awt.FontMetrics;
6
import java.awt.Graphics;
7
import java.awt.Insets;
8
import javax.swing.JFrame;
9
import javax.swing.JLabel;
10
import javax.swing.JSpinner;
11
import javax.swing.event.ChangeEvent;
12
import javax.swing.event.ChangeListener;
13
14
public class SpinnerTest {
15
16
    public static void main(String[] args) {
17
        JSpinner spinner = new JSpinner();
18
        SpinnerEditor editor = new SpinnerEditor();
19
        editor.upDateFrom(spinner);
20
        spinner.addChangeListener(editor);
21
        spinner.setEditor(editor);
22
        JFrame frame = new JFrame();
23
        frame.setSize(200, 100);
24
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
25
        frame.setLocationRelativeTo(null);
26
        frame.add(spinner);
27
        frame.setVisible(true);
28
    }
29
30
    private static class SpinnerEditor extends JLabel implements ChangeListener {
31
32
        private static final long serialVersionUID = -1601826295344734066L;
33
34
        @Override
35
        public void stateChanged(ChangeEvent ce) {
36
            if (ce.getSource() instanceof JSpinner) {
37
                JSpinner spinner = (JSpinner) ce.getSource();
38
                upDateFrom(spinner);
39
            }
40
        }
41
42
        public void upDateFrom(JSpinner spinner) {
43
            setText(spinner.getValue().toString());
44
        }
45
46
        @Override
47
        protected void paintComponent(Graphics g) {
48
            //nur um zu sehen wie unser Orginal zeichnet...
49
            super.paintComponent(g);
50
            //wir werden in rot darüberzeichenen...
51
            g.setColor(Color.RED);
52
            //Ränder bestimmen....
53
            Insets insets = getInsets();
54
            int x = insets.left;
55
            int y = insets.top;
56
            //Breite und Höhe bestimmen
57
            Dimension size = getSize();
58
            int w = size.width - x - insets.right;
59
            int h = size.height - y - insets.bottom;
60
            //Rahmen zeichenen für tests...
61
            g.drawRect(x, y, w - 1, h - 1);
62
            Font font = g.getFont();
63
            String text = getText();
64
            FontMetrics fm = g.getFontMetrics(font);
65
            while (fm.stringWidth(text) < w && fm.getMaxAscent() + fm.getMaxDescent() < h) {
66
                font = font.deriveFont(font.getSize2D() + 0.5f);
67
                fm = g.getFontMetrics(font);
68
            }
69
            g.setFont(font);
70
            //nun endlich zeichnen...
71
            g.drawString(text, x, y + font.getSize());
72
            //Zeichen von Bounding Box in Blau
73
            g.setColor(Color.BLUE);
74
            g.drawRect(x, y, fm.stringWidth(text), fm.getMaxAscent() + fm.getMaxDescent());
75
        }
76
    }
77
}
Je nach darstellbarem Inhalt kann man hier noch etwas justieren und z.B. 
die Höhe noch etwas anders berechnen (z.B. bei Zahlen kann man direkt 
nur von der Baseline rechnen)

von Vlad T. (vlad_tepesch)


Lesenswert?

wow, Danke, hast dir ja richtig Arbeit gemacht.
Ich werds bei gelegenheit mal ausprobieren, danke.

Mir ist folgendes noch nicht ganz klar:
du zeichnest das super "nur um zu sehen wie unser Orginal zeichnet..."
wenn das später weggelassen wird, fehlt doch der Rest des Controlls, 
oder?

Bei den Spinnern gehts vielleicht noch, da die zweigeteilt sind, aber 
bei Buttons? da müsste man ja den kompletten button selbst zeichnen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Bei meinem Spinnerbeispiel kannst du das einfach auskommentieren. Ein 
Editor ist wirklich in diesem Fall nur für den Dartstellungsbereich des 
Controls zuständig. Wenn das ganze editierbar sein soll wird wohl etwas 
trickreicher, ggf. kann man auch einfach die benötigte Fontgrösse 
berechnen und dann den Font setzen und ein repaint auslösen falls sich 
die Fontgröße geändert hat.

Bei einem Button funktioniert auch folgendes:
1
    private static class DynButton extends JButton {
2
        private static final long serialVersionUID = -6029717230072874871L;
3
4
        public DynButton(String string) {
5
            super(string);
6
        }
7
8
        @Override
9
        protected void paintComponent(Graphics g) {
10
            calcFont(g);
11
            super.paintComponent(g);
12
        }
13
14
        private void calcFont(Graphics g) {
15
            Insets insets = getInsets();
16
            Insets margin = getMargin();
17
            int x = insets.left + margin.left;
18
            int y = insets.top + margin.top;
19
            //Breite und Höhe bestimmen
20
            Dimension size = getSize();
21
            int w = size.width - x - insets.right - margin.right;
22
            int h = size.height - y - insets.bottom - margin.bottom;
23
            Font font = g.getFont();
24
            String text = getText();
25
            FontMetrics fm = g.getFontMetrics(font);
26
            while (fm.stringWidth(text) < w && fm.getMaxAscent() + fm.getMaxDescent() < h) {
27
                font = font.deriveFont(font.getSize2D() + 0.5f);
28
                fm = g.getFontMetrics(font);
29
            }
30
            g.setFont(font);
31
        }
32
    }
Da das paintComponent wohl davon ausgeht das bereits der korrekte Font 
gesetzt ist. Allerdings muss man da noch den Margin berücksichtigen wie 
ich gerade festgestellt habe.

von Vlad T. (vlad_tepesch)


Lesenswert?

ok, hätt nicht gedacht, dass das so geht.
Ich hätte da mit einer Endlosschleife gerechnet, da ein Ändern der Font 
ja ein Repaint auslöen sollte.


Edit:

Oh ich seh grad, die Font wird nicht bem Button, sondern beim Graphics 
objekt gesetzt.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Vlad Tepesch schrieb:
> Oh ich seh grad, die Font wird nicht bem Button, sondern beim Graphics
> objekt gesetzt.
Ja ich hab auch erst überlegt den Font direkt anzupassen, man müsste dan 
nur abbrechen sobald aktuelle Fontgröße = berechnete Größe.
*ABER:* vermutlich würde man dadurch auch sobald die Komponenten einmal 
vergrößert wurde diese nicht mehr verkleinern können (oder noch eine 
Routine bauen welche den Font wieder verkleinert ggf.)

von tabina (Gast)


Lesenswert?

Wie würde man das für eine Checkbox lösen?

Ich möchte, dass immer der ganze Text einer Checkbox sichtbar ist. Wenn 
der Textbereich kürzer ist, müsste die Schriftgröße angepasst werden.

Das oben beschriebene Vorgehen funktioniert bei mir prima mit Buttons, 
aber nicht bei Checkboxen.

Gruß,

tabina

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

tabina schrieb:
> Wie würde man das für eine Checkbox lösen?
Wie gesagt das muss man gff. für verschiedene Komponenten eine eigene 
Lösung finden. Soll den nur der Text oder auch das Icon Skaliert werden?

Bei der Berechnung musst du auf jeden Fall noch die Breite des Icons 
berücksichtigen. (gilt im Übrigen eigentlich auch für den Button).

Das ganze ist wie gesagt nur eine Art Demo und sicher weit von der 
Perfektion entfernt ;)


> Das oben beschriebene Vorgehen funktioniert bei mir prima mit Buttons,
> aber nicht bei Checkboxen.
Was funktioniert den nicht?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.