首页
Preview

使用JavaFX构建自己的代码编辑器

Markus SpiskeUnsplash 上分享的照片

我一直对创建类似 IntelliJ 的自己的 IDE 感到好奇,但很快就意识到这是一个具有挑战性的任务。因此,我决定从一个更简单的版本开始,构建一个基本的代码编辑器。

我们将做什么:

  • 构建带选项卡的垂直选项卡栏
  • 顶部的水平菜单栏,具有加载文件和文件夹的功能。
  • 用于显示文件内容的文本区域。

那么,让我们开始吧。

让我们从 IntelliJ 中有的垂直选项卡开始,例如项目、书签、结构。

所以,我将使用 Enum,因为它是我最少使用的数据类型之一,而且这是一个好习惯。

enum TAB {
        PROJECT ("Project"),
        BOOKMARK ("Bookmark"),
        STRUCTURE ("Structure");

        private String value;
        TAB(String value){
            this.value = value;
        }
    }

接下来是构建这三个选项卡:

EventHandler<Event> replaceBackgroundColorHandler = event -> {
        Tab currentTab = (Tab) event.getTarget();
        System.out.println(currentTab.getText() + currentTab.isSelected());
};
public Tab buildTab(TAB tabType) {
    Tab tab = new Tab();
    tab.setClosable(false);
                            
    tab.setText(tabType.value);
    switch (tabType) {
        case PROJECT:
            tab.setOnSelectionChanged(replaceBackgroundColorHandler);
            break;
        case BOOKMARK:
            tab.setOnSelectionChanged(replaceBackgroundColorHandler);
            break;
        case STRUCTURE:
            tab.setOnSelectionChanged(replaceBackgroundColorHandler);
            break;
    }
    return tab;
}

projectTab = buildTab(TAB.PROJECT);
bookmarkTab = buildTab(TAB.BOOKMARK);
structureTab = buildTab(TAB.STRUCTURE);

然后我会将它们添加到选项卡窗格中,这类似于选项卡的组。

    TabPane tabPane = new TabPane();
    
    tabPane.setSide(Side.LEFT);
    tabPane.getTabs().add(projectTab);
    tabPane.getTabs().add(bookmarkTab);
    tabPane.getTabs().add(structureTab);

接下来是构建包含文件、编辑、菜单的顶部菜单栏。

文件很重要,因为它将有一个下拉列表,其中包含“打开”,这将把存储库加载到我们的编辑器中作为 Treeview。


DirectoryChooser directoryChooser = new DirectoryChooser();
public MenuBar buildMenuBar(Stage stage) {
        // create a menu
        Menu file = new Menu("File");

        // create menuitems
        MenuItem m1 = new MenuItem("New");
        MenuItem m2 = new MenuItem("Open");
        m2.setOnAction(e -> {
            File selectedDirectory = directoryChooser.showDialog(stage);
            projectTab.setContent(menuListView.buildListView(selectedDirectory));
        });

        MenuItem m3 = new MenuItem("Recent Projects");
        MenuItem m4 = new MenuItem("Close Projects");

        // add menu items to menu
        file.getItems().add(m1);
        file.getItems().add(m2);
        file.getItems().add(m3);
        file.getItems().add(m4);

        // create a menu
        Menu edit = new Menu("Edit");
        MenuItem e1 = new MenuItem("Edit");
        edit.getItems().add(e1);

        // create a menu
        Menu view = new Menu("View");
        MenuItem v1 = new MenuItem("View");
        view.getItems().add(v1);

        // create a menubar
        MenuBar mb = new MenuBar();
        // add menu to menubar
        mb.getMenus().add(file);
        mb.getMenus().add(edit);
        mb.getMenus().add(view);

        return mb;
    }

buildMenulist:

VBox buildListView(File root) {
        parent = root;

        TreeView<Path> listView = new TreeView<>(new TreeItem<>());
        Arrays.stream(Objects.requireNonNull(root.listFiles())).forEach(file -> {
            try {
                nameToFile.put(file.getName(), file);
                ls.add(file);
            } catch (Exception e) {
            }
        });
        listView.setEditable(true);
        listView.setMinHeight(screenHeight);

        //Creating the layout
        VBox layout = new VBox();
        layout.getChildren().addAll(listView);
        VBox.setVgrow(listView, Priority.ALWAYS);

        listView.setShowRoot(false);
        listView.setCellFactory(LazyTreeCell.forTreeView("Loading...", MenuListView::pathToString));
        TreeViewUtils.installSelectionBugWorkaround(listView);

        for (File f: Objects.requireNonNull(root.listFiles())) {
            listView.getRoot().getChildren().add(f.isDirectory()
                    ? new LoadingTreeItem<>(f.toPath(), new DirectoryLoader(f))
                    : new TreeItem<>(f.toPath()));
        }
        listView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                System.out.println("clicked on " + listView.getSelectionModel().getSelectedItem());
                File selectedFile = listView.getSelectionModel().getSelectedItem().getValue().toFile();

                if(selectedFile.isDirectory()) {
                } else {
                    loadFileToTextArea(selectedFile);
                }
            }
        });
        return layout;
    }

所以这些代码片段将在我们的菜单列表中作为树形视图加载嵌套的文件夹/目录结构。为什么是树形视图,因为在树形视图中,它只会显示文件和文件夹的第一层,单击文件夹旁边的下拉菜单后,它将加载该目录中的第二层文件和文件夹,就像在代码编辑器中一样。

此“loadFileToTextArea(selectedFile)”将加载文件中的数据并显示在我们的代码编辑器的文本区域中。

现在我们需要一个分割面板,其中有一个平面由可调边界分割。左侧将显示树形视图中的文件和目录,右侧将是我们的文本区域。

SplitPane leftRightSplitPane = new SplitPane();
leftRightSplitPane.minHeight(screenHeight);
leftRightSplitPane.minWidth(screenWidth);
stage.showingProperty().addListener(new ChangeListener<>() {
    @Override
    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
        if (newValue) {
            leftRightSplitPane.setDividerPositions(0.1);
            observable.removeListener(this);
        }
    }
});

tabPane.setMinWidth(getMenuWidth());
tabPane.maxWidth(screenWidth);
leftRightSplitPane.getItems().add(tabPane);
leftRightSplitPane.getItems().add(textArea);

vb.getChildren().add(leftRightSplitPane);
VBox.setVgrow(leftRightSplitPane, Priority.ALWAYS);
VBox.setVgrow(vb, Priority.ALWAYS);
Scene scene = new Scene(vb);

stage.setScene(scene);
scene.getStylesheets().add(getClass().getResource("/styles/global.css").toExternalForm());

stage.show();

在下面的 URL 中找到源代码以及 CSS。

himmish/Qudit (github.com)

我试图使文本区域内的代码看起来有颜色,但这需要一段时间。所以,请继续关注下一部分。谢谢。

— — — — — — — — — —

译自:https://medium.com/@himanshumishra_60274/building-my-own-code-editor-using-javafx-1df6fc36a8e6

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
阿波
The minute I see you, I want your clothes gone!

评论(0)

添加评论