Javafx 替代 swing javax.swing.text.Document

Her*_*rod 2 swing javafx

我有一个 swing 应用程序,它重写 javax.swing.text.Document 以将基础文档的内容限制为某些字符和文本长度。我想将我的应用程序移植到 Javafx,但我不知道此类是否有 Javafx 等效项。有没有办法在Javafx中替换它?

我的类正在做的是包装文档以添加新功能(在我的情况下是有限的)。许多方法仅遵循我使用的底层文档,但其中一些方法增加了我的限制,它们是:

  • 线路长度限制

  • 行数限制

  • 大写限制

  • 字符限制

    public class ConstrainedDocument implements Document {
     protected Document document = null;
     private boolean limitLength = false;
     private boolean limitLines = false;
     private int maxLength = -1;
     private int maxLines = -1;
     private boolean limitText = false;
     private String allowedText = null;
     private boolean uppercase = false;
    
     /**
      * Constructor.
      *
      * @param doc the document
      */
     public ConstrainedDocument(Document doc) {
        this.document = doc;
     }
    
     /**
      * Constructor.
      */
     public ConstrainedDocument() {
        this.document = new PlainDocument();
     }
    
     public Document getDocument() {
        return document;
     }
    
     /**
      * Limits the allowed length for each line of the document.
      * 
      * @param maxLength the maximum line length
      */
     public void setMaximumLength(int maxLength) {
        this.maxLength = maxLength;
        this.limitLength = true;
     }
    
     /**
      * Limits the allowed number of lines for the document.
      * 
      * @param maxLines the maximum number of lines
      */
     public void setMaximumLines(int maxLines) {
        this.maxLines = maxLines;
        this.limitLines = true;
     }
    
     /**
      * Limits the characters allowed to compose the document.
      *
      * @param allowedText the String defining the allowed characters
      */
     public void setAllowedText(String allowedText) {
        this.allowedText = allowedText;
        this.limitText = true;
     }
    
     /**
      * Forces only upper case.
      * 
      * @param uppercase true if only upper case are forced
      */
     public void setUpperCase(boolean uppercase) {
        this.uppercase = uppercase;
     }
    
     /**
      * Resets all the limitations and settings for this document.
      */
     public void resetLimitations() {
        this.limitText = false;
        this.limitLength = false;
        this.limitLines = false;
     }
    
     /**
      * Returns the allowed length for each line of the document.
      * 
      * @return the maximum line length
      */
     public int getMaximumLineLength() {
        return maxLength;
     }
    
     /**
      * Returns the allowed number of lines for the document.
      * 
      * @return the maximum number of lines
      */
     public int getMaximumLines() {
        return maxLines;
     }
    
     /**
      * Returns true if the maximum length of the text is set.
      * 
      * @return true if the maximum length of the text is set
      *
      * @see #getMaximumLineLength()
      */
     public boolean isLineLengthLimited() {
        return limitLength;
     }
    
     /**
      * Returns true if the number of allowed lines is limited.
      * 
      * @return true if the maximum number of lines is set
      *
      * @see #getMaximumLines()
      */
     public boolean isLinesLimited() {
        return limitLines;
     }
    
     /**
      * Returns the characters allowed to compose the document.
      * 
      * @return the allowed characters as a string
      */
     public String getAllowedText() {
        return allowedText;
     }
    
     /**
      * Returns true if the allowed characters are limited.
      * 
      * @return true if the allowed characters are limited
      *
      * @see #getAllowedText()
      */
     public boolean isTextLimited() {
        return limitText;
     }
    
     /**
      * Returns true if the insertion is forced to upper case characters.
      * 
      * @return true if the insertion is forced to upper case characters
      */
     public boolean isUpperCase() {
        return uppercase;
     }
    
     /**
      * Extends the remove method from the parent Document class to fire remove events
      * when lines are removed.
      */
     @Override
     public void remove(int offset, int length) throws BadLocationException {
        document.remove(offset, length);
     }
    
     /**
      * Extends the insertString method from the parent Document class. This adds :
      * <ul>
      * <li>the ability to force upper case characters insertion if the {@link #isUpperCase()}
      * property is set</li>
      * <li>the ability to block insertion of unauthorized characters if the {@link #isTextLimited()}
      * property is set. In that case, the text is limited to the {@link #getAllowedText()} characters</li>
      * <li>the ability to limit the number of lines if the {@link #isLinesLimited()} property is set. In
      * that case, the number of allowed lines is limited to {@link #getMaximumLines()}</li>
      * <li>the ability to limit the length of each line if the {@link #isLineLengthLimited()} property
      * is set. In that case, the length for each line is limited to {@link #getMaximumLineLength()}</li>
      * </ul>
      * <p>
      * It also fire insertion events when lines are inserted.</p>
      */
     @Override
     public void insertString(int offset, String inputStr, AttributeSet a) throws BadLocationException {
        String str = inputStr;
        // handle showSpaces, upper case and characters limitation
        if (uppercase || limitText) {
           StringBuilder buf = new StringBuilder();
           for (int i = 0; i < str.length(); i++) {
              char c = str.charAt(i);
              if (uppercase) {
                 c = Character.toUpperCase(c);
              }
              if (limitText) {
                 if (allowedText.indexOf(c) != -1) {
                    buf.append(c);
                 }
              } else {
                 buf.append(c);
              }
           }
           str = buf.toString();
        }
        Element root = document.getDefaultRootElement();
        AbstractDocument.LeafElement elt = (AbstractDocument.LeafElement) root.getElement(root.getElementIndex(offset));
        // Gets the text to insert, taking care of adding new lines in the process
        str = getTextToInsert(root, elt, str);
        if (str.length() > 0) {
           document.insertString(offset, str, a);
        }
        // if only the length of the text is limited
     }
    
     /**
      * Returns the text to insert on the current line.
      *
      * @param root the root element of the Document
      * @param elt the leaf element, interface the line of text where to insert the text
      * @param t the String to insert
      */
     protected String getTextToInsert(Element root, AbstractDocument.LeafElement elt, String t) {
        // Gets the length of the line where to insert the text
        int begin = elt.getStartOffset();
        int end = elt.getEndOffset();
        int length = end - begin - 1;
        // Gets the number of lines
        int lineCount = root.getElementCount();
    
        // iterate through the text to insert, taking care of the line length
        // and number of lines limitation
        StringBuilder buf = new StringBuilder();
    
        for (int i = 0; i < t.length(); i++) {
           char c = t.charAt(i);
    
           // if this is a new line, we must check if we are allowed to add a new line
           if (c == '\n') {
              // we are not allowed to add a new line
              if (limitLines && lineCount >= maxLines) {
                 break;
              } else {
                 // ok, we can add a new line
                 buf.append(c);
                 lineCount++;
                 length = 0;
              }
              // this is not a new line character, we add the character if we can
           } else {
              // if no line length limitation, we just add the character
              if (!limitLength) {
                 buf.append(c);
              } else if (length >= maxLength) {
                 // else current length >= maximum line length, we try to add a new line
                 // not allowed, finish to add
                 if (limitLines && lineCount >= maxLines) {
                    break;
                 } else {
                    // adding a new line is allowed, there is remaining available lines
                    buf.append('\n').append(c);
                    lineCount++;
                    length = 1;
                 }
                 // current length < maximum line length, we just add the character
              } else {
                 buf.append(c);
                 length++;
              }
           }
        }
        return buf.toString();
     }
    
     /**
      * Return the text of this Document. Special spaces characters will be trasnformed to "real" spaces.
      */
     @Override
     public String getText(int offset, int length) throws BadLocationException {
        String text = document.getText(offset, length);
    
        return text;
     }
    
     /**
      * get the offset position in the Document for the selected line.
      *
      * @param line the selected line
      * @return the offset position.
      */
     public int getOffsetPosition(int line) {
        int offset = 0;
        int count = 0;
    
        if (line == 0) {
           return offset;
        }
    
        Element root = document.getDefaultRootElement();
    
        try {
           for (int i = 0; i < root.getElementCount(); i++) {
              AbstractDocument.LeafElement elt = (AbstractDocument.LeafElement) root.getElement(i);
    
              offset = elt.getStartOffset();
              String text = getText(elt.getStartOffset(), elt.getEndOffset() - elt.getStartOffset());
    
              if (count == line) {
                 break;
              }
              if (text.charAt(text.length() - 1) == '\n') {
                 count++;
              }
           }
        } catch (BadLocationException e) {
           e.printStackTrace();
        }
        return offset;
     }
    
     @Override
     public int getLength() {
        return document.getLength();
     }
    
     @Override
     public void render(Runnable runnable) {
        document.render(runnable);
     }
    
     @Override
     public void addDocumentListener(DocumentListener listener) {
        document.addDocumentListener(listener);
     }
    
     @Override
     public void removeDocumentListener(DocumentListener listener) {
        document.removeDocumentListener(listener);
     }
    
     @Override
     public void addUndoableEditListener(UndoableEditListener listener) {
        document.addUndoableEditListener(listener);
     }
    
     @Override
     public void removeUndoableEditListener(UndoableEditListener listener) {
        document.removeUndoableEditListener(listener);
     }
    
     @Override
     public Element getDefaultRootElement() {
        return document.getDefaultRootElement();
     }
    
     @Override
     public Element[] getRootElements() {
        return document.getRootElements();
     }
    
     @Override
     public Position getEndPosition() {
        return document.getEndPosition();
     }
    
     @Override
     public Position getStartPosition() {
        return document.getStartPosition();
     }
    
     @Override
     public Position createPosition(int i) throws BadLocationException {
        return document.createPosition(i);
     }
    
     @Override
     public void getText(int i, int i0, Segment segment) throws BadLocationException {
        document.getText(i, i0, segment);
     }
    
     @Override
     public Object getProperty(Object key) {
        return document.getProperty(key);
     }
    
     @Override
     public void putProperty(Object key, Object value) {
        document.putProperty(key, value);
     }
    }
    
    Run Code Online (Sandbox Code Playgroud)

Jam*_*s_D 5

此功能可以在 JavaFX 中使用TextFormatter.

例如,这个快速示例实现了最大文本长度。Swing 示例中的其他功能可以类似地实现:

package org.jamesd.examples.maxtextlength;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) {
        TextArea textArea = new TextArea();
        Spinner<Integer> maxLengthSpinner = new Spinner<>(10, 200, 100);
        maxLengthSpinner.valueProperty().addListener((obs, oldLength, newLength) ->
                textArea.setText(textArea.getText().substring(0, Math.min(newLength, textArea.getLength())))
        );
        textArea.setTextFormatter(new TextFormatter<String>(change -> {
            int proposedTextLength = change.getControlNewText().length();
            if (proposedTextLength > maxLengthSpinner.getValue()) {
                // truncate text to maximum allowed length:
                int newTextLength = change.getText().length();
                int delta = proposedTextLength - maxLengthSpinner.getValue();
                change.setText(change.getText().substring(0, newTextLength - delta));
                // adjust caret:
                change.setCaretPosition(change.getCaretPosition() - delta);
                change.setAnchor(change.getAnchor() - delta);
            } 
            return change;
        }));
        Label length = new Label();
        length.textProperty().bind(textArea.textProperty().map(String::length).map(len -> "Length: "+len));
        length.setPadding(new Insets(5));

        HBox controls = new HBox(5, new Label("Max text length:"), maxLengthSpinner);
        controls.setPadding(new Insets(5));
        controls.setAlignment(Pos.CENTER);
        BorderPane root = new BorderPane(textArea);
        root.setBottom(length);
        root.setTop(controls);

        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}
Run Code Online (Sandbox Code Playgroud)

我有时发现它的使用TextFormatter有点不直观(尽管它非常强大)。您可能想参考这个优秀的教程