Swing [JTextPane] Farbliche Hervorhebung

Tobse

Top Contributor
Hey leute,
ich habe ein Problem mit der Klasse JTextPane: Ich möchte bestimmte bereiche (genauer Syntax-Highlighting für simple dinge wie INI etc) realisieren, allerdings zählt JTextPane "falsch".
Ich habe ein Interface MarkupFinder:
Java:
package dide.gui.markup;
import java.util.HashMap;
import java.awt.Color;

public interface MarkupFinder {
    /*
     * int[0]: Start index of markup-color
     * int[1]: End index of markup-color
     * Color: The color to mark the defined area in
     */
    public HashMap<int[], Color> findMarkup(String text);
    /*
     * Defines what characters will have what color
     * e.g. for operators
     */
    public HashMap<Character, Color> getStaticChars();
}
Das funktioniert auch wunderbar, allerdings scheint die JTextPane die '\n' nicht zu zählen:
Java:
package dide.gui.markup;
import java.awt.Color;
import java.util.HashMap;
import java.util.regex.*;

public class INIMarkupFinder implements MarkupFinder {
    public static final Color GROUP=new Color(0, 0, 107);
    public static final Color COMMENT=new Color(0, 107, 0);
    /* ... */
}
ergibt dann:
Anhang anzeigen 3708

Was kann ich jetzt da machen? Zum herausfinden von den Start und zielpositionen im Text benutze ich Regex.

danke schonmal im vorraus an alle, die sich gedanken machen ;)
 

Tobse

Top Contributor
*push* Hat niemand ne Idee? Das wird mir echt zum performance problem, weil ich sonst total viel rumrechnen muss, um das zu korrigieren.
 

diggaa1984

