总结用Java写记事本的过程

笔者是个Java小白,这几天用Java写记事本的源码,不懂的地方就在博客上查找学习,文章中有一些代码就是从CSDN上学习或者摘抄的嘻嘻!在这里笔者对在写代码的过程中进行一些总结。另外也希望读者看完可以的话给出一些建议或者指出我的不足嘻嘻,我将不胜感激!!!

//导包,创建所需组件和添加组件
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import javax.security.auth.callback.ConfirmationCallback;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.BadLocationException;
import javax.swing.undo.UndoManager;
class noteBookDemo extends JFrame implements ActionListener {

	private Container c = getContentPane();
	private JMenuBar jmb = new JMenuBar();// 菜单栏
	private JPopupMenu pop = new JPopupMenu();// 弹出菜单
	
	// 父菜单
	private JMenu fileMenu = new JMenu("文件(F)");
	private JMenu editMenu = new JMenu("编辑(E)");
	private JMenu helpMenu = new JMenu("帮助(H)");
	private JMenu readMenu = new JMenu("查看(V)");
	private JMenu formatMenu = new JMenu("格式(O)");
	
	// 子菜单
	private JMenuItem newMenu = new JMenuItem("   新建(N)      ");
	private JMenuItem openMenu = new JMenuItem("   打开(O)      ");
	private JMenuItem saveMenu = new JMenuItem("   保存(S)      ");
	private JMenuItem saveAnotherMenu = new JMenuItem("   另存为(A)      ");
	private JMenuItem printMenu = new JMenuItem("   打印(P)      ");
	private JMenuItem setPageMenu = new JMenuItem("   页面设置(U)      ");
	private JMenuItem exitMenu = new JMenuItem("   退出(X)      ");
	private JMenuItem cancelMenu1 = new JMenuItem("   撤销(U)      "), cancelMenu2 = new JMenuItem("  撤销(U)   ");
	private JMenuItem shearMenu1 = new JMenuItem("   剪切(T)      "), shearMenu2 = new JMenuItem("  剪切(T)   ");
	private JMenuItem copyMenu1 = new JMenuItem("   复制(C)      "), copyMenu2 = new JMenuItem("  复制(C)   ");
	private JMenuItem pasteMenu1 = new JMenuItem("   粘贴(P)      "), pasteMenu2 = new JMenuItem("  粘贴(P)   ");
	private JMenuItem deleteMenu1 = new JMenuItem("   删除(L)         "), deleteMenu2 = new JMenuItem("  删除(L)   ");
	private JMenuItem foundMenu = new JMenuItem("   查找(F)      ");
	private JMenuItem foundNextMenu = new JMenuItem("   查找下一个(N)    ");
	private JMenuItem replaceMenu = new JMenuItem("   替换(R)      ");
	private JMenuItem allSectionMenu1 = new JMenuItem("   全选(A)      "), allSectionMenu2 = new JMenuItem("  全选(A)   ");
	private JMenuItem DateMenu = new JMenuItem("   时间/日期(D)     ");
	private JRadioButtonMenuItem autoMenu = new JRadioButtonMenuItem("   自动换行(W)      ", true);
	private JMenuItem sizeMenu = new JMenuItem("   字体(F)      ");
	private JRadioButtonMenuItem stateMenu = new JRadioButtonMenuItem("   状态栏(S)      ");
	private JMenuItem readHelpMenu = new JMenuItem("   查看帮助(H)      ");
	private JMenuItem aboutMenu = new JMenuItem("   关于记事本(A)      ");
	
	// 其他组件
	private JTextArea jta = new JTextArea("");
	private JScrollPane jsp = new JScrollPane(jta);
	private FileDialog _Open = new FileDialog(this, "打开文件", FileDialog.LOAD);
	private FileDialog _Save = new FileDialog(this, "保存文件", FileDialog.SAVE)
	private UndoManager undom = new UndoManager();
	private JLabel jla = new JLabel("");
	
	// 构造方法
	noteBookDemo() {
		super("记事本");
		setJMenuBar(jmb);
		// 向文件菜单添加子菜单,设置键盘标识符,快捷键,添加子菜单监听器
		fileMenu.add(newMenu);
		newMenu.setMnemonic('N');
		newMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
		newMenu.addActionListener(this);
		fileMenu.add(openMenu);
		openMenu.setMnemonic('O');
		openMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
		openMenu.addActionListener(this);
		fileMenu.add(saveMenu);
		saveMenu.setMnemonic('S');
		saveMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
		saveMenu.addActionListener(this);
		fileMenu.add(saveAnotherMenu);
		saveAnotherMenu.setMnemonic('A');
		saveAnotherMenu.addActionListener(this);
		fileMenu.addSeparator();
		fileMenu.add(setPageMenu);
		setPageMenu.setMnemonic('U');
		setPageMenu.addActionListener(this);
		fileMenu.add(printMenu);
		printMenu.setMnemonic('P');
		printMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK));
		printMenu.addActionListener(this);
		fileMenu.addSeparator();
		fileMenu.add(exitMenu);
		exitMenu.setMnemonic('X');
		exitMenu.addActionListener(this);
		fileMenu.setMnemonic(KeyEvent.VK_F);
		// 向编辑菜单添加子菜单,设置键盘标识符,快捷键,添加子菜单监听器(包括弹出菜单)
		editMenu.add(cancelMenu1);
		cancelMenu1.setMnemonic('U');
		cancelMenu1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK));
		cancelMenu1.addActionListener(this);
		cancelMenu2.addActionListener(this);
		editMenu.addSeparator();
		editMenu.add(shearMenu1);
		shearMenu1.setMnemonic('T');
		shearMenu1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK));
		shearMenu1.addActionListener(this);
		shearMenu2.addActionListener(this);
		editMenu.add(copyMenu1);
		copyMenu1.setMnemonic('C');
		copyMenu1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
		copyMenu1.addActionListener(this);
		copyMenu2.addActionListener(this);
		editMenu.add(pasteMenu1);
		pasteMenu1.setMnemonic('P');
		pasteMenu1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK));
		pasteMenu1.addActionListener(this);
		pasteMenu2.addActionListener(this);
		editMenu.add(deleteMenu1);
		deleteMenu1.setMnemonic('L');
		deleteMenu1.setAccelerator(KeyStroke.getKeyStroke("Delete"));
		deleteMenu2.setAccelerator(KeyStroke.getKeyStroke("Backspace"));
		deleteMenu1.addActionListener(this);
		deleteMenu2.addActionListener(this);
		editMenu.addSeparator();
		editMenu.add(foundMenu);
		foundMenu.setMnemonic('F');
		foundMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, ActionEvent.CTRL_MASK));
		foundMenu.addActionListener(this);
		editMenu.add(foundNextMenu);
		foundNextMenu.setMnemonic('N');
		foundNextMenu.setAccelerator(KeyStroke.getKeyStroke("F3"));
		foundNextMenu.addActionListener(this);
		editMenu.add(replaceMenu);
		replaceMenu.setMnemonic('R');
		replaceMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, ActionEvent.CTRL_MASK));
		replaceMenu.addActionListener(this);
		editMenu.addSeparator();
		editMenu.add(allSectionMenu1);
		allSectionMenu1.setMnemonic('A');
		allSectionMenu1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.CTRL_MASK));
		allSectionMenu1.addActionListener(this);
		allSectionMenu2.addActionListener(this);
		editMenu.add(DateMenu);
		DateMenu.setMnemonic('D');
		DateMenu.setAccelerator(KeyStroke.getKeyStroke("F5"));
		DateMenu.addActionListener(this);
		editMenu.setMnemonic(KeyEvent.VK_E);
		// 向格式菜单添加子菜单,设置键盘标识符,快捷键,添加子菜单监听器
		formatMenu.add(autoMenu);
		autoMenu.setMnemonic('W');
		autoMenu.addActionListener(this);
		formatMenu.add(sizeMenu);
		sizeMenu.setMnemonic('F');
		sizeMenu.addActionListener(this);
		formatMenu.setMnemonic(KeyEvent.VK_O);
		// 向查看菜单添加子菜单,设置键盘标识符,快捷键,添加子菜单监听器
		readMenu.add(stateMenu);
		stateMenu.setMnemonic('S');
		stateMenu.addActionListener(this);
		readMenu.setMnemonic(KeyEvent.VK_V);
		// 向帮助菜单添加子菜单,设置键盘标识符,快捷键,添加子菜单监听器
		helpMenu.add(readHelpMenu);
		readHelpMenu.setMnemonic('H');
		readHelpMenu.addActionListener(this);
		helpMenu.addSeparator();
		helpMenu.add(aboutMenu);
		aboutMenu.setMnemonic('A');
		aboutMenu.addActionListener(this);
		helpMenu.setMnemonic(KeyEvent.VK_H);
		// 添加菜单和组件
		jmb.add(fileMenu);
		jmb.add(editMenu);
		jmb.add(formatMenu);
		jmb.add(readMenu);
		jmb.add(helpMenu);
		c.add(jsp, BorderLayout.CENTER);
		c.add(jla, BorderLayout.SOUTH);
		// 设置文本域字体和自动换行
		jta.setFont(new Font("宋体", 0, 25));
		jta.setLineWrap(true);
		jta.setWrapStyleWord(true);// 单词格式
		// 设置菜单和子菜单的字体
		fileMenu.setFont(new Font("宋体", 0, 20));
		editMenu.setFont(new Font("宋体", 0, 20));
		formatMenu.setFont(new Font("宋体", 0, 20));
		readMenu.setFont(new Font("宋体", 0, 20));
		helpMenu.setFont(new Font("宋体", 0, 20));

		newMenu.setFont(new Font("宋体", 0, 20));
		openMenu.setFont(new Font("宋体", 0, 20));
		saveMenu.setFont(new Font("宋体", 0, 20));
		saveAnotherMenu.setFont(new Font("宋体", 0, 20));
		setPageMenu.setFont(new Font("宋体", 0, 20));
		printMenu.setFont(new Font("宋体", 0, 20));
		exitMenu.setFont(new Font("宋体", 0, 20));

		cancelMenu1.setFont(new Font("宋体", 0, 20));
		cancelMenu2.setFont(new Font("宋体", 0, 20));
		shearMenu1.setFont(new Font("宋体", 0, 20));
		shearMenu2.setFont(new Font("宋体", 0, 20));
		copyMenu1.setFont(new Font("宋体", 0, 20));
		copyMenu2.setFont(new Font("宋体", 0, 20));
		pasteMenu1.setFont(new Font("宋体", 0, 20));
		pasteMenu2.setFont(new Font("宋体", 0, 20));
		deleteMenu1.setFont(new Font("宋体", 0, 20));
		deleteMenu2.setFont(new Font("宋体", 0, 20));
		foundMenu.setFont(new Font("宋体", 0, 20));
		foundNextMenu.setFont(new Font("宋体", 0, 20));
		replaceMenu.setFont(new Font("宋体", 0, 20));
		allSectionMenu1.setFont(new Font("宋体", 0, 20));
		allSectionMenu2.setFont(new Font("宋体", 0, 20));
		DateMenu.setFont(new Font("宋体", 0, 20));

		autoMenu.setFont(new Font("宋体", 0, 20));
		sizeMenu.setFont(new Font("宋体", 0, 20));

		stateMenu.setFont(new Font("宋体", 0, 20));
		readHelpMenu.setFont(new Font("宋体", 0, 20));
		aboutMenu.setFont(new Font("宋体", 0, 20));
		jla.setFont(new Font("宋体", 0, 30));
		// 添加弹出菜单选项
		pop.add(cancelMenu2);
		pop.add(shearMenu2);
		pop.add(copyMenu2);
		pop.add(pasteMenu2);
		pop.add(deleteMenu2);
		pop.add(allSectionMenu2);
		jta.requestFocus();
		// 设置窗口属性以及编辑器菜单的可用性
		checkMenuItemEnabled();
		foundMenu.setEnabled(false);
		foundNextMenu.setEnabled(false);
		cancelMenu1.setEnabled(false);
		cancelMenu2.setEnabled(false);
		jla.setVisible(false);
		setBounds(200, 200, 1114, 744);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);"

总结:
1.FileDialog 类显示一个对话框窗口,用户可以从中选择文件。构造方法如下:
FileDialog(Frame parent, String title, int mode)
创建一个具有指定标题的文件对话框窗口,用于打开或保存文件。其中mode包括FileDialog.LOAD和FileDialog.SAVE
2.UndoManager与撤销操作有关(这是在CSDN上学到借鉴的代码,详细内容可以去看看API)
3.setMnemonic()方法是菜单的键盘标识符
setAccelerator(KeyStroke keyStroke)
eg:Ctrl+C的快捷键 copyMenu1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
setLineWrap(true/false) 设置是否自动换行
setWrapStyleWord(true/false) 设置单词格式
addSeparator() 在菜单栏添加分隔线

添加文本框的监听器

 // 通过内部类添加弹出菜单监听器并实现文本域的鼠标事件
		jta.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseReleased(MouseEvent e) {
				if (e.getModifiers() == InputEvent.BUTTON3_MASK)
					pop.show(jta, e.getX(), e.getY());//弹出菜单弹出的位置
				// 设置编辑中一些功能的可用性
				checkMenuItemEnabled();
				jta.requestFocus();
			}// end mouseReleased
		}// end MouseAdapter
		);// end addMouseListener
			// 通过内部类对文本内容添加监听器
		jta.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void changedUpdate(DocumentEvent e) {
				cancelMenu1.setEnabled(true);
				cancelMenu2.setEnabled(true);
			}// end changedUpdate

			@Override
			public void insertUpdate(DocumentEvent e) {
				cancelMenu1.setEnabled(true);
				cancelMenu2.setEnabled(true);
				// 当向文本输入内容即文本不为空,查找功能可用
				foundMenu.setEnabled(true);
				foundNextMenu.setEnabled(true);
			}// end insertUpdate

			@Override
			public void removeUpdate(DocumentEvent e) {
				cancelMenu1.setEnabled(true);
				cancelMenu2.setEnabled(true);
				// 当删除(所选)文本内容时,将编辑中一些功能禁用
				shearMenu1.setEnabled(false);
				shearMenu2.setEnabled(false);
				copyMenu1.setEnabled(false);
				copyMenu2.setEnabled(false);
				deleteMenu1.setEnabled(false);
				deleteMenu2.setEnabled(false);
				// 当文本域无内容时,将查找功能禁用
				if (jta.getText().length() == 0) {
					foundMenu.setEnabled(false);
					foundNextMenu.setEnabled(false);
				} // end if
			}// end removeUpdate
		}// end DocumentListener
		);// end addDocumentListener
			// 通过内部类对文本内容添加监听器(撤销功能)
		jta.getDocument().addUndoableEditListener(new UndoableEditListener() {
			@Override
			public void undoableEditHappened(UndoableEditEvent e) {
				undom.addEdit(e.getEdit());
			}// end undoableEditHappened
		}// end UndoableEditListener
		);// end addUndoableEditListener

总结:
1.getDocument() 获取与编辑器关联的模型(对文本域的内容进行监控)
2.setEnabled(true/false) 设置组件的可操作性(例如菜单中的复制操作)

// 通过内部类对窗口添加监听器(右上角关闭按钮)
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				// 如果是新文件,即标题任为记事本,则执行exit()方法
				if (getTitle() == "记事本")
					exit();
				// 如果不是新文件,即有标题为包含".txt"的文件名,则进行判断文本域内容是否与原文件相同
				// (注意:末尾存在换行问题)(这里有一点小bug)
				else {
					try {
						// 定义3个String对象并获得文件目录
						String s = _Open.getDirectory(), str1 = "", line = "";
						if (_Open.getDirectory() == null)
							s = _Save.getDirectory();
						// 创建指定文件和读取文件流的对象
						File f = new File(s + getTitle());
						BufferedReader r = new BufferedReader(new FileReader(f));
						// 一行一行的读取文件
						while ((line = r.readLine()) != null)
							str1 += line + "\n";
						// 处理末尾换行问题
						if (jta.getText().length() > 0) {
							if (jta.getText().charAt(jta.getText().length() - 1) != '\n')
								str1 = str1.substring(0, str1.length() - 1);
						}
						// 判断两者是否相等,不等则执行exit()方法,相等则直接关闭窗口
						if (!str1.equals(jta.getText()))
							exit();
						else
							System.exit(0);
						r.close();
					} // end try
					catch (FileNotFoundException em) {
						em.printStackTrace();
					} // end catch
					catch (IOException ee) {
						ee.printStackTrace();
					} // end catch
				} // end else
			}// end windowClosing
		}// end WindowAdapter
		);// end addWindowListener
	}// end 构造方法

总结:WindowAdapter类:接收窗口事件的抽象适配器类。此类中的方法为空。此类存在的目的是方便创建侦听器对象。

