Texte zeichenweise übereinander darstellen, gemeinsam umbrechen

David R.

Mitglied
Hallo :)

Dies ist mein erster Beitrag in diesem Forum, auch wenn es mir schon früher des öfteren weitergeholfen hat. Vielen Dank dafür! (Auch für die Hilfe im IRC!)

Nun bin ich bei einem Punkt angelangt, an dem meine Frage für den IRC wahrscheinlich zu umfangreich ist. Über Ideen dazu würde ich mich sehr freuen!

Folgende Situation:

Es sollen in einem Panel zwei Texte parallel dargestellt werden. Jedem Buchstaben des einen Textes ist hierbei eindeutig ein Buchstabe des zweiten Textes zugeordnet, der genau darüber bzw. darunter steht. Wenn die Breite des Panels nicht mehr ausreicht, sollen die Texte gemeinsam umbrechen. Wenn auch die Höhe nicht ausreicht soll vertikales Scrollen möglich sein.

Bisher wurde das Problem gelöst, indem jedem Buchstabenpaar ein eigenes Panel mit zwei übereinander angeordneten Labels spendiert wurde. Diese wurden dann in ein Panel eingefügt, das das WrapLayout verwendet.

Java:
public JScrollPane createAnalysisPane(char[] plain, char[] cypher) {
    JPanel analysisPanel = new JPanel(new WrapLayout(WrapLayout.LEFT));
    for (int i = 0; i < plain.length; i++) {
        JLabel plainLabel = new JLabel(plain[i] + "");
        JLabel cypherLabel = new JLabel(cypher[i] + "");
        JPanel charPanel = new JPanel(new GridLayout(2, 1));
        charPanel.add(plainLabel);
        charPanel.add(cypherLabel);
        analysisPanel.add(charPanel);
    }
    JScrollPane analysisPane = new JScrollPane(analysisPanel);
    return analysisPane;
}

Das funktioniert soweit auch ganz gut, nur dass diese Lösung natürlich extrem inperformant ist, bei längeren Texten völlig versagt und sich auch nicht wirklich sauber anfühlt (dafür sind JLabels einfach nicht da...).

Hat wer ne Idee?
 

Marco13

Top Contributor
Nur eine kurze Zwischenfrage: Spricht was dagegen, eine ganz normale JTextArea mit
[c]Monospaced[/c]
[c]Npoptqbdfe[/c]
Font zu verwenden?
 

David R.

Mitglied
Naja, die Texte sollen ja gemeinsam umbrechen.

Im Moment sieht das so aus:

lxpfic5w.jpg


Bei deiner Lösung müsste man die Anzahl der Zeichen pro Zeile bei jedem Resize neu ermitteln, um anschließend einen angepassten Text zu setzen.

(Dass die zwei Texte im Beispiel unterschiedlich gefärbt sind ist zwar nett, muss aber nicht unbedingt sein.)
 

Marco13

Top Contributor
Vielleicht gibt es sowas auch schon vorgefertigt. Wobei. Eher nicht, da es recht speziell ist. Hab' mal rumgespielt. Das "highlighting" kann man ausschalten, indem man 'null' übergibt.

Java:
// Marco13 for [url=http://www.java-forum.org/awt-swing-swt/]AWT, Swing & SWT - java-forum.org[/url]
//   110869-texte-zeichenweise-uebereinander-darstellen-gemeinsam-umbrechen.html

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;



public class TextComparePanel extends JPanel implements Scrollable
{

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                JFrame f = new JFrame();
                String s0 = 
                    "This is a small test case "+
                    "with some wierd line wrapping "+
                    "just to test this thing. And now, "+
                    "ladies and gentlemen ... just "+
                    "kidding ;-) ... And now, gentlemen, "+
                    "the famous words: LOREM IPSUM :-)";

                String s1 = 
                    "This is a  big  test case "+
                    "with some wired line warping  "+
                    "just to test this thing. And now, "+
                    "ladies and gentlemen ... just "+
                    "kidding ;-) ... and now, gentlemen, "+
                    "the famous word : LOREM IPSUM :-)";

                TextComparePanel p = new TextComparePanel(
                    s0.toCharArray(), Color.BLACK,
                    s1.toCharArray(), Color.LIGHT_GRAY, 
                    Color.RED);
                
