9

以前在 Swing 中,我使用过JSyntaxPane用于制作小型 Java 源代码编辑器。为了练习,我决定在 JavaFX 中重做整个项目并添加对更多语言的支持。最好是尽可能多的。

但是,似乎没有类似的东西JSyntaxPane

一些研究将我带到了Tom Schindl博客,在那里他制作了一个带有适当语法突出显示的源代码查看器。遗憾的是,没有编辑支持。

然后是JewelSea博客,但从截图来看,它看起来像 SO 的type-and-preview方法。代码编辑器中不需要的东西。

同样,JFXperience我发现突出显示、缩进和编辑面板/节点将在 JavaFX 8 中可用,它还允许将 Swing 嵌入到 Java 中。

到那时,我还有什么其他选择?

我知道 JavaFX 可以与 JavaScript 互操作,那么有没有办法可以使用一些 JavaScript 库来完成相同的操作?

4

4 回答 4

14

RichTextFX可让您进行突出显示。查看Java 关键字示例

请注意,它需要 JDK8。

于 2014-02-01T16:17:17.503 回答
2

我目前在我的开源项目中通过WebEngine. 这是厨房水槽演示。

更新

从当前 JDK 版本开始,一种可能的 JS/FX 交互方法:

  • 编写 JS app/widget 部分,独立测试。如果您只打算嵌入一个编辑器小部件,那么它可能是一个空网页,<div>其中一个是您的编辑器。
  • 那么“从 JS 获取文本”方案的计划可能是这样的:“从 Java 调用 JS 函数,它将从编辑器元素中获取文本,并使用作为方法的字符串参数传递的文本回调 Java 部分” .
  • 学习 Java-JS 绑定 - 即来自 Javascript 的 WebView 回调
  • 嵌入 FirebugLite 以从WebView. 唯一对我有用的版本是:

    <script src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'>

一些一般性建议 - 尽量避免 JS 到 Java 调用的复杂性。我向 JavaFX 团队提交了一些错误,因为一些简单的事情(例如覆盖方法)对我不起作用。避免将 Java 对象传递给 JS——尽管理论上是可能的,但我总是以应用程序崩溃告终。所以现在我正在传递 JSON 并将其转换为双方的对象。

您可以在此处查看AngularJS/JavaFX 应用程序的工作示例。它处于 pre-alpha 状态,因此它甚至可能不会在您的机器上启动,但可以看作是 AngularJS 桌面应用程序的概念证明。

于 2013-10-26T08:02:28.433 回答
1

我发布的编辑器示例不是类型和预览方法,它是使用 WebKit 嵌入 ( codemirror ) 到 JavaFX 应用程序中的 JavaScript 编辑器。您可以在此处找到相关源代码或在概念项目中找到迷你 IDE 的更新版本。

于 2013-10-26T06:15:34.597 回答
0

我为RichTextFX改编了这段代码,以创建我自己的自包含 TextCodeArea。您应该能够将其添加到您的应用程序并使用它运行。你只需要传递一个节点来附加它自己。AnchorPane

public class TextCodeArea {

    private static final String[] KEYWORDS = new String[] {
            "abstract", "assert", "boolean", "break", "byte",
            "case", "catch", "char", "class", "const",
            "continue", "default", "do", "double", "else",
            "enum", "extends", "final", "finally", "float",
            "for", "goto", "if", "implements", "import",
            "instanceof", "int", "interface", "long", "native",
            "new", "package", "private", "protected", "public",
            "return", "short", "static", "strictfp", "super",
            "switch", "synchronized", "this", "throw", "throws",
            "transient", "try", "void", "volatile", "while"
    };

    private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b";
    private static final String PAREN_PATTERN = "\\(|\\)";
    private static final String BRACE_PATTERN = "\\{|\\}";
    private static final String BRACKET_PATTERN = "\\[|\\]";
    private static final String SEMICOLON_PATTERN = "\\;";
    private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
    private static final String COMMENT_PATTERN = "//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/";
    private static final String ASSIGNMENT_PATTERN = "\\s+\\w+?\\s+=" + "|" + "\\s+\\w+\\[.*\\]?\\s+=";

