Java课程大作业之记事本完美复刻

一、项目结构

JDK8.0

img

domain是记事本的各个组件,main是入口类包,utils存放处理文本框的工具类,resource存放记事本资源,为避免不必要的资源路径问题,本文不提供resource下的文件

二、domain包—记事本各个组件

2.1、MenuBarFactory菜单组件

菜单效果图

img

img

代码

MenuBarFactory.java

package domain;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import utils.TextAreaUtils;

import java.awt.print.PageFormat;
import java.awt.print.PrinterJob;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @ClassName MenuButtonFactory
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/20 9:26
 * @Version 1.0
 */
public class MenuBarFactory {
    public StringBuffer originalPath;
    private SearchPaneFactory searchPaneFactory = new SearchPaneFactory();
    private TextAreaFactory textAreaFactory = new TextAreaFactory();
    private TextArea textArea = new TextArea();
    private final Menu fileMenu = new Menu("文件(F)");
    private final MenuItem newItem = new MenuItem("新建(N)");
    private final MenuItem openItem = new MenuItem("打开(O)...");
    private final MenuItem saveItem = new MenuItem("保存(S)");
    private final MenuItem aItem = new MenuItem("另存为(A)...");
    private final SeparatorMenuItem separator0 = new SeparatorMenuItem();
    private final MenuItem uItem = new MenuItem("页面设置(U)...");
    private final MenuItem printItem = new MenuItem("打印(P)...");
    private final SeparatorMenuItem separator1 = new SeparatorMenuItem();
    private final MenuItem exitItem = new MenuItem("退出(X)");
    private final Menu editMenu = new Menu("编辑(E)");
    private final MenuItem undoItem = new MenuItem("撤销(U)");
    private final MenuItem tItem = new MenuItem("剪切(T)");
    private final MenuItem copyItem = new MenuItem("复制(C)");
    private final MenuItem pasteItem = new MenuItem("粘贴(P)");
    private final MenuItem delItem = new MenuItem("删除(L)");
    private final MenuItem exploreItem = new MenuItem("使用Bing搜索");
    private final MenuItem findItem = new MenuItem("查找(F)");
    private final MenuItem nextFindItem = new MenuItem("查找下一个(N)");
    private final MenuItem prevFindItem = new MenuItem("查找上一个(V)");
    private final MenuItem replaceItem = new MenuItem("替换(R)...");
    private final MenuItem forwardItem = new MenuItem("转到(G)...");
    private final MenuItem selectAllItem = new MenuItem("全选(A)");
    private final MenuItem dateItem = new MenuItem("时间/日期(D)");
    private final SeparatorMenuItem separator3 = new SeparatorMenuItem();
    private final SeparatorMenuItem separator4 = new SeparatorMenuItem();
    private final SeparatorMenuItem separator5 = new SeparatorMenuItem();
    private final Menu formatMenu = new Menu("格式(O)");
    private final RadioMenuItem wrapItem = new RadioMenuItem("自动换行(W)");
    private final MenuItem fontStyleItem = new MenuItem("字体(F)...");
    private final Menu viewMenu = new Menu("查看(V)");
    private final Menu zoomMenu = new Menu("缩放(Z)");
    private final RadioMenuItem stateItem = new RadioMenuItem("状态栏(S)");
    private final MenuItem largeItem = new MenuItem("放大(I)");
    private final MenuItem smallItem = new MenuItem("缩小(O)");
    private final MenuItem defaultSizeItem = new MenuItem("恢复默认缩放");
    private final Menu helpMenu = new Menu("帮助(H)");
    private final MenuItem searchForHelpItem = new MenuItem("查看帮助(H)");
    private final MenuItem sendFeedbackItem = new MenuItem("发送反馈(F)");
    private final MenuItem aboutItem = new MenuItem("关于记事本(A)");
    private final SeparatorMenuItem separator6 = new SeparatorMenuItem();
    private final MenuBar menuBar = new MenuBar(fileMenu, editMenu, formatMenu, viewMenu, helpMenu);

