String suchen und wenn gefunden, einfärben

Hallo :slight_smile:

Das das andere Forum zu gemacht hat und die einzige Antwort ein Link zu diesem Forum war und im anderen sich iwie nix mehr tut, poste ich mein Problem hier nochmal:

Also ich habe mir einen Text-Editor gebastelt (steckt noch in den Kinderschuhen :P) und hab nun ein Problem.
Ich will eine Suchfunktion nach bestimmten Text-Passagen reinmachen, eine Suchen-&-Ersetzen Funktion habe ich bereits. Die Suchfunktion soll eine Text-Passage suchen und wenn Sie gefunden wurde, markieren. Allerdings klappt das nicht so ganz. Es soll halt so sein, das alle entsprechenden Textstellen markiert werden sollen und sie sollen markiert bleiben, bis man woanders hinklickt oder sonstwas tut, wie ganz normal mit der aus markieren halt.
Hier erstmal die (denke ich) wichtigsten bzw. betroffenen Stellen bzw. Klassen:

Die Ersetzen-Funktion


import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;


public class Ersetze { 

    
    JDialog replaceDialog;
    JTextField replaceOldTextField = new JTextField(15);
    JLabel replaceOldLabel = new JLabel("Ersetze:");
    JTextField replaceNewTextField = new JTextField(15);
    JLabel replaceNewLabel = new JLabel("Durch:");
    static JButton replaceOkay = new JButton("OK");
    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
    JPanel textPanelOld = new JPanel(new FlowLayout(FlowLayout.CENTER));
    JPanel textPanelNew = new JPanel(new FlowLayout(FlowLayout.CENTER));
    private boolean isSearched = false;

    public Ersetze() {
        replaceDialog = new JDialog();
        replaceDialog.setResizable(false);
        replaceDialog.setTitle("Ersetze...");
//        replaceDialog.setSize(new Dimension(300, 200));
        replaceDialog.setModal(true);

        replaceOkay.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                String searched = replaceOldTextField.getText();
                String newText = replaceNewTextField.getText();
                String source = EditorPane.textArea.getText();

                String markedText = source.replaceAll("(" + Pattern.quote(searched) + ")", newText);
                System.out.println(markedText);
                EditorPane.textArea.setText(markedText);
                isSearched = false;
                replaceDialog.setVisible(false);
            }
        });
        buttonPanel.add(replaceOkay, BorderLayout.SOUTH);

        textPanelOld.add(replaceOldLabel);
        textPanelOld.add(replaceOldTextField, BorderLayout.NORTH);
        
        textPanelNew.add(replaceNewLabel);
        textPanelNew.add(replaceNewTextField);

        replaceDialog.add(textPanelOld, BorderLayout.NORTH);
        replaceDialog.add(textPanelNew);
        replaceDialog.add(buttonPanel, BorderLayout.SOUTH);


        KeyListener buttonOK = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent ke) {
                if (!isSearched) {
                    if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
                        replaceOkay.doClick();
                        isSearched = true;
                    }
                }
            }
        };

        replaceOldTextField.addKeyListener(buttonOK);
        replaceNewTextField.addKeyListener(buttonOK);

        replaceDialog.setPreferredSize(new Dimension(300, 125));
        replaceDialog.pack();
        replaceDialog.setVisible(true);
    }

    private static boolean containsString(String source, String searched) {
        return source.indexOf(searched) > -1 ? true : false;
    }

} ```

Meine TextArea (Auch schon mit JEditorPane versucht und dann mit HTML-Tags, aber uich konnte die Standard-Schriftfarbe nicht von Schwarz auf Cyan ändern und so bringt mir das nix.)
```package TextEditor;

import java.awt.Color;
import java.awt.Image;
import java.io.File;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class TextArea {

    Image Bild;
    File BildFile;
    static JTextArea textArea = new JTextArea();
    static JScrollPane scrollPane;

    public TextArea() {
        textArea.setBackground(Color.BLACK);
        textArea.setForeground(Color.CYAN);
        textArea.setCaretColor(Color.CYAN);
        textArea.setComponentPopupMenu(Fenster.popup);
        scrollPane = new JScrollPane(textArea);
        scrollPane.setWheelScrollingEnabled(true);
        scrollPane.setComponentPopupMenu(Fenster.popup);
    }
}

Meine Finde-Funktion:


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Finde {

    static JDialog findDialog;
    JTextField findTextField = new JTextField(15);
    static JButton findOkay = new JButton("OK");
    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
    JPanel textPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
    private boolean isSearched;

    public Finde() {
        findDialog = new JDialog();
        findDialog.setResizable(false);
        findDialog.setTitle("Finde...");
        findDialog.setSize(new Dimension(300, 100));
        findDialog.setModal(true);

        findOkay.addActionListener(new ActionListener() {
            @Override
            @SuppressWarnings("ResultOfMethodCallIgnored")
            public void actionPerformed(ActionEvent ae) {
                String searched = findTextField.getText();
                String source = TextArea.textArea.getText();

                String markedText = source.replaceAll("(" + Pattern.quote(searched) + ")", "<b>$1</b>");
                System.out.println(markedText);
                TextArea.textArea.setText(markedText);
                isSearched = false;
                findDialog.setVisible(false);
            }
        });
        buttonPanel.add(findOkay, BorderLayout.SOUTH);

        textPanel.add(findTextField, BorderLayout.NORTH);

        findDialog.add(textPanel, BorderLayout.NORTH);
        findDialog.add(buttonPanel, BorderLayout.SOUTH);


        KeyListener buttonOK = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent ke) {
                if (!isSearched) {
                    if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
                        findOkay.doClick();
                        isSearched = true;
                    }
                }
            }
        };

        findTextField.addKeyListener(buttonOK);

        findDialog.setVisible(true);
        findDialog.pack();
    }

    private static boolean containsString(String source, String searched) {
        return source.indexOf(searched) > -1 ? true : false;
    }
}

(Die Methode am Ende war ein Versuch ausem Internet mein Vorhaben zu realisieren, kann eig weg, da ich ja eine andere gefunden habe)

Das müssten die Relevanten Klassen sein, wenn ich eine vergessen habe, sagt es mir :slight_smile:

Ahoi

Muss es denn eine JTextArea sein? Afaik kann das Ding keine simplen Anweisungen ala “setForegroundColor”, zumindest nicht ohne größeren Aufwand.
Die einfachere Variante wäre das ganze auf ein JTextPane umzuschreiben

mm also ich hab gerade selber mal ein bisschen geschaut,… was is denn dein genaues Vorhaben damit?
Die JTextArea ansich hat ja die Methode select(Start, End) damit könntest du springen jeweils zu den Worten und diese markieren.

Ansonsten hatte ich noch Swing Highlighter gesehen:
http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/text/Highlighter.html

aber das wäre ja nur „Färben“ soweit ich das gerade überblickt habe

Also es funktioniert alles bis jetzt, auch das setForeground bei der TextArea, nur beim JEditorPane hats nicht funktioniert. Aber ich probiers mal mitem JTextPane.

@pl4gu33 : Das hatte ich auch schon gefunden, allerdings brachte mich das nicht wirklich weiter, weil ich mit den ganzen Methoden die Netbeans dazu ausspuckte ich nicht viel mit anfangen konnte :stuck_out_tongue: Aber die select Methode klingt auch Interessant…

Edit: Select klappt schonmal nicht, dann meckert er rum, vonwegen void nicht erlaubt.

Suchen/Finden geht also, aber markiert wird nur eine Textstelle statt allen?

Nö, ich kriegs ja nicht hin, das er überhaupt etwas markiert :stuck_out_tongue: das Suchen und Ersetzen klappt ja mit replaceAll aber ich finde nix zum markieren

[QUOTE=Schesam]
Edit: Select klappt schonmal nicht, dann meckert er rum, vonwegen void nicht erlaubt.[/QUOTE]

mm wie meinst du das ? ^^

Also ich rede hier von http://docs.oracle.com/javase/7/docs/api/javax/swing/text/JTextComponent.html#select(int,%20int)

wenn man dort dann z.b. textArea.select(1,6) macht, werden die Zeichen 1-6 markiert.
Ich hatte jetzt eher an sowas gedacht, dass man vom Anfang an einen Text nach x durchsucht und dann wenn man x gefunden hat, lässt man sich die Position zurückgeben, markiert und sucht ab dem Ende dann weiter.

Das alle aufeinmal markieren, wäre damit dann aber nicht gegeben. Man würde dann halt die Textpassagen nach und nach finden. War eher nur so als Hinweis gedacht :slight_smile:

TextArea.textArea.select(searched.charAt(searched.length()-searched.length()+1), searched.length()));

So hab ich das da stehen und select() ist vom Typ void, der Compiler sagt aber:
„‚void‘ Type not allowed here“
Aber selbst mit select(1,6) kommt das^^ iwie ja auch logisch, weil er muss ja was zurückkriegen, das er da einsetzen kann.

Aber ich hab noch ein anderes Problem gefunden:
Wenn die Zeile so ist:

Dann schreibe ich das hier in die Area rein ( ist inzwischen ein JTextPane, trz das selbe):

Das ist ein Text, haha ein Text…

Dann geb ich das TextField „Text“ ein (ohne „“) und dann kommt das raus:

Das ist ein TextTest, haha ein TextTest…

kopiere ich das 1. aber wieder rein, schreibe wieder „Text“ rein, dann gibt er das aus:

Das ist ein TextTestTest, haha ein TextTestTest…

usw. usf. Nicht das dann später stört, wenns ums markieren geht

[QUOTE=Schesam]``` String markedText = source.replaceAll("(" + Pattern.quote(searched) + “)”, TextArea.textArea.select(searched.charAt(searched.length()-searched.length()+1), searched.length()));


Naja die Methode gibt auch nix zurück, sie markiert nur die Stelle von x bis y. Also sie wird in der JTextArea ausgewählt, als ob du sie mit der Maus markiert hast. 

Oder kann es sein, dass wir gerade ein anderes Empfinden von "markiert" haben? Meinst du vll. nur einfärben z.b. ?^^ :D

[QUOTE=Schesam;20925] Die Suchfunktion soll eine Text-Passage suchen und wenn Sie gefunden wurde, markieren. Allerdings klappt das nicht so ganz. Es soll halt so sein, das alle entsprechenden Textstellen markiert werden sollen und sie sollen markiert bleiben, bis man woanders hinklickt oder sonstwas tut, wie ganz normal mit der aus markieren halt.
[/QUOTE]

Hat sich irgendwie nach mit der Maus "markieren"/"selektrieren" angehört? :D
JTextArea area = new JTextArea("Hallo Welt. Wir gehts dir");
Highlighter h = area.getHighlighter();

try{
h.addHighlight(0, 10, DefaultHighlighter.DefaultPainter);
}

sollte zeichen 0-10 markieren. Wenn du nun irgendwo anders hinklickst müsstest du das noch abfangen und die Selektion aufheben.

@pl4gu33 : Wenn du mit der Maus z.B. diesen Text hier markierst, dass wird er doch Weiß mit blauem Grund? Genau das will ich mit der Funktion bewerkstelligen :stuck_out_tongue:

@MannOhneNick : Danke, ich probiers mal

Edit: So, danke MannOhneNick, klappt jetzt, das mitem Markieren unso. Jetzt nurnoch auf das Wort irgendwie beziehen… Ach und, wie kann ich die Farbe vom markierten ändern? Weil dieses Blau und das Cyan vertragen sich nicht so wirklich^^ Bzw. kann man das nicht so machen, das wie bei „Mit-Maus-Markieren“ Nicht nur die Stelle markiert wird, sondern die Schriftfarbe sich an dieser Stelle ändert?

ungetestet könntest du dir nen eigenen Highlighter schreiben, statt diesem DefaultPainter

Schau ich dann morgen mal, ich versuch erstmal das mitem markieren hinzukriegen…
Soweit bin ich:

                String source = TextArea.textArea.getText();
                try {
                    int index = source.indexOf(searched);
                    int length = findTextField.getText().length();
                    TextArea.highlighter.addHighlight(index, length, DefaultHighlighter.DefaultPainter);
                    TextArea.isHighLighted = true;
                } catch (BadLocationException ex) {
                    Logger.getLogger(Finde.class.getName()).log(Level.SEVERE, null, ex);
                    System.err.println("Fehler: " + ex);
                }```

Bekomm aber ne Exception, die sich "javax.swing.text.BadLocationException: Invalid end offset" schimpft. Aber keine Ahnung wieso, weil wenn ich findTextField.getText() mit source austausche klappts, allerdings malt er mir dann den ganzen Text zu...

probiere es mal mit
Java Code:
[LEFT]TextArea.highlighter.addHighlight(index, length-1, DefaultHighlighter.DefaultPainter);
[/LEFT]

Hab ich schon versucht, genauso mit -2, aber immer das selbe^^ Ich emine ja, bei source.lenght() klappts ja, auch wenn die Markierung mittendrin anfängt und eingentlich länger als der Text ist.

weil vermutlich dein index größer ist als deine länge. du markierst z.B. von 10 bis 4. versuch mal die länge auf den index zu addieren .)

danke, jetzt klappts. nur wie stelle ich es an, das er alles markiert und nicht nur das 1. Wort? In meinem Beispiel kommt “Text” ja 2x vor, er markiert aber nur das erste. hab gedacht ne while (index != source.lastIndexOf(searched)) drumzumachen, aber wie stell ich es an, das er zum nächsten Index geht?

Hab mir gedacht, ne eigene Methode zu schreiben, die etwa so aussehen soll:

// Alten Index nehmen und zum nächsten gehen, in der Quelle und nach dem Gesuchten suchen

return nextIndex;
}```

hol dir den gesamten text, errechne dir daraus ein array an wörtern und laufe dieses durch. jedesmal wenn du einen “hit” mit deinem suchwort hast markierst du die stelle

                String source = TextArea.textArea.getText();
                try {
                    System.out.println("Try angefangen");
                    final String[] searchedItems = source.split(" ");
                    for (String searchedItem : searchedItems) {
                        System.out.println("In for drin");
                        if (searchedItem.equals(searched)) {
                            System.out.println("Im equals drin");
                            int index = source.indexOf(searchedItem);
                            int length = findTextField.getText().length();
                            TextArea.highlighter.addHighlight(index, index + length, DefaultHighlighter.DefaultPainter);
                            TextArea.isHighLighted = true;
                        }
                    }

                } catch (BadLocationException ex) {
                    Logger.getLogger(Finde.class.getName()).log(Level.SEVERE, null, ex);
                    System.err.println("Fehler: " + ex);
                }```
Das wäre mein Vorschlag. Aber das klappt nur, wenn ich vor den Punkt und vor das Komma ein Leerzeichen mache und auch wieder markiert er nur das erste Wort. Die Ausgabe ist btw.:

> Try angefangen
> In for drin
> In for drin
> In for drin
> In for drin
> Im equals drin
> In for drin
> In for drin
> In for drin
> In for drin
> Im equals drin
> In for drin

Also gibts auch 2 Treffer, aber wieso wird nur das erste markiert?

Anhand welchen Kriteriums splittest du denn deinen Text und vergleichst deinen String dann? Vielleicht wird dann klarer wieso es mit “.” und “,” Probleme gibt.
Das nur das 1. Wort markiert wird liegt an der Art und Weise wie “indexOf” arbeitet. So wie es da steht weis es nichts davon das du quasi den Satz schon bis Stelle X abgesucht hast. Du musst dir also noch merken wo du schon warst und ab wo du weitermachst.