Gemittelte Ausgabe von Buchstaben

kodela

Bekanntes Mitglied
Ich habe das Problem, dass einzelne Buchstaben im Interface gemittelt, beim Ausdruck dagegen ungemittelt gezeigt werden.

1708960823569.png

Gebe ich zum Beispiel diese Buchstaben über g2.drawString() für einen Ausdruck aus, dann steht das 'I' genau so weit links wie der linke Anstrich des 'N'.
In Beiden Fällen ist Arial Bold die Schriftart. Wie erreiche ich, dass auch bei einem Ausdruck alle Zeichen mit der selben Breite ausgegeben werden=
 
Ja, das habe ich versucht, zum Beispiel mit IntelOne Mono Bold. Der Font wird ohne Murren angenommen, aber ignoriert, wie wenn ich Arial gewählt hätte.
 
In Beiden Fällen ist Arial Bold die Schriftart. Wie erreiche ich, dass auch bei einem Ausdruck alle Zeichen mit der selben Breite ausgegeben werden=
Arial ist eine proportionale Schrift. Das bedeutet jedes Zeichen nimmt nur so viel Platz ein wie es benötigt.
Lösung:
1) benutze ein nicht proportionale Schrift.
2) Berechne mit FontMetricts die Größe des Zeichen und platziere sie dann selbst.
 
Ja, das habe ich versucht, zum Beispiel mit IntelOne Mono Bold. Der Font wird ohne Murren angenommen, aber ignoriert, wie wenn ich Arial gewählt hätte.
Du meinst den Ausdruck ? Dann in etwa so. Beim Drucken ist es wichtig, im Graphics Objekt den Font neu zu setzen.
Du kannst dir zum Testen die Jar herunterladen. 😉

Java:
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import javax.swing.JFrame;

public class StartCenterLetterDemo {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Letter Center Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        TestCenterLetterPanel letterPanel = new TestCenterLetterPanel(400);
        frame.add(letterPanel);
        frame.pack();
        frame.setVisible(true);
        printLetterBox(letterPanel);
    }

    private static void printLetterBox(TestCenterLetterPanel letterPanel) {
        PrinterJob printJob = PrinterJob.getPrinterJob();
        printJob.setPrintable(new PrintLetterBox(letterPanel));
        if (printJob.printDialog()) {
            try {
                printJob.print();
            } catch (PrinterException e) {
                e.printStackTrace();
            }
        }
    }
}
Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class TestCenterLetterPanel extends JPanel implements LetterBoxPrinter {
    private char[][] letter = { { 'H', 'R', 'O' }, { 'I', 'N', 'A' }, { 'M', 'E', 'C' } };
    private int boxSize;
    private Rectangle border = new Rectangle();
    private int gap;

    public TestCenterLetterPanel(int size) {
        setFont(new Font("Arial Bold", Font.BOLD, 5));
        updateSize(size);
    }

    private int getLetterCenterX(FontMetrics fm, String txt) {
        return (boxSize - fm.stringWidth(txt)) / 2;
    }

    private int getNumCol() {
        return letter.length;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        renderLetterBox(g);
    }

    @Override
    public void renderLetterBox(Graphics g) {     
        FontMetrics fm = g.getFontMetrics();
        g.setColor(Color.YELLOW);
        g.fillRect(border.x, border.y, border.width, border.height);
        g.setColor(Color.BLACK);
        int letterHeight = 4 * (boxSize - getFont().getSize()) / 3;
        int y = 2 * gap;
        for (int row = 0; row < letter.length; row++) {
            int x = 2 * gap;
            for (int col = 0; col < letter[row].length; col++) {
                String txt = "" + letter[row][col];
                g.drawRect(x, y, boxSize, boxSize);
                g.drawString(txt, x + getLetterCenterX(fm, txt), y + letterHeight);
                x += gap + boxSize;
            }
            y += boxSize + gap;
        }
    }

    private void updateSize(int size) {
        setPreferredSize(new Dimension(size, size));
        gap = (int) (size * .05);
        border.x = gap;
        border.y = gap;
        border.width = border.height = size - 2 * gap;
        boxSize = (size - 6 * gap) / getNumCol();
        setFont(getFont().deriveFont(boxSize / 2f));
    }
}
Java:
import java.awt.Font;
import java.awt.Graphics;

