JavaFX仅允许用户编辑文本的某些区域

时间:2018-04-13 09:21:07

标签: java xml javafx

我正在使用javafx设计自定义XML视图。 想象一下以下的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样式实现此目的,并且不要向用户显示输入,对话框。

我是如何实现这一目标的?

3 个答案:

答案 0 :(得分:2)

您可以使用带有正则表达式过滤器的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));

答案 1 :(得分:1)

您可以使用TextFlow组件来实现此目的。

它的工作原理是将对象传递给TextFlow,例如TextFieldText等。

您可以为每个对象添加自定义样式。

现在,您的XML标题可以是Text个对象,例如TextField个。

然后,您可以选择要添加到TextField的{​​{1}}对象是否可编辑。例如:

TextFlow

答案 2 :(得分:1)

您可以自行为xml布局,其中{/ 1}}节点用于开始/结束标记,Text用于文本内容:

TextField

CSS样式表

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");