    /*
    初始化,设置菜单栏和菜单项的从属关系,绑定快捷键
     */
    {
        fileMenu.setAccelerator(KeyCombination.valueOf("alt+f"));
        newItem.setAccelerator(KeyCombination.valueOf("CTRL+N"));
        openItem.setAccelerator(KeyCombination.valueOf("CTRL+O"));
        saveItem.setAccelerator(KeyCombination.valueOf("CTRL+S"));
        aItem.setAccelerator(KeyCombination.valueOf("CTRL+SHIFT+S"));
        printItem.setAccelerator(KeyCombination.valueOf("CTRL+P"));
        setMenu(fileMenu, newItem, openItem, saveItem, aItem, separator0,
                uItem, printItem, separator1, exitItem);
        undoItem.setAccelerator(KeyCombination.valueOf("CTRL+Z"));
        undoItem.setDisable(true);
        tItem.setAccelerator(KeyCombination.valueOf("CTRL+T"));
        tItem.setDisable(true);
        copyItem.setAccelerator(KeyCombination.valueOf("CTRL+C"));
        copyItem.setDisable(true);
        pasteItem.setAccelerator(KeyCombination.valueOf("CTRL+V"));
        pasteItem.setDisable(false);
        delItem.setAccelerator(KeyCombination.valueOf("DEL"));
        delItem.setDisable(true);
        exploreItem.setAccelerator(KeyCombination.valueOf("CTRL+E"));
        exploreItem.setDisable(true);
        findItem.setAccelerator(KeyCombination.valueOf("CTRL+F"));
        findItem.setDisable(true);
        nextFindItem.setAccelerator(KeyCombination.valueOf("SHIFT+F4"));
        nextFindItem.setDisable(true);
        prevFindItem.setAccelerator(KeyCombination.valueOf("SHIFT+F3"));
        prevFindItem.setDisable(true);
        replaceItem.setAccelerator(KeyCombination.valueOf("CTRL+H"));
        forwardItem.setAccelerator(KeyCombination.valueOf("CTRL+G"));
        forwardItem.setDisable(true);
        selectAllItem.setAccelerator(KeyCombination.valueOf("CTRL+A"));
        dateItem.setAccelerator(KeyCombination.valueOf("F5"));
        editMenu.setAccelerator(KeyCombination.valueOf("alt+e"));
        setMenu(editMenu, undoItem, separator3, tItem, copyItem, pasteItem, delItem, separator4, exploreItem, findItem,
                nextFindItem, prevFindItem, replaceItem, forwardItem, separator5, selectAllItem, dateItem);
        wrapItem.setSelected(true);
        textArea.setWrapText(wrapItem.isSelected());
        setMenu(formatMenu, wrapItem, fontStyleItem);
        formatMenu.setAccelerator(KeyCombination.valueOf("alt+o"));
        stateItem.setSelected(true);
        largeItem.setAccelerator(KeyCombination.valueOf("ctrl+l"));
        smallItem.setAccelerator(KeyCombination.valueOf("ctrl+m"));
        defaultSizeItem.setAccelerator(KeyCombination.valueOf("ctrl+0"));

        setMenu(zoomMenu, largeItem, smallItem, defaultSizeItem);
        setMenu(viewMenu, zoomMenu, stateItem);
        viewMenu.setAccelerator(KeyCombination.valueOf("alt+v"));

        setMenu(helpMenu, searchForHelpItem, sendFeedbackItem, separator6, aboutItem);
        helpMenu.setAccelerator(KeyCombination.valueOf("alt+h"));
        menuBar.setPrefWidth(900);
        menuBar.setPadding(new Insets(0.0));




        findItem.setOnAction(e->searchPaneFactory.showSearchStage(textAreaFactory));


        largeItem.setOnAction(e->TextAreaUtils.enLarge(textArea));
        smallItem.setOnAction(e->TextAreaUtils.shrink(textArea));
        defaultSizeItem.setOnAction(e->textArea.setStyle("-fx-font-size: 15"));
        replaceItem.setOnAction(e->searchPaneFactory.showSearchStage(textAreaFactory));
        nextFindItem.setOnAction(e->TextAreaUtils.findWords(textArea,textArea.getSelectedText(),false,true,false));
        prevFindItem.setOnAction(e->TextAreaUtils.backSearch(textArea,textArea.getSelectedText(),false,true,false));
        selectAllItem.setOnAction(e->textArea.selectAll());
        dateItem.setOnAction(e->{
            Date date = new Date();
            //0:15 2022/5/23
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm yyyy/MM/dd");
            String insertDate = sdf.format(date);
            textArea.insertText(textArea.getCaretPosition(),insertDate);
        });

        uItem.setOnAction(event -> {
            PageFormat pf = new PageFormat();
            PrinterJob.getPrinterJob().pageDialog(pf);
        });


        wrapItem.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                System.out.println("是否换行:"+newValue);
                forwardItem.setDisable(newValue);
                textArea.setWrapText(newValue);
            }
        });


        undoItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                if(textArea.isUndoable()){
                    textArea.undo();
                }
            }
        });

        tItem.setOnAction(e->textArea.cut());
        copyItem.setOnAction(e->textArea.copy());
        pasteItem.setOnAction(e->textArea.paste());
        delItem.setOnAction(e->textArea.replaceSelection(""));
        exploreItem.setOnAction(event -> {
            String searchString = textArea.getSelectedText();
            try
            {
                java.net.URI uri = java.net.URI.create("https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd=" + searchString);
                java.awt.Desktop dp = java.awt.Desktop.getDesktop();
                if(dp.isSupported(java.awt.Desktop.Action.BROWSE))
                {
                    dp.browse(uri);
                }
            }
            catch(Exception e)
            {
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setTitle("自动搜索出错!");
                alert.setHeaderText("");
                alert.setContentText("搜索内容过长!请手动搜索!");
                alert.showAndWait();
                try
                {
                    java.net.URI uri = java.net.URI.create("www.baidu.com");
                    java.awt.Desktop dp = java.awt.Desktop.getDesktop();
                    if(dp.isSupported(java.awt.Desktop.Action.BROWSE))
                    {
                        try
                        {
                            dp.browse(uri);
                        }
                        catch(IOException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
                catch(Exception e2) {
                    e2.printStackTrace();
                }
            }
        });

        FileSavePromptFactory.bindFileSaveMenuBar(this);


    }


    public void setTextFactory(TextAreaFactory textAreaFactory,Stage stage){
        this.textAreaFactory = textAreaFactory;
        this.textArea = textAreaFactory.getTextArea();
        bindMenuText(stage);
        textArea.setWrapText(wrapItem.isSelected());
        findItem.setDisable(textAreaFactory.isEmpty());
        nextFindItem.setDisable(textAreaFactory.isEmpty());
        prevFindItem.setDisable(textAreaFactory.isEmpty());
        replaceItem.setDisable(textAreaFactory.isEmpty());
    }

    public MenuBar getMenubar() {
        menuBar.setStyle(
                "-fx-background-color: #fdfdfe"
        );
        return menuBar;
    }



    public void setOwnerAnc(AnchorPane anc){
        anc.getChildren().add(menuBar);
        AnchorPane.setLeftAnchor(menuBar,0.0);
        AnchorPane.setBottomAnchor(menuBar,0.0);
        AnchorPane.setRightAnchor(menuBar,0.0);
        AnchorPane.setTopAnchor(menuBar,0.0);
        anc.widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                adjustWidth(newValue.doubleValue());
            }
        });
    }


    /**
     * @description: 绑定菜单与文本框的监听事件,作为初始化条件
     * @param:
     * @return: void
     * @author
     * @date: 13:44 2022/5/21
     * @param stage
     */

    private void bindMenuText(Stage stage){
        aboutItem.setOnAction(e-> System.out.println(originalPath));
        aItem.setOnAction(e->FileSavePromptFactory.showSaveAsPane(textArea,stage));

        saveItem.setOnAction(e-> {
            FileSavePromptFactory.showSavePromptPane(textArea,stage,originalPath);
        });
        exitItem.setOnAction(e->FileSavePromptFactory.showExistSavePane(textArea,stage));

        newItem.setOnAction(e->FileSavePromptFactory.showNewFileSavePane(textArea,stage));
        openItem.setOnAction(e->FileSavePromptFactory.showOpenFileSavePane(textArea,stage));

        forwardItem.setOnAction(e-> ToTargetPaneFactory.showToTargetStage(stage,textArea));
        fontStyleItem.setOnAction(e->FontSettingPaneFactory.showFontSettingPane(stage,textArea));

        //监听文本是否可撤销操作以便判断是否需要提示保存更改
        textArea.undoableProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {

                undoItem.setDisable(!newValue);
                System.out.println("是否可撤销:"+newValue);
                if(newValue){
                    addStarTitle(stage);
                }else{
                    if(stage.getTitle().contains("无标题")) {
                        removeStarTitle(stage);
                    }
                }
            }
        });



        //监听新文本的输入
        textArea.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                boolean hasContent = newValue != null && newValue.length() != 0;
                findItem.setDisable(!hasContent);
                nextFindItem.setDisable(!hasContent);
                prevFindItem.setDisable(!hasContent);
                replaceItem.setDisable(!hasContent);
                //通知SearchPaneFactory需要重置存储条件
                SearchPaneFactory.setCanReset(true);
                System.out.println("menu判断是否有内容"+hasContent);
                addStarTitle(stage);
            }
        });

        //监听选择的文本内容
        textArea.selectedTextProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                boolean isUsable = true;
                if(newValue == null || newValue.length() == 0){
                    isUsable = false;
                }
                System.out.println("是否选中内容:\t"+isUsable);
                tItem.setDisable(!isUsable);
                copyItem.setDisable(!isUsable);
                delItem.setDisable(!isUsable);
                exploreItem.setDisable(!isUsable);
            }
        });


        //监听文本框的光标
        textArea.caretPositionProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                //一切正常
                System.out.println("新光标的位置为:\t"+textAreaFactory.getCaretPosition());
                //更新状态栏
                TextAreaUtils.updateStatusLabel(textArea,textAreaFactory.getStatusLabel());
                //待定
                textArea.setScrollTop(textArea.getScrollTop());
            }
        });



    }



    public void addStarTitle(Stage stage){
        String original = stage.getTitle();
        if(!original.contains("*")){
            stage.setTitle("*"+original);
        }
    }
    public void removeStarTitle(Stage stage){
        stage.setTitle(stage.getTitle().replace("*",""));
    }



    private void adjustWidth(double width){
        menuBar.setPrefWidth(width);
    }

    private void setMenu(Menu m, MenuItem... menuItems) {
        for (MenuItem menuItem : menuItems) {
            m.getItems().add(menuItem);
        }
    }

}

2.2、TextAreaFactory文本框组件

效果图

img

代码

TextAreaFactory.java

package domain;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.AnchorPane;
import javafx.scene.text.Font;
import utils.TextAreaUtils;

/**可以获得设置文本框的光标位置,获取改动状态、获取设置文本是否为空、获取设置文本内容
 * @ClassName TextAreaFactory
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/20 17:55
 * @Version 1.0
 */
public class TextAreaFactory {
    private int caretPosition = 0;
    private boolean isUnchanged = true;
    public TextArea textArea = new TextArea();
    private boolean isEmpty = true;
    private String textContent = "";
    private String selectContent = textArea.getSelectedText();
    private Label statusLabel = new Label();


    public TextArea getTextArea(){
        initializeTextArea();

        return textArea;
    }

    public void setOwnerAnc(AnchorPane anc){
        anc.getChildren().add(textArea);
        AnchorPane.setLeftAnchor(textArea,0.0);
        AnchorPane.setBottomAnchor(textArea,0.0);
        AnchorPane.setRightAnchor(textArea,0.0);
        AnchorPane.setTopAnchor(textArea,0.0);
    }

    /**
     * 根据需求移动光标
     * @param caretPosition
     */
    public void setCaretPosition(int caretPosition) {
        textArea.positionCaret(caretPosition);
        this.caretPosition = caretPosition;
    }


    /**
     * 得到实时的光标位置
     * @return
     */
    public int getCaretPosition() {
        caretPosition = textArea.getCaretPosition();
        return caretPosition;
    }

    public void setTextContent(String textContent) {
        textArea.setText(textContent);
        this.textContent = textContent;
    }

    public void setEmpty(boolean empty) {
        if(empty){
            textArea.clear();
        }
        isEmpty = empty;
    }

    public String getSelectContent() {
        selectContent = textArea.getSelectedText();
        return selectContent;
    }

//    public void setSelectContent(String selectContent) {
//        this.selectContent = selectContent;
//    }


    public Label getStatusLabel() {
        return statusLabel;
    }

    public String getTextContent() {
        textContent = textArea.getText();
        return textContent;
    }

    public boolean isEmpty() {
        isEmpty = textArea.getText().isEmpty();
        return isEmpty;
    }

    public boolean isUnchanged() {
        //如果不可以撤销文本那么可以认为此文本未做改动,故可直接退出不鄙视保存
        isUnchanged = textArea.isUndoable();
        return isUnchanged;
    }

    public void bindTextAreaLabel(Label bindLabel){
        this.statusLabel = bindLabel;
        textArea.fontProperty().addListener(new ChangeListener<Font>() {
            @Override
            public void changed(ObservableValue<? extends Font> observable, Font oldValue, Font newValue) {
                TextAreaUtils.updateStatusLabel(textArea,bindLabel);
            }
        });
    }



    public void initializeTextArea(){
        textArea.setStyle("-fx-font-size: 15");
        textArea.setOnScroll(event -> {
            if(event.isControlDown() && event.getDeltaY() < 0) {
                //缩小文本
                TextAreaUtils.shrink(textArea);
            } else if(event.isControlDown() && event.getDeltaY() > 0) {
                //放大文本
                TextAreaUtils.enLarge(textArea);
            }
            //更新状态栏
            System.out.println("环论滚动");
        });
    }

}