public interface LetterBoxPrinter {
    public void renderLetterBox(Graphics g);

    public Font getFont();
}
Java:
import java.awt.Graphics;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;

public class PrintLetterBox implements Printable {
    private LetterBoxPrinter boxRenderer;

    public PrintLetterBox(LetterBoxPrinter boxRenderer) {
        this.boxRenderer = boxRenderer;
    }

    @Override
    public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException {
        if (pageIndex > 0)
            return NO_SUCH_PAGE;
        g.setFont(boxRenderer.getFont());
        boxRenderer.renderLetterBox(g);
        return PAGE_EXISTS;
    }

}
 

Anhänge

Danke, über die Einbindung von getLetterCenterX() bekomme ich die Buchstaben zentriert.

Großes Aber! Bei mir werden auf einer Seite vier solcher Felder mit jeweils neun Buchstaben ausgedruckt (im Anhang ist ein Beispiel). Ohne die Einbindung von getLetterCenterX() sehen alle vier Felder so aus, wie das Feld links oben. Am 'I' in der Mitte sieht man, dass die Buchstaben nicht zentriert sind. Ausgenommen dem 'I' sind die Buchstaben aber eigentlich alle mittig. Das galt auch für die drei anderen Felder. In diesen sind die Buchstaben jetzt aber zentriert, gut an den 'I's der rechten beiden Felder zu erkennen. Dafür sind aber nach links gerutscht, was man allerdings ausgleichen könnte.

Ich muss jetzt herausfinden, warum sich die Einbindung von getLetterCenterX() auf das erste Feld nicht auswirkt. Es ist jedenfalls nicht so, dass getLetterCenterX() für die Buchstaben des ersten Feldes nicht aufgerufen würde. Hier die Rückgabewerte für alle 36 Buchstaben, beginnend beim ersten Feld links oben. Ich kann mir auf diese Werte keinen Reim machen.

"48 229 408 47 228 408 46 228 408 1202 1390 1570 1213 1393 1573 1205 1409 1573 20 200 378 12 219 378 18 199 378 1210 1388 1570 1213 1409 1562 1229 1390 1568"


Für boxsize in getLetterCenterX() wird bei mir übrigens noch '0' genommen, da ich dies Variable zwar deklariert aber nicht definiert habe.
 

Anhänge

  • img20240227_00112350.jpg
    img20240227_00112350.jpg
    620,5 KB · Aufrufe: 0
Zuletzt bearbeitet:
Hier noch ein Aufstellung von einem erneuten Durchlauf, diesmal mit den zugehörigen Buchstaben:

"48 - U 230 - I 408 - F 48 - E 227 - G 409 - L 48 - N 229 - L 410 - I 1229 - I 1388 - B 1568 - N 1213 - F 1390 - E 1568 - R 1210 - E 1385 - G 1570 - E 20 - E 200 - S 378 - R 19 - A 200 - E 378 - N 39 - I 192 - M 378 - K 1209 - A 1390 - P 1570 - S 1208 - U 1393 - T 1573 - F 1213 - T 1393 - L 1573 - L"

Was wird hier für was zurückgegeben. Diese total unterschiedlichen Werte, selbst für die selben Buchstaben, was sollen sie bewirken?
 
Problem gelöst!

@Blender3D:

