Text(6) Text Editor ——自制文本编辑器
题目描述:
Text Editor – Notepad style application that can open, edit, and save text documents. Add syntax highlighting and other features.
题目翻译:
文本编辑器——编写一个笔记本类型的应用,可以打开,编辑和保存文本文档(text文档)。可以添加一些语法高亮和其他的特性。
实现过程:
基于java的GUI框架javaFX来实现整个编辑器的功能。
使用java的textArea组件作为文本编辑器的编辑区,并且textArea已经集成了基本的文本编辑操作(复制,剪切,粘贴,撤销,恢复,全选),所以编辑器的实现重点是文本文件的新建(create),保存(save)和另存为(save as)
接下来按照前端界面(front-end)和后端(back-end)讲述文本编辑器的实现。
javaFX框架简介
javaFX框架可以用来开发跨平台的GUI应用程序。
javaFX框架可以基于MVC模式来构建GUI应用程序。
javaFX框架使用FXML文件来定义用户界面。(View层,展示数据),使用Controller来操作前端上的数据。
1.1 前端设计
整个编辑器主界面采用BorderPane布局(top,center,left,right,bottom五个子节点)。
top节点为菜单栏(MenuBar)
center节点设置为编辑区(editArea)
bottom节点设置为尾部状态栏(state)
left节点暂定为行号显示栏(暂时未实现)

