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;
}
}