Nachdem ich den ganzen Tag zum Teil mit dem Studium Deines Programms und mit allen möglichen Versucht verbracht habe, kam mir eben ein Gedanke. Da das ' I ' ja der einzige Buchstabe ist, der stört, kann man ihn ja besonders behandeln. Ein Versuch mit folgendem Code und die Welt war für mich wieder in Ordnung.
Java:
    private void setLetters(Graphics g2, int x0, int y0) {  
        String aufgabe = nDS[0];
        for (int i = 0; i < 9; i++) {
            String w = aufgabe.substring(i, i+1);
            if (w.equals("I")) {
                g2.drawString(w, x0 + 20 + xPos[i], y0 + yPos[i]);
            }else {
                g2.drawString(w, x0 + xPos[i], y0 + yPos[i]);
            }
        }
 
Nachdem ich den ganzen Tag zum Teil mit dem Studium Deines Programms und mit allen möglichen Versucht verbracht habe, kam mir eben ein Gedanke. Da das ' I ' ja der einzige Buchstabe ist, der stört, kann man ihn ja besonders behandeln. Ein Versuch mit folgendem Code und die Welt war für mich wieder in Ordnung.
Das freut mich, dass du für dich eine Lösung gefunden hast.😄

Es ist aber grundsätzlich keine gute Lösung bei Textformatierung einen Buchstaben gesondert mit einem konstanten Versatzwert zu behandeln.
Der Grund dafür ist einfach erklärt. Mit dem gewählten Font und der passenden Auflösung hast du das gewünschte Ergebnis. Deine App läuft dann auf einem anderem System mit einer anderen Auflösung und - oder der gewählte Font ist nicht vorhanden. --> der Konstante Wert passt nicht mehr. Deshalb solltest Du unbedingt FontMetrics im konkreten grafischen Kontext benutzen. Hier noch einmal ein etwas verändertes Beispiel mit 4 Buchstabenfeldern. Ich habe eine eigene Klasse LetterBox verwendet, die an einer gewählten Position und Breite gezeichnet werden kann.
Damit habe ich das Problem die Seite mit vier Boxen und Zeilen zu zeichnen geteilt. ( Teile und Herrsche ) Das vereinfacht das Problem.
Die Klasse LetterBoxPage verwendete dann LetterBox. Alle notwendigen Größen hängen von der gewählten Dimension und nicht von einer Konstanten ab.
Wie du siehst passt damit auch bei der Seitenausgabe die Zentrierung der Buchstaben.
1709139931867.png
Java:
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import javax.swing.JFrame;

public class StartCenterLetterDemo {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Letter Center Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        LetterBoxPage letterPanel = new LetterBoxPage(600, 800, new char[][] {
                { 'L', 'I', 'M', 'K', 'R', 'F', 'T', 'I', 'C' }, { 'H', 'R', 'O', 'I', 'N', 'A', 'M', 'E', 'C' },
                { 'G', 'E', 'L', 'C', 'S', 'U', 'H', 'I', 'A' }, { 'E', 'N', 'T', 'T', 'S', 'U', 'Z', 'E', 'B' } });
        frame.add(letterPanel);
        frame.pack();
        frame.setVisible(true);
        printLetterBox(letterPanel);
    }

    private static void printLetterBox(LetterBoxPage letterPanel) {
        PrinterJob printJob = PrinterJob.getPrinterJob();
        printJob.setPrintable(new PrintLetterBox(letterPanel));
        if (printJob.printDialog()) {
            try {
                printJob.print();
            } catch (PrinterException e) {
                e.printStackTrace();
            }
        }
    }
}
Java:
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;

public class LetterBox {
    public static final int DIM = 3;
    private char[] box = new char[DIM * DIM];
    private Color backColor = Color.GRAY;
    private Color letterBackColor = Color.GRAY.brighter();
    private Color fontColor = Color.WHITE;

    public LetterBox(char[] letters) {
        setLetters(letters);
    }

    private void adaptFontSize(Graphics g, int boxSize) {
        g.setFont(g.getFont().deriveFont(boxSize / 2f));
    }

    public void draw(Graphics g, Point pos, int width) {
        int gap = (int) (width * .02);
        int boxSize = (width - 4 * gap) / DIM;
        adaptFontSize(g, boxSize);
        drawBackGround(g, pos, width);
        drawLetters(g, pos, gap, boxSize);
    }

    private void drawBackGround(Graphics g, Point pos, int width) {
        g.setColor(backColor);
        g.fillRect(pos.x, pos.y, width, width);
    }

    private void drawLetters(Graphics g, Point pos, int gap, int boxSize) {
        int letterHeight = 4 * (boxSize - g.getFont().getSize()) / 3;
        FontMetrics fm = g.getFontMetrics();
        int x = pos.x + gap;
        int y = pos.y + gap;
        for (int i = 0; i < box.length; i++) {
            if (isNextLineId(i)) {
                x = pos.x + gap;
                y += gap + boxSize;
            }
            g.setColor(letterBackColor);
            g.fillRect(x, y, boxSize, boxSize);
            g.setColor(fontColor);
            g.drawRect(x, y, boxSize, boxSize);
            String str = box[i] + "";
            g.drawString(str, x + getLetterCenterX(fm, str, boxSize), y + letterHeight);
            x += gap + boxSize;
        }
    }

