本次做这个记事本小程序,主要是为了学习Swing包中几个重要的类JFileChooser,JOptionPane,JMenu,当然也顺便巩固一下前面学的IO 流的知识。
一、简要介绍
1、JFileChooser
JFileChooser为用户选择文件提供了一种简单机制,可弹出针对用户主目录的文件选择器。编写记事本程序主要用到了以下几种方法:
a. showOpenDialog(Component parent) :弹出一个 "Open File" 文件选择器对话框,该文件选择器被弹下时返回一个int型数据,包括以下几种状态:
JFileChooser.CANCEL_OPTION 取消
JFileChooser.APPROVE_OPTION 确认
JFileChooser.ERROR_OPTION 如果发生错误或者该对话框已被解除
b. showSaveDialog(Component parent) : 弹出一个 "Save File" 文件选择器对话框,该文件选择器被弹下时返回一个int型数据,状态同上;
c. getSelectedFile() 返回选中的文件,返回值为File类型;
d. getName(File f) 返回文件名,返回值为String类型
2、JOptionPane
1.1、用途:JOptionPane主要用来弹出要求用户提供值或向其发出通知的标准对话框。
1.2、特点:所有对话框都是有模式的,在用户交互完成之前,每个 showXxxDialog 方法都一直阻塞调用者。
1.3、基本类型:
showConfirmDialog(): 确认对话框
showInputDialog(): 输入对话框
showMessageDialog():消息提示框
showOptionDialog(): 选择对话框
JOptionPane类方法众多,但基本上用起来都是对上述四种方法的单行调用。
1.4、参数介绍:
以下述方法为例:
showOptionDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue) |
参数 | 描述 | 类型 |
parentComponent | 对话框所在容器 | Component |
message | 消息 | Object |
title | 对话框标题 | String |
optionType | 选择按钮类型 |
|
messageType | 消息类型 |
|
icon | 自定义消息图标 | Icon |
options | 操作选项 | Object[] |
initialValue | 默认选择 | Object |
有关JOptionPane的具体用法可参考源代码或者下面这篇博客:
https://blog.csdn.net/tjk123456/article/details/77868034
3、JMenu
3.1、菜单分为下拉式菜单和弹出式菜单(JPopupMenu),其中下拉式菜单需要使用三个组件:JMenuBar(菜单栏)、JMenu(菜单)、JMenuItem(菜单项)。
3.2、JMenuBar:
a. JMenuBar表示一个水平的菜单栏,用来管理菜单,不参与用户交互操作;
b. 可通过调用setJMenuBar( )方法将JMenuBar设置在顶级窗口的顶部;
c. 可通过调用add( JMenu menu)方法添加菜单。
3.3、 JMenu
a. JMenu 表示一个菜单,用来整理菜单项;
b. 通过调用add( )方法可向菜单里面添加菜单项或者菜单、按钮等;
c. 通过调用addSeparator( )方法可向菜单栏里面添加分隔符。
3.4、 JMenuItem
a. JMenuIten表示菜单项,是菜单系统中最基本的组件;
b. JMenuIten继承AbstractButton类,因此可以把它看作一个按钮。
二、记事本功能实现
1、实现了记事本的文件打开和保存功能(主要功能);
2、更换了标题栏默认的java图标,改成记事本图标;
3、重写了窗体关闭事件方法,点击关闭按钮时,先做文件是否保存判断,若文件已保存则直接退出程序,否则弹出是否保存文件对话框;
4、记事本输入框采用滚动条加文本框设计;
5、文中多次运用JOptionPane和JFileChooser对话框,尽量做到与windows运行机制一样,包含大量操作提示信息;
6、实现了文件读取、写入、命名、路径选择等功能;
三、代码实现
package com.liao.notepad0822;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class MainUI extends JFrame {
private static final long serialVersionUID = -8533346717300013642L;
private JTextArea jta;
private JScrollPane jsp;
private static String name;
private JFileChooser jfc = new JFileChooser();
public static void main(String[] args) {
new MainUI().init();
}
// 初始化界面
public void init() {
setSize(800, 600);
setLocationRelativeTo(null);
// 设置关闭按钮动作不执行任何操作
setDefaultCloseOperation(0);
name = "新建文本文档.txt";
// 设置标志图案
ImageIcon ii = new ImageIcon("file\\1.png");
setIconImage(ii.getImage());
// 设置文件名
setTitle(name + " - 记事本");
// 添加菜单栏
addMenu();
// 添加文本框
jta = new JTextArea();
// 添加滚动条
jsp = new JScrollPane(jta);
jsp.setPreferredSize(new Dimension(780, 550));
add(jsp, BorderLayout.CENTER);
setVisible(true);// 设置窗口可见
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
if (showSaveDialog() != JOptionPane.CANCEL_OPTION)// 若不是取消按钮,关闭程序
setDefaultCloseOperation(3);
}
});
}
// 添加菜单栏
private void addMenu() {
// 添加菜单栏
JMenuBar jmb = new JMenuBar();
// 设置菜单栏位置在顶级窗口的顶部
setJMenuBar(jmb);
// 菜单栏菜单
JMenu jm_file = new JMenu("文件");
JMenu jm_edit = new JMenu("编辑");
jmb.add(jm_file);
jmb.add(jm_edit);
// 给文件菜单添加菜单项
JMenuItem item1 = new JMenuItem("打开");
JMenuItem item2 = new JMenuItem("保存");
jm_file.add(item1);
jm_file.add(item2);
// "打开"菜单项添加动作监听器
item1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 是否保存对原文件修改
if (showSaveDialog() == JOptionPane.CANCEL_OPTION) {// 取消按钮,则返回
return;
}
// 弹出一个 "Open File" 文件选择器对话框
int select = jfc.showOpenDialog(MainUI.this);
// 选择打开文件,则读写文件
if (select == JFileChooser.APPROVE_OPTION) {
jta.setText(readFile());// 写入文本框
jta.setCaretPosition(0);// 定位光标至行首
}
}
});
// “保存”菜单项添加动作监听器
item2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (jfc.getSelectedFile() == null) {
createFile();//调用创建文件方法
} else {
showSaveDialog();//调用文件是否保存方法
}
}
});
}
// 读取文件
private String readFile() {
// 声明缓冲字符流变量
BufferedReader br = null;
StringBuilder sb = null;
try {
br = new BufferedReader(new FileReader(jfc.getSelectedFile()));
sb = new StringBuilder();// 创建缓冲字符串
String str;
int count = 0;//控制添加换行符,与原文保持一致
while ((str = br.readLine()) != null) {
if (count == 0)
sb.append(str);
if (count++ != 0)
sb.append("\n" + str);// 添加换行
}
} catch (FileNotFoundException e1) {
// 弹出“文件未找到”对话框,返回null
JOptionPane.showMessageDialog(null, "未找到该文件!");
return null;
} catch (IOException e1) {
// 弹出“文件读取异常”对话框,返回null
JOptionPane.showMessageDialog(null, "文件读取异常");
return null;
} finally {
// 关闭字符流
if (br != null)
try {
br.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
name = jfc.getSelectedFile().getName();
setTitle(name + " - 记事本");//设置文件名
return sb.toString();
}
// 保存对话框
private int showSaveDialog() {
int select = 0;
// 判断文本框是否为空
if (!jta.getText().equals("")) {
// 判断文件是否为空
if (jfc.getSelectedFile() == null) {
select = JOptionPane.showConfirmDialog(MainUI.this, "是否保存修改?");
if (select == JOptionPane.YES_OPTION) {
createFile();//文件不存在,则创建文件
}
} else {
if (!isSaved()) {// 文件未保存
select = JOptionPane.showConfirmDialog(MainUI.this, "是否保存修改?");
if (select == JOptionPane.YES_OPTION) {
saveFile(jfc.getSelectedFile());
}
}
}
}
return select;// 返回选项
}
// 创建新文件
private void createFile() {
// String name = null;
File file = null;
// 选择保存或取消
if (jfc.showSaveDialog(MainUI.this) == JFileChooser.APPROVE_OPTION) {
file = jfc.getSelectedFile();// 获取选中的文件
} else {
return;
}
name = jfc.getName(file);// 获取输入的文件名
if (file.exists()) { // 若选择已有文件----询问是否要覆盖
int i = JOptionPane.showConfirmDialog(null, "该文件已存在,是否覆盖原文件", "确认", JOptionPane.YES_NO_OPTION);
if (i == JOptionPane.YES_OPTION) {
saveFile(file);
} else {
jfc.showSaveDialog(MainUI.this);// 重新选择
}
} else {//文件不存在,则直接保存
saveFile(file);
}
}
// 判断文件是否保存
private Boolean isSaved() {
// 比较内容
if (jta.getText().equals(readFile())) {
return true;
}
return false;
}
// 保存文件,文件不存在则创建新文件
private void saveFile(File file) {
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
bw.write(jta.getText());//写入文件
bw.flush();
} catch (FileNotFoundException e1) {
JOptionPane.showMessageDialog(MainUI.this, "文件保存出错" + e1.getMessage());
} catch (IOException e1) {
e1.printStackTrace();
} finally {
try {
if (bw != null)
bw.close();
} catch (IOException e1) {
}
}
}
}
四、小结
此次编写记事本程序,基本完成了预期目标,熟悉了解了菜单栏、标题栏、对话框、JFileChooser,JOptionPane以及IO流的相关知识。不过花费的时间略微超过了预期,主要是记事本这个程序看着简单,但实际上对逻辑上的要求比较高。主体功能实现后,后期的一些细节处理往往需要大量的时间去测试、整理及优化。
这里有个小细节需要注意一下,使用reaLline()读取数据时,要特别注意换行符的使用,保持跟原文结构一样。
好了,由于本次写记事本主要是为了熟悉Swing里面的几个类,所以记事本其它的一些功能并未去实现,各位有兴趣的话可以自己去尝试!