2.3、SearchPaneFactory查找替换组件

效果

img

代码(其中的TextAreaUtils.java在下文)

SearchPaneFactory.java

package domain;


import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.Mnemonic;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import utils.TextAreaUtils;

import java.io.InputStream;

/**
 * @ClassName SearchPaneFactory
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/21 20:08
 * @Version 1.0
 */
public class SearchPaneFactory {
    private final static double STAGE_HEIGHT = 430;
    private final static double STAGE_WIDTH = 320;
    private final static Label KEY_LABEL = new Label("查找内容(N)");
    private final static Label REPLACE_LABEL = new Label("替换为");
    private final static Label TOWARD_LABEL = new Label("方向");
    private final static Label SCOPE_LABEL = new Label("范围");
    private final static Label OPTION_LABEL = new Label("可选项");
    private final static Label OPERA_LABEL = new Label("操作指令");
    private final static TextField KEY_STRING_TF = new TextField();
    private final static TextField REPLACEMENT_TF = new TextField();
    private final static RadioButton UP_RADIO_BTN = new RadioButton("向上(U)");
    private final static RadioButton DOWN_RADIO_BTN = new RadioButton("向下(D)");
    private final static ToggleGroup TOWARD_TG = new ToggleGroup();
    private final static RadioButton WRAP_RADIO_BTN = new RadioButton("所在行内");
    private final static RadioButton ALL_RADIO_BTN = new RadioButton("全文范围");
    private final static ToggleGroup SCOPE_TG = new ToggleGroup();
    private final static Button NEXT_BTN = new Button("查找下一个(F)");
    private final static Button REPLACE_BTN = new Button("替换");
    private final static Button REPLACE_ALL_BTN = new Button("全部替换");
    private final static Button EXIT_BTN = new Button("取消");
    private final static CheckBox IGNORE_CASE_BOX = new CheckBox("区分大小写(C)");
    private final static CheckBox RECYCLE_BOX = new CheckBox("循环(R)");
    private final static VBox INPUT_TIP_VBOX = new VBox(KEY_LABEL, REPLACE_LABEL);
    private final static VBox INPUT_VBOX = new VBox(KEY_STRING_TF, REPLACEMENT_TF);
    private final static VBox TOWARD_VBOX = new VBox(TOWARD_LABEL, UP_RADIO_BTN, DOWN_RADIO_BTN);
    private final static VBox SCOPE_VBOX = new VBox(SCOPE_LABEL, WRAP_RADIO_BTN, ALL_RADIO_BTN);
    private final static VBox OPTION_VBOX = new VBox(OPTION_LABEL, IGNORE_CASE_BOX, RECYCLE_BOX);
    private final static VBox OPERA_VBOX = new VBox(OPERA_LABEL, NEXT_BTN, REPLACE_BTN, REPLACE_ALL_BTN, EXIT_BTN);
    private final static GridPane GRID_PANE = new GridPane();
    private final static Scene SCENE = new Scene(GRID_PANE);
    private final static Stage PRIMARY_STAGE = new Stage();
    private final static KeyCombination KC_NEXT = new KeyCodeCombination(KeyCode.F, KeyCombination.ALT_DOWN);
    private final static Mnemonic MNEMONIC_NEXT = new Mnemonic(NEXT_BTN, KC_NEXT);
    private static boolean isCaseIgnored = true;
    private static boolean isCycle = false;
    private static boolean isAllScope = false;
    private static String key;
    private static String replacement;
    private static boolean isUp;
    private static boolean canReset = false;

    /*
      初始化加载,只加载一次即可,减少内存占用
     */
    static {
        REPLACEMENT_TF.setFocusTraversable(false);
        REPLACEMENT_TF.setPromptText("可输入代替换词");
        UP_RADIO_BTN.setToggleGroup(TOWARD_TG);
        DOWN_RADIO_BTN.setToggleGroup(TOWARD_TG);
        WRAP_RADIO_BTN.setToggleGroup(SCOPE_TG);
        ALL_RADIO_BTN.setToggleGroup(SCOPE_TG);
        NEXT_BTN.setPrefWidth(100.0);
        EXIT_BTN.setPrefWidth(100.0);
        REPLACE_BTN.setPrefWidth(100.0);
        REPLACE_ALL_BTN.setPrefWidth(100.0);
        DOWN_RADIO_BTN.setSelected(true);
        ALL_RADIO_BTN.setSelected(true);
        TOWARD_VBOX.setStyle(
                "-fx-border-style: dotted"
        );
        SCOPE_VBOX.setStyle(
                "-fx-border-style: dotted"
        );
        OPTION_VBOX.setStyle(
                "-fx-border-style: dotted"
        );
        INPUT_TIP_VBOX.setSpacing(15.0);
        INPUT_VBOX.setSpacing(5.0);
        TOWARD_VBOX.setSpacing(10.0);
        SCOPE_VBOX.setSpacing(10.0);
        OPTION_VBOX.setSpacing(10.0);
        OPERA_VBOX.setSpacing(10.0);
        GRID_PANE.add(INPUT_TIP_VBOX, 0, 0);
        GRID_PANE.add(INPUT_VBOX, 1, 0);
        GRID_PANE.add(TOWARD_VBOX, 0, 1);
        GRID_PANE.add(SCOPE_VBOX, 1, 1);
        GRID_PANE.add(OPTION_VBOX, 0, 2);
        GRID_PANE.add(OPERA_VBOX, 1, 2);
        GridPane.setMargin(OPERA_VBOX, new Insets(10.0));
        GRID_PANE.setAlignment(Pos.CENTER);
        GRID_PANE.setHgap(20.0);
        GRID_PANE.setVgap(20.0);
        GRID_PANE.setStyle(
                "-fx-background-color: #efefef"
        );
        PRIMARY_STAGE.setScene(SCENE);
        PRIMARY_STAGE.setTitle("查找");
        PRIMARY_STAGE.setHeight(STAGE_HEIGHT);
        PRIMARY_STAGE.setWidth(STAGE_WIDTH);
        InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");
        assert rs1 != null;
        Image image = new Image(rs1, 50, 50, false, true);
        PRIMARY_STAGE.getIcons().add(image);
        SCENE.addMnemonic(MNEMONIC_NEXT);
        NEXT_BTN.setOnAction(e -> System.out.println("nextBtn触发"));
        NEXT_BTN.setDisable(true);
        REPLACE_BTN.setDisable(true);
        REPLACE_ALL_BTN.setDisable(true);

        //绑定输入框监听
        KEY_STRING_TF.textProperty().addListener((observable, oldValue, newValue) -> {
            NEXT_BTN.setDisable(newValue.isEmpty());
            if(!newValue.isEmpty()){
                key = newValue;
                System.out.println("查找的单词为:"+key);
            }
            boolean isEmpty = newValue.isEmpty() ||  REPLACEMENT_TF.getText().isEmpty();
            REPLACE_BTN.setDisable(isEmpty);
            REPLACE_ALL_BTN.setDisable(isEmpty);
        });
        REPLACEMENT_TF.textProperty().addListener((observable, oldValue, newValue) -> {
            boolean isEmpty = newValue.isEmpty() ||  KEY_STRING_TF.getText().isEmpty();
            if(!newValue.isEmpty()){
                replacement = newValue;
                System.out.println("替换为:"+replacement);
            }
            REPLACE_BTN.setDisable(isEmpty);
            REPLACE_ALL_BTN.setDisable(isEmpty);

        });

        //设置单选组的响应
        TOWARD_TG.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
            RadioButton r = (RadioButton) newValue;
            isUp = r == UP_RADIO_BTN;
            System.out.println("是否向上:\t"+isUp);
        });

        SCOPE_TG.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
            RadioButton r = (RadioButton) newValue;
            isAllScope = r == ALL_RADIO_BTN;
            System.out.println("是否全文范围:\t"+isAllScope);
        });

        //设置可选项的监听响应
        IGNORE_CASE_BOX.selectedProperty().addListener((observable, oldValue, newValue) -> {
            isCaseIgnored = !newValue;
            System.out.println("是否区分大小写:\t"+isCaseIgnored);
        });
        RECYCLE_BOX.selectedProperty().addListener((observable, oldValue, newValue) -> {
            isCycle = newValue;
            System.out.println("是否循环寻找目标:\t"+isCaseIgnored);
        });
        //设置按钮的响应事件
        EXIT_BTN.setOnAction(e -> PRIMARY_STAGE.close());


    }

    /** 当文本框中的内容发生改变时,全局循环的触发条件也相应地发生改变,此时需要重置TextAreaUtils中的参数
     * @description:
     * @param: canReset
     * @return: void
     * @author
     * @date: 20:33 2022/5/22
     */

    public static void setCanReset(boolean canReset) {
        SearchPaneFactory.canReset = canReset;
    }

    public void showSearchStage(TextAreaFactory textAreaFactory) {
        bindTextSearch(textAreaFactory);
        textAreaFactory.textArea.requestFocus();
        KEY_STRING_TF.setText(textAreaFactory.getSelectContent());
        PRIMARY_STAGE.show();
    }



    public static void bindTextSearch(TextAreaFactory textAreaFactory) {
        TextArea textArea = textAreaFactory.textArea;
        textArea.requestFocus();

        /*
            private final static Button NEXT_BTN = new Button("查找下一个(F)");
            private final static Button REPLACE_BTN = new Button("替换");
            private final static Button REPLACE_ALL_BTN = new Button("全部替换");
         */
        NEXT_BTN.setOnAction(e->{
            if(isUp){
                TextAreaUtils.backSearch(textArea,key,isCaseIgnored,isAllScope,isCycle);
            }else{
                TextAreaUtils.findWords(textArea,key,isCaseIgnored,isAllScope,isCycle);
            }
        });
        REPLACE_BTN.setOnAction(e->TextAreaUtils.replace(textArea,key,replacement,isCaseIgnored,isAllScope,isCycle));
        REPLACE_ALL_BTN.setOnAction(e->TextAreaUtils.replaceAll(textArea,key,replacement,isCaseIgnored));

    }

}