Top Contributor
alleine mit dem code is nix zu erkennen, zeige doch mal den teil wo dann explizit die farbwerte des inhalts angepasst werden (bei mir mit StyledDocument mittels #setCharacterAttributes)

ich nutze auch einen Editor und realisiere manuell das Syntaxhighlighting (Lexer sagt mir was er fürn Texttyp gefunden hat und ich färbs ein, geht auch wunderbar)
 

Tobse

Top Contributor
Ok. Inzwischen hab ich das etwas verbessert um Bold/italic auch zu unterstützen:
MarkupStyle.java
Java:
package dide.gui.markup;
import java.awt.Color;
import java.awt.Font;

public class MarkupStyle {
    public static final MarkupStyle BLACK=new MarkupStyle(Color.BLACK);
    public static final MarkupStyle GRAY=new MarkupStyle(new Color(0x2A, 0x2A, 0x2A));
    public static final MarkupStyle BLUE=new MarkupStyle(Color.BLUE);
    private static Font def=new Font(Font.MONOSPACED, Font.PLAIN, 12);
    private Color color;
    private String name=Font.MONOSPACED;
    private int size=12;
    public boolean bold=false;
    public boolean italic=false;
    public MarkupStyle(Color color) {
        this.color=color;
    }
    public MarkupStyle(boolean bold, boolean italic) {
        this.bold=bold;
        this.italic=italic;
    }
    public MarkupStyle(Color color, boolean bold, boolean italic) {
        this(color, bold, italic, 12);
    }
    public MarkupStyle(Color color, boolean bold, boolean italic, int size) {
        this.color=color;
        this.bold=bold;
        this.italic=italic;
        this.size=size;
    }
    public Color getColor() {
        return this.color;
    }
    public int getSize() {
        return this.size;
    }
    public String getName() {
        return this.name;
    }
}
HighlightedEditorPanel.java
Java:
package dide.gui;
import dide.gui.markup.MarkupFinder;
import dide.gui.markup.MarkupStyle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Color;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Iterator;
import java.util.Set;
import javax.swing.text.StyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;

public class HighlightedEditorPanel extends LinedEditorPanel {
    private MarkupFinder markup;
    private HashMap<MarkupStyle, Style> styles=new HashMap<MarkupStyle, Style>();
    private Set<Entry<Character, MarkupStyle>> chars;
    private Style default_style;
    public HighlightedEditorPanel(MarkupFinder markup) {
        super();
        this.markup=markup;
        if (markup!=null) this.chars=this.markup.getStaticChars().entrySet();
        this.textPane.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
                return;
            }
            @Override
            public void keyPressed(KeyEvent e) {
                return;
            }
            @Override
            public void keyReleased(KeyEvent e) {
                updateSyntaxHighlighting(); 
            }
        });
        this.default_style=this.textPane.getStyledDocument().addStyle("Plain 12 Monospaced", null);
        StyleConstants.setForeground(this.default_style, Color.BLACK);
        this.updateSyntaxHighlighting();
        this.updateLines();
    }
    public void updateSyntaxHighlighting() {
        if (this.markup==null) return;
        String text=this.textPane.getText();
        StyledDocument doc=this.textPane.getStyledDocument();
        doc.setCharacterAttributes(0, text.length(), default_style, true);
        text=text.replaceAll("\n", "");
        HashMap<int[], MarkupStyle> map=this.markup.findMarkup(text);
        if (map==null) return;
        Iterator<Entry<int[], MarkupStyle>> highlight=map.entrySet().iterator();
        while (highlight.hasNext()) {
            Entry<int[], MarkupStyle> current=highlight.next();
            MarkupStyle mstyle=current.getValue();
            Style style=this.styles.get(mstyle);
            if (style==null) {
                style=doc.addStyle("", null);
                StyleConstants.setForeground(style, mstyle.getColor());
                StyleConstants.setFontFamily(style, mstyle.getName());
                StyleConstants.setBold(style, mstyle.bold);
                StyleConstants.setItalic(style, mstyle.italic);
            }
            int[] ar=current.getKey();
            doc.setCharacterAttributes(ar[0], ar[1]-ar[0], style, true);
        }
        Iterator<Entry<Character, MarkupStyle>> chars=this.chars.iterator();
        while (chars.hasNext()) {
            Entry<Character, MarkupStyle> cur=chars.next();
            MarkupStyle mstyle=cur.getValue();
            Style style=this.styles.get(mstyle);
            if (style==null) {
                style=doc.addStyle("", null);
                StyleConstants.setForeground(style, mstyle.getColor());
                StyleConstants.setFontFamily(style, mstyle.getName());
                StyleConstants.setBold(style, mstyle.bold);
                StyleConstants.setItalic(style, mstyle.italic);
            }
            int c=(int) cur.getKey().charValue();
            int index=text.indexOf(c);
            while (index!=-1) {
                doc.setCharacterAttributes(index, 1, style, true);
                index=text.indexOf(c, index+1);
            }
        }
    }
    public void setMarkup(MarkupFinder markup) {
        this.markup=markup;
        this.chars=this.markup.getStaticChars().entrySet();
    }
    public void setText(String txt) {
        this.textPane.setText(txt);
        this.updateSyntaxHighlighting();
        this.updateLines();
    }
}
Hier ist in Zeile 48 mein Workaround für die linefeeds.

Und im speziellen Fall:
Java:
new HighlightedEditorPane(new INIMarkupFinder());
INIMarkupFinder.java
Java:
package dide.gui.markup;
import java.awt.Color;
import java.util.HashMap;
import java.util.regex.*;

public class INIMarkupFinder implements MarkupFinder {
    public static final MarkupStyle GROUP=new MarkupStyle(new Color(0, 0, 107), true, false);
    public static final MarkupStyle COMMENT=new MarkupStyle(new Color(0, 107, 0));
    public static final MarkupStyle KEY=new MarkupStyle(new Color(230, 0, 0));
    public static final HashMap<Character, MarkupStyle> STATIC_CHARS=new HashMap<Character, MarkupStyle>();
    static {
        STATIC_CHARS.put(new Character('='), MarkupStyle.GRAY);
    }
    private static final Pattern GROUP_PATTERN=Pattern.compile("\\[\\w*\\]");
    private static final Pattern CMT_PATTERN=Pattern.compile("#.*");
    private static final Pattern KEY_PATTERN=Pattern.compile("[\\w|\\d|_|.|-|]*=");
    @Override
    public HashMap<int[], MarkupStyle> findMarkup(String text) {
        // groups [group]
        Matcher matcher=GROUP_PATTERN.matcher(text);
        HashMap<int[], MarkupStyle> markups=new HashMap<int[], MarkupStyle>();
        while (matcher.find()) {
            int[] ar=new int[2];
            ar[0]=matcher.start();
            ar[1]=matcher.end();
            markups.put(ar, GROUP);
        }
        // comments #comment
        matcher=CMT_PATTERN.matcher(text);
        while (matcher.find()) {
            int[] ar=new int[2];
            ar[0]=matcher.start();
            ar[1]=matcher.end();
            markups.put(ar, COMMENT);
        }
        // keys key=value
        matcher=KEY_PATTERN.matcher(text);
        while (matcher.find()) {
            int[] ar=new int[2];
            ar[0]=matcher.start();
            ar[1]=matcher.end()-1;
            markups.put(ar, KEY);
        }
        return markups;
    }
    public HashMap<Character, MarkupStyle> getStaticChars() {
        return STATIC_CHARS;
    }
}
 

diggaa1984

Top Contributor
Funktioniert es denn durch deinen Workaround? Ich habe bei mir gerade mal getestet .. das offset erhöht sich intern durch einen Zeilenumbruch nur um 1 .. das würde sich ja mit deinem Beispiel decken. Aber wenn du jetzt die Umbrüche gegen den leeren String ersetzt, dann dürfte das wieder nicht hinkommen?!

Der MarkupFinder könnte pauschal alle Umbrüche und Rückläufe mit einem Leerzeichen ersetzen, dann wäre der Index korrekt, da das Steuerzeichen somit nur die Länge eines Zeichens widerspiegelt?

In meinem Editor löse ich das derart, dass ich mein Highlight an Stelle X beginne. Dann nehme ich mir das erste Token vom Lexer (quasi das erste Element von deinem Iterator) und lasse per indexOf diesen Text suchen, dann wird ab da über die Länge des Textes das Highlight angewendet .. dann korrigiere ich die Stelle X nach hinten und suche das Vorkommen des 2. Tokens im Text. Da kümmern mich Umbrüche und Zeilen quasi nicht. Ich benötige nur die Art und den Text für das Highlight, die Position wird gesucht und dann das Highlight angewandt. Ich Highlighte ja nur zusammenhängende Textblöcke, daher kann ich da sukzessive durch den Text gehen.

Java:
private void highlightString(int startOffset, int endOffset) throws BadLocationException {
		String str = this.getText(startOffset, endOffset-startOffset);		
		List<Token> tokenList = scanString(str);
		int suboffs = 0;
		int begin = 0;
		
		//highlight each token data
		for (int i=0; i<tokenList.size(); i++) {
			Token t = tokenList.get(i);
			begin = str.indexOf(t.getText(),suboffs);
			
			//sind alle durch die Grammatik im Lexer erfasst (IDENT, INT, FLOAT, COMMENTS)
			if (tokenTypeToStyle.containsKey(t.getType())) {
				super.setCharacterAttributes(begin+startOffset, t.getText().length(), 
						context.getStyle(tokenTypeToStyle.get(t.getType()).getLabel()).copyAttributes(), true);
			} else {
				if (t.getType() == Token.INVALID_TOKEN_TYPE) {
					//UNKNOWN
					if (showErrors) {
						super.setCharacterAttributes(begin+startOffset, t.getText().length(), 
								errorAttributeSet.copyAttributes(), true);
					} else {
						super.setCharacterAttributes(begin+startOffset, t.getText().length(), 
								defaultAttributeSet.copyAttributes(), true);
					}//if
				} else if ( .. )
					// weitere spezifische checks ..
				} else {
					//DEFAULT
					super.setCharacterAttributes(begin+startOffset, t.getText().length(), 
							defaultAttributeSet.copyAttributes(), true);
				}//if
			}//if
			
			suboffs = begin + t.getText().length();
		}//for
	}//highlightString
 
Zuletzt bearbeitet:

Tobse

Top Contributor
Naja, z.B. folgender Code ist da problematisch:
Code:
// Das ist D
improt std.stdio;

void main(string[] args) {
}
Hier findet mein Code [c]std.stdio;void[/c] anstadt [c]std.stdio;[/c] und [c]void[/c], weshalb [c]void[/c], was ein keyword ist, nicht hervorgehoben wird.

Funktioniert es denn durch deinen Workaround? Ich habe bei mir gerade mal getestet .. das offset erhöht sich intern durch einen Zeilenumbruch nur um 1 .. das würde sich ja mit deinem Beispiel decken. Aber wenn du jetzt die Umbrüche gegen den leeren String ersetzt, dann dürfte das wieder nicht hinkommen?!
Doch genau dadurch. Für JTextPane gibt es keine Zeilenumbrüche. Also nehm ich sie auch alle raus, dann behandeln beide codeteile das gleiche und dann passts. Aber s.o.
 
Zuletzt bearbeitet:

diggaa1984

Top Contributor
hm das beispiel deckt sich grad nich mit den patterns unten, da kann ich nun nicht viel zu sagen, aber wenn es ein syntaxhighlight für ne programmiersprache sein soll, so muss es ja ne liste mit keywords geben etc. und die sind abgeschlossen wenn sie von leerzeichen umgeben wären.

was ich nicht verstehe, warum es für JTextPane kein Zeilenumbruch gibt?!

Code:
a
a
im JEditorPane wäre der offset des oberen a's 0 und des unteren 2, der Umbruch macht quasi 1 Zeichen aus. Wie ist das dann beim JTextPane? Daher mein Gedanke, dass ein ersetzen durch den leeren String auch fehlerhaft wäre.
 

Tobse

Top Contributor
da kann ich nun nicht viel zu sagen
Mein problem bezieht sich eher auf JTextPane als auf das umsetzen des syntax-highlightings.

Im JTextPane sieht das z.B so aus:
Code:
ab
c
Wenn ich dann auf das StyledDocument setCharacterAttributes aufrufe, gilt:
[c]a[/c] index [c]0[/c]
[c]b[/c] index [c]1[/c]
[c]c[/c] index [c]2[/c]

Im String gilt ja bekannterweise
[c]a[/c] index [c]0[/c]
[c]b[/c] index [c]1[/c]
[c]c[/c] index [c]3[/c]

Und da ist das problem. Aber wenn du grade sagst, dass du mit dem JEditorPane keine derartigen probs hast, dann versuch ichs mal damit.
 

Tobse

Top Contributor
Ah! Siehe da, [c]StyledDocument.putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n");[/c] hat das Problem gelöst. Danke!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
B Stylen eines JTextPane funktioniert nicht AWT, Swing, JavaFX & SWT 1
T JTextPane ignoriert HTML Zeilenumbruch <br> tag wegen eigenem HTMLEditorKit AWT, Swing, JavaFX & SWT 5
J Swing JTextpane aktuallisiert nicht den setText? AWT, Swing, JavaFX & SWT 9
M Strings im JTextPane vergleichen und mit StyledDocument formatieren AWT, Swing, JavaFX & SWT 3
X JTextPane automatischer Zeilenumbruch IM Wort AWT, Swing, JavaFX & SWT 2
R GUI Element in einer Methode aktualisieren (JTextPane) AWT, Swing, JavaFX & SWT 13
M Swing JTextPane, Bilder und Text-flow AWT, Swing, JavaFX & SWT 2
D Swing Breite einer HTML Tabelle in einer JTextPane AWT, Swing, JavaFX & SWT 6
S Swing Warum funktioniert der automatische Zeilenumbruch mit arabischen Zeichen beim JTextPane nicht AWT, Swing, JavaFX & SWT 3
S Swing JtextPane sau langsam AWT, Swing, JavaFX & SWT 15
J Swing JTextPane mit JScrollPane auf JPanel scrollen nicht AWT, Swing, JavaFX & SWT 6
C JTextPane scrollt mit setText() immer nach oben AWT, Swing, JavaFX & SWT 2
S Swing Style Attribute aus JTextPane kopieren AWT, Swing, JavaFX & SWT 1
E JTextPane Focus AWT, Swing, JavaFX & SWT 1
TheJavaKid JTextPane: komplexe Formatierung (links) AWT, Swing, JavaFX & SWT 2
B Swing JTextPane - Einfärbungen auf "default" AWT, Swing, JavaFX & SWT 2
A Swing Einrücken mehrerer Zeilen per Tab in einem JTextPane/JTextArea AWT, Swing, JavaFX & SWT 3
T JtextPane Zeile aktualisieren AWT, Swing, JavaFX & SWT 3
T Hintergrundbild in JTextPane fixieren AWT, Swing, JavaFX & SWT 2
M Swing JTextPane frisst Anführungszeichen AWT, Swing, JavaFX & SWT 2
M Swing JTextPane + Scrollbar = Fragen AWT, Swing, JavaFX & SWT 15
H Swing JTextPane hat unästhetisches Scrollbar AWT, Swing, JavaFX & SWT 3
R Swing Renderproblem bei HTML in einer JTextPane AWT, Swing, JavaFX & SWT 12
N Swing JTextPane zur Anzeige von HTML AWT, Swing, JavaFX & SWT 2
E Swing jTextPane Text datei anzeigen AWT, Swing, JavaFX & SWT 7
xehpuk Swing Line-wrapping von JTextPane (in JScrollPane) AWT, Swing, JavaFX & SWT 3
X Swing JTextPane bei Größenänderung Formatierung behalten AWT, Swing, JavaFX & SWT 11
0 JTextPane copy/paste trotz editable(false) ? AWT, Swing, JavaFX & SWT 10
T Swing JTextPane Tastatureingabe abfangen AWT, Swing, JavaFX & SWT 4
B Durchsichtiges JScroll und JTextPane AWT, Swing, JavaFX & SWT 4
xehpuk Swing JTextPane in JScrollPane wird nicht ordentlich neugezeichnet AWT, Swing, JavaFX & SWT 3
S Swing JTextPane append formatprobleme AWT, Swing, JavaFX & SWT 5
C JTextPane / JEditorPane ohne Keywords farbig machen AWT, Swing, JavaFX & SWT 4
C Zeilenumbruch von JTextPane wird nicht erkannt AWT, Swing, JavaFX & SWT 2
S JEditorPane oder JTextPane? AWT, Swing, JavaFX & SWT 2
P Aktuelle Zeile in JTextPane farblich hervorheben AWT, Swing, JavaFX & SWT 3
J JTextPane Background setzen AWT, Swing, JavaFX & SWT 6
T Text in JTextPane vertikal (!) zentrieren AWT, Swing, JavaFX & SWT 4
M Zugriff paralleler Threads auf selbes JTextPane AWT, Swing, JavaFX & SWT 6
M JTextPane - bewegungsloses Hintergrundsbild (Duplikat) AWT, Swing, JavaFX & SWT 2
B JTextPane formatierten Inhalt speichern AWT, Swing, JavaFX & SWT 2
E JTextPane setText ignoriert \n AWT, Swing, JavaFX & SWT 6
P Swing Sichtbaren teil eines JTextPane herausbekommen (mit JScrollPane) AWT, Swing, JavaFX & SWT 2
C Swing JTextPane zeigt HTML-Text aus Variable nicht an :( AWT, Swing, JavaFX & SWT 3
T Zeichen zählen JTextPane AWT, Swing, JavaFX & SWT 4
K Swing JTextPane Formatierungen SyntaxHighlighting AWT, Swing, JavaFX & SWT 11
F Mit TAB JTextPane wechseln AWT, Swing, JavaFX & SWT 5
J JSlider auf JTextPane? AWT, Swing, JavaFX & SWT 2
S Buchstabenpositionen in JTextPane erhalten..? AWT, Swing, JavaFX & SWT 5
I JTextPane und Hyperlink (ohne JEditorPane) AWT, Swing, JavaFX & SWT 5
T Swing JTextArea, JTextPane, JEditorPane...Unterschied?! AWT, Swing, JavaFX & SWT 3
A Swing JTextPane sehr langsam AWT, Swing, JavaFX & SWT 6
P Drucken von Jtextpane mit Seitenangabe AWT, Swing, JavaFX & SWT 1
M Swing JTextPane mit JScrollPane soll aussehen wie JLabel AWT, Swing, JavaFX & SWT 3
A JTextPane: Text hinzufügen AWT, Swing, JavaFX & SWT 9
E Swing JTextPane Inhalt(Text und Bilder) als HTML text bekommen AWT, Swing, JavaFX & SWT 3
K Swing jTextPane zeilenumbruch AWT, Swing, JavaFX & SWT 2
Stillmatic JTextPane langsam? AWT, Swing, JavaFX & SWT 5
E Swing JTextPane linewrap AWT, Swing, JavaFX & SWT 4
M Swing [JTextPane] Cursor lässt sich nicht mit Pfeiltasten bewegen AWT, Swing, JavaFX & SWT 3
T Swing xml in JTextPane mit EditorKit, StyledDocument & co. AWT, Swing, JavaFX & SWT 3
M Cursor setzen im JTextPane AWT, Swing, JavaFX & SWT 3
M Formatierungsfehler JTextPane WARUM ?? AWT, Swing, JavaFX & SWT 4
JavaKaffee Array auslesen in jTextPane? AWT, Swing, JavaFX & SWT 9
E JTextPane Bold Italic und Co AWT, Swing, JavaFX & SWT 6
M JTextPane Ende des Feldes AWT, Swing, JavaFX & SWT 4
D JTextPane - Text andersfarbig unterstreichen AWT, Swing, JavaFX & SWT 7
P Probleme mit JTextpane AWT, Swing, JavaFX & SWT 7
M Größe von JTextPane manuell bei Bedarf anpassen AWT, Swing, JavaFX & SWT 6
bugmenot JTextPane String stimmt nicht mit übergebenem String überein AWT, Swing, JavaFX & SWT 9
C JTextPane <br oder <p> statt \n AWT, Swing, JavaFX & SWT 2
C JTextPane HTML und eigene Tags AWT, Swing, JavaFX & SWT 10
G JTextPane durchsichtig? AWT, Swing, JavaFX & SWT 6
GilbertGrape Fehler bei HTML in JTextPane AWT, Swing, JavaFX & SWT 2
S JTextPane: Probem mit AlignmentAction AWT, Swing, JavaFX & SWT 3
J Problem mit JTextPane & JScrollPane (horizontal) AWT, Swing, JavaFX & SWT 3
B JTextPane und Image importieren in HTML String. AWT, Swing, JavaFX & SWT 2
J JTextPane mit genau 80 Zeichen breite definieren? AWT, Swing, JavaFX & SWT 3
J Html in JTextPane anzeigen? AWT, Swing, JavaFX & SWT 2
Steev JTextPane mit Textformatierung funktioniert nicht AWT, Swing, JavaFX & SWT 5
S JTextPane - markierten Text Formatieren AWT, Swing, JavaFX & SWT 11
P HTMLDocument in einem JTextPane. Anhängen von HTML-Code AWT, Swing, JavaFX & SWT 2
M Makierten Text in JTextPane zentrieren AWT, Swing, JavaFX & SWT 2
F JTextPane aktive Zeile AWT, Swing, JavaFX & SWT 2
G insert & JTextPane AWT, Swing, JavaFX & SWT 4
J JTextPane bekommt keinen Focus! AWT, Swing, JavaFX & SWT 3
S Farben eienr JTextPane dynamisch zuweisen AWT, Swing, JavaFX & SWT 2
R JTextPane scrollen vermeiden AWT, Swing, JavaFX & SWT 2
B Feste Breite einer JTextPane, die HTML anzeigt AWT, Swing, JavaFX & SWT 8
A JScrollPane in JTextPane AWT, Swing, JavaFX & SWT 2
B Swing Logging: Ein/Ausblenden eines scrollenden JTextPane AWT, Swing, JavaFX & SWT 2
F Java JTextPane AWT, Swing, JavaFX & SWT 13
Saxony JTextPane - letzte Zeile löschen AWT, Swing, JavaFX & SWT 4
TheJavaKid LineWrap & WrapStyleWord in JTextPane AWT, Swing, JavaFX & SWT 3
G Zeilenabstand bei HTML-Texten in JLabel/JTextPane AWT, Swing, JavaFX & SWT 7
O Swing Xml highlightning mit JTextPane und Regular expressions AWT, Swing, JavaFX & SWT 5
J JTextPane Alignment AWT, Swing, JavaFX & SWT 6
Y entfernten String einer JTextPane per DocumentListener AWT, Swing, JavaFX & SWT 5
B Ein großes JTextPane komplett drucken AWT, Swing, JavaFX & SWT 2
7 Latex/MathML Code in JTextPane AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben