Я разрабатываю собственное представление XML с помощью javafx. Представьте себе следующий XML.
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
Теперь я хочу, чтобы пользователь мог редактировать заголовок, исполнителя и т. д. Без возможности изменения остальной части XML. Обратите внимание, что моя цель - добиться этого с помощью стиля XML и не предоставлять пользователю диалоговое окно ввода.
Есть идеи, как я могу этого добиться?
Я использую TextArea.




Вы можете использовать TextFormatter с фильтром регулярных выражений, чтобы гарантировать формат:
Это всего лишь небольшой пример: (Вы должны адаптировать регулярное выражение к своим потребностям)
TextArea ta = new TextArea();
ta.setText("<CD>\n <TITLE>Empire Burlesque</TITLE>\n <ARTIST>Bob Dylan</ARTIST>\n <COUNTRY>USA</COUNTRY>\n <COMPANY>Columbia</COMPANY>\n <PRICE>10.90</PRICE>\n <YEAR>1985</YEAR>\n</CD>");
UnaryOperator<Change> filter = c -> {
if (c.getControlNewText().matches("<CD>\\n <TITLE>.*</TITLE>\\n <ARTIST>.*</ARTIST>\\n <COUNTRY>.*</COUNTRY>\\n <COMPANY>.*</COMPANY>\\n <PRICE>[0-9]*\\.?[0-9]*</PRICE>\\n <YEAR>[0-9]{0,4}</YEAR>\\n</CD>")) {
return c;
}
// The new input doesn't match the regex and gets discarded
return null;
};
ta.setTextFormatter(new TextFormatter<String>(filter));
Вы можете добиться этого, используя компонент TextFlow.
Он работает, передавая объекты на ваш TextFlow, такие как TextField, Text и т. д.
Вы можете добавить индивидуальный стиль к каждому из этих объектов.
Теперь ваши заголовки XML могут быть, например, объектами Text, а ваши значения - объектами TextField.
Затем вы можете выбрать, можно ли редактировать объект TextField, который вы добавляете в TextFlow. Например:
Text field = new Text("one");
TextField value = new TextField("two");
value.setPrefWidth(value.getText().length()*12); // customize if needed
value.setStyle("-fx-fill: RED;-fx-font-weight:normal;"); // adding css
value.setEditable(false); // this field cannot be edited
textFlow.getChildren().addAll(field,value);
Вы можете самостоятельно создать макет для xml, который использует узлы Text для начальных / конечных тегов и TextField для текстового содержимого:
String input = "<CD>\n"
+ " <TITLE>Empire Burlesque</TITLE>\n"
+ " <ARTIST>Bob Dylan</ARTIST>\n"
+ " <COUNTRY>USA</COUNTRY>\n"
+ " <COMPANY>Columbia</COMPANY>\n"
+ " <PRICE>10.90</PRICE>\n"
+ " <YEAR>1985</YEAR>\n"
+ "</CD>";
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
XMLStreamReader reader = inputFactory.createXMLStreamReader(new ByteArrayInputStream(input.getBytes()));
List<List<Node>> currentChildren = new ArrayList<>();
currentChildren.add(new ArrayList<>(1));
String text = null;
int depth = 0;
final Insets insets = new Insets(0, 0, 0, 20);
boolean hasChildren = false;
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
depth++;
hasChildren = false;
currentChildren.add(new ArrayList<>());
break;
case XMLStreamConstants.CHARACTERS:
text = reader.getText();
break;
case XMLStreamConstants.END_ELEMENT:
String suffix = reader.getName().getLocalPart() + ">";
if (hasChildren) {
// element group
VBox vbox = new VBox(new Text("<" + suffix));
for (Node n : currentChildren.get(depth)) {
VBox.setMargin(n, insets);
}
vbox.getChildren().addAll(currentChildren.get(depth));
vbox.getChildren().add(new Text("</" + suffix));
currentChildren.get(depth - 1).add(vbox);
} else {
// text element
TextField textField = new TextField(text);
textField.setMinWidth(Region.USE_PREF_SIZE);
textField.setMaxWidth(Region.USE_PREF_SIZE);
// keep size of TextField large enough to contain all the text
ChangeListener<String> listener = new ChangeListener<String>() {
private final Text measureElement = new Text();
{
measureElement.setFont(Font.font("monospaced"));
}
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
measureElement.setText(newValue);
textField.setPrefWidth(measureElement.getLayoutBounds().getWidth() + 2);
}
};
listener.changed(null, null, text);
textField.textProperty().addListener(listener);
HBox hbox = new HBox(new Text('<' + suffix), textField, new Text("</" + suffix));
currentChildren.get(depth - 1).add(hbox);
hasChildren = true;
text = null;
}
currentChildren.remove(depth);
depth--;
break;
}
}
VBox root = (VBox) currentChildren.get(0).get(0);
root.getStyleClass().add("xml-editor");
.xml-editor .text-field,
.xml-editor .text-field:focused {
/* remove TextField border & background */
-fx-focus-color: transparent;
-fx-control-inner-background: transparent;
-fx-faint-focus-color: transparent;
-fx-text-box-border: transparent;
-fx-text-fill: black;
-fx-padding: 0;
-fx-font-family: 'monospaced';
}
.xml-editor Text {
-fx-font-family: 'monospaced';
}
Потрясающие! Прекрасно работает. Могу ли я использовать это в моем коде? Под какой лицензией находится ваш код? знак равно
какой компонент JavaFX вы используете для представления xml?