                f.getContentPane().add(new JScrollPane(p));
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setSize(200,200);
                f.setVisible(true);
            }
        });
    }
    
    private char array0[];
    private Color color0;
    private char array1[];
    private Color color1;
    private Color highlight;
    private int additionalSpacing = 1;
    
    public TextComparePanel(char[] array0, Color color0, char[] array1, Color color1, Color highlight)
    {
        this.array0 = array0;
        this.color0 = color0;
        this.array1 = array1;
        this.color1 = color1;
        this.highlight = highlight;
    }
    
    public void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;
        
        FontMetrics fm = g.getFontMetrics();
        int lineHeight = fm.getHeight();
        
        int y = lineHeight;
        int x = 0;
        for (int i=0; i<array0.length; i++)
        {
            char c0 = array0[i];
            char c1 = array1[i];
            int offset0 = 0;
            int offset1 = 0;
            int w0 = fm.charWidth(c0);
            int w1 = fm.charWidth(c1);
            int maxW = -Integer.MAX_VALUE;
            if (w0 > w1)
            {
                maxW = w0;
                offset1 = (w0 - w1)/2;
            }
            else 
            {
                maxW = w1;
                offset0 = (w1 - w0)/2;
            }
            maxW += additionalSpacing;
            int nextX = x + maxW;
            if (nextX >= getWidth())
            {
                x = 0;
                y += lineHeight * 2;
                nextX = maxW;
            }
            if (c0 != c1 && highlight != null)
            {
                g.setColor(highlight);
            }
            else
            {
                g.setColor(color0);
            }
            g.drawString(String.valueOf(c0), x+offset0, y);

            if (c0 != c1 && highlight != null)
            {
                g.setColor(highlight);
            }
            else
            {
                g.setColor(color1);
            }
            g.drawString(String.valueOf(c1), x+offset1, y+lineHeight);

            x = nextX;
        }
    }
    
    private int computePreferredHeight(int availableWidth)
    {
        FontMetrics fm = getFontMetrics(getFont());
        int lineHeight = fm.getHeight();
        int y = lineHeight;
        int x = 0;
        for (int i=0; i<array0.length; i++)
        {
            char c0 = array0[i];
            char c1 = array1[i];
            int w0 = fm.charWidth(c0);
            int w1 = fm.charWidth(c1);
            int maxW = Math.max(w0, w1) + additionalSpacing;
            int nextX = x + maxW;
            if (nextX >= availableWidth)
            {
                x = 0;
                y += lineHeight * 2;
                nextX = maxW;
            }
            x = nextX;
        }
        return y + lineHeight + fm.getDescent();
    }
    
    @Override
    public Dimension getMinimumSize()
    {
        return getPreferredSize();
    }
    
    @Override
    public Dimension getPreferredSize()
    {
        if (isPreferredSizeSet())
        {
            return super.getPreferredSize();
        }
        if (getWidth() == 0)
        {
            return super.getPreferredSize();
        }
        Dimension dim = super.getPreferredSize();
        dim.height = computePreferredHeight(getWidth());
        return dim;
    }
    
    @Override
    public Dimension getPreferredScrollableViewportSize()
    {
        return getPreferredSize();
    }

    @Override
    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
    {
        FontMetrics fm = getFontMetrics(getFont());
        int lineHeight = fm.getHeight();
        return lineHeight;
    }

    @Override
    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
    {
        return getScrollableUnitIncrement(visibleRect, orientation, direction);
    }

    @Override
    public boolean getScrollableTracksViewportWidth()
    {
        return true;
    }

    @Override
    public boolean getScrollableTracksViewportHeight()
    {
        return false;
    }
}
 

David R.

Mitglied
Wow...

Ich meine WOW!!!

Für mal eben rumgespielt ist das so ziemlich genau das, was ich brauche, selbst mit dem Highlighting! (Highlighting hatte ich auch im Original, für das Codebeispiel hab ich das rausgenommen :))

Super herzlichen Dank Dir! Jetzt ist es leider schon ein bisschen spät, morgen werde ich das mal alles im Detail nachvollziehen und einbauen. Denke, dass mich das auch in Zukunft weiterbringen wird, da ähnliche Problemstellungen schon öfters aufgetaucht sind.

Ich meld mich dann nochmal wenns läuft :D
 

David R.

Mitglied
So, ein bisschen angepasst, eingebaut, und läuft wunderbar :)