    private static final Pattern PATTERN = Pattern.compile(
            "(?<KEYWORD>" + KEYWORD_PATTERN + ")"
                    + "|(?<PAREN>" + PAREN_PATTERN + ")"
                    + "|(?<BRACE>" + BRACE_PATTERN + ")"
                    + "|(?<BRACKET>" + BRACKET_PATTERN + ")"
                    + "|(?<SEMICOLON>" + SEMICOLON_PATTERN + ")"
                    + "|(?<STRING>" + STRING_PATTERN + ")"
                    + "|(?<COMMENT>" + COMMENT_PATTERN + ")"
                    + "|(?<ASSIGNMENT>" + ASSIGNMENT_PATTERN + ")"
    );

    private CodeArea codeArea;

    public  TextCodeArea(AnchorPane pane) {
        codeArea = new CodeArea();

        VirtualizedScrollPane sp = new VirtualizedScrollPane(codeArea);
        pane.getChildren().add(sp);
        AnchorPane.setLeftAnchor(sp, 0.0);
        AnchorPane.setRightAnchor(sp, 0.0);
        AnchorPane.setBottomAnchor(sp, 0.0);
        AnchorPane.setTopAnchor(sp, 0.0);
        codeArea.prefWidthProperty().bind(pane.widthProperty());
        codeArea.prefHeightProperty().bind(pane.heightProperty());
        codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea));
        Subscription cleanupWhenNoLongerNeedIt = codeArea.multiPlainChanges()
                .successionEnds(java.time.Duration.ofMillis(50))
                .subscribe(ignore -> codeArea.setStyleSpans(0, computeHighlighting(codeArea.getText())));
        final Pattern whiteSpace = Pattern.compile( "^\\s+" );
        codeArea.addEventHandler( KeyEvent.KEY_PRESSED, key -> {
            if (key.getCode() == KeyCode.ENTER) {
                int pos = codeArea.getCaretPosition();
                int par = codeArea.getCurrentParagraph();
                Matcher matcher = whiteSpace.matcher(codeArea.getParagraph(par-1).getSegments().get(0));
                if (matcher.find()) Platform.runLater(() -> codeArea.insertText(pos, matcher.group()));
            }
        });
//        cleanupWhenNoLongerNeedIt.unsubscribe();    // to stop and clean up
    }

    private static StyleSpans<Collection<String>> computeHighlighting(String text) {
        int lastKwEnd = 0;
        Matcher matcher = PATTERN.matcher(text);
        StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>();

        while(matcher.find()) {
            String styleClass =
                    matcher.group("KEYWORD") != null ? "keyword" :
                            matcher.group("PAREN") != null ? "paren" :
                                    matcher.group("BRACE") != null ? "brace" :
                                            matcher.group("BRACKET") != null ? "bracket" :
                                                    matcher.group("SEMICOLON") != null ? "semicolon" :
                                                            matcher.group("STRING") != null ? "string" :
                                                                    matcher.group("COMMENT") != null ? "comment" :
                                                                            matcher.group("ASSIGNMENT") != null ? "assignment" :
                                                                                    null; /* never happens */ assert styleClass != null;
            spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
            spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
            lastKwEnd = matcher.end();
        }
        spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
        return spansBuilder.create();
    }
}

还要确保在您的 JavaFX 应用程序Main函数中包含您的 CSS:

    scene.getStylesheets().add(getClass().getResource("../java-keywords.css").toExternalForm());
.styled-text-area {
    -fx-font-size: 18;
    -fx-background-color: rgb(0, 27, 51);
}

.styled-text-area .caret {
    -fx-stroke: white;
}

.styled-text-area .text{
    -fx-fill:white;
}

.styled-text-area .line {
    -fx-fill: black;
}

.styled-text-area .text.assignment {
    -fx-fill: orange;
    -fx-font-weight: bold;
}

.styled-text-area .text.keyword {
    -fx-fill: rgb(110, 252, 187);
    -fx-font-weight: bold;
}

.styled-text-area .text.semicolon {
    -fx-fill: rgb(110, 252, 187);
    -fx-font-weight: bold;
}

.styled-text-area .text.paren {
    -fx-fill: yellow;
    -fx-font-weight: bold;
}

.styled-text-area .text.bracket {
    -fx-fill: white;
    -fx-font-weight: bold;
}

.styled-text-area .text.brace {
    -fx-fill: yellow;
    -fx-font-weight: bold;
}

.styled-text-area .text.string {
    -fx-fill: rgb(58,213,11);
}

.styled-text-area .text.comment {
    -fx-fill: rgb(0, 200, 255);
}

.paragraph-box:has-caret{
    -fx-background-color: rgb(50, 77, 101);
}
于 2020-11-06T12:35:31.133 回答