2.4、ToTargetPaneFactory转到行组件

效果

img

代码

ToTargetPaneFactory.java

package domain;

import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import utils.TextAreaUtils;

import java.io.InputStream;

/**
 * @ClassName ToTargetPane
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/22 22:09
 * @Version 1.0
 */
public class ToTargetPaneFactory {
    private static final double STAGE_WIDTH = 300;
    private static final double STAGE_HEIGHT = 150;
    private static final Label LABEL = new Label("行号(L):");
    private static final TextField TEXT_FIELD = new TextField();
    private static final Label PLACE_HOLDER = new Label();
    private static final Button TURN_TO_BTN = new Button("转到");
    private static final Button CANCEL_BTN = new Button("取消");
    private static final HBox H_BOX = new HBox(10.0, PLACE_HOLDER, TURN_TO_BTN, CANCEL_BTN);
    private static final VBox V_BOX = new VBox(5.0, LABEL, TEXT_FIELD, H_BOX);
    private static final Scene SCENE = new Scene(V_BOX);
    private static final Tooltip TOOLTIP = new Tooltip();
    private static final Alert ALERT = new Alert(Alert.AlertType.ERROR);
    private static final String REG = "^[0-9]*[1-9][0-9]*$";
    /*
        初始化一次,节约内存开销
     */
    static {
        PLACE_HOLDER.setPrefWidth(90);
        TURN_TO_BTN.setPrefWidth(60);
        CANCEL_BTN.setPrefWidth(60);
        TEXT_FIELD.setPrefWidth(120);
        V_BOX.setPadding(new Insets(10.0));
        VBox.setMargin(H_BOX,new Insets(20.0));

        TOOLTIP.setText("不能接受的字符\n你只能在此处输入数字。");
        TEXT_FIELD.setTooltip(TOOLTIP);

        ALERT.setTitle("跳行");
        ALERT.setHeaderText("");
        ALERT.setContentText("输入行数必须为正整数");


    }


    public static void showToTargetStage(Stage ownerStage,TextArea textArea){
        Stage stage = new Stage();
        InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");
        Image image = new Image(rs1, 50, 50, false, true);
        stage.getIcons().add(image);
        stage.setResizable(false);
        stage.setScene(SCENE);
        stage.setTitle("转到指定行");
        stage.setHeight(STAGE_HEIGHT);
        stage.setWidth(STAGE_WIDTH);
        stage.initModality(Modality.APPLICATION_MODAL);
        stage.initOwner(ownerStage);

        TURN_TO_BTN.setOnAction(e->{
            if(!TEXT_FIELD.getText().matches(REG)){
                ALERT.showAndWait();
                TEXT_FIELD.clear();
            }else{
                TextAreaUtils.turnToTargetLine(textArea,Integer.parseInt(TEXT_FIELD.getText()));
            }
        });
        CANCEL_BTN.setOnAction(e->stage.close());


        stage.show();
    }

}

2.5、FontSettingPaneFactory字体设置组件

效果

img

代码

FontSettingPaneFactory.java

package domain;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.awt.*;
import java.io.InputStream;

/**
 * @ClassName FontSettingPaneFactory
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/23 9:00
 * @Version 1.0
 */
public class FontSettingPaneFactory{

    private static final double STAGE_WIDTH = 600;
    private static final double STAGE_HEIGHT = 500;

    private static final Label FONT_LABEL = new Label("字体(F):");
    private static final Label GLYPH_LABEL = new Label("字形(Y):");
    private static final Label SIZE_LABEL = new Label("大小(S):");
    private static final Label COLOR_LABEL = new Label("颜色(C):");
    private static final Label PREVIEW_LABEL = new Label("预览:");
    private static final TextField FONT_TF = new TextField();
    private static final TextField GLYPH_TF = new TextField();
    private static final TextField SIZE_TF = new TextField();
    private static final GraphicsEnvironment E = GraphicsEnvironment.getLocalGraphicsEnvironment();

    private static final ObservableList<String> FONT_ARRAY = FXCollections.observableArrayList(E.getAvailableFontFamilyNames());
    private static final ObservableList<String> GLYPH_ARRAY = FXCollections.observableArrayList("常规","粗体","细体","斜体");
    private static final ObservableList<String> SIZE_ARRAY = FXCollections.observableArrayList("8", "9", "10", "11", "12", "14", "16", "18", "20",
            "22", "24", "26", "28", "36", "48", "72", "初号", "小初", "一号", "小一", "二号", "小二", "三号", "小三",
            "四号", "小四", "五号", "小五", "六号", "小六", "七号", "八号");
    private static final ObservableList<String> COLOR_ARRAY = FXCollections.observableArrayList("BLACK", "BLUE",
            "GREEN", "GRAY", "RED", "WHITE", "YELLOW");
    private static final int[] SIZE_INT_ARRAY = {8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36,
            48, 72, 42, 36, 26, 24, 22, 18, 16, 15, 14, 12, 10, 9, 8, 7, 6, 5};
    private static final FontPosture[] FONT_POSTURES = new FontPosture[]{FontPosture.REGULAR,FontPosture.ITALIC};
    private static final FontWeight[] FONT_WEIGHTS = new FontWeight[]{FontWeight.NORMAL,FontWeight.BOLD,FontWeight.LIGHT};
    private static final ListView<String> FONT_SELECTOR = new ListView<>(FONT_ARRAY);
    private static final ListView<String> GLYPH_SELECTOR = new ListView<>(GLYPH_ARRAY);
    private static final ListView<String> SIZE_SELECTOR = new ListView<>(SIZE_ARRAY);
    private static final ComboBox<String> COLOR_SELECTOR = new ComboBox<>(COLOR_ARRAY);

    private static final String EXP_CHINESE = "为人民服务";
    private static final String EXP_ENGLISH = "Migrant workers in the new era";
    private static final String EXP_NUMBER = "1024";
    private static final TextArea PREVIEW_TEXTAREA = new TextArea(EXP_CHINESE+"\n"+EXP_ENGLISH+"\n"+EXP_NUMBER);


    private static final javafx.scene.control.Button CONFIRM_BTN = new javafx.scene.control.Button("确定");
    private static final javafx.scene.control.Button CANCEL_BTN = new javafx.scene.control.Button("取消");
    private static final VBox FONT_VBOX = new VBox(5.0, FONT_LABEL, FONT_TF, FONT_SELECTOR);
    private static final VBox GLYPH_VBOX = new VBox(5.0, GLYPH_LABEL, GLYPH_TF, GLYPH_SELECTOR);
    private static final VBox SIZE_VBOX = new VBox(5.0, SIZE_LABEL, SIZE_TF, SIZE_SELECTOR);
    private static final VBox COLOR_VBOX = new VBox(5.0, COLOR_LABEL, COLOR_SELECTOR);
    private static final VBox PREVIEW_AREA_VBOX = new VBox(5.0, PREVIEW_LABEL, PREVIEW_TEXTAREA);
    private static final VBox BUTTON_VBOX = new VBox(10.0, CONFIRM_BTN, CANCEL_BTN);
    private static final GridPane FONT_SET_PANE = new GridPane();

    private static int fontSize = 15;
    private static String fontColor = "BLACK";
    private static String family = FONT_SELECTOR.getSelectionModel().getSelectedItem();
    private static FontPosture fontPosture = FontPosture.REGULAR;
    private static FontWeight fontWeight = FontWeight.NORMAL;
    private static Font font = Font.font(family, fontWeight, fontPosture, fontSize);
    private static String colorStyle = "-fx-text-fill: black";

    private static TextArea mainTextArea = new TextArea();
    private static final Scene SCENE = new Scene(FONT_SET_PANE);

    static {
        FONT_TF.setEditable(false);
        GLYPH_TF.setEditable(false);
        SIZE_TF.setEditable(false);
        PREVIEW_TEXTAREA.setEditable(false);

        FONT_TF.setFocusTraversable(false);
        GLYPH_TF.setFocusTraversable(false);
        SIZE_TF.setFocusTraversable(false);
        PREVIEW_TEXTAREA.setFocusTraversable(false);

        PREVIEW_TEXTAREA.setPrefWidth(300);
        PREVIEW_TEXTAREA.setPrefHeight(100);

        //绑定文本框的显示
        FONT_TF.textProperty().bind(FONT_SELECTOR.getSelectionModel().selectedItemProperty());
        GLYPH_TF.textProperty().bind(GLYPH_SELECTOR.getSelectionModel().selectedItemProperty());
        SIZE_TF.textProperty().bind(SIZE_SELECTOR.getSelectionModel().selectedItemProperty());

        //默认选择字体选项
        FONT_SELECTOR.getSelectionModel().select("微软雅黑");
        GLYPH_SELECTOR.getSelectionModel().select(0);
        SIZE_SELECTOR.getSelectionModel().select(4);
        COLOR_SELECTOR.getSelectionModel().select(0);


        CONFIRM_BTN.requestFocus();


        FONT_SET_PANE.add(GLYPH_VBOX,0,0);
        FONT_SET_PANE.add(FONT_VBOX,1,0);
        FONT_SET_PANE.add(SIZE_VBOX,2,0);
        FONT_SET_PANE.add(COLOR_VBOX,0,1);
        FONT_SET_PANE.add(BUTTON_VBOX,2,1);
        FONT_SET_PANE.add(PREVIEW_AREA_VBOX,1,1);
        FONT_SET_PANE.setPadding(new Insets(10.0));
        FONT_SET_PANE.setHgap(10.0);
        FONT_SET_PANE.setVgap(10.0);
        GridPane.setMargin(BUTTON_VBOX,new Insets(20.0));

        SIZE_SELECTOR.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                fontSize = SIZE_INT_ARRAY[newValue.intValue()];
                System.out.println("fontSize:\t"+fontSize);
                font = Font.font(family, fontWeight, fontPosture, fontSize);
                PREVIEW_TEXTAREA.setFont(font);
                mainTextArea.setFont(font);
            }
        });

        GLYPH_SELECTOR.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                int index = newValue.intValue();
                //"常规","粗体","细体","斜体");设置字体
                if(index == 0){
                    fontWeight = FONT_WEIGHTS[index];
                    fontPosture = FONT_POSTURES[index];
                }else if(index == 1){
                    fontWeight = FONT_WEIGHTS[index];
                }else if(index == 2){
                    fontWeight = FONT_WEIGHTS[index];
                }else if(index == 3){
                    fontPosture = FONT_POSTURES[1];
                }
                font = Font.font(family, fontWeight, fontPosture, fontSize);
                PREVIEW_TEXTAREA.setFont(font);
                mainTextArea.setFont(font);
                System.out.println("weight:\t"+fontWeight+"\t,posture:\t"+fontPosture);
            }
        });


        COLOR_SELECTOR.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                fontColor = newValue;
                font = Font.font(family, fontWeight, fontPosture, fontSize);
                PREVIEW_TEXTAREA.setFont(font);
                //将设置的颜色传入
                colorStyle = "-fx-text-fill: "+fontColor;
                PREVIEW_TEXTAREA.setStyle("-fx-text-fill: "+fontColor);
                mainTextArea.setStyle("-fx-text-fill: "+fontColor);
                System.out.println("fontColor:\t"+fontColor);
            }
        });

        FONT_SELECTOR.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                family = newValue;
                font = Font.font(family, fontWeight, fontPosture, fontSize);
                System.out.println("family:\t"+family);
                PREVIEW_TEXTAREA.setFont(font);
                mainTextArea.setFont(font);
            }
        });



    }

    public static void showFontSettingPane(Stage ownerStage,TextArea mainArea){
        //存储源文本的原格式,若用户点击取消按钮,则恢复源格式
        mainTextArea = mainArea;
        Font originalFont = mainArea.getFont();
        String originalStyle = mainArea.getStyle();
        Stage stage = new Stage();
        InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");
        Image image = new Image(rs1, 50, 50, false, true);
        stage.getIcons().add(image);
        stage.setResizable(false);
        stage.setScene(SCENE);
        stage.setTitle("字体设置");
        stage.setHeight(STAGE_HEIGHT);
        stage.setWidth(STAGE_WIDTH);
        stage.initOwner(ownerStage);
        stage.initModality(Modality.APPLICATION_MODAL);
        CONFIRM_BTN.setOnAction(e->{
            mainArea.setFont(font);
            mainArea.setStyle("-fx-text-fill: "+fontColor);
            stage.close();
        });
        CANCEL_BTN.setOnAction(e->{
            mainArea.setStyle(originalStyle);
            mainArea.setFont(originalFont);
            stage.close();
        });
        stage.show();
    }
}

2.6、StatusLabelFactory状态栏组件

效果

img

代码

StatusLabelFactory.java

package domain;

import javafx.scene.control.Label;
import javafx.scene.control.TextArea;

/**
 * @ClassName LabelFactory
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/21 11:10
 * @Version 1.0
 */
public class StatusLabelFactory {
    private static Label statusLabel = new Label();
    public Label getLabel(double stageWidth,TextArea textArea){
        statusLabel.setText("    第 1 行, 第 1列   共 0 字  缩放:100%");
        statusLabel.setPrefWidth(stageWidth);
        return statusLabel;
    }

}

2.7、FileSavePromptFactory文件保存提示组件

效果

img

img

代码

FileSavePromptFactory.java

package domain;

import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import utils.TextAreaUtils;

import java.io.File;
import java.io.InputStream;

/**
 * 保存文件的提示弹窗
 *
 * @ClassName FileSaveHintPane
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/23 18:49
 * @Version 1.0
 */
public class FileSavePromptFactory {
    private static MenuBarFactory menuBarFactory;
    private final static double STAGE_WIDTH = 400;
    private final static double STAGE_HEIGHT = 160;
    private static final Label INFO_LABEL = new Label();
    private static final Label PLACE_HOLDER = new Label();
    private static final Button SAVE_BTN = new Button("保存(S)");
    private static final Button ABORT_BTN = new Button("不保存(N)");
    private static final Button CANCEL_BTN = new Button("取消");
    private static final HBox BTN_BOX = new HBox(10.0, PLACE_HOLDER, SAVE_BTN, ABORT_BTN, CANCEL_BTN);
    private static final VBox CONTENT_VBOX = new VBox(10.0, INFO_LABEL, BTN_BOX);
    private static final Scene SCENE = new Scene(CONTENT_VBOX);
    private static StringBuffer path;

    static {
        INFO_LABEL.setPrefWidth(STAGE_WIDTH);
        INFO_LABEL.setPrefHeight(STAGE_HEIGHT / 2);
        INFO_LABEL.setStyle(
                "-fx-text-fill: #003398;" +
                        "-fx-font-size: 16"
        );
        SAVE_BTN.setPrefWidth(90.0);
        ABORT_BTN.setPrefWidth(90.0);
        CANCEL_BTN.setPrefWidth(90.0);

        CONTENT_VBOX.setPadding(new Insets(10.0));

    }


    public static void bindFileSaveMenuBar(MenuBarFactory factory) {
        menuBarFactory = factory;
    }


    /**
     * 设置保存事件
     *
     * @description:
     * @param: textArea ownerStage originalPath
     * @return: void
     * @author
     * @date: 19:14 2022/5/23
     */

    public static void showSavePromptPane(TextArea textArea, Stage ownerStage, StringBuffer originalPath) {


        //说明是新建的文本,直接弹出对话框,选择保存
        if (originalPath == null) {
            Stage fileStage = new Stage();
            FileChooser fc = new FileChooser();
            fc.setTitle("保存文件");
            ///设置默认打开的文件夹路径
            fc.setInitialDirectory(new File("C:\\"));
            //设置过滤器,指定打开文件的类型
            fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文本文件", "*.txt"));
            //打开文件选择器并返回返回打开的文件所在的完整路径
            File file = fc.showSaveDialog(fileStage);
            if (file != null) {
                //选择了路径,保存,更改主面板标题、MenuBar源文件路径不为空了
                String absolutePath = file.getAbsolutePath();
                try {
                    TextAreaUtils.saveTextAreaContent(textArea, absolutePath);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                path = new StringBuffer(absolutePath);
                menuBarFactory.originalPath = path;
                ownerStage.setTitle(path.toString());
            }

        } else {
            //保存过,静默保存,将源窗口的标题的*去除
            ownerStage.setTitle(ownerStage.getTitle().replace("*", ""));
            try {
                TextAreaUtils.saveTextAreaContent(textArea, ownerStage.getTitle());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

    }

    public static Stage getModelSaveStage(Stage ownerStage){
        Stage stage = new Stage();
        stage.setScene(SCENE);
        stage.setWidth(STAGE_WIDTH);
        stage.setHeight(STAGE_HEIGHT);
        stage.initOwner(ownerStage);
        stage.initModality(Modality.APPLICATION_MODAL);
        InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");
        Image image = new Image(rs1, 50, 50, false, true);
        stage.setTitle("保存提示");
        stage.getIcons().add(image);
        stage.setResizable(false);
        return stage;
    }

    public static void showNewFileSavePane(TextArea textArea, Stage ownerStage) {
        if (menuBarFactory.originalPath == null && textArea.getText().isEmpty()) {
            return;
        }
        //无原路径,--》有内容:弹出对话框,无内容不做处理
        Stage stage = new Stage();

        CANCEL_BTN.setOnAction(e -> stage.close());

        if (menuBarFactory.originalPath == null) {

            //有内容需要弹出对话框提醒保存

            INFO_LABEL.setText("你想将更改保存到无标题吗?");
            SAVE_BTN.setOnAction(e -> {
                //从未保存过,则直接需要再开出一个文件保存的窗口,此时需要更改源地址,String的不可更改性需要去优化
                Stage fileStage = new Stage();
                FileChooser fc = new FileChooser();
                fc.setTitle("保存文件");
                ///设置默认打开的文件夹路径
                fc.setInitialDirectory(new File("C:\\"));
                //设置过滤器,指定打开文件的类型
                fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文本文件", "*.txt"));
                //打开文件选择器并返回返回打开的文件所在的完整路径
                File file = fc.showSaveDialog(fileStage);
                if (file != null) {

                    String absolutePath = file.getAbsolutePath();
                    try {
                        TextAreaUtils.saveTextAreaContent(textArea, absolutePath);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }

                    ownerStage.setTitle("无标题");

                }

                stage.close();
            });
            ABORT_BTN.setOnAction(e -> {
                textArea.clear();
                stage.close();
            });

        }else{
            //有源路径的新建,弹出对话框,确定就默认保存,舍弃就直接清空textArea,取消就除去面板

            INFO_LABEL.setText("你想将更改保存到"+menuBarFactory.originalPath+"吗?");
            SAVE_BTN.setOnAction(e->{
                //静默保存
                ownerStage.setTitle(ownerStage.getTitle().replace("*",""));
                try {
                    TextAreaUtils.saveTextAreaContent(textArea,ownerStage.getTitle());
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                //保存之后设置主面板标题,清空文本框、清空源路径
                textArea.clear();
                stage.close();
                menuBarFactory.originalPath = null;
                ownerStage.setTitle("无标题");


            });
            ABORT_BTN.setOnAction(e -> {
                textArea.clear();
                stage.close();
                menuBarFactory.originalPath = null;
                ownerStage.setTitle("无标题");
            });

        }
        stage.setScene(SCENE);
        stage.setWidth(STAGE_WIDTH);
        stage.setHeight(STAGE_HEIGHT);
        stage.initOwner(ownerStage);
        stage.initModality(Modality.APPLICATION_MODAL);
        InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");
        Image image = new Image(rs1, 50, 50, false, true);
        stage.setTitle("保存提示");
        stage.getIcons().add(image);
        stage.setResizable(false);
        stage.show();
    }


    /** 设置打开文件时对现存文件的保存面板
     * @description:
     * @param: textArea ownerStage
     * @return: void
     * @author
     * @date: 22:18 2022/5/23
     */

    public static void showOpenFileSavePane(TextArea textArea, Stage ownerStage){
        boolean hasStar = ownerStage.getTitle().contains("*");
        StringBuffer tempPath = menuBarFactory.originalPath;
        boolean directRead = (tempPath != null && !hasStar) || (tempPath == null && textArea.getText().isEmpty());
        if(directRead){
            //直接唤醒导入数据面板
            callFileImportPane(textArea,ownerStage);
        }else{
            Stage stage = new Stage();
            CANCEL_BTN.setOnAction(e -> stage.close());
            ABORT_BTN.setOnAction(e->{
                callFileImportPane(textArea,ownerStage);
                stage.close();
            });

            if(tempPath!=null){
                //有源路径,如果不含星星直接弹出读文件对话框打开,如果含星星说明更改,弹出保存面板,如果确认,先静默保存文本,再读入文件,如果放弃,直接读入文本
                INFO_LABEL.setText("你想将更改保存到"+menuBarFactory.originalPath+"吗?");
                SAVE_BTN.setOnAction(e->{
                    try {
                        TextAreaUtils.saveTextAreaContent(textArea,ownerStage.getTitle());
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    ownerStage.setTitle(ownerStage.getTitle().replace("*",""));
                    callFileImportPane(textArea,ownerStage);
                    stage.close();
                });
            }else{
                //无源路径,如果无内容,直接弹出读文件对话框打开,如果有内容,弹出对话框,如果确认,弹出文件保存选择器,保存文本,再读入文件,如果放弃,直接读入文本
                INFO_LABEL.setText("你想先将更改保存到无标题吗?");
                SAVE_BTN.setOnAction(e -> {
                    //从未保存过,则直接需要再开出一个文件保存的窗口
                    Stage fileStage = new Stage();
                    FileChooser fc = new FileChooser();
                    fc.setTitle("保存文件");
                    ///设置默认打开的文件夹路径
                    fc.setInitialDirectory(new File("C:\\"));
                    //设置过滤器,指定打开文件的类型
                    fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文本文件", "*.txt"));
                    //打开文件选择器并返回返回打开的文件所在的完整路径
                    File file = fc.showSaveDialog(fileStage);
                    if (file != null) {

                        String absolutePath = file.getAbsolutePath();
                        try {
                            //导入与否,一旦按下保存,那就保存一波
                            TextAreaUtils.saveTextAreaContent(textArea, absolutePath);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                        ownerStage.setTitle(ownerStage.getTitle().replace("*",""));
                    }
                    callFileImportPane(textArea,ownerStage);
                    stage.close();
                });
            }

            stage.setScene(SCENE);
            stage.setWidth(STAGE_WIDTH);
            stage.setHeight(STAGE_HEIGHT);
            stage.initOwner(ownerStage);
            stage.initModality(Modality.APPLICATION_MODAL);
            InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");
            Image image = new Image(rs1, 50, 50, false, true);
            stage.setTitle("保存提示");
            stage.getIcons().add(image);
            stage.setResizable(false);
            stage.show();
        }


    }

    public static void showSaveAsPane(TextArea textArea,Stage ownerStage){
        Stage fileStage = new Stage();
        FileChooser fc = new FileChooser();
        fc.setTitle("保存文件");
        ///设置默认打开的文件夹路径
        fc.setInitialDirectory(new File("C:\\"));
        //设置过滤器,指定打开文件的类型
        fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文本文件", "*.txt"));
        //打开文件选择器并返回返回打开的文件所在的完整路径
        File file = fc.showSaveDialog(fileStage);
        if (file != null) {

            String absolutePath = file.getAbsolutePath();
            try {
                TextAreaUtils.saveTextAreaContent(textArea, absolutePath);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            ownerStage.setTitle(absolutePath);
            menuBarFactory.originalPath = new StringBuffer(absolutePath);
        }
    }


    public static void showExistSavePane(TextArea textArea,Stage ownerStage){
        if(!ownerStage.getTitle().contains("*")){
            ownerStage.close();
            return;
        }
        String info = menuBarFactory.originalPath == null?"无标题":menuBarFactory.originalPath.toString();
        Stage stage = new Stage();
        INFO_LABEL.setText("你想将更改保存到"+info+"吗?");
        CANCEL_BTN.setOnAction(e -> stage.close());
        ABORT_BTN.setOnAction(e->{
            stage.close();
            ownerStage.close();
        });
        SAVE_BTN.setOnAction(e->{
            showSavePromptPane(textArea,ownerStage,menuBarFactory.originalPath);
            stage.close();
            ownerStage.close();
        });
        stage.setScene(SCENE);
        stage.setWidth(STAGE_WIDTH);
        stage.setHeight(STAGE_HEIGHT);
        stage.initOwner(ownerStage);
        stage.initModality(Modality.APPLICATION_MODAL);
        InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");
        Image image = new Image(rs1, 50, 50, false, true);
        stage.setTitle("保存提示");
        stage.getIcons().add(image);
        stage.setResizable(false);
        stage.show();
    }


    private static void callFileImportPane(TextArea textArea,Stage ownerStage){
        Stage stage = new Stage();
        FileChooser fc = new FileChooser();
        fc.setTitle("打开导入文件");
        ///设置默认打开的文件夹路径
        fc.setInitialDirectory(new File("C:\\"));
        //设置过滤器,指定打开文件的类型
        fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本类型","*.txt"));
        //打开文件选择器并返回返回打开的文件所在的完整路径
        File file = fc.showOpenDialog(stage);
        if(file!=null){
            //清除一下
            textArea.clear();
            String absolutePath = file.getAbsolutePath();
            try {
                TextAreaUtils.readFileToTextArea(textArea,absolutePath);

            } catch (Exception e) {
                e.printStackTrace();
            }
            ownerStage.setTitle(absolutePath);
            menuBarFactory.originalPath = new StringBuffer(absolutePath);
        }
    }


}

三、Utils包

3.1、TextAreaUtils文本框控制工具类

结构

img

代码

TextAreaUtils.java

package utils;

import javafx.scene.control.Alert;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;

import java.io.*;


/**
 * @ClassName TextAreaUtils
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/22 15:44
 * @Version 1.0
 */
public class TextAreaUtils {
    private static int replacementCount = 0;
    private static final int[] FONT_SIZE_OPTIONS = new int[]{4,6,8,10,12,14,
            18, 20,22, 25,27,29,33, 35,36, 40,43, 45,47 ,50,53, 55,58, 60,65,69,72};
    private static final int DEFAULT_SIZE = 15;
    private static int zoomIndex = 7;

    /**
     * 查找功能的实现,默认向下查找
     *
     * @description:
     * @param: textArea key isCaseIgnored isAllScope isCycle
     * @return: void
     * @author
     * @date: 17:31 2022/5/22
     */

    public static void findWords(TextArea textArea, String key, boolean isCaseIgnored, boolean isAllScope, boolean isCycle) {
        int findStartIndex = 0;
        int keyLength = key.length();
        //从光标位置开始查找
        int findStartPos = textArea.getCaretPosition();
        String src = textArea.getText();
        //首先判断是否有这个
        boolean hasResult = src.contains(key);
        if (!hasResult) {
            //没有就直接退出
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("记事本");
            alert.setHeaderText("查找结果");
            alert.setContentText("找不到" + key);
            alert.showAndWait();
            return;
        }

        //范围是循环时,需要重定锚
        if (findStartPos >= src.length()) {
            if (isCycle) {
                findStartPos = 0;
            }
        }

        if (textArea.getSelectedText().isEmpty()) {

            if (isCaseIgnored) {
                String caseIgnoredStrA = src.toLowerCase();
                String caseIgnoredStrB = key.toLowerCase();
                findStartIndex = caseIgnoredStrA.indexOf(caseIgnoredStrB, findStartPos);
            } else {
                findStartIndex = src.indexOf(key, findStartPos);
            }
        } else {
            if (isCaseIgnored) {
                String caseIgnoredStrA = src.toLowerCase();
                String caseIgnoredStrB = key.toLowerCase();
                findStartIndex = caseIgnoredStrA.indexOf(caseIgnoredStrB, findStartPos - caseIgnoredStrB.length() + 1);
            } else {
                findStartIndex = src.indexOf(key, findStartPos - key.length() + 1);
            }
        }

        if (findStartIndex > -1) {
            textArea.selectRange(findStartIndex, findStartIndex + keyLength);
        } else {
            if (!isCycle) {

                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setTitle("记事本");
                alert.setHeaderText("查找结果");
                alert.setContentText("找不到" + key);
                alert.showAndWait();
            } else {
                //从头找
                String s;
                String k;
                //循环,重定位
                if (isCaseIgnored) {
                    s = src.toLowerCase();
                    k = key.toLowerCase();
                } else {
                    s = src;
                    k = key;
                }
                findStartIndex = s.indexOf(k);
                textArea.selectRange(findStartIndex, findStartIndex + keyLength);
            }
        }
    }

    /**
     * 向上查询的实现
     *
     * @description:
     * @param: textArea key isCaseIgnored isAllScope isCycle
     * @return: void
     * @author
     * @date: 17:34 2022/5/22
     */
    public static void backSearch(TextArea textArea, String key, boolean isCaseIgnored, boolean isAllScope, boolean isCycle) {
        int findStartIndex = 0;
        int keyLength = key.length();

        //从光标位置开始查找
        int findStartPos = textArea.getCaretPosition();
        String src = textArea.getText();

        boolean hasResult = src.contains(key);
        if (!hasResult) {
            //没有就直接退出
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("记事本");
            alert.setHeaderText("查找结果");
            alert.setContentText("找不到" + key);
            alert.showAndWait();
            return;
        }
        //范围是循环时,需要重定锚
        if (findStartPos == 0) {
            if (isCycle) {
                findStartPos = src.length();
            }
        }

        String strTemp = src.substring(0, findStartPos);

        if (textArea.getSelectedText().isEmpty()) {
            strTemp = src.substring(0, findStartPos);
            if (isCaseIgnored) {
                String caseIgnoredStrTemp = strTemp.toLowerCase();
                String caseIgnoredStrB = key.toLowerCase();
                findStartIndex = caseIgnoredStrTemp.lastIndexOf(caseIgnoredStrB);
            } else {
                findStartIndex = strTemp.lastIndexOf(key);
            }
        } else {
            //如果当前有选中的文本,右移一单位
            strTemp = src.substring(0, strTemp.length() - 1);
            if (isCaseIgnored) {
                String caseIgnoredStrTemp = strTemp.toLowerCase();
                String caseIgnoredStrB = key.toLowerCase();
                findStartIndex = caseIgnoredStrTemp.lastIndexOf(caseIgnoredStrB);
            } else {
                findStartIndex = strTemp.lastIndexOf(key);
            }
        }


        //查找失败时索引返回值为-1
        if (findStartIndex > -1) {
            textArea.selectRange(findStartIndex, findStartIndex + keyLength);
        } else {
            if (!isCycle) {
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setTitle("记事本");
                alert.setHeaderText("查找结果");
                alert.setContentText("找不到" + key);
                alert.showAndWait();
            } else {
                String s;
                String k;
                //循环,重定位
                if (isCaseIgnored) {
                    s = src.toLowerCase();
                    k = key.toLowerCase();
                } else {
                    s = src;
                    k = key;
                }
                findStartIndex = s.lastIndexOf(k);
                textArea.selectRange(findStartIndex, findStartIndex + keyLength);
            }
        }
    }


    /**
     * 替换功能的实现
     *
     * @description:
     * @param: textArea key replacement isCaseIgnored isAllScope isCycle
     * @return: void
     * @author
     * @date: 17:48 2022/5/22
     */

    public static void replace(TextArea textArea, String key, String replacement, boolean isCaseIgnored, boolean isAllScope, boolean isCycle) {
        int findStartIndex = 0;
        int keyLength = key.length();

        //从光标位置开始查找
        int findStartPos = textArea.getCaretPosition();

        String src = textArea.getText();


        //范围是循环时,需要重定锚
        if (findStartPos >= src.length()) {
            if (isCycle) {
                findStartPos = 0;
            }
        }

        if (textArea.getSelectedText().isEmpty()) {
            if (isCaseIgnored) {
                String caseIgnoredStrA = src.toLowerCase();
                String caseIgnoredStrB = key.toLowerCase();
                findStartIndex = caseIgnoredStrA.indexOf(caseIgnoredStrB, findStartPos);
            } else {
                findStartIndex = src.indexOf(key, findStartPos);
            }
        } else {
            if (isCaseIgnored) {
                String caseIgnoredStrA = src.toLowerCase();
                String caseIgnoredStrB = key.toLowerCase();
                findStartIndex = caseIgnoredStrA.indexOf(caseIgnoredStrB, findStartPos - caseIgnoredStrB.length() + 1);
            } else {
                findStartIndex = src.indexOf(key, findStartPos - key.length() + 1);
            }
        }

        //查找失败时索引返回值为-1
        if (findStartIndex > -1) {
            textArea.positionCaret(findStartIndex);
            textArea.selectRange(findStartIndex, findStartIndex + keyLength);

            try {
                if (replacement.length() == 0 && !textArea.getSelectedText().isEmpty()) {
                    textArea.replaceSelection("");
                }
                if (replacement.length() > 0 && !textArea.getSelectedText().isEmpty()) {
                    textArea.replaceSelection(replacement);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        } else {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("记事本");
            alert.setHeaderText("查找结果");
            alert.setContentText("找不到" + key);
            alert.showAndWait();
        }
    }

    /**
     * 实现全部替换功能
     *
     * @description:
     * @param: textArea key replacement isCaseIgnored
     * @return: void
     * @author
     * @date: 19:55 2022/5/22
     */

    public static void replaceAll(TextArea textArea, String key, String replacement, boolean isCaseIgnored) {

        textArea.positionCaret(0);
        int findStartIndex = 0;
        int keyLength = key.length();
        if (!textArea.getText().contains(key)) {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("替换");
            alert.setHeaderText("替换结果");
            alert.setContentText("替换 " + replacementCount + "处!");
            alert.showAndWait();
        }
        while (findStartIndex > -1) {
            int findStartPos = textArea.getCaretPosition();
            String src = textArea.getText();

            if (textArea.getSelectedText().isEmpty()) {
                if (isCaseIgnored) {
                    String caseIgnoredStrA = src.toLowerCase();
                    String caseIgnoredStrB = key.toLowerCase();
                    findStartIndex = caseIgnoredStrA.indexOf(caseIgnoredStrB, findStartPos);
                } else {
                    findStartIndex = src.indexOf(key, findStartPos);
                }
            } else {
                if (isCaseIgnored) {
                    String caseIgnoredStrA = src.toLowerCase();
                    String caseIgnoredStrB = key.toLowerCase();
                    findStartIndex = caseIgnoredStrA.indexOf(caseIgnoredStrB, findStartPos - caseIgnoredStrB.length() + 1);
                } else {
                    findStartIndex = src.indexOf(key, findStartPos - key.length() + 1);
                }
            }

            if (findStartIndex > -1) {
                textArea.positionCaret(findStartIndex);
                textArea.selectRange(findStartIndex, findStartIndex + keyLength);
            } else {
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setTitle("替换");
                alert.setHeaderText("替换结果");
                alert.setContentText("成功替换 " + replacementCount + "处!");
                alert.showAndWait();
                //重置
                replacementCount = 0;
            }
            if (replacement.length() == 0 && !textArea.getSelectedText().isEmpty()) {
                textArea.replaceSelection("");
                replacementCount++;
            }
            if (replacement.length() > 0 && !textArea.getSelectedText().isEmpty()) {
                textArea.replaceSelection(replacement);
                replacementCount++;
            }
        }
    }

    /**
     * 转到指定行
     * @description:
     * @param: textArea targetLine
     * @return: void
     * @author
     * @date: 22:08 2022/5/22
     */
    public static void turnToTargetLine(TextArea textArea, int targetLine) {
        int lineCount;
        String strA, strB;
        String[] strings;
        strA = textArea.getText();
        strings = strA.split("\n");
        lineCount = strings.length + 1;

        textArea.positionCaret(0);
        if (targetLine >= lineCount) {
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setTitle("跳行");
            alert.setHeaderText("");
            alert.setContentText("行数超过了总行数");
            alert.showAndWait();
            return;
        }
        int i = 0;
        int findStartPos = textArea.getCaretPosition();
        while (findStartPos <= strA.length()) {
            findStartPos = textArea.getCaretPosition();
            textArea.selectRange(0, findStartPos);
            strB = textArea.getSelectedText();
            strings = strB.split("\n");
            i = strings.length;
            if (i == targetLine) {
                textArea.positionCaret(findStartPos);
                break;
            }
            findStartPos++;
            textArea.positionCaret(findStartPos);
        }
    }

    /** 放大文本
     * @description:
     * @param: textArea
     * @return: void
     * @author
     * @date: 16:51 2022/5/23
     */
    public static void enLarge(TextArea textArea) {
        zoomIndex++;
        if (zoomIndex == FONT_SIZE_OPTIONS.length) {
            zoomIndex--;
        }
        textArea.setStyle("-fx-font-size: " + FONT_SIZE_OPTIONS[zoomIndex]);
    }

    /** 缩小文本
     * @description:
     * @param: textArea
     * @return: void
     * @author
     * @date: 16:52 2022/5/23
     */
    public static void shrink(TextArea textArea) {
        zoomIndex--;
        if (zoomIndex == -1) {
            zoomIndex++;
        }
        textArea.setStyle("-fx-font-size: " + FONT_SIZE_OPTIONS[zoomIndex]);
    }

    /** 更新状态栏
     * @description:
     * @param: textArea statusLabel
     * @return: void
     * @author
     * @date: 17:34 2022/5/23
     */

    public static void updateStatusLabel(TextArea textArea, Label statusLabel){
        double zoomPercentage= 1;
        int columnIndex;
        int rowIndex;
        int findStartPos;
        String src = textArea.getText();
        findStartPos = textArea.getCaretPosition();
        String aboveContent = src.substring(0, findStartPos);
        String[] stringLines = aboveContent.split("\n");
        rowIndex = stringLines.length;

        if(rowIndex == 0)
        {
            src += "*";
            aboveContent = src.substring(0, findStartPos + 1);
            stringLines = aboveContent.split("\n");
            rowIndex = stringLines.length;
            columnIndex = stringLines[rowIndex - 1].length() - 1;
        }
        else {
            columnIndex = stringLines[rowIndex - 1].length();
        }
        zoomPercentage = textArea.getFont().getSize()/DEFAULT_SIZE*100;
        double floor = Math.floor(zoomPercentage);
        statusLabel.setText("    第 " + rowIndex + " 行, 第 " + (columnIndex + 1) + " 列  " + " 共 " + src.length() + " 字 "  + " 缩放:"  + floor + "%");
    }


    /** 将指定的文本框内容写入到指定的文件路径进行保存操作
     * @description:
     * @param: textArea path
     * @return: void
     * @author
     * @date: 18:47 2022/5/23
     */
    public static void saveTextAreaContent(TextArea textArea,String path) throws Exception {
        String tempPath = path;
        if(path.contains("*")){
            tempPath = path.replace("*","");
        }
        FileWriter fileWriter = new FileWriter(tempPath);
        BufferedWriter bw = new BufferedWriter(fileWriter);
        String content = textArea.getText();
        bw.write(content);
        bw.close();
    }

    /** 读取指定路径文件内容至文本框
     * @description:
     * @param: textArea path
     * @return: void
     * @author
     * @date: 22:23 2022/5/23
     */
    public static void readFileToTextArea(TextArea textArea,String path) throws Exception {
        FileReader fileReader = new FileReader(path);
        BufferedReader br = new BufferedReader(fileReader);

        String line;
        while((line = br.readLine())!=null){
            textArea.appendText(line);
            textArea.appendText("\n");
        }

        br.close();
    }


}

四、Resource包

logo.jpg

img

注意:如果出现资源路径错误(程序报错logo.jpg找不到路径),那就将所有代码中出现的下列语句及其相关变量(rs1)删除即可,或者将路径变为图片的绝对路径即可

InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");

五、记事本入口

Main类

代码

package main;

import domain.FileSavePromptFactory;
import domain.StatusLabelFactory;
import domain.MenuBarFactory;
import domain.TextAreaFactory;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.io.InputStream;

/**
 * @ClassName ShowPaneTest
 * @Description TODO
 * @Author Mr_X
 * @Date 2022/5/20 9:16
 * @Version 1.0
 */
public class Main extends Application {
    private final static double STAGE_WIDTH = 600;
    private final static double STAGE_HEIGHT = 600;
    private final MenuBarFactory menuBarFactory = new MenuBarFactory();
    private final TextAreaFactory textAreaFactory = new TextAreaFactory();
    private final StatusLabelFactory statusLabelFactory = new StatusLabelFactory();


    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        AnchorPane menuAnc = new AnchorPane();
        menuAnc.setStyle(
                "-fx-background-color:#c7c3c3;"
        );
        menuBarFactory.setOwnerAnc(menuAnc);
        menuAnc.setPrefWidth(STAGE_WIDTH);
        AnchorPane contentAnc = new AnchorPane();
        textAreaFactory.setOwnerAnc(contentAnc);
        Label statusLabel = statusLabelFactory.getLabel(STAGE_WIDTH,textAreaFactory.textArea);
        textAreaFactory.bindTextAreaLabel(statusLabel);

        BorderPane borderPane = new BorderPane(contentAnc, menuAnc, null, statusLabel, null);
        BorderPane.setAlignment(contentAnc, Pos.CENTER);
        BorderPane.setAlignment(menuAnc, Pos.CENTER);
        BorderPane.setAlignment(statusLabel, Pos.CENTER);

        borderPane.setPadding(new Insets(0.0));
        Scene scene = new Scene(borderPane);
        primaryStage.setScene(scene);
        primaryStage.setTitle("无标题");
        primaryStage.setHeight(STAGE_HEIGHT);
        primaryStage.setWidth(STAGE_WIDTH);
        InputStream rs1 = Thread.currentThread().getContextClassLoader().getResourceAsStream("resource/logo.jpg");
        Image image = new Image(rs1, 50, 50, false, true);
        primaryStage.getIcons().add(image);

        //核心绑定
        menuBarFactory.setTextFactory(textAreaFactory,primaryStage);
        primaryStage.show();


        primaryStage.setOnCloseRequest(event -> {
            //如果带星直接关闭,否则进行保存操作
            event.consume();
            FileSavePromptFactory.showExistSavePane(textAreaFactory.textArea,primaryStage);
        });

    }
}

最终效果

img

写这个的时候陪着我的那个她,还是走了。 --2022.7.9

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值