//实现接口中的方法
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().contains("新建"))
			news();
		if (e.getActionCommand().contains("打开"))
			open();
		if (e.getActionCommand().contains("保存"))
			save();
		if (e.getActionCommand().contains("另存为"))
			saveAnother();
		if (e.getActionCommand().contains("页面设置"))
			setPage();
		if (e.getActionCommand().contains("打印"))
			print();
		if (e.getActionCommand().contains("退出"))
			exit();
		if (e.getActionCommand().contains("撤销"))
			cancel();
		if (e.getActionCommand().contains("剪切"))
			shear();
		if (e.getActionCommand().contains("复制"))
			copy();
		if (e.getActionCommand().contains("粘贴"))
			paste();
		if (e.getActionCommand().contains("删除"))
			delete();
		if (e.getActionCommand().equals("   查找(F)      "))
			found();
		if (e.getActionCommand().contains("替换"))
			replace();
		if (e.getActionCommand().contains("全选"))
			allSelection();
		if (e.getActionCommand().contains("日期"))
			date();
		if (e.getActionCommand().contains("自动换行"))
			auto();
		if (e.getActionCommand().contains("字体"))
			font();
		if (e.getActionCommand().contains("状态栏"))
			state();
		if (e.getActionCommand().contains("查看帮助"))
			readHelp();
		if (e.getActionCommand().contains("关于记事本"))
			about();
	}
	// 设置编辑器的功能可用性
	public void checkMenuItemEnabled() {
		String selectText = jta.getSelectedText();
		// 文本域没有内容被选中时一些菜单功能不可用
		if (selectText == null) {
			shearMenu1.setEnabled(false);
			shearMenu2.setEnabled(false);
			copyMenu1.setEnabled(false);
			copyMenu2.setEnabled(false);
			deleteMenu1.setEnabled(false);
			deleteMenu2.setEnabled(false);
		} // end if
			// 文本域有内容被选中时菜单功能可用
		else {
			shearMenu1.setEnabled(true);
			shearMenu2.setEnabled(true);
			copyMenu1.setEnabled(true);
			copyMenu2.setEnabled(true);
			deleteMenu1.setEnabled(true);
			deleteMenu2.setEnabled(true);
		} // end else
	}// end checkMenuItemEnabled

新建功能
思路:判断文本域是否有内容,有内容在新建之前弹出是否保存的窗口后再进行新建,无内容则直接新建

private void news() {
		// 如果文本域有内容执行以下if语句中代码,否则直接执行新建功能
		if (!jta.getText().equals("")) {
			// 弹出提示窗口
			int result = JOptionPane.showConfirmDialog(this, "是否保存", "记事本", JOptionPane.YES_NO_CANCEL_OPTION);
			// 执行是按钮
			if (result == JOptionPane.YES_OPTION) {
				// 如果窗口标题为"记事本"即文件尚未存在,则执行saveAnother()方法进行另存为功能
				if (getTitle() == "记事本")
					saveAnother();
				// 如果窗口标题为包含“.txt”的文件名即文件已存在,则执行save()方法进行保存功能
				else
					save();
				// 保存后将文本域内容清空并将标题改为"记事本",完成新建功能
				jta.setText("");
				setTitle("记事本");
			} // end if
				// 执行否按钮,即不进行保存工作,直接将文本域内容清空并将窗口标题改为"记事本"完成新建功能
			if (result == JOptionPane.NO_OPTION) {
				jta.setText("");
				setTitle("记事本");
			} // end if
		} // end if
	}// end news()

总结:
JOptionPane 有助于方便地弹出要求用户提供值或向其发出通知的标准对话框。其中的一些方法如下:

方法名 描述
showConfirmDialog 询问一个确认问题,如 yes/no/cancel
showInputDialog 提示要求某些输入
showMessageDialog 告知用户某事已发生
showOptionDialog 上述三项的大统一 (Grand Unification)

messageType
定义 message 的样式。外观管理器根据此值对对话框进行不同地布置,并且通常提供默认图标。可能的值为:
ERROR_MESSAGE ;INFORMATION_MESSAGE; WARNING_MESSAGE;QUESTION_MESSAGE ;
PLAIN_MESSAGE
optionType
定义在对话框的底部显示的选项按钮的集合:
DEFAULT_OPTION ;YES_NO_OPTION ;
YES_NO_CANCEL_OPTION ;OK_CANCEL_OPTION

例子:JOptionPane.showConfirmDialog(this, “是否保存”, “记事本”, JOptionPane.YES_NO_CANCEL_OPTION);
例
打开功能
思路:打开前先弹出是否保存的窗口判断是否对当前内容进行保存,然后在弹出打开窗口选择目标文件打开,若未选择目标文件(关闭选择文件的窗口),文本域的内容不变化,仍为执行打开前的内容

// 打开功能的实现方法
	private void open() {
		String str = "";
		// 打开操作前判断是否进行保存工作
		// if (getTitle() != "记事本" || jta.getText() != null) {
		int result = JOptionPane.showConfirmDialog(this, "是否保存", "记事本", JOptionPane.YES_NO_CANCEL_OPTION);
		if (result == JOptionPane.YES_OPTION)
			save();
		if (result == JOptionPane.YES_OPTION || result == JOptionPane.NO_OPTION) {
			_Open.setVisible(true);// 将打开窗口可视化
			try {
				// 获得文件名并创建流
				File f = new File(_Open.getDirectory() + _Open.getFile());
				BufferedReader r = new BufferedReader(new FileReader(f));
				if (_Open.getFile() != null) {
					jta.setText("");
					// 读取文件内容并写入文本域中
					while ((str = r.readLine()) != null)
						jta.append(str + "\n");
					// 将窗口标题设置为打开文件的文件名
					// if (_Open.getFile() != null)
					this.setTitle(_Open.getFile());
				}
				r.close();
			} // end try
			catch (FileNotFoundException e) {
				// 所指定的打开文件如果不存在则弹出错误窗口
				JOptionPane.showMessageDialog(null, "所选文件不存在或未选择文件", "错误", JOptionPane.ERROR_MESSAGE);
			} // end catch
			catch (IOException e) {
				e.printStackTrace();
			} // end catch
		} // end if
	}// end open

保存功能
思路:若文件不存在,则弹出另存为窗口,若文件已存在,则只弹出是否保存的窗口

// 保存功能的实现方法
	private void save() {
		// 如果窗口标题为 "记事本"即不是文件名,直接执行saveAnother()方法
		if (this.getTitle() == "记事本")
			saveAnother();
		// 否则,执行保存功能
		else {
			try {
				// 创建指定文件和输出流的对象
				File f = new File(_Open.getDirectory() + this.getTitle());
				BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
				// 将文本域的内容转换为字符并写入指定文件中
				char[] str = jta.getText().toCharArray();
				for (int i = 0; i < str.length; i++) {
					if (str[i] != '\n')
						w.write(str[i]);
					else
						w.newLine();
				} // end for
				w.close();
			} // end try
			catch (IOException e) {
				e.printStackTrace();
			} // end catch
		} // end else
	}// end save

另存为功能
思路:弹出保存窗口,选择保存路径及文件名

// 另存为功能的方法
	private void saveAnother() {
		// 将另存为弹出的界面可视化
		_Save.setVisible(true);
		try {
			// 创建指定文件和写文件流的对象
			File f = new File(_Save.getDirectory() + _Save.getFile());
			BufferedWriter w = new BufferedWriter(new FileWriter(f));
			// 将文本域的内容转换为字符并写入指定文件中
			char[] str = jta.getText().toCharArray();
			for (int i = 0; i < str.length; i++) {
				if (str[i] != '\n')
					w.write(str[i]);
				else
					w.newLine();
			} // end for
				// 实现另存为功能后将窗口标题改为所存的文件名,未实现则只关闭提示窗口不关闭主窗口
			if (_Save.getFile() != null)
				this.setTitle(_Save.getFile());
			setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
			w.close();
		} // end try
		catch (IOException e) {
			e.printStackTrace();
		} // end catch
	}// end saveAnother
	
	// 打印的方法
	private void print() {
		JOptionPane.showMessageDialog(null, "对不起,此菜单功能尚未实现!", "打印", JOptionPane.YES_NO_CANCEL_OPTION);
	}
	
	// 页面设置的方法
	private void setPage() {
		JOptionPane.showMessageDialog(null, "对不起,此菜单功能尚未实现!", "页面设置", JOptionPane.YES_NO_CANCEL_OPTION);
	}

总结:设置用户在此窗体上发起 “close” 时默认执行的操作。必须指定以下选项之一:
DO_NOTHING_ON_CLOSE(在 WindowConstants 中定义):不执行任何操作;要求程序在已注册的 WindowListener 对象的 windowClosing 方法中处理该操作。
HIDE_ON_CLOSE(在 WindowConstants 中定义):调用任意已注册的 WindowListener 对象后自动隐藏该窗体。
DISPOSE_ON_CLOSE(在 WindowConstants 中定义):调用任意已注册 WindowListener 的对象后自动隐藏并释放该窗体。
EXIT_ON_CLOSE(在 JFrame 中定义):使用 System exit 方法退出应用程序。仅在应用程序中使用。
默认情况下,该值被设置为 HIDE_ON_CLOSE。更改此属性的值将导致激发属性更改事件,其属性名称为 “defaultCloseOperation”。

关闭功能
思路:弹出是否保存窗口选择后关闭窗口

// 关闭的方法
	private void exit() {
		int result = JOptionPane.showConfirmDialog(this, "是否保存", "记事本", JOptionPane.YES_NO_CANCEL_OPTION);
		// 执行是按钮
		if (result == JOptionPane.YES_OPTION) {
			// 判断标题是否为包含“.txt”的文件名,是则执行save()方法并关闭窗口
			if (this.getTitle().contains(".txt")) {
				save();
				System.exit(0);
			}
			// 标题为“记事本”即为非文件名,执行saveAnother()方法,另存为动作完毕后,直接关闭窗口
			else {
				saveAnother();
				if (getTitle() != "记事本")
					System.exit(0);
			} // end else
		} // end if
			// 执行否按钮,直接关闭窗口
		if (result == JOptionPane.NO_OPTION)
			System.exit(1);
		// 设置提示窗口的属性,即未操作则只关闭提示窗口而不关闭主窗口
		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
	}// end exit