    private int getLetterCenterX(FontMetrics fm, String txt, int boxSize) {
        return (boxSize - fm.stringWidth(txt)) / 2;
    }

    private boolean isNextLineId(int i) {
        return i > 0 && i % DIM == 0;
    }

    public void setLetters(char[] letters) {
        for (int i = 0; i < box.length && i < letters.length; i++)
            box[i] = letters[i];
    }

    @Override
    public String toString() {
        StringBuilder tmp = new StringBuilder();
        for (int i = 0; i < box.length; i++) {
          
            if (isNextLineId(i))
                tmp.append(System.lineSeparator());
            tmp.append(box[i]);
        }
        return tmp.toString();
    }

}
Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class LetterBoxPage extends JPanel implements LetterBoxPrinter {
    private ArrayList<LetterBox> boxes = new ArrayList<>();
    private Rectangle border = new Rectangle();
    private int gap;

    public LetterBoxPage(int width, int height, char[][] letter) {
        setFont(new Font("Arial Bold", Font.BOLD, 5));
        updateSize(width, height);
        for (int i = 0; i < letter.length; i++)
            boxes.add(new LetterBox(letter[i]));
    }

    private void drawPage(Graphics g, Point pos, int pageWidth, int pageHeight, int lineHeight) {
        int numLines = pageHeight / lineHeight;
        int y = pos.y;
        g.setColor(Color.LIGHT_GRAY);
        g.fillRect(pos.x, pos.y, pageWidth - 2 * gap, pageHeight - gap);
        g.setColor(Color.GRAY);
        y += lineHeight / 2;
        for (int i = 0; i < numLines; i++) {
            g.drawLine(pos.x + gap / 2, y, pos.x + pageWidth - 5 * gap / 2, y);
            y += lineHeight;
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        renderLetterBox(g);
    }

    @Override
    public void renderLetterBox(Graphics g) {
        g.setColor(Color.DARK_GRAY);
        g.fillRect(border.x, border.y, border.width, border.height);

        int startX = 0;
        int startY = 0;
        int boxSize = getWidth() / 4;
        Point pos = new Point();
        int pageWidth = 2 * boxSize;
        int pageHeight = getHeight() / 2 - gap;
        for (int i = 0; i < boxes.size(); i++) {
            LetterBox b = boxes.get(i);
            pos.x = border.x + startX;
            pos.y = border.y + startY;
            drawPage(g, pos, pageWidth, pageHeight, boxSize / 4);
            b.draw(g, pos, boxSize);
            startX = startX == 0 ? pageWidth : 0;
            startY = i > 0 ? pageHeight + gap : 0;
        }
    }

    private void updateSize(int width, int height) {
        setPreferredSize(new Dimension(width, height));
        gap = (int) (width * .03);
        border.x = gap;
        border.y = gap;
        border.width = width - 2 * gap;
        border.height = height - 2 * gap;
    }
}
😉


Ich habe für eine Casinogruppe eine Pokerwatch programmiert. Da kam es unter anderem auf die Positionierung am Bildschirm der verschiedenen Texte wie Preisgelder, Zeit, Blinds, Level Turniertyp etc. an. Eine Anforderung der Software war es unter verschiedenen Auflösungen zu laufen und Fonts dynamisch einstellen zu können.
 

Anhänge

Danke für Eure Antworten und, @Blender3D, Du hast natürlich völlig Recht, meine Lösung ist keine Gute und ich werde mich mit Deinen Hinweisen und der LetterBox noch gründlich beschäftigen. Im Augenblick muss mein "Werk" aber schnell fertig werden. Es ist ein Geburtstagsgeschenk und der Empfänger verwendet das selbe System, wie ich.
 
Hallo @Blender3D,

jetzt muss ich mich schon noch einmal melden und mich für Deine Mühe, die Du Dir mit mir gemacht hast, bedanken. Heute hatte ich die Zeit dafür und habe endlich aus meiner provisorischen Lösung eine saubere gemacht.

Es war eigentlich sehr einfach. Bei der Font-Definition "FontMetrics fm = g.getFontMetrics();" hinzugefügt und für die Festlegung der X-Position auf "getLetterCenterX(FontMetrics fm, String txt)" zurückgegriffen.
 

Zurück
Oben