diff --git a/.gitignore b/.gitignore index 5cf1ae1..2413d24 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,7 @@ target/ !**/src/test/**/target/ ### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ +.idea/ *.iws *.iml *.ipr @@ -38,3 +35,4 @@ build/ .DS_Store /JNotepad/ /src/main/JNotepad.java +/.idea/ diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 35410ca..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# 默认忽略的文件 -/shelf/ -/workspace.xml -# 基于编辑器的 HTTP 客户端请求 -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 36e5495..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index ee9f695..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 8e852c2..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index 2b63946..0000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index e927e2e..db8498c 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -11,4 +11,5 @@ module org.jcnc.jnotepad { exports org.jcnc.jnotepad.view.init; exports org.jcnc.jnotepad.view.manager; exports org.jcnc.jnotepad.constants; + exports org.jcnc.jnotepad.ui; } \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java b/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java index 4d9c808..b482a09 100644 --- a/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java +++ b/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java @@ -2,7 +2,7 @@ package org.jcnc.jnotepad.Interface; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import javafx.scene.control.TextArea; +import org.jcnc.jnotepad.ui.LineNumberTextArea; import java.io.File; import java.util.List; @@ -18,7 +18,7 @@ public interface ControllerInterface { * @param rawParameters 原始参数列表 * @return 创建的 TextArea */ - TextArea openAssociatedFileAndCreateTextArea(List rawParameters); + LineNumberTextArea openAssociatedFileAndCreateTextArea(List rawParameters); /** * 获取换行符处理事件处理程序 @@ -26,7 +26,7 @@ public interface ControllerInterface { * @param textArea 文本区域 * @return 换行符处理事件处理程序 */ - EventHandler getLineFeedEventHandler(TextArea textArea); + EventHandler getLineFeedEventHandler(LineNumberTextArea textArea); /** * 获取新建文件处理事件处理程序 @@ -34,7 +34,7 @@ public interface ControllerInterface { * @param textArea 文本区域 * @return 新建文件处理事件处理程序 */ - EventHandler getNewFileEventHandler(TextArea textArea); + EventHandler getNewFileEventHandler(LineNumberTextArea textArea); /** * 获取打开文件处理事件处理程序 @@ -56,14 +56,14 @@ public interface ControllerInterface { * * @param textArea 文本区域 */ - void autoSave(TextArea textArea); + void autoSave(LineNumberTextArea textArea); /** * 更新状态标签 * * @param textArea 文本区域 */ - void updateStatusLabel(TextArea textArea); + void updateStatusLabel(LineNumberTextArea textArea); /** * 打开关联文件 @@ -109,5 +109,5 @@ public interface ControllerInterface { */ void initTabPane(); - void updateUIWithNewTextArea(TextArea textArea); + void updateUIWithNewTextArea(LineNumberTextArea textArea); } diff --git a/src/main/java/org/jcnc/jnotepad/LunchApp.java b/src/main/java/org/jcnc/jnotepad/LunchApp.java index 451118c..3fb856c 100644 --- a/src/main/java/org/jcnc/jnotepad/LunchApp.java +++ b/src/main/java/org/jcnc/jnotepad/LunchApp.java @@ -4,13 +4,13 @@ import atlantafx.base.theme.PrimerLight; import javafx.application.Application; import javafx.application.Platform; import javafx.scene.Scene; -import javafx.scene.control.Tab; -import javafx.scene.control.TextArea; + import javafx.scene.image.Image; import javafx.scene.layout.Pane; import javafx.stage.Stage; import org.jcnc.jnotepad.constants.Constants; import org.jcnc.jnotepad.controller.manager.Controller; +import org.jcnc.jnotepad.ui.LineNumberTextArea; import org.jcnc.jnotepad.view.init.View; import org.jcnc.jnotepad.view.manager.ViewManager; @@ -24,29 +24,30 @@ public class LunchApp extends Application { public static boolean isRelevance = true; Controller controller = Controller.getInstance(); - + Scene scene; View view; @Override public void start(Stage primaryStage) { - view =new View(); + view = new View(); Pane root = new Pane(); + double width = Constants.SCREEN_WIDTH; double length = Constants.SCREEN_LENGTH; String name = Constants.APP_NAME; String icon = Constants.APP_ICON; - Scene scene = new Scene(root, width, length); - + scene = new Scene(root, width, length); Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet()); primaryStage.setTitle(name); primaryStage.setWidth(width); primaryStage.setHeight(length); primaryStage.setScene(scene); + primaryStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResource(icon)).toString())); primaryStage.show(); ViewManager viewManager = ViewManager.getInstance(scene); @@ -58,15 +59,17 @@ public class LunchApp extends Application { view.initShortcutKey(); if (isRelevance) { + // 使用线程池加载关联文件并创建文本区域 List rawParameters = getParameters().getRaw(); threadPool.execute(() -> { - TextArea textArea = controller.openAssociatedFileAndCreateTextArea(rawParameters); + LineNumberTextArea textArea = controller.openAssociatedFileAndCreateTextArea(rawParameters); if (!Objects.isNull(textArea)) { Platform.runLater(() -> controller.updateUIWithNewTextArea(textArea)); } }); } + } @Override diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/LineFeed.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/LineFeed.java index 870ee9d..bf8e9ab 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/LineFeed.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/LineFeed.java @@ -2,7 +2,7 @@ package org.jcnc.jnotepad.controller.event.handler; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import javafx.scene.control.TextArea; +import org.jcnc.jnotepad.ui.LineNumberTextArea; /** * 换行程序。 @@ -10,13 +10,13 @@ import javafx.scene.control.TextArea; * 用于在文本区域中插入一个换行符。 */ public class LineFeed implements EventHandler { - private final TextArea textArea; + private final LineNumberTextArea textArea; /** * 构造函数,初始化 LineFeed 对象。 * @param textArea 要操作的文本区域 */ - public LineFeed(TextArea textArea) { + public LineFeed(LineNumberTextArea textArea) { this.textArea = textArea; } @@ -26,7 +26,7 @@ public class LineFeed implements EventHandler { */ @Override public void handle(ActionEvent event) { - String text = textArea.getText(); - textArea.setText(text + "\n"); + String text = textArea.getMainTextArea().getText(); + textArea.getMainTextArea().setText(text + "\n"); } } diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/NewFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/NewFile.java index c23c3ae..0a7fae9 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/NewFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/NewFile.java @@ -3,7 +3,7 @@ package org.jcnc.jnotepad.controller.event.handler; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.Tab; -import javafx.scene.control.TextArea; +import org.jcnc.jnotepad.ui.LineNumberTextArea; import org.jcnc.jnotepad.controller.manager.Controller; import org.jcnc.jnotepad.view.manager.ViewManager; @@ -25,18 +25,24 @@ public class NewFile implements EventHandler { // 获取控制器 Controller controller = Controller.getInstance(); + LineNumberTextArea lineNumberTextArea = new LineNumberTextArea(); + + // 创建一个新的文本编辑区 - TextArea textArea = new TextArea(); + LineNumberTextArea textArea = new LineNumberTextArea(); + + textArea.setStyle( - "-fx-border-color:white;" + - "-fx-background-color:white" + "-fx-border-color:white ;-fx-background-color:white;" ); + //TODO: refactor:统一TextArea新建、绑定监听器入口 // 增加autoSave监听器绑定 controller.autoSave(textArea); + // 创建一个新的Tab页 Tab tab = new Tab("新建文本 " + ++ViewManager.tabIndex); - tab.setContent(textArea); + tab.setContent(lineNumberTextArea.getMainTextArea()); // 将Tab页添加到TabPane中 tabPane.getTabs().add(tab); @@ -45,9 +51,9 @@ public class NewFile implements EventHandler { tabPane.getSelectionModel().select(tab); // 更新状态标签 - controller.updateStatusLabel(textArea); + controller.updateStatusLabel(lineNumberTextArea); // 更新编码信息 - controller.upDateEncodingLabel(textArea.getText()); + controller.upDateEncodingLabel(lineNumberTextArea.getMainTextArea().getText()); } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/OpenFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/OpenFile.java index 3e06a29..635a34a 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/OpenFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/OpenFile.java @@ -3,8 +3,9 @@ package org.jcnc.jnotepad.controller.event.handler; import javafx.concurrent.Task; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import javafx.scene.control.TextArea; + import javafx.stage.FileChooser; +import org.jcnc.jnotepad.ui.LineNumberTextArea; import org.jcnc.jnotepad.controller.manager.Controller; import java.io.File; @@ -38,7 +39,7 @@ public class OpenFile implements EventHandler { // 调用控制器的getText方法,读取文件内容 controller.getText(file); // 更新编码标签 - controller.upDateEncodingLabel(((TextArea) tabPane.getSelectionModel().getSelectedItem().getContent()).getText()); + controller.upDateEncodingLabel(((LineNumberTextArea) tabPane.getSelectionModel().getSelectedItem().getContent()).getMainTextArea().getText()); return null; } }; diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/SaveAsFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/SaveAsFile.java index 712865f..3299bf6 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/SaveAsFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/SaveAsFile.java @@ -3,9 +3,8 @@ package org.jcnc.jnotepad.controller.event.handler; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.Tab; -import javafx.scene.control.TextArea; import javafx.stage.FileChooser; -import org.jcnc.jnotepad.controller.manager.Controller; +import org.jcnc.jnotepad.ui.LineNumberTextArea; import java.io.BufferedWriter; import java.io.File; @@ -33,14 +32,14 @@ public class SaveAsFile implements EventHandler { Tab selectedTab = tabPane.getSelectionModel().getSelectedItem(); if (selectedTab != null) { FileChooser fileChooser = new FileChooser(); - fileChooser.setInitialFileName("新建文本"); + fileChooser.setInitialFileName(selectedTab.getText()); fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本文档", "*.txt")); File file = fileChooser.showSaveDialog(null); if (file != null) { try { BufferedWriter writer = new BufferedWriter(new FileWriter(file)); - TextArea textArea = (TextArea) selectedTab.getContent(); // 获取当前Tab页的文本编辑区 - String text = textArea.getText(); + LineNumberTextArea textArea = (LineNumberTextArea) selectedTab.getContent(); // 获取当前Tab页的文本编辑区 + String text = textArea.getMainTextArea().getText(); writer.write(text); // 写入文件内容 writer.flush(); writer.close(); diff --git a/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java b/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java index af6b089..00f8fa1 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java +++ b/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java @@ -5,10 +5,9 @@ import javafx.concurrent.Task; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.Tab; -import javafx.scene.control.TextArea; -import javafx.scene.paint.Color; -import javafx.scene.shape.Rectangle; + import org.jcnc.jnotepad.Interface.ControllerInterface; +import org.jcnc.jnotepad.ui.LineNumberTextArea; import org.jcnc.jnotepad.LunchApp; import org.jcnc.jnotepad.controller.event.handler.LineFeed; import org.jcnc.jnotepad.controller.event.handler.NewFile; @@ -43,13 +42,13 @@ public class Controller implements ControllerInterface { * @return 创建的文本区域 */ @Override - public TextArea openAssociatedFileAndCreateTextArea(List rawParameters) { + public LineNumberTextArea openAssociatedFileAndCreateTextArea(List rawParameters) { if (!rawParameters.isEmpty()) { String filePath = rawParameters.get(0); openAssociatedFile(filePath); return null; } else { - TextArea textArea = createNewTextArea(); + LineNumberTextArea textArea = createNewTextArea(); configureTextArea(textArea); return textArea; } @@ -62,7 +61,7 @@ public class Controller implements ControllerInterface { * @return 行分隔事件处理程序 */ @Override - public EventHandler getLineFeedEventHandler(TextArea textArea) { + public EventHandler getLineFeedEventHandler(LineNumberTextArea textArea) { return new LineFeed(textArea); } @@ -73,7 +72,7 @@ public class Controller implements ControllerInterface { * @return 新建文件事件处理程序 */ @Override - public EventHandler getNewFileEventHandler(TextArea textArea) { + public EventHandler getNewFileEventHandler(LineNumberTextArea textArea) { return new NewFile(); } @@ -93,7 +92,7 @@ public class Controller implements ControllerInterface { * @param textArea 文本区域 */ @Override - public void autoSave(TextArea textArea) { + public void autoSave(LineNumberTextArea textArea) { textArea.textProperty().addListener((observable, oldValue, newValue) -> { Tab tab = ViewManager.tabPane.getSelectionModel().getSelectedItem(); if (tab != null) { @@ -126,11 +125,11 @@ public class Controller implements ControllerInterface { * @param textArea 文本区域 */ @Override - public void updateStatusLabel(TextArea textArea) { - int caretPosition = textArea.getCaretPosition(); - int row = getRow(caretPosition, textArea.getText()); - int column = getColumn(caretPosition, textArea.getText()); - int length = textArea.getLength(); + public void updateStatusLabel(LineNumberTextArea textArea) { + int caretPosition = textArea.getMainTextArea().getCaretPosition(); + int row = getRow(caretPosition, textArea.getMainTextArea().getText()); + int column = getColumn(caretPosition, textArea.getMainTextArea().getText()); + int length = textArea.getMainTextArea().getLength(); ViewManager.statusLabel.setText("行: " + row + " \t列: " + column + " \t字数: " + length); } @@ -155,7 +154,7 @@ public class Controller implements ControllerInterface { */ @Override public void getText(File file) { - TextArea textArea = createNewTextArea(); + LineNumberTextArea textArea = createNewTextArea(); try (BufferedReader reader = new BufferedReader(new FileReader(file))) { StringBuilder textBuilder = new StringBuilder(); String line; @@ -165,7 +164,7 @@ public class Controller implements ControllerInterface { String text = textBuilder.toString(); Platform.runLater(() -> { - textArea.setText(text); + textArea.getMainTextArea().setText(text); Tab tab = createNewTab(file.getName(), textArea); tab.setUserData(file); @@ -234,22 +233,22 @@ public class Controller implements ControllerInterface { ViewManager.tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldTab, newTab) -> { if (newTab != null) { // 获取新选定的标签页并关联的文本区域 - TextArea textArea = (TextArea) newTab.getContent(); + LineNumberTextArea textArea = (LineNumberTextArea) newTab.getContent(); // 更新状态标签 controller.updateStatusLabel(textArea); // 监听文本光标位置的变化,更新状态标签 - textArea.caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> controller.updateStatusLabel(textArea)); + textArea.getMainTextArea().caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> controller.updateStatusLabel(textArea)); // 更新编码标签 - controller.upDateEncodingLabel(textArea.getText()); + controller.upDateEncodingLabel(textArea.getMainTextArea().getText()); } }); } @Override - public void updateUIWithNewTextArea(TextArea textArea) { + public void updateUIWithNewTextArea(LineNumberTextArea textArea) { Tab tab = new Tab("新建文件 " + (++ViewManager.tabIndex)); tab.setContent(textArea); ViewManager.tabPane.getTabs().add(tab); @@ -262,9 +261,9 @@ public class Controller implements ControllerInterface { * * @param textArea 文本区域 */ - private void configureTextArea(TextArea textArea) { - textArea.setWrapText(true); - upDateEncodingLabel(textArea.getText()); + private void configureTextArea(LineNumberTextArea textArea) { + textArea.getMainTextArea().setWrapText(true); + upDateEncodingLabel(textArea.getMainTextArea().getText()); updateStatusLabel(textArea); textArea.textProperty().addListener((observable, oldValue, newValue) -> updateStatusLabel(textArea)); @@ -277,8 +276,8 @@ public class Controller implements ControllerInterface { * * @return 新的文本区域 */ - private TextArea createNewTextArea() { - TextArea textArea = new TextArea(); + private LineNumberTextArea createNewTextArea() { + LineNumberTextArea textArea = new LineNumberTextArea(); textArea.setStyle( "-fx-border-color:white;" + "-fx-background-color:white" @@ -293,7 +292,7 @@ public class Controller implements ControllerInterface { * @param textArea 文本区域 * @return 新的标签页 */ - private Tab createNewTab(String tabName, TextArea textArea) { + private Tab createNewTab(String tabName, LineNumberTextArea textArea) { Tab tab = new Tab(tabName); tab.setContent(textArea); tab.setUserData(null); @@ -307,12 +306,12 @@ public class Controller implements ControllerInterface { * @return 打开文件的任务 */ private Task createOpenFileTask(File file) { - TextArea textArea = createNewTextArea(); + LineNumberTextArea textArea = createNewTextArea(); return new Task<>() { @Override protected Void call() { getText(file); - upDateEncodingLabel(textArea.getText()); + upDateEncodingLabel(textArea.getMainTextArea().getText()); return null; } }; diff --git a/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java b/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java index 4dc32f3..0bdd00c 100644 --- a/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java +++ b/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java @@ -1,6 +1,7 @@ package org.jcnc.jnotepad.tool; -import javafx.scene.control.TextArea; + +import org.jcnc.jnotepad.ui.LineNumberTextArea; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -16,8 +17,8 @@ public class EncodingDetector { * @param textArea 文本区域 * @return 字符串表示的编码,如果检测失败则返回 "UNKNOWN" */ - public static String detectEncoding(TextArea textArea) { - String text = textArea.getText(); + public static String detectEncoding(LineNumberTextArea textArea) { + String text = textArea.getMainTextArea().getText(); return detectEncoding(text); } diff --git a/src/main/java/org/jcnc/jnotepad/tool/FileUtil.java b/src/main/java/org/jcnc/jnotepad/tool/FileUtil.java index eb05b24..752350f 100644 --- a/src/main/java/org/jcnc/jnotepad/tool/FileUtil.java +++ b/src/main/java/org/jcnc/jnotepad/tool/FileUtil.java @@ -1,6 +1,7 @@ package org.jcnc.jnotepad.tool; import java.io.*; +import java.nio.charset.StandardCharsets; /** * @author 一个大转盘 @@ -18,7 +19,7 @@ public class FileUtil { String jsonStr = ""; try { FileReader fileReader = new FileReader(jsonFile); - Reader reader = new InputStreamReader(new FileInputStream(jsonFile),"utf-8"); + Reader reader = new InputStreamReader(new FileInputStream(jsonFile), StandardCharsets.UTF_8); int ch = 0; StringBuffer sb = new StringBuffer(); while ((ch = reader.read()) != -1) { diff --git a/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java b/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java new file mode 100644 index 0000000..d44d41f --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java @@ -0,0 +1,70 @@ +package org.jcnc.jnotepad.ui; + +import javafx.beans.property.StringProperty; + +import javafx.scene.control.TextArea; +import javafx.scene.layout.BorderPane; + +import java.util.Objects; + +public class LineNumberTextArea extends BorderPane { + + + private final TextArea mainTextArea; + private final TextArea lineNumberArea; + + public LineNumberTextArea() { + mainTextArea = new TextArea(); + lineNumberArea = new TextArea(); + lineNumberArea.setEditable(false); + lineNumberArea.setMinWidth(55); + lineNumberArea.setMaxWidth(55); + // 设置显示滚动条样式类 +/* lineNumberArea.getStyleClass().add("hide-scrollbars"); + mainTextArea.getStyleClass().add("show-scrollbars"); */ + + mainTextArea.textProperty().addListener((observable, oldValue, newValue) -> updateLineNumberArea()); + + // 当主要文本区域的垂直滚动位置发生变化时,使行号文本区域的滚动位置保持一致 + mainTextArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> { + lineNumberArea.setScrollTop(mainTextArea.getScrollTop()); + }); + + // 当行号文本区域的垂直滚动位置发生变化时,使主要文本区域的滚动位置保持一致 + lineNumberArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> { + mainTextArea.setScrollTop(lineNumberArea.getScrollTop()); + }); + + setCenter(mainTextArea); + setLeft(lineNumberArea); + } + + public StringProperty textProperty() { + return mainTextArea.textProperty(); + } + + + private void updateLineNumberArea() { + // 保存当前的滚动位置 + /* + 更新行号文本区域的内容,根据主要文本区域的段落数生成行号。 + */ + double mainTextAreaScrollTop = mainTextArea.getScrollTop(); + double lineNumberAreaScrollTop = lineNumberArea.getScrollTop(); + + int numOfLines = mainTextArea.getParagraphs().size(); + StringBuilder lineNumberText = new StringBuilder(); + for (int i = 1; i <= numOfLines; i++) { + lineNumberText.append(i).append("\n"); + } + lineNumberArea.setText(lineNumberText.toString()); + + // 恢复之前的滚动位置 + mainTextArea.setScrollTop(mainTextAreaScrollTop); + lineNumberArea.setScrollTop(lineNumberAreaScrollTop); + } + + public TextArea getMainTextArea() { + return mainTextArea; + } +} diff --git a/src/main/java/org/jcnc/jnotepad/view/init/View.java b/src/main/java/org/jcnc/jnotepad/view/init/View.java index 037b2dd..4e99f63 100644 --- a/src/main/java/org/jcnc/jnotepad/view/init/View.java +++ b/src/main/java/org/jcnc/jnotepad/view/init/View.java @@ -2,11 +2,7 @@ package org.jcnc.jnotepad.view.init; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import javafx.scene.Scene; -import javafx.scene.control.TextArea; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyCodeCombination; -import javafx.scene.input.KeyCombination; +import org.jcnc.jnotepad.ui.LineNumberTextArea; import org.jcnc.jnotepad.controller.manager.Controller; import org.jcnc.jnotepad.controller.manager.ShortcutKey; @@ -21,13 +17,13 @@ public class View { public void initItem() { // 初始化菜单项的事件处理器 - EventHandler newFileEventHandler = Controller.getInstance().getNewFileEventHandler(new TextArea()); + EventHandler newFileEventHandler = Controller.getInstance().getNewFileEventHandler(new LineNumberTextArea()); newItem.setOnAction(newFileEventHandler); EventHandler openFileEventHandler = Controller.getInstance().getOpenFileEventHandler(); openItem.setOnAction(openFileEventHandler); EventHandler saveAsFileEventHandler = Controller.getInstance().getSaveAsFileEventHandler(); saveAsItem.setOnAction(saveAsFileEventHandler); - lineFeedItem.setOnAction(Controller.getInstance().getLineFeedEventHandler(new TextArea())); + lineFeedItem.setOnAction(Controller.getInstance().getLineFeedEventHandler(new LineNumberTextArea())); } public void initTabPane() { diff --git a/src/main/java/org/jcnc/jnotepad/view/manager/ViewManager.java b/src/main/java/org/jcnc/jnotepad/view/manager/ViewManager.java index 1609b92..fbcda7a 100644 --- a/src/main/java/org/jcnc/jnotepad/view/manager/ViewManager.java +++ b/src/main/java/org/jcnc/jnotepad/view/manager/ViewManager.java @@ -3,12 +3,12 @@ package org.jcnc.jnotepad.view.manager; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.*; -import javafx.scene.input.KeyCombination; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * 该类管理记事本应用程序的视图组件。 @@ -30,6 +30,8 @@ public class ViewManager { // 主界面布局 public static BorderPane root; //主布局 + + // 多个标签页 public static TabPane tabPane; //标签页栏 @@ -47,6 +49,7 @@ public class ViewManager { * @return ViewManager的实例。 */ public static ViewManager getInstance(Scene scene) { + if (instance == null) { instance = new ViewManager(scene); } @@ -60,7 +63,11 @@ public class ViewManager { */ private ViewManager(Scene scene) { root = new BorderPane(); + scene.setRoot(root); + + + } /** @@ -125,5 +132,8 @@ public class ViewManager { BorderPane.setMargin(statusBox, new Insets(5, 10, 5, 10)); scene.setRoot(root); + + + } } diff --git a/src/main/resources/styles.css b/src/main/resources/styles.css new file mode 100644 index 0000000..4184796 --- /dev/null +++ b/src/main/resources/styles.css @@ -0,0 +1,11 @@ +/* 显示滚动条 */ +.show-scrollbars .scroll-pane { + -fx-hbar-policy: as-needed; + -fx-vbar-policy: as-needed; +} + +/* 不显示滚动条 */ +.hide-scrollbars .scroll-pane { + -fx-hbar-policy: never; + -fx-vbar-policy: never; +}