编辑器的撤销、剪切、复制、粘贴、删除、全选功能

	// 撤销的方法(有bug)
	private void cancel() {
		if (undom.canUndo()) // 撤销
			undom.undo();
		else
			undom.redo();// 恢复
	}// end cancel

	// 剪贴的方法
	private void shear() {
		copy();// 复制所选段
		// 标记开始结束位置
		int start = jta.getSelectionStart(), end = jta.getSelectionEnd();
		jta.replaceRange("", start, end);// 删除所选段
	}// end shear
	
	// 复制的方法
	private void copy() {
		jta.requestFocus();
		String temp = jta.getSelectedText();// 拖动选取文本
		StringSelection text = new StringSelection(temp);// 把获取内容复制到连续字符器
		getToolkit().getSystemClipboard().setContents(text, null);// 把内容放在剪贴板
	}// end copy

	// 粘贴的方法
	private void paste() {
		// Transferable接口,把剪贴板内容转换为数据
		Transferable contents = getToolkit().getSystemClipboard().getContents(this);
		// DataFlavor类判断是否能把剪贴板的内容转换为所需数据的类型
		DataFlavor flavor = DataFlavor.stringFlavor;
		// 如果能转换
		if (contents.isDataFlavorSupported(flavor)) {
			String str;
			try {
				// 开始转换
				str = (String) contents.getTransferData(flavor);
				// 鼠标已选中内容
				if (jta.getSelectedText() != null) {
					// 定义被选中内容的开始和末尾位置
					int start = jta.getSelectionStart(), end = jta.getSelectionEnd();
					jta.replaceRange(str, start, end);// 把选中的内容替换为剪贴板的内容
				} // end if
					// 鼠标未选中内容
				else {
					// 获得鼠标在文本域的位置并插入剪贴板的内容
					int mouse = jta.getCaretPosition();
					jta.insert(str, mouse);
				} // end else
			} // end try
			catch (UnsupportedFlavorException e) {
				e.printStackTrace();
			} // end catch
			catch (IOException e) {
				e.printStackTrace();
			} // end catch
			catch (IllegalArgumentException e) {
				e.printStackTrace();
			} // end catch
		} // end if
	}// end paste
	
	// 删除的方法
	private void delete() {
		jta.replaceSelection("");
	}
	
	// 全选的方法
	private void allSelection() {
		jta.selectAll();
	}// end allSelection

总结:
1./标记开始结束位置
int start = jta.getSelectionStart(), end = jta.getSelectionEnd();
jta.replaceRange(str, start, end); 将选中的内容替换为str
2.requestFocus() 方法用于请求此 Component 获取输入焦点。
getCaretPosition()方法用于获得鼠标在文本域的位置
setCaretPosition()方法用于设置鼠标在文本域的位置
insert(str, mouse)方法用于在光标位置插入字符串str
3.粘贴方法的实现
StringSelection(String data) 此构造方法用于创建能传输指定 String 的 Transferable。
getToolkit().getSystemClipboard().setContents(text, null); 把内容放在剪贴板 Transferable接口,把剪贴板内容转换为数据
Transferable contents = getToolkit().getSystemClipboard().getContents(this);
DataFlavor类判断是否能把剪贴板的内容转换为所需数据的类型
DataFlavor flavor = DataFlavor.stringFlavor;
判断是否能转换 :contents.isDataFlavorSupported(flavor)
能转换则转为字符串准备进行粘贴工作 (String)contents.getTransferData(flavor)

查找功能
思路:创建查找窗口,并给其组件添加监听器(注意是否区分大小写,查找的方向)。窗口的截图和代码如下
在这里插入图片描述

	// 查找的方法
	private void found() {
		// 创建查找窗口所需组件
		JDialog findDialog = new JDialog(this, "查找", false);
		Container con = findDialog.getContentPane();
		JLabel findLabel = new JLabel("查找内容(N)");
		JTextField findText = new JTextField((15));
		JButton findNextButton = new JButton("查找下一个");
		JButton cancelButton = new JButton("取消");
		JRadioButton upButton = new JRadioButton("向上(U)");
		JRadioButton downButton = new JRadioButton("向下(D)");
		ButtonGroup bg = new ButtonGroup();
		JCheckBox findCheckButton = new JCheckBox("区分大小写");
		GridLayout g = new GridLayout(2, 1);
		g.setVgap(10);// 设置网格布局器的垂直间距
		bg.add(upButton);
		bg.add(downButton);
		JPanel p1 = new JPanel();
		JPanel p2 = new JPanel();
		JPanel p3 = new JPanel();
		JPanel p4 = new JPanel();
		JPanel p5 = new JPanel();
		p3.setBorder(BorderFactory.createTitledBorder("方向"));
		// 设置布局管理器
		con.setLayout(new FlowLayout());
		p4.setLayout(new BorderLayout());
		p5.setLayout(g);
		// 添加组件
		p1.add(findLabel);
		p1.add(findText);
		p2.add(findCheckButton);
		p2.add(p3);
		p3.add(upButton);
		p3.add(downButton);
		p4.add(p1, BorderLayout.NORTH);
		p4.add(p2, BorderLayout.CENTER);
		p5.add(findNextButton);
		p5.add(cancelButton);
		con.add(p4, BorderLayout.CENTER);
		con.add(p5, BorderLayout.EAST);
		// 设置查找窗口属性
		downButton.setSelected(true);// 默认向下查找
		findNextButton.setEnabled(false);
		findDialog.setBounds(230, 280, 410, 150);
		findDialog.setResizable(false);
		findDialog.setVisible(true);
		// 添加取消按钮的监听器(内部类的形式)
		cancelButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				findDialog.dispose();
			}// end actionPerformed
		}// end ActionListener
		);// end addActionListener
			// 添加查找文本框内容的监听器(内部类的形式)
		findText.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void changedUpdate(DocumentEvent e) {
			}

			@Override
			// 查找文本框内容不为空时查找按钮可用
			public void insertUpdate(DocumentEvent e) {
				findNextButton.setEnabled(true);
			}// end insertUpdate

			@Override
			// 查找文本框内容为空时查找按钮不可用
			public void removeUpdate(DocumentEvent e) {
				if (findText.getText().length() == 0)
					findNextButton.setEnabled(false);
			}// end removeUpdate
		}// end ActionListener
		);// end addActionListener
			// 添加查找下一个按钮的监听器(内部类的形式)
		findNextButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int k = 0;
				String str1, str2, str3, str4, strA, strB;
				str1 = jta.getText();
				str2 = findText.getText();
				str3 = str1.toUpperCase();
				str4 = str2.toUpperCase();
				// 区分大小写
				if (findCheckButton.isSelected()) {
					strA = str1;
					strB = str2;
				}
				// 不区分大小写
				else {
					strA = str3;
					strB = str4;
				}
				// 向上查找的方式
				if (upButton.isSelected()) {
					// 文本未选中内容
					if (jta.getSelectedText() == null)
						k = strA.lastIndexOf(strB, jta.getCaretPosition());
					// 文本已选中内容
					else
						k = strA.lastIndexOf(strB, jta.getCaretPosition() - strB.length() - 1);
					// 查找未结束,继续向上查找
					if (k != -1) {
						jta.setCaretPosition(k);
						jta.select(k, k + strB.length());
					}
					// 查找结束,弹出错误窗口
					else
						JOptionPane.showMessageDialog(null, "找不到" + " “ " + findText.getText() + " ” ", "查找",
								JOptionPane.INFORMATION_MESSAGE);
				} // end 向上查找
					// 向下查找的方式
				else if (downButton.isSelected()) {
					// 文本未选中内容
					if (jta.getSelectedText() == null) {
						k = strA.indexOf(strB, jta.getCaretPosition());
					}
					// 文本已选中内容
					else
						k = strA.indexOf(strB, jta.getCaretPosition() - strB.length() + 1);
					// 查找未结束,继续向下查找
					if (k != -1) {
						jta.setCaretPosition(k);
						jta.select(k, k + strB.length());
					}
					// 查找结束,弹出错误窗口
					else
						JOptionPane.showMessageDialog(null, "找不到" + " “ " + findText.getText() + " ” ", "查找",
								JOptionPane.INFORMATION_MESSAGE);
				} // end 向下查找
			}// end actionPerformed
		}// end ActionListener
		);// end addActionListener
			// 添加菜单中查找下一个菜单的监听器(有bug)
		foundNextMenu.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int k = 0;
				String str1, str2, str3, str4, strA, strB;
				str1 = jta.getText();
				str2 = findText.getText();
				str3 = str1.toUpperCase();
				str4 = str2.toUpperCase();
				// 区分大小写
				if (findCheckButton.isSelected()) {
					strA = str1;
					strB = str2;
				}
				// 不区分大小写
				else {
					strA = str3;
					strB = str4;
				}
				// 向上查找的方式
				if (upButton.isSelected()) {
					// 文本未选中内容
					if (jta.getSelectedText() == null)
						k = strA.lastIndexOf(strB, jta.getCaretPosition());
					// 文本已选中内容
					else
						k = strA.lastIndexOf(strB, jta.getCaretPosition() - strB.length() - 1);
					// 查找未结束,继续向上查找
					if (k != -1) {
						jta.setCaretPosition(k);
						jta.select(k, k + strB.length());
					}
					// 查找结束,弹出错误窗口
					else
						JOptionPane.showMessageDialog(null, "找不到" + " “ " + findText.getText() + " ” ", "查找",
								JOptionPane.INFORMATION_MESSAGE);
				} // end 向上查找
					// 向下查找的方式
				else if (downButton.isSelected()) {
					// 文本未选中内容
					if (jta.getSelectedText() == null) {
						k = strA.indexOf(strB, jta.getCaretPosition());
					}
					// 文本已选中内容
					else
						k = strA.indexOf(strB, jta.getCaretPosition() - strB.length() + 1);
					// 查找未结束,继续向下查找
					if (k != -1) {
						jta.setCaretPosition(k);
						jta.select(k, k + strB.length());
					}
					// 查找结束,弹出错误窗口
					else
						JOptionPane.showMessageDialog(null, "找不到" + " “ " + findText.getText() + " ” ", "查找",
								JOptionPane.INFORMATION_MESSAGE);
				} // end 向下查找
			}// end actionPerformed
		}// end ActionListener
		);// end addActionListener
	}// end found

