Замена Javafx для качания javax.swing.text.Document

У меня есть приложение 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);
     }
    }
    

Вы можете предоставить эту функциональность с помощью TextFormatter

James_D 28.09.2023 13:38

См. Javadocs и этот хороший учебник

James_D 28.09.2023 14:52

Спасибо!! Я посмотрю документацию этого класса. Кажется, это отвечает моим потребностям!!!

Hervé Girod 28.09.2023 15:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Эту функциональность можно реализовать в 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();
    }
}

Иногда я нахожу использование TextFormatter немного неинтуитивным (хотя оно очень мощное). Возможно, вам захочется обратиться к этому отличному уроку.

Другие вопросы по теме