对于菜单栏:包括菜单,编辑,保存,字体调整等菜单(Menu)
菜单:
打开文件
新建文件
编辑:(javaFx的TextArea以及集成了全部功能,无须自己实现)
- 复制(copy)
- 剪切(cut)
- 粘贴(paste)
- 撤销(undo)
- 恢复(consume)
- 高亮(highlight)
保存:
- 保存文件
- 另存为文件
字体调整:
设置三个级别的字体大小(small,middle,large)
整个编辑器界面对应的fxml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.sunfulv.ViewController"
fx:id="borderPane"
prefHeight="400.0" prefWidth="600.0">
<top>
<MenuBar>
<Menu id="fileMenu" text="菜单">
<MenuItem fx:id="openMenu" text="打开文件" onAction="#openFileAction"></MenuItem>
<MenuItem id="createMenu" text="新建文件" onAction="#createFileAction"></MenuItem>
</Menu>
<Menu id="editMenu" text="编辑">
<MenuItem fx:id="copyMenu" text="复制" onAction="#copyMenuAction"></MenuItem>
<MenuItem id="cutMenu" text="剪切"></MenuItem>
<MenuItem id="pasteMenu" text="粘贴"></MenuItem>
<MenuItem id="undo" text="撤销"></MenuItem>
<MenuItem id="resumeMenu" text="恢复"></MenuItem>
</Menu>
<Menu id="saveMenu" text="保存" >
<MenuItem id="save" text="保存文件" onAction="#saveFileAction"></MenuItem>
<MenuItem id="saveAs" text="另存为" onAction="#saveAsFileAction"></MenuItem>
</Menu>
<Menu id="fontMenu" text="字体大小">
<MenuItem id="smallFont" text="小字" onAction="#smallFontAction"></MenuItem>
<MenuItem id="middleFont" text="中号字体" onAction="#middleFontAction"></MenuItem>
<MenuItem id="largeFont" text="大号字体" onAction="#lagreFontAction"></MenuItem>
</Menu>
</MenuBar>
</top>
<center>
<TextArea fx:id="textArea" text="Hello World">
</TextArea>
</center>
<bottom >
<AnchorPane snapToPixel="true"></AnchorPane>
</bottom>
<left>
<
</left>
</BorderPane>
1.2 后端设计
在设计完前端界面时,会为每个菜单绑定(onAction)事件响应方法,我们需要在后端实现这些事件响应方法。
在javaFX框架中,我们将这些事件响应方法统一定义在自定义的ViewController类中。同时在fxml文件中引入这个类。
首先在ViewController类中定义一个File实例,用于代表当前正被激活的文本文件(当前没有打开的文件时,File实例默认为null)
在ViewController类中,使用@FXML注解来导入在fxml文件中定义的容器和组件
这里导入在fxml中定义的布局组件(borderPane)和文本区域组件(textArea)
@FXML private BorderPane borderPane;
@FXML private TextArea textArea;
在定义事件响应方法时,方法名要和fxml中各个菜单组件绑定的响应方法名相同,
在响应方法前添加@FXML注解, 可以将两者绑定起来。
package com.sunfulv;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
public class ViewController {
File currentFile = null;//始终代表当前编辑框中对应的文件
@FXML private BorderPane borderPane;
@FXML private TextArea textArea;
//打开文件
@FXML protected void openFileAction(ActionEvent event) throws IOException {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("打开所选文件");
fileChooser.getExtensionFilters().addAll( //添加文件过滤器,默认只允许文本文件
new FileChooser.ExtensionFilter("文本文件","*.txt"),
new FileChooser.ExtensionFilter("全部文件","*.*")
);
Stage currentStage = (Stage)borderPane.getScene().getWindow();
currentFile = fileChooser.showOpenDialog(currentStage);//读取选中的文件
if(currentFile == null) return; //如果没有选择要打开的文件,直接返回
currentStage.setTitle("Text Editor-"+currentFile.getName());
//System.out.println(textFile.getName());
FileInputStream fin= null;
Reader fr = null;
try {
fin= new FileInputStream(currentFile);
fr = new InputStreamReader(fin, StandardCharsets.UTF_8); //默认使用utf8格式打开
String str = null;
char[] byteArray = new char[(int) currentFile.length()];
fr.read(byteArray);
str = new String(byteArray);
System.out.println(str);
textArea.setText(str);
}catch(Exception e){
e.printStackTrace();
}finally{
fr.close();
}
}
// 新建文件
@FXML protected void createFileAction(ActionEvent event) throws IOException{
//新建一个文件前,首先确认是否保存当前正在编辑的文件
Alert alert = new Alert(Alert.AlertType.INFORMATION,"是否保存当前文件!",new ButtonType("是", ButtonBar.ButtonData.YES),new ButtonType("否",ButtonBar.ButtonData.NO));
alert.setHeaderText("提示信息");
Optional<ButtonType> buttonType = alert.showAndWait(); //显示对话框,并等待返回,用于确定对话框选择的是确认按钮还是取消按钮
if(buttonType.get().getButtonData().equals(ButtonBar.ButtonData.YES)){ //如果选择的是,表明要保存当前正在编辑的文件
////判断当前编辑框中没有打开的文件,如果没有,直接清空当前编辑框
if(currentFile !=null)
saveFile(currentFile);
}else{
return;
}
textArea.setText(""); //清空当前编辑框
currentFile = null;
Stage currentStage = (Stage)borderPane.getScene().getWindow();
currentStage.setTitle("Text Editor-"+"未命名文件");
}
// 保存文件
@FXML protected void saveFileAction(ActionEvent event) throws IOException{
//保存当前编辑器中的内容
if(currentFile !=null) //如果当前有打开的文件,可以进行保存,否则将当前编辑框中的内容另存为一个新的文件
saveFile(currentFile);
else {
if(saveAsFile()) {
Stage currentStage = (Stage) borderPane.getScene().getWindow();
currentStage.setTitle("Text Editor-" + currentFile.getName());
}
}
}
//文件另存为
@FXML protected void saveAsFileAction(ActionEvent event) throws IOException{
saveAsFile();
}
//字体大小调整
@FXML protected void smallFontAction(ActionEvent event){
textArea.setStyle("-fx-font-size: 20px");
}
@FXML protected void middleFontAction(ActionEvent event){
textArea.setStyle("-fx-font-size: 40px");
}
@FXML protected void lagreFontAction(ActionEvent event){
textArea.setStyle("-fx-font-size: 60px");
}
//保存当前正在编辑的文件(将编辑框中的字符串保存到对应的文件中)
private boolean saveFile(File currentFile) throws IOException{
String currentStr = textArea.getText();//读取编辑框中的内容
Writer writer = null;
try {
writer = new FileWriter(currentFile);
char[] byteArray = currentStr.toCharArray();
writer.write(byteArray);
// System.out.println(new String(byteArray));
return true;
}catch(Exception e){
e.printStackTrace();
return false;
}finally{
writer.close();
}
}
// 将当前编辑框中的内容另存为一个新的文件
protected boolean saveAsFile() throws IOException{
//新建一个txt文件
FileChooser createFileChooser = new FileChooser();
createFileChooser.setTitle("另存为");
createFileChooser.getExtensionFilters().addAll( //添加文件过滤器,默认只允许文本文件
new FileChooser.ExtensionFilter("文本文件","*.txt"),
new FileChooser.ExtensionFilter("全部文件","*.*")
);
Stage currentStage = (Stage)borderPane.getScene().getWindow();
File newFile = createFileChooser.showSaveDialog(currentStage);
if(newFile == null) //如果没有选择要将文件另存为,直接返回
return false;
saveFile(newFile);
currentFile = newFile;
System.out.println(newFile.getName());
return true;
}
}