总结:
1.JDialog(Dialog owner, String title, boolean modal)
此构造方法用于创建一个具有指定标题、模式和指定所有者 Dialog 的自定义对话框。参数如下:
owner - 显示该对话框的所有者 Dialog;如果此对话框没有所有者,则为 null
title - 该对话框的标题栏中所显示的 String
modal - 指定对话框在显示时是否阻塞用户向其他顶层窗口输入。如果为 true,则模式类型属性被设置为 DEFAULT_MODALITY_TYPE;否则对话框是无模式的
2.网络布局管理器中setHgap(int hgap) 方法用于将组件之间的水平间距设置为指定值。setVgap(int vgap) 方法用于将组件之间的垂直间距设置为指定值。
3.setSelected(true/false)方法用于默认选中组件
dispose()方法简单地理解可理解为关闭窗口。
select(int start,int end) 选中内容范围
setBorder(BorderFactory.createTitledBorder(String str))方法用于向现有边框添加一个标题,使其具有默认的位置(位于顶线上)、默认的调整 (leading),以及默认的字体和文本颜色。(BorderFactory类具体构造方法可参考API)

替换功能
思路:与查找功能基本一致,通过查找功能将查找出的内容替换。窗口截图和代码如下。
在这里插入图片描述

// 替换的方法
	private void replace() {
		// 定义替换提示窗口所需组件
		JDialog replaceDialog = new JDialog(this, "替换", false);
		Container replaceCon = replaceDialog.getContentPane();
		JLabel findContentLabel = new JLabel("查找内容(N):");
		JLabel replaceLabel = new JLabel("替换为(P):");
		JTextField findField = new JTextField(15);
		JTextField replaceField = new JTextField(15);
		JButton findNextButton = new JButton("查找下一个(F)");
		JButton replaceButton = new JButton("替换(R)");
		JButton replaceAllButton = new JButton("全部替换(A)");
		JButton cancelButton = new JButton("取消");
		JCheckBox checkButton = new JCheckBox("区分大小写");
		JRadioButton upButton = new JRadioButton("向上(U)");
		JRadioButton downButton = new JRadioButton("向下(D)");
		ButtonGroup bg = new ButtonGroup();
		bg.add(upButton);
		bg.add(downButton);
		GridLayout g = new GridLayout(4, 1);
		JPanel p1 = new JPanel();
		JPanel p2 = new JPanel();
		JPanel p3 = new JPanel();
		JPanel p4 = new JPanel();
		JPanel p5 = new JPanel();
		JPanel p6 = new JPanel();
		JPanel p7 = new JPanel();
		p2.setBorder(BorderFactory.createTitledBorder("方向"));
		// 设置布局管理器
		p1.setLayout(new BorderLayout());
		p4.setLayout(new BorderLayout());
		p5.setLayout(g);
		g.setVgap(5);// 设置网格布局管理器垂直间距
		p6.setLayout(new BorderLayout());
		p7.setLayout(new BorderLayout());
		replaceCon.setLayout(new FlowLayout(10));
		// 添加组件
		p1.add(findContentLabel, BorderLayout.NORTH);
		p1.add(replaceLabel, BorderLayout.CENTER);
		p6.add(findField, BorderLayout.NORTH);
		p6.add(replaceField, BorderLayout.CENTER);
		p7.add(p1, BorderLayout.WEST);
		p7.add(p6, BorderLayout.CENTER);
		p2.add(upButton);
		p2.add(downButton);
		p3.add(checkButton);
		p3.add(p2);
		p4.add(p7, BorderLayout.NORTH);
		p4.add(p3, BorderLayout.CENTER);
		p5.add(findNextButton);
		p5.add(replaceButton);
		p5.add(replaceAllButton);
		p5.add(cancelButton);
		replaceCon.add(p4);
		replaceCon.add(p5);
		// 设置替换窗口属性
		downButton.setSelected(true);// 默认向下查找
		findNextButton.setEnabled(false);
		replaceButton.setEnabled(false);
		replaceAllButton.setEnabled(false);
		replaceDialog.setBounds(230, 280, 410, 180);
		replaceDialog.setVisible(true);
		replaceDialog.setResizable(false);
		// 添加取消按钮的监听器(内部类的形式)
		cancelButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				replaceDialog.dispose();
			}// end actionPerformed
		}// end ActionListener
		);// end addActionListener
			// 通过内部类的形式添加文本域内容的监听器
		findField.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void changedUpdate(DocumentEvent e) {
			}

			@Override
			// 查找文本框内容不为空时查找按钮,替换按钮,全部替换按钮都可用
			public void insertUpdate(DocumentEvent e) {
				findNextButton.setEnabled(true);
				replaceButton.setEnabled(true);
				replaceAllButton.setEnabled(true);
			}// end insertUpdate

			@Override
			// 查找文本框内容为空时查找按钮,替换按钮,全部替换按钮都不可用
			public void removeUpdate(DocumentEvent e) {
				if (findField.getText().length() == 0) {
					findNextButton.setEnabled(false);
					replaceButton.setEnabled(false);
					replaceAllButton.setEnabled(false);
				}
			}// end removeUpdate
		}// end DocumentListener
		);// end addDocumentListener
			// 添加查找下一个按钮的监听器(内部类的形式)
		findNextButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int k;
				String str1, str2, str3, str4, strA, strB;
				str1 = jta.getText();
				str2 = findField.getText();
				str3 = str1.toUpperCase();
				str4 = str2.toUpperCase();
				// 区分大小写
				if (checkButton.isSelected()) {
					strA = str1;
					strB = str2;
				}
				// 不区分大小写
				else {
					strA = str3;
					strB = str4;
				}
				// 向上查找的方式
				if (upButton.isSelected()) {
					// 文本未选中内容
					if (jta.getSelectedText() == null)
						k = strA.lastIndexOf(strB, jta.getCaretPosition());
					// 文本已选中内容
					else
						k = strA.lastIndexOf(strB, jta.getCaretPosition() - strB.length() - 1);
					// 查找未结束,继续向上查找
					if (k != -1) {
						jta.setCaretPosition(k);
						jta.select(k, k + strB.length());
					}
					// 查找结束,弹出错误窗口
					else
						JOptionPane.showMessageDialog(null, "找不到" + " “ " + findField.getText() + " ” ", "查找",
								JOptionPane.INFORMATION_MESSAGE);
				} // end 向上查找
					// 向下查找的方式
				else if (downButton.isSelected()) {
					// 文本未选中内容
					if (jta.getSelectedText() == null)
						k = strA.lastIndexOf(strB, jta.getCaretPosition());
					// 文本已选中内容
					else
						k = strA.lastIndexOf(strB, jta.getCaretPosition() - strB.length() + 1);
					// 查找未结束,继续向下查找
					if (k != -1) {
						jta.setCaretPosition(k);
						jta.select(k, k + strB.length());
					}
					// 查找结束,弹出错误窗口
					else
						JOptionPane.showMessageDialog(null, "找不到" + " “ " + findField.getText() + " ” ", "查找",
								JOptionPane.INFORMATION_MESSAGE);
				} // end 向下查找
			}// end actionPerformed
		}// end ActionListener
		);// end addActionListener
			// 添加替换按钮的监听器(内部类的形式)
		replaceButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int k = 0;
				String str1, str2, str3, str4, str5, strA, strB;
				str1 = jta.getText();
				str2 = findField.getText();
				str3 = str1.toUpperCase();
				str4 = str2.toUpperCase();
				str5 = replaceField.getText();
				// 区分大小写
				if (checkButton.isSelected()) {
					strA = str1;
					strB = str2;
				}
				// 不区分大小写
				else {
					strA = str3;
					strB = str4;
				}
				// 向上查找的方式
				if (upButton.isSelected()) {
					// 文本未选中内容
					if (jta.getSelectedText() == null)
						k = strA.lastIndexOf(strB, jta.getCaretPosition());
					// 文本已选中内容
					else
						k = strA.lastIndexOf(strB, jta.getCaretPosition() - strB.length() - 1);
					// 查找未结束,继续向上查找
					if (k != -1) {
						// 将所查找的内容替换并选中
						jta.setCaretPosition(k);
						jta.select(k, k + strB.length());
						jta.replaceSelection(str5);
						jta.select(k, k + str5.length());
					}
					// 查找替换结束,弹出错误窗口
					else
						JOptionPane.showMessageDialog(null, "找不到" + " “ " + findField.getText() + " ” ", "替换",
								JOptionPane.INFORMATION_MESSAGE);
				} // end 向上查找
					// 向下查找的方式
				else if (downButton.isSelected()) {
					// 文本未选中内容
					if (jta.getSelectedText() == null)
						k = strA.indexOf(strB, jta.getCaretPosition());
					// 文本已选中内容
					else
						k = strA.indexOf(strB, jta.getCaretPosition() - strB.length() + 1);
					// 查找未结束,继续向下查找
					if (k != -1) {
						// 将所查找的内容替换并选中
						jta.setCaretPosition(k);
						jta.select(k, k + strB.length());
						jta.replaceSelection(str5);
						jta.select(k, k + str5.length());
					}
					// 查找替换结束,弹出错误窗口
					else
						JOptionPane.showMessageDialog(null, "找不到" + " “ " + findField.getText() + " ” ", "替换",
								JOptionPane.INFORMATION_MESSAGE);
				}
			}// end ActionPerformed
		}// end ActionListener
		);// end addActionListener
			// 添加全部替换按钮的监听器(内部类)
		replaceAllButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int k = 0;
				String str1, str2, str3, str4, str5, strA, strB;
				str1 = jta.getText();
				str2 = findField.getText();
				str3 = str1.toUpperCase();
				str4 = str2.toUpperCase();
				str5 = replaceField.getText();
				// 区分大小写
				if (checkButton.isSelected()) {
					strA = str1;
					strB = str2;
				}
				// 不区分大小写
				else {
					strA = str3;
					strB = str4;
				}
				// 如果文本未选中内容,将文本中所查找的内容全部替换
				if (jta.getSelectedText() != null)
					jta.setText(
							jta.getText().replace(jta.getSelectedText(), jta.getSelectedText().replace(strB, str5)));
				// 如果文本有选中的内容,则在此内容内将所查找的内容全部替换
				else
					jta.setText(jta.getText().replace(strB, str5));
			}// end actionPerformed
		}// end ActionListener
		);// end addActionListener
	}// end replace

插入当前时间的功能
思路:在光标位置插入当前时间

// 获取当前时间的方法
	private void date() {
		Calendar cal = Calendar.getInstance();
		GregorianCalendar time = new GregorianCalendar();
		// 获得小时,分钟,秒钟并解决小于10的问题
		String hour = "" + time.get(Calendar.HOUR_OF_DAY), min = "" + time.get(Calendar.MINUTE),
				second = "" + time.get(Calendar.SECOND), year = "" + cal.get(Calendar.YEAR),
				month = cal.get(Calendar.MONTH) + 1 + "", day = "" + cal.get(Calendar.DATE);
		if (Integer.valueOf(hour).intValue() < 10)
			hour = "0" + hour;
		if (Integer.valueOf(min).intValue() < 10)
			min = "0" + min;
		if (Integer.valueOf(second).intValue() < 10)
			second = "0" + second;
		if (Integer.valueOf(month).intValue() < 10)
			month = "0" + month;
		if (Integer.valueOf(day).intValue() < 10)
			day = "0" + day;
		String str = "当前时间:" + hour + ":" + min + ":" + second + " " + year + "/" + month + "/" + day;
		// 将鼠标所指位置插入当前时间
		jta.insert(str, jta.getCaretPosition());
	}// end date```

自动换行功能

	// 自动换行的方法
	private void auto() {
		// 判断自动换行菜单按钮是否被选中
		if (!autoMenu.isSelected())
			jta.setLineWrap(false);
		else
			jta.setLineWrap(true);
	}// end auto

字体功能
思路:通过列表来设置文本框内容的字体、字形、大小。窗口截图和代码如下
在这里插入图片描述

	// 自定义方法返回字体大小(有偏差)
	private int setSize(JTextField jtf, int size) {
		switch (jtf.getText()) {
		case "初号":size = 42;break;
		case "小初":size = 36;break;
		case "一号":size = 26;break;
		case "小一":size = 24;break;
		case "二号":size = 22;break;
		case "小二":size = 18;break;
		case "三号":size = 16;break;
		case "小三":size = 15;break;
		case "四号":size = 14;break;
		case "小四":size = 12;break;
		case "五号":size = 11;break;
		case "小五":size = 9;break;
		case "六号":size = 8;break;
		case "小六":size = 7;break;
		case "七号":size = 6;break;
		case "八号":size = 5;break;
		default:size = Integer.valueOf(jtf.getText());
		}
		return size;
	}// end setSize
	
	// 字体的方法
	private void font() {
		String fontName[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
		String styleName[] = { "常规", "粗体", "斜体", "粗斜体" };
		String sizeName[] = { "8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48",
				"72", "初号", "小初", "一号", "小一", "二号", "小二", "三号", "小三", "四号", "小四", "五号", "小五", "六号", "小六", "七号", "八号" };
		String script[] = { "中文GB2312", "西欧语言", "希腊语", "中欧字符" };
		// 定义字体窗口所需的组件
		JDialog fontDialog = new JDialog(this, "字体", false);
		Container sizeCon = fontDialog.getContentPane();
		JLabel fontLabel = new JLabel("字体(F)");
		JLabel styleLabel = new JLabel("字形(Y)");
		JLabel sizeLabel = new JLabel("大小(S)");
		JLabel scriptLable = new JLabel("脚本(R)");
		JLabel nullLabel = new JLabel();
		JTextField egjtf = new JTextField(20);
		JTextField fontField = new JTextField(15);
		JTextField styleField = new JTextField(15);
		JTextField sizeField = new JTextField(5);
		JComboBox scriptBox = new JComboBox(script);
		JList fontList = new JList(fontName);
		JList styleList = new JList(styleName);
		JList sizeList = new JList(sizeName);
		JScrollPane jsp1 = new JScrollPane(fontList);
		JScrollPane jsp2 = new JScrollPane(styleList);
		JScrollPane jsp3 = new JScrollPane(sizeList);
		JButton bt1 = new JButton("确定");
		JButton bt2 = new JButton("取消");
		JPanel p1 = new JPanel();
		JPanel p2 = new JPanel();
		JPanel p3 = new JPanel();
		JPanel p4 = new JPanel();
		JPanel p5 = new JPanel();
		JPanel p6 = new JPanel();
		JPanel p7 = new JPanel();
		JPanel p8 = new JPanel();
		JPanel p9 = new JPanel();
		JPanel p10 = new JPanel();
		// 设置布局管理器
		p1.setLayout(new BorderLayout());
		p2.setLayout(new BorderLayout());
		p3.setLayout(new BorderLayout());
		p4.setLayout(new FlowLayout(20, 20, FlowLayout.CENTER));
		p5.setLayout(new BorderLayout());
		p6.setLayout(new BorderLayout(10, 10));
		p7.setLayout(new FlowLayout(10, 10, FlowLayout.CENTER));
		p8.setLayout(new BorderLayout(10, 10));
		p9.setLayout(new BorderLayout(330, 20));
		// 添加组件
		p1.add(fontLabel, BorderLayout.NORTH);
		p1.add(fontField, BorderLayout.CENTER);
		p1.add(jsp1, BorderLayout.SOUTH);
		p2.add(styleLabel, BorderLayout.NORTH);
		p2.add(styleField, BorderLayout.CENTER);
		p2.add(jsp2, BorderLayout.SOUTH);
		p3.add(sizeLabel, BorderLayout.NORTH);
		p3.add(sizeField, BorderLayout.CENTER);
		p3.add(jsp3, BorderLayout.SOUTH);
		p4.add(p1);
		p4.add(p2);
		p4.add(p3);
		p5.setBorder(BorderFactory.createTitledBorder("示例"));
		p5.add(egjtf, BorderLayout.NORTH);
		p5.add(nullLabel, BorderLayout.CENTER);
		p6.add(scriptBox, BorderLayout.CENTER);
		p6.add(scriptLable, BorderLayout.NORTH);
		p10.add(p6);
		p7.add(bt1);
		p7.add(bt2);
		p8.add(p5, BorderLayout.NORTH);
		p8.add(p6, BorderLayout.CENTER);
		p8.add(p7, BorderLayout.SOUTH);
		p9.add(nullLabel, BorderLayout.WEST);
		p9.add(p8, BorderLayout.CENTER);
		sizeCon.add(p4, BorderLayout.NORTH);
		sizeCon.add(p9, BorderLayout.CENTER);
		// 设置示例文本框的属性
		egjtf.setFont(new Font(jta.getFont().getFontName(), jta.getFont().getStyle(), jta.getFont().getSize()));
		egjtf.setHorizontalAlignment(JTextField.CENTER);
		egjtf.setEnabled(false);
		// 设置标签,文本框,列表,下拉列表的字体属性
		fontLabel.setFont(new Font("宋体", 0, 20));
		styleLabel.setFont(new Font("宋体", 0, 20));
		sizeLabel.setFont(new Font("宋体", 0, 20));
		fontField.setFont(new Font("宋体", 0, 20));
		styleField.setFont(new Font("宋体", 0, 20));
		sizeField.setFont(new Font("宋体", 0, 20));
		fontList.setFont(new Font("宋体", 0, 20));
		styleList.setFont(new Font("宋体", 0, 20));
		sizeList.setFont(new Font("宋体", 0, 20));
		scriptLable.setFont(new Font("宋体", 0, 20));
		scriptBox.setFont(new Font("宋体", 0, 20));
		// 设置窗口属性
		fontDialog.setVisible(true);
		setEnabled(false);
		fontDialog.setResizable(false);
		fontDialog.setBounds(200, 200, 600, 480);
		// 设置文本框的初始内容
		fontField.setText(jta.getFont().getFontName());
		egjtf.setText(jta.getFont().getFontName());
		if (jta.getFont().getStyle() == Font.PLAIN)
			styleField.setText("常规");
		if (jta.getFont().getStyle() == Font.ITALIC)
			styleField.setText("倾斜");
		if (jta.getFont().getStyle() == Font.BOLD)
			styleField.setText("粗体");
		if (jta.getFont().getStyle() == Font.BOLD + Font.ITALIC)
			styleField.setText("粗斜体");
		// 以数字的形式设置初始字体大小文本框的内容
		for (int i = 0; i < 100000; i++) {
			if (jta.getFont().getSize() == i)
				sizeField.setText(i + "");
		}
		// 添加下拉列表的监听器(内部类的形式)
		scriptBox.addItemListener(new ItemListener() {
			@Override
			public void itemStateChanged(ItemEvent e) {
				// 通过选择下拉列表来设置示例文本框的内容
				if (scriptBox.getSelectedIndex() == 0)
					egjtf.setText(fontField.getText());
				if (scriptBox.getSelectedIndex() == 1)
					egjtf.setText("ABCYyZz");
				if (scriptBox.getSelectedIndex() == 2)
					egjtf.setText("AaBbAαBβ");
				if (scriptBox.getSelectedIndex() == 3)
					egjtf.setText("AaBbÁáÔô");
			}// end itemStateChanged
		}// end ItemListener
		);// end addItemListener
		fontField.selectAll();
		fontList.setSelectedValue(jta.getFont().getFontName(), true);// 从列表中选择指定的对象
		// 添加字体列表的监听器(内部类的形式)
		fontList.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				int size = 0;// 定义字体大小变量
				fontField.setText(fontName[fontList.getSelectedIndex()]);// 将字体文本框内容变为所选字体名称
				// 选中字体文本框中的内容(有颜色)
				fontField.requestFocus();
				fontField.select(0, fontField.getText().length());
				// 通过自定义的方法获得字体大小并将示例文本框的字体设置为目标字体属性
				size = setSize(sizeField, size);
				egjtf.setFont(new Font(fontField.getText(), styleList.getSelectedIndex(), size));
			}// end valueChanged
		}// end ListSelectionListener
		);// end addListSelectionListener
			// 添加字形列表的监听器(内部类的形式)
		styleList.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				int size = 0;// 定义字体大小变量
				styleField.setText((String) styleList.getSelectedValue());// 将字形文本框内容变为所选字形名称
				// 选中字体文本框中的内容(有颜色)
				styleField.requestFocus();
				styleField.select(0, styleField.getText().length());
				// 通过自定义的方法获得字体大小并将示例文本框的字体设置为目标字体属性
				size = setSize(sizeField, size);
				egjtf.setFont(new Font(fontField.getText(), styleList.getSelectedIndex(), size));
			}// end valueChanged
		}// end ListSelectionListener
		);// end addListSelectionListener
			// 添加字体大小列表的监听器(内部类的形式)
		sizeList.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				int size = 0;// 定义字体大小变量
				sizeField.setText((String) sizeList.getSelectedValue());// 将字形文本框内容变为所选字体大小
				// 选中字体文本框中的内容(有颜色)
				sizeField.requestFocus();
				sizeField.select(0, sizeField.getText().length());
				// 通过自定义的方法获得字体大小并将示例文本框的字体设置为目标字体属性
				size = setSize(sizeField, size);
				egjtf.setFont(new Font(fontField.getText(), styleList.getSelectedIndex(), size));
			}// end valueChanged
		}// end ListSelectionListener
		);// end addListSelectionListener
			// 添加确定按钮的监听器
		bt1.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int size = 0, len = 0;// 定义字体大小和fontName的长度变量
				String fontname = fontField.getText(), style = styleField.getText();// 定义fontname和字形字符串变量
				try {
					size = setSize(sizeField, size);// 通过自定义的方法获得字体大小
					// 通过for循环判断字体文本框的内容在系统中是否存在,存在则跳出循环,不存在则至循环结束
					for (len = 0; len < fontName.length; len++) {
						if (fontname.equals(fontName[len]))
							break;
					}
					// 如果if条件成立,即for循环完整的结束,抛出匹配异常
					if (len == fontName.length)
						throw new InputMismatchException();
					// 如果if条件成立,即字形文本框内容中的字形有误,抛出匹配异常
					if (!(style.equals("常规") || style.equals("斜体") || style.equals("粗体") || style.equals("粗斜体")))
						throw new InputMismatchException();
					// 设置记事本文本框的字体属性
					jta.setFont(new Font(fontname, styleList.getSelectedIndex(), size));
					// 设置完关闭字体窗口并将记事本窗口恢复可操作性
					fontDialog.dispose();
					setEnabled(true);
				} // end try
				catch (InputMismatchException em) {
					// 如果字体名称系统不存在,捕获异常,弹出警告窗口
					if (len == fontName.length)
						JOptionPane.showMessageDialog(null, "没有该名称的字体" + "\n请从字体列表中选择字体", "字体",
								JOptionPane.WARNING_MESSAGE);
					// 如果字形名称输入有误,捕获异常,弹出警告窗口
					if (!(style.equals("常规") || style.equals("斜体") || style.equals("粗体") || style.equals("粗斜体")))
						JOptionPane.showMessageDialog(null, "没有该字形的字体" + "\n请从字形列表中选择字形", "字体",
								JOptionPane.WARNING_MESSAGE);
				} // end catch
				catch (NumberFormatException en) {
					// 如果输入的字体大小不是整数,捕获异常,弹出警告窗口
					JOptionPane.showMessageDialog(null, "“大小”必须是整数", "字体", JOptionPane.WARNING_MESSAGE);
				} // end catch
			}// end actionPerformed
		}// end ActionEvent
		);// end addActionEvent
			// 添加取消按钮的监听器(内部类的形式)
		bt2.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// 不设置字体,关闭字体窗口并将记事本窗口恢复可操作性
				fontDialog.dispose();
				setEnabled(true);
			}// end actionPerformed
		}// end ActionListener
		);// end addActionListener
			// 添加字体文本框的监听器(内部类的形式)
		fontField.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int size = 0, len = 0;// 定义字体大小和fontName的长度变量
				String fontname = fontField.getText(), style = styleField.getText();// 定义fontname和字形字符串变量
				try {
					size = setSize(sizeField, size);// 通过自定义的方法获得字体大小
					// 通过for循环判断字体文本框的内容在系统中是否存在,存在则跳出循环,不存在则至循环结束
					for (len = 0; len < fontName.length; len++) {
						if (fontname.equals(fontName[len]))
							break;
					}
					// 如果if条件成立,即for循环完整的结束,抛出匹配异常
					if (len == fontName.length)
						throw new InputMismatchException();
					// 如果if条件成立,即字形文本框内容中的字形有误,抛出匹配异常
					if (!(style.equals("常规") || style.equals("斜体") || style.equals("粗体") || style.equals("粗斜体")))
						throw new InputMismatchException();
					// 设置记事本文本框的字体属性
					jta.setFont(new Font(fontname, styleList.getSelectedIndex(), size));
					// 设置完关闭字体窗口并将记事本窗口恢复可操作性
					fontDialog.dispose();
					setEnabled(true);
				} // end try
				catch (InputMismatchException em) {
					// 如果字体名称系统不存在,捕获异常,弹出警告窗口
					if (len == fontName.length)
						JOptionPane.showMessageDialog(null, "没有该名称的字体" + "\n请从字体列表中选择字体", "字体",
								JOptionPane.WARNING_MESSAGE);
					// 如果字形名称输入有误,捕获异常,弹出警告窗口
					if (!(style.equals("常规") || style.equals("斜体") || style.equals("粗体") || style.equals("粗斜体")))
						JOptionPane.showMessageDialog(null, "没有该字形的字体" + "\n请从字形列表中选择字形", "字体",
								JOptionPane.WARNING_MESSAGE);
				} // end catch
				catch (NumberFormatException en) {
					// 如果输入的字体大小不是整数,捕获异常,弹出警告窗口
					JOptionPane.showMessageDialog(null, "“大小”必须是整数", "字体", JOptionPane.WARNING_MESSAGE);
				} // end catch
			}// end actionPerformed
		}// end ActionEvent
		);// end addActionEvent
			// 添加字形文本框的监听器(内部类的形式)
		styleField.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int size = 0, len = 0;// 定义字体大小和fontName的长度变量
				String fontname = fontField.getText(), style = styleField.getText();// 定义fontname和字形字符串变量
				try {
					size = setSize(sizeField, size);// 通过自定义的方法获得字体大小
					// 通过for循环判断字体文本框的内容在系统中是否存在,存在则跳出循环,不存在则至循环结束
					for (len = 0; len < fontName.length; len++) {
						if (fontname.equals(fontName[len]))
							break;
					}
					// 如果if条件成立,即for循环完整的结束,抛出匹配异常
					if (len == fontName.length)
						throw new InputMismatchException();
					// 如果if条件成立,即字形文本框内容中的字形有误,抛出匹配异常
					if (!(style.equals("常规") || style.equals("斜体") || style.equals("粗体") || style.equals("粗斜体")))
						throw new InputMismatchException();
					// 设置记事本文本框的字体属性
					jta.setFont(new Font(fontname, styleList.getSelectedIndex(), size));
					// 设置完关闭字体窗口并将记事本窗口恢复可操作性
					fontDialog.dispose();
					setEnabled(true);
				} // end try
				catch (InputMismatchException em) {
					// 如果字体名称系统不存在,捕获异常,弹出警告窗口
					if (len == fontName.length)
						JOptionPane.showMessageDialog(null, "没有该名称的字体" + "\n请从字体列表中选择字体", "字体",
								JOptionPane.WARNING_MESSAGE);
					// 如果字形名称输入有误,捕获异常,弹出警告窗口
					if (!(style.equals("常规") || style.equals("斜体") || style.equals("粗体") || style.equals("粗斜体")))
						JOptionPane.showMessageDialog(null, "没有该字形的字体" + "\n请从字形列表中选择字形", "字体",
								JOptionPane.WARNING_MESSAGE);
				} // end catch
				catch (NumberFormatException en) {
					// 如果输入的字体大小不是整数,捕获异常,弹出警告窗口
					JOptionPane.showMessageDialog(null, "“大小”必须是整数", "字体", JOptionPane.WARNING_MESSAGE);
				} // end catch
			}// end actionPerformed
		}// end ActionEvent
		);// end addActionEvent
			// 添加字体大小文本框的监听器(内部类的形式)
		sizeField.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int size = 0, len = 0;// 定义字体大小和fontName的长度变量
				String fontname = fontField.getText(), style = styleField.getText();// 定义fontname和字形字符串变量
				try {
					size = setSize(sizeField, size);// 通过自定义的方法获得字体大小
					// 通过for循环判断字体文本框的内容在系统中是否存在,存在则跳出循环,不存在则至循环结束
					for (len = 0; len < fontName.length; len++) {
						if (fontname.equals(fontName[len]))
							break;
					}
					// 如果if条件成立,即for循环完整的结束,抛出匹配异常
					if (len == fontName.length)
						throw new InputMismatchException();
					// 如果if条件成立,即字形文本框内容中的字形有误,抛出匹配异常
					if (!(style.equals("常规") || style.equals("斜体") || style.equals("粗体") || style.equals("粗斜体")))
						throw new InputMismatchException();
					// 设置记事本文本框的字体属性
					jta.setFont(new Font(fontname, styleList.getSelectedIndex(), size));
					// 设置完关闭字体窗口并将记事本窗口恢复可操作性
					fontDialog.dispose();
					setEnabled(true);
				} // end try
				catch (InputMismatchException em) {
					// 如果字体名称系统不存在,捕获异常,弹出警告窗口
					if (len == fontName.length)
						JOptionPane.showMessageDialog(null, "没有该名称的字体" + "\n请从字体列表中选择字体", "字体",
								JOptionPane.WARNING_MESSAGE);
					// 如果字形名称输入有误,捕获异常,弹出警告窗口
					if (!(style.equals("常规") || style.equals("斜体") || style.equals("粗体") || style.equals("粗斜体")))
						JOptionPane.showMessageDialog(null, "没有该字形的字体" + "\n请从字形列表中选择字形", "字体",
								JOptionPane.WARNING_MESSAGE);
				} // end catch
				catch (NumberFormatException en) {
					// 如果输入的字体大小不是整数,捕获异常,弹出警告窗口
					JOptionPane.showMessageDialog(null, "“大小”必须是整数", "字体", JOptionPane.WARNING_MESSAGE);
				} // end catch
			}// end actionPerformed
		}// end ActionEvent
		);// end addActionEvent
			// 设置字体窗口右上角关闭按钮的监听器(内部类)
		fontDialog.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				setEnabled(true);// 关闭字体窗口并恢复记事本窗口的可操作性
			}// end windowClosing
		}// end WindowAdapter
		);// end addWindowListener
	}// end font

总结:
1.GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();方法用于返回本地的字体名称(以字符串的形式)。
2.setHorizontalAlignment()方法用于设置文本对齐方式

状态栏功能
思路:激活状态栏时,文本域下方显示光标位置的状态并显示总字数。

核心代码
int caretpos = jta.getCaretPosition();// 返回文本组件的文本插入符的位置
int lineNum = jta.getLineOfOffset(caretpos);// 将组件文本中的偏移量转换为行号(从0开始)
int columnNum = caretpos - jta.getLineStartOffset(lineNum);// 文本插入符位置减去给定行起始处的偏移量就是列数
	lineNum += 1;// 返回文本的行数(从1开始)
	setText("第" + lineNum + "行,第" + columnNum + "列       " + "共" + num + "字");

截图和代码如下
在这里插入图片描述

// 状态栏的方法
	private void state() {
		// 状态栏被激活
		if (stateMenu.isSelected()) {
			try {
				// 激活时显示初始状态栏信息
				jla.setText("第" + String.valueOf(jta.getLineOfOffset(jta.getCaretPosition()) + 1) + "行,第"
						+ String.valueOf(jta.getCaretPosition() - jta.getLineStartOffset(jta.getCaretPosition()))
						+ "列       " + "共" + jta.getText().length() + "字");
			} // end try
			catch (BadLocationException e) {
				System.out.println();
			} // end catch
			jta.addCaretListener(new CaretListener() {
				@Override
				public void caretUpdate(CaretEvent e) {
					int lineNum = 0, columnNum = 0, num = jta.getText().length();
					try {
						int caretpos = jta.getCaretPosition();// 返回文本组件的文本插入符的位置
						lineNum = jta.getLineOfOffset(caretpos);// 将组件文本中的偏移量转换为行号(从0开始)
						columnNum = caretpos - jta.getLineStartOffset(lineNum);// 文本插入符位置减去给定行起始处的偏移量就是列数
						lineNum += 1;// 返回文本的行数(从1开始)
						jla.setText("第" + lineNum + "行,第" + columnNum + "列       " + "共" + num + "字");
					} // end try
					catch (BadLocationException ex) {
						ex.printStackTrace();
					} // end catch
				}// end caretUpdate
			}// end CaretListener
			);// end addCaretListener
			jla.setVisible(true);// 设置状态栏可视化
		} // end if
			// 屏蔽状态栏
		else
			jla.setVisible(false);
	}// end state
}// end noteBookDemo

主方法

public class noteBook {
	public static void main(String[] args) {
		new noteBookDemo();
	}// end main
}// end noteBook

以上便是笔者对本次写记事本代码过程的总结。其中的不足就是有一些弹出窗口的快捷键未实现以及一些功能有一点bug。另外,笔者在这个写代码的过程中可以说是受益匪浅了嘻嘻!

发布了1 篇原创文章 · 获赞 0 · 访问量 428

猜你喜欢

转载自blog.csdn.net/weixin_44849651/article/details/96189132