Letztlich war ich dann doch überrascht, wie einfach die Lösung gewesen ist. Von der FontMetrics-Klasse wusste ich bis jetzt noch gar nichts, das ist ja super cool was man damit machen kann!

Vielen Dank nochmal!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Thallius Swing Warum kann man Texte im Panel nicht markieren? AWT, Swing, JavaFX & SWT 1
E Texte mit Konstante aus CSV in GUI anzeigen AWT, Swing, JavaFX & SWT 16
T Texte farbig ausgeben AWT, Swing, JavaFX & SWT 2
Antoras Swing Umfangreiche formatierte Texte in Fenster darstellen AWT, Swing, JavaFX & SWT 2
Raidri Kreisdiagramme und texte anpassen AWT, Swing, JavaFX & SWT 2
G Texte miteinander vergleichen AWT, Swing, JavaFX & SWT 5
A Grosse Texte >2mb anzeigen in JTextPane AWT, Swing, JavaFX & SWT 2
G ActionListener - Texte ändern per Knopfdruck AWT, Swing, JavaFX & SWT 4
S mehrzeilige texte ausgeben AWT, Swing, JavaFX & SWT 10
CptK JPanels übereinander legen AWT, Swing, JavaFX & SWT 6
M Zwei JPanel übereinander nur vorderes "repainten" AWT, Swing, JavaFX & SWT 3
M Java FX Layouts übereinander statt nebeneinander AWT, Swing, JavaFX & SWT 4
S Swing Mehrere Modal-Dialoge übereinander AWT, Swing, JavaFX & SWT 5
C LayoutManager Bei verkleinern des Fensters, verschieben sich JPanels übereinander. AWT, Swing, JavaFX & SWT 7
F Swing JPanels übereinander ohne Mananger AWT, Swing, JavaFX & SWT 1
M Komponenten übereinander AWT, Swing, JavaFX & SWT 7
N Komponenten übereinander AWT, Swing, JavaFX & SWT 3
T Prüfen ob 2 JLabel übereinander liegen. Performance Problem. AWT, Swing, JavaFX & SWT 5
S 2 Canvas übereinander AWT, Swing, JavaFX & SWT 2
J Swing Componenten übereinander platzieren. AWT, Swing, JavaFX & SWT 17
M 2D-Grafik Mehrere Linien (nacheinander) übereinander Zeichnen AWT, Swing, JavaFX & SWT 6
M Swing JPanel lagern übereinander AWT, Swing, JavaFX & SWT 14
C Swing JPanel übereinander legen AWT, Swing, JavaFX & SWT 4
C Zwei Bilder übereinander legen AWT, Swing, JavaFX & SWT 1
S Graphics2D: Transparent übereinander zeichnen AWT, Swing, JavaFX & SWT 7
M Komponenten übereinander prüfen AWT, Swing, JavaFX & SWT 3
J LayoutManager Panels übereinander AWT, Swing, JavaFX & SWT 3
I 2 Panels übereinander, 1 transparent AWT, Swing, JavaFX & SWT 2
S mehere panels übereinander AWT, Swing, JavaFX & SWT 2
M JProgressBar übereinander legen? AWT, Swing, JavaFX & SWT 3
Y Mehrere Komponenten übereinander ohne Swing AWT, Swing, JavaFX & SWT 2
B Komponenten übereinander platzieren AWT, Swing, JavaFX & SWT 2
S Labels und Button übereinander --> Reihenfolge? AWT, Swing, JavaFX & SWT 4
F JPanel übereinander zeichnen AWT, Swing, JavaFX & SWT 4
W Bilder übereinander legen AWT, Swing, JavaFX & SWT 1
N Mehrere JComponents übereinander AWT, Swing, JavaFX & SWT 3
H Komponenten übereinander anordnen, I/O-Konsole AWT, Swing, JavaFX & SWT 3
E Panels übereinander darstellen AWT, Swing, JavaFX & SWT 2
D 2 Komponenten übereinander AWT, Swing, JavaFX & SWT 2
S Komponenten übereinander anordnen? AWT, Swing, JavaFX & SWT 5
P JLabels übereinander legen AWT, Swing, JavaFX & SWT 8
M JTabbedPane zeigt alle Panels übereinander an :( AWT, Swing, JavaFX & SWT 8

Ähnliche Java Themen


Oben