Swing Buchstaben im Label anders färben

KrokoDiehl

Top Contributor
Hallo zusammen.

Ich habe nun eine Frage zu einer Darstellung von Textunterschieden: Ich habe zwei Strings, einen SOLL- und einen IST-String. Beide würde ich in der (Swing-)Oberfläche nun gerne so darstellen, dass sie
a) untereinander stehen und vor allem
b) die unterschiedlichen Buchstaben im IST-String in rot dargestellt werden.

Ich bin nun auf der Suche nach sinnvollen und natürlich einfachen Umsetzungsmöglichkeiten. Dabei ist es mir relativ egal ob es über ein JLabel, JTextField, JTextArea, JWasAuchImmer gemacht wird.
Da ich die Unterschiede dynamisch ermittle fände ich es ungeschickt über HTML zu lösen, da man es flexibel aufbauen müsste und immer dieses
Code:
<font color=...></font>
reinhängen muss, aber vermutlich ist es auch ein denkbarer Ansatz.

Im ersten, naiven Ansatz habe ich ein einfaches JLabel mit überschriebener
Code:
paintComponent()
-Methode, die jeden Buchstaben einzeln zeichnet. Einfach betrachtet tut es das, was ich wünsche, jedoch mit diversen Probleme betreffend der Größe / Position des Textes, Look&Feel usw.

Java:
public final class DiffLabel extends JLabel {

    private final String expected;
    private final String actual;
    
    public DiffLabel(String exp, String act) {
        super(act);
        expected = exp;
        actual   = act;
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        
        try {
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            if (this.isOpaque()) {
                g2d.setColor(this.getBackground());
                g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
            }
            
            this.paintBorder(g2d);
            this.paintChildren(g2d);
            
            
            Insets      insets  = this.getInsets();
            FontMetrics metrics = g2d.getFontMetrics( this.getFont() );
            int         strPos  = this.getHeight() -insets.top -insets.bottom;
            int         offset  = insets.left;
            
            for (int i = 0; i < actual.length(); ++i) {
                char c = actual.charAt(i);
                if (this.diffs(c, i)) {
                    g2d.setColor(Color.red);
                }
                else {
                    g2d.setColor(this.getForeground());
                }
                
                String str = ""+c;
                g2d.drawString(str, offset, strPos); 
                offset += metrics.getStringBounds(str, g2d).getWidth();
            } //for
        }
        finally {
            g2d.dispose();
        }
    }

    private boolean diffs(char c, int i) {
        if (i < expected.length()) {
            return (c != expected.charAt(i));
        }
        
        return true;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                String exp = "HaLlo Welt";
                String act = "Hallo welti";
                
                JFrame f = new JFrame("Test Diff Label");
                f.setLayout(new GridLayout(2, 1));
                f.add(new JLabel(exp));
                f.add(new DiffLabel(exp, act));
                f.setResizable(false);
                f.pack();
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setVisible(true);
            }
        });
    }
}

Gibt es von euch Anregungen, Ideen usw. zu diesem Thema? Danke im Voraus!
 
möglich wäre auch in einem panel mit 2 Labels zu arbeiten und das einem entsprechendem Layoutmanager machen zu lassen
 
Ich versteh nicht ganz, warum du es nicht mit HTML lösen möchtest!?

Du musst den String eh vergleichen und die Buchstaben rausfinden, die sich unterscheiden. Ob du das nun in der paint()-methode machst oder immer dann, wenn der Text sich ändert (und entsprechend HTML) ergänzt ist doch egal.

Zumal du mit dem HTML-Ansatz flexibler bist, was L&F angeht.
 
Nun ja, der Reiz der HTML-Lösung ist es durchaus dass es am wenigsten Eingriff erfordert. Vermutlich werde ich auch hiermit anfangen. Aber ich bin gern offen für weitere Ideen.
 
So, mein bisheriger Stand:

Ich habe es tatsächlich über HTML gelöst und ein Label entsprechend aufgebaut. Man musste noch ein wenig mit Leerzeichen aufpassen (-->
Code:
&nbsp;
) damit es zur Darstellung normaler Labels passt.

Ich hatte das Ganze ebenfalls in einem TreeRenderer drin, was meistens ging aber es gab auch sehr oft hässliche Darstellungseffekte. Ich nehme an dass er mit der Größenberechnung des HTMLs nicht wirklich zurande kam.
Als normale Labels ging es wiederum gut genug (außer bei starken Verkleinern der Fenstergröße), sodass ich mich damit begnügen kann. Es ist ohnehin eine nice-to-have Sache, daher will ich auch nicht ewig Zeit reinstecken. Andere Versuche mit Textfelder und eigenen Dokument-Implementierungen habe ich also nur kurz und ohne wirkliche Ergebnisse verfolgt.

Für mich ist das Thema damit erledigt, aber wenn es anderen in den Finger juckt: Bitteschön ;-)
 

Zurück
Oben