Swing DefaultStyledDocument .. Cursorposition bei insertString

Status
Nicht offen für weitere Antworten.

diggaa1984

Top Contributor
hallo,

ich arbeite zur Zeit daran das Syntaxhighlighting für meinen Editor einzubaun, und bin gerade dabei die Funktion dafür im Document zu implementieren. Das Document muss bei insertString gemäß bekannter Strings (Schluesselwörter, Klammern etc.) die Attribute des eingefügten Textes durch vom Nutzer definierte Styles ersetzen.

ich habe, um es erstmal zu testen, so gemacht, dass ich jeweils den kompletten Inhalt des Documentes noch einmal analysiere. Ich weiss, dass es nicht wirklich schön ist sobald der Inhalt des Documentes umfangreicher wird, aber zu Testzweckens ob diese Ersetzungen überhaupt funktionierens ging es damit am schnellsten.

Das Problem dabei ist nun, dass der Cursor immer ans Ende des Documentes springt egal wo ich gerade neuen Text eintippe. Mir ist klar woran das liegt ... ich füge ja quasi den gesamten Text des Documentes erneut ein und somit bekommen die DocumentListener (JTextPane in meinem Fall) die Information eines Offsets von 0 und einer Textlänge die bis zum Ende des Documentes reicht. Die Listener setzen nun den Cursor ans Ende des eingefügten Textes.

Gibt es eine Möglichkeit den Listener glauben zu lassen, dass an Stelle xy es eingefügt wurde und somit die Cursorposition korrigiert wird? Ein insertString mit "" funktioniert nicht, das wird im AbstractDocument oder im DefaultStyledDocument abgefangen und kommt gar nicht erst bis zu den Listenern durch.

Was ich mich auch frage:
Wenn ich nicht jedesmal den kompletten Text des Documentes erneut mit Attributen versehe, dann kann es ja trotzdem passieren das ich nachfolgenden Text, hinter der aktuellen Cursorposition ändern muss (bspw habe ich an Offset 0 ein Schlüsselwort fett dargestellt, und schreibe nun etwas direkt vor dieses Schlüsselwort. Aufgrund dessen das mein Parser das Schlüsselwort eh nicht mehr direkt erkennen kann, würde ich nun das den kompletten String mit Standardwerten darstellen, das heisst das Schlüsselwort muss nachträglich wieder normal dargestellt werden. Das wäre hinter der aktuellen insert-Position. Dabei darf sich ber der Cursor nicht gleich ans Ende vom Schlüsselwort bewegen.) Aber wie würde ich das machen können?

Ich hoffe ihr wisst in etwa was mein Problem ist :D
Code an sich sollte eigentlich nicht notwendig sein, er funktioniert ja soweit abgesehen davon das eben die Cursorposition nachträglich korrigiert werden müsste ^^
 
Zuletzt bearbeitet:

Ebenius

Top Contributor
Wenn Du remove + insert machst, springt der Cursor. Daran lässt sich aus dem Document meiner Meinung nach nichts ändern.

Was Deine zweite Frage angeht: Warum solltest Du da insert benutzen und nicht update? Du setzt doch sicher nur Attribute auf bestehendem Inhalt neu (also auf dem Schlüsselwort). Da gibt's kein Insert hinter der insert-Position. Und dann sollte auch der Cursor nicht springen, oder? Falls ich da falsch liege, kannst Du ja auch das Aussehen des Schlüsselwortes ändern und danach den Buchstaben einfügen, der direkt vor dem Schlüsselwort liegt. Dann geht der Cursor an die richtige Stelle.

Ebenius
 

diggaa1984

Top Contributor
kannst Du ja auch das Aussehen des Schlüsselwortes ändern und danach den Buchstaben einfügen, der direkt vor dem Schlüsselwort liegt. Dann geht der Cursor an die richtige Stelle.

Ebenius

Aeh ja hatte ich vergessen zu erwähnen :D ... ich habe gestern auch testhalber statt dem "" ein "-" eingefügt an der Stelle wo der Cursor am Ende sein soll .. das Zeichen erscheint aber der Cursor war trotzdem am Ende des docs ^^ ... ich probiers mal mit update .. mal schaun
 

Ebenius

Top Contributor
Mal eben dahingeschmiert; so geht's:
Java:
/* (@)CursorFun.java */

/* Copyright 2009 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.awt.BorderLayout;
import java.awt.Color;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.*;
import javax.swing.text.*;

/**
 * TODO: Javadoc me!
 * 
 * @version $Revision$ as of $Date$
 * @author Sebastian Haufe
 * @since Playground-3.8
 */
public class CursorFun {

  /**
   * Test main method.
   * 
   * @param args ignored
   */
  public static void main(String[] args) {
    final StyledDocument doc = new DefaultStyledDocument() {

      final Matcher matcher =
            Pattern.compile("(?:^|\\s)THE_KEYWORD(?:\\s|$)").matcher("");

      int keywordPosition = 0;
      int keywordLength = 0;
      Style keyStyle;
      Style rootStyle;
      {
        try {
          rootStyle = addStyle("root", null);

          keyStyle = addStyle("key", rootStyle);
          StyleConstants.setBold(keyStyle, true);
          StyleConstants.setForeground(keyStyle, Color.RED);

          final String kw = "THE_KEYWORD";
          keywordLength = kw.length();
          insertString(0, kw, null);
        } catch (BadLocationException ex) {
          ex.printStackTrace();
        }
      }

      @Override
      public void insertString(int offs, String str, AttributeSet a)
            throws BadLocationException {
        super.insertString(offs, str, a);
        checkDocument();
      }

      @Override
      public void remove(int offs, int len) throws BadLocationException {
        super.remove(offs, len);
        checkDocument();
      }

      private void checkDocument() {

        setCharacterAttributes(0, getLength(), rootStyle, true);
        try {
          matcher.reset(getText(0, getLength()));
          while (matcher.find()) {
            setCharacterAttributes(matcher.start(), matcher.end()
                  - matcher.start(), keyStyle, true);
          }
        } catch (BadLocationException ex) {
          ex.printStackTrace();
        }
      }
    };

    final JPanel contentPane = new JPanel(new BorderLayout(6, 6));
    contentPane.add(new JScrollPane(new JTextPane(doc)));

    final JFrame f = new JFrame("Test Frame: CursorFun"); //$NON-NLS-1$
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
}
Ebenius
 

diggaa1984

Top Contributor
ah gut ok, habs nun damit gelöst
Java:
super.setCharacterAttributes(...);

bösten dank :D
werd später auch versuchen das ganze optimaler zu lösen, aber da müsst ich zumindest alles betrachten was um Änderungsposition herum von bestimmten Zeichen eingeschlossen wird (Klammernpaare, Whitespaces). Da müsste ich ab Änderungsposition also im Document erstmal suchen wo vor und hinter der Position solche Zeichen zu finden sind. Das ist mit Sicherheit nicht so ganz effizient machbar oder?!

Code:
AX(foo U (baaaaaaaaaar >= 1.243,5e-6)) //wäre korrekt

AX(foo U (baaaaaaaaaaaaar >= 1.234,5e-6)) //wäre falsch

Wenn ich das bar verändere, muss ich ja das ganze Wort als solches erkennen da der eingefügte Text dieses verändert. Aber es gibt nun ne ganze Menge von Symbolen welche ich als explizite Trenner betrachten kann. Ich müsste also alles von der ( bis zum Leerzeichen erkennen und ggf. den Style ändern.

Gibts dazu eine etablierte Lösung? Vor allem für die Rückwärts-Suche ab Änderungsposition.

EDIT: ja hatte die Methode schon gefunden ^^ aber warst schneller mits schreiben
 

Ebenius

Top Contributor
Auf Deine weiteren Fragen kann ich eigentlich nicht antworten. Hängt ja alles stark von der jeweiligen Gramatik ab... Im Prinzip müsstest Du immer alles gesamtheitlich prüfen.

Ebenius
 

diggaa1984

Top Contributor
gut ok dann schau ich mal wie er sich anstellt wenn das Document n paar 1000 Zeichen enthält ^^

Aber hast mich ja n Stück weiter gebracht, danke dir
 

diggaa1984

Top Contributor
jut also bei paar-hundert Zeichen dauerts eindeutig zu lange das komplette Document zu checken.

Es reicht meiner nach auch, wenn man nur zeilenweise neu checken muss, das ganze habe ich nun so umgesetzt und funktioniert bisher einwandfrei ^^ .. hoffe das es mir nich irgendwann querschlägt

Java:
//check actual line
int start = root.getElement(root.getElementIndex(offs)).getStartOffset();
int end = root.getElement(root.getElementIndex(offs)).getEndOffset();
checkString(start,this.getText(start, end-start));

seh grad, das ganze funktioniert nicht ganz, wenn ich mehrere Zeilen per paste einfüge :D .. aber ok denk da find ich noch ne Lösung, im Notfall split ich den String der ins insertString geht nach Umbrüchen und rufe dann checkString pro Zeile auf
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen


Oben