我有一个 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)
此功能可以在 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有点不直观(尽管它非常强大)。您可能想参考这个优秀的教程。