v一、前言
聚天地之灵气,集日月之精华!一个简单的java文本编辑器由此而生。毕设所需,很是无奈!
v二、界面预览
v三、实现思路
v 1.字体选择器的实现
(1).字体类
View Code
(2).字体选择器
View Code
v 2.编辑器的实现
(1).字符串样式修饰类
功能:主要是将JTextPane对应的Document的文本进行处理。使得不同类型的文本显示为不同的风格样式。由于这个编辑器是用来编辑java语言的,所以会对java中的关键字进行特殊的显示,使得关键字,注释,以及其他串的不同的显示。
View Code
(2).串节点
功能:通过正则表达式,将JTextPane对应的Document的文本进行分割,记录每个分割串的起始位置,然后通过字符串修饰类(DecorateKeyWords)中的decorateStyleConstants方法根据每个分割串的起始位置对JTextPane对应的Document的文本进行不同风格样式的修饰。
View Code
(3).编辑器类
功能:文件的新建,文件的保存,文件的编辑;确定JTextPane中光标的位置(行号和列号),显示行号,字体样式的选择,重新设置新字体样式。
通过DocumentListener可以监听文档的改变,删除和插入的时候,调用字体选择器对文档的内容重新设置样式,另外在文档删除的时候判断是否行数减少,如果是,则更新行号面板的显示。
textPane.getDocument().addDocumentListener(new DocumentListener() { @Override public void changedUpdate(DocumentEvent e) {} @Override public void insertUpdate(final DocumentEvent e) { new Thread(new Runnable() { @Override public void run() { DecorateKeyWords.decorateKeyWords(textPane, myFont); } }).start(); } @Override public void removeUpdate(DocumentEvent e) { new Thread(new Runnable() { @Override public void run() { String text; try { text = textPane.getDocument().getText(0, textPane.getDocument().getLength()).replaceAll("\\r", ""); Pattern pattern = Pattern.compile("\\n"); Matcher matcher = pattern.matcher(text); int lineRow = 1; while(matcher.find()){ //计算行数 ++lineRow; } while(lineRow < linePane.getComponentCount()) { --lineNum; linePane.remove(linePane.getComponentCount()-1); } linePane.updateUI(); } catch (BadLocationException ex) { ex.printStackTrace(); } finally { DecorateKeyWords.decorateKeyWords(textPane, myFont); } } }).start(); } }
通过CaretListener可以监听光标位置的变化,实时获得光标所在的行号和列号并显示出来。
textPane.addCaretListener(new CaretListener() { @Override public void caretUpdate(CaretEvent e) { try { String text = textPane.getDocument().getText(0, e.getDot()).replaceAll("\\r", ""); Pattern pattern = Pattern.compile("\\n"); Matcher matcher = pattern.matcher(text); int lineRow = 1; int lastLineBeginPos = -1;//记录文本中最后一行的开始的位置 while(matcher.find()){ //计算行数 ++lineRow; lastLineBeginPos = matcher.start();//得到下一行光标所在的位置(根据上一行的换行符) } int lineCol = e.getDot() - lastLineBeginPos; //显示行号和列号 caretStatusBar.setText("光标 " + lineRow + " : " + lineCol); } catch (BadLocationException ey) { ey.printStackTrace(); } } });
通过KeyListener可以监听按键的操作,如果是回车键,那么为行号面板增加新的行号!
textPane.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { super.keyPressed(e); if(e.getKeyCode() == KeyEvent.VK_ENTER) { //添加新的行号 addLineNum(); } } });
编辑器全部代码如下
public class EditorDemo extends JFrame { public static final String MAX_LINE_NUM = "9999"; private JTextPane textPane = new JTextPane(); //文本窗格,编辑窗口 private JLabel timeStatusBar = new JLabel(); //时间状态栏 private JLabel caretStatusBar = new JLabel(); //光标位置状态栏 private JFileChooser filechooser = new JFileChooser(); //文件选择器 private JPanel linePane = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); private int lineNum = 0; private MyFont myFont = null; private void initTextPaneDocument(){ textPane.getDocument().addDocumentListener(new DocumentListener() { @Override public void changedUpdate(DocumentEvent e) {} @Override public void insertUpdate(final DocumentEvent e) { new Thread(new Runnable() { @Override public void run() { DecorateKeyWords.decorateKeyWords(textPane, myFont); } }).start(); } @Override public void removeUpdate(DocumentEvent e) { new Thread(new Runnable() { @Override public void run() { String text; try { text = textPane.getDocument().getText(0, textPane.getDocument().getLength()).replaceAll("\\r", ""); Pattern pattern = Pattern.compile("\\n"); Matcher matcher = pattern.matcher(text); int lineRow = 1; while(matcher.find()){ //计算行数 ++lineRow; } while(lineRow < linePane.getComponentCount()) { --lineNum; linePane.remove(linePane.getComponentCount()-1); } linePane.updateUI(); } catch (BadLocationException ex) { ex.printStackTrace(); } finally { DecorateKeyWords.decorateKeyWords(textPane, myFont); } } }).start(); } }); } public EditorDemo() { //构造函数 super("简单的文本编辑器"); //调用父类构造函数 //初始字体 myFont = new MyFont(); myFont.setColor(Color.black); myFont.setFont(new Font("宋体", Font.PLAIN, 24)); myFont.setSizeIndex(19); myFont.setStyleIndex(0); myFont.setColorIndex(0); Action[] actions = //Action数组,各种操作命令 { new NewAction(), new OpenAction(), new SaveAction(), new CutAction(), new CopyAction(), new PasteAction(), new NewFontStyle(), new AboutAction(), new ExitAction() }; textPane.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { super.keyPressed(e); if(e.getKeyCode() == KeyEvent.VK_ENTER) { //添加新的行号 addLineNum(); } } }); textPane.addCaretListener(new CaretListener() { @Override public void caretUpdate(CaretEvent e) { try { String text = textPane.getDocument().getText(0, e.getDot()).replaceAll("\\r", ""); Pattern pattern = Pattern.compile("\\n"); Matcher matcher = pattern.matcher(text); int lineRow = 1; int lastLineBeginPos = -1;//记录文本中最后一行的开始的位置 while(matcher.find()){ //计算行数 ++lineRow; lastLineBeginPos = matcher.start();//得到下一行光标所在的位置(根据上一行的换行符) } int lineCol = e.getDot() - lastLineBeginPos; //显示行号和列号 caretStatusBar.setText("光标 " + lineRow + " : " + lineCol); } catch (BadLocationException ey) { ey.printStackTrace(); } } }); initTextPaneDocument(); setJMenuBar(createJMenuBar(actions)); //设置菜单栏 add(createJToolBar(actions), BorderLayout.NORTH); //增加工具栏 JPanel textBackPanel = new JPanel(new BorderLayout()); textBackPanel.add(linePane, BorderLayout.WEST);//增加行号面板 textBackPanel.add(textPane, BorderLayout.CENTER);//增加文本面板 add(new JScrollPane(textBackPanel), BorderLayout.CENTER); //文本窗格嵌入到JscrollPane JPanel statusPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 50, 0)); statusPane.add(caretStatusBar); statusPane.add(timeStatusBar); //初始化光标位置 caretStatusBar.setText("光标 1 : 1"); //初始化系统时间显示 new Timer().schedule(new TimerTask() { @Override public void run() { Date now = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//可以方便地修改日期格式 timeStatusBar.setText(dateFormat.format(now)); } }, 0, 1000); add(statusPane, BorderLayout.SOUTH); //增加状态栏 FontMetrics fm = FontDesignMetrics.getMetrics(myFont.getFont()); //设置光标的大小 textPane.setFont(myFont.getFont()); //设置行数面板的宽度 linePane.setPreferredSize(new Dimension(fm.stringWidth(MAX_LINE_NUM), 0)); addLineNum(); setBounds(200, 100, 800, 500); //设置窗口尺寸 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //关闭窗口时退出程序 setVisible(true); //设置窗口可视 } private void addLineNum(){ //为textPane添加行号 String numText = String.valueOf(++lineNum); int tmpNum = MAX_LINE_NUM.length() - (int)(Math.log10(lineNum*1.0)+1); String spaces = ""; while(tmpNum > 0){ spaces += " "; --tmpNum; } JLabel lineLabel = new JLabel(numText.replaceAll("(\\d+)", spaces+"$1"), JLabel.RIGHT); lineLabel.setForeground(Color.GRAY); lineLabel.setFont(myFont.getFont()); linePane.add(lineLabel); linePane.updateUI(); } private JMenuBar createJMenuBar(Action[] actions) { //创建菜单栏 JMenuBar menubar = new JMenuBar(); //实例化菜单栏 JMenu menuFile = new JMenu("文件"); //实例化菜单 JMenu menuEdit = new JMenu("编辑"); JMenu menuAbout = new JMenu("帮助"); menuFile.add(new JMenuItem(actions[0])); //增加新菜单项 menuFile.add(new JMenuItem(actions[1])); menuFile.add(new JMenuItem(actions[2])); menuFile.add(new JMenuItem(actions[7])); menuEdit.add(new JMenuItem(actions[3])); menuEdit.add(new JMenuItem(actions[4])); menuEdit.add(new JMenuItem(actions[5])); menuAbout.add(new JMenuItem(actions[6])); menubar.add(menuFile); //增加菜单 menubar.add(menuEdit); menubar.add(menuAbout); return menubar; //返回菜单栏 } private JToolBar createJToolBar(Action[] actions) { //创建工具条 JToolBar toolBar = new JToolBar(); //实例化工具条 for (int i = 0; i < actions.length; i++) { JButton bt = new JButton(actions[i]); //实例化新的按钮 bt.setRequestFocusEnabled(false); //设置不需要焦点 toolBar.add(bt); //增加按钮到工具栏 } return toolBar; //返回工具栏 } class NewFontStyle extends AbstractAction{ public NewFontStyle() { super("字体"); } @Override public void actionPerformed(ActionEvent e) { JFontChooser one = new JFontChooser(myFont); MyFont tmpFont = one.showDialog(null, "字体选择器", textPane.getLocationOnScreen().x, textPane.getLocationOnScreen().y); if(tmpFont == null) return; myFont = tmpFont; //重新设置 textPane的字体,改变光标的大小 textPane.setFont(myFont.getFont()); FontMetrics fm = FontDesignMetrics.getMetrics(myFont.getFont()); //重新设置数字行数面板的宽度 linePane.setPreferredSize(new Dimension(fm.stringWidth(MAX_LINE_NUM), 0)); //重新设置行号的字体 for(int i=0; i < linePane.getComponentCount(); ++i) linePane.getComponent(i).setFont(myFont.getFont()); StyledDocument doc = textPane.getStyledDocument(); SimpleAttributeSet wordAttr = new SimpleAttributeSet(); DecorateKeyWords.decorateStyleConstants(wordAttr, myFont.getFont()); doc.setCharacterAttributes(0, doc.getLength(), wordAttr, false); } } class NewAction extends AbstractAction { //新建文件命令 public NewAction() { super("新建"); } public void actionPerformed(ActionEvent e) { textPane.setDocument(new DefaultStyledDocument()); //清空文档 while(linePane.getComponentCount() > 1) linePane.remove(linePane.getComponent(linePane.getComponentCount()-1)); linePane.updateUI(); lineNum = 1; initTextPaneDocument(); } } class OpenAction extends AbstractAction { //打开文件命令 public OpenAction() { super("打开"); } public void actionPerformed(ActionEvent e) { int i = filechooser.showOpenDialog(EditorDemo.this); //显示打开文件对话框 if (i == JFileChooser.APPROVE_OPTION) { //点击对话框中打开选项 File f = filechooser.getSelectedFile(); //得到选择的文件 try { InputStream is = new FileInputStream(f); //得到文件输入流 textPane.read(is, "d"); //读入文件到文本窗格 is.close(); is = new FileInputStream(f); LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is)); lnr.skip(Long.MAX_VALUE); int newLineNum = lnr.getLineNumber()+1; lnr.close(); if(lineNum < newLineNum){ while(lineNum < newLineNum) addLineNum(); } else { while(lineNum > newLineNum && lineNum > 1){ linePane.remove(linePane.getComponentCount()-1); --lineNum; } linePane.updateUI(); } } catch (Exception ex) { ex.printStackTrace(); //输出出错信息 } } DecorateKeyWords.decorateKeyWords(textPane, myFont); initTextPaneDocument(); } } class SaveAction extends AbstractAction { //保存命令 public SaveAction() { super("保存"); } public void actionPerformed(ActionEvent e) { int i = filechooser.showSaveDialog(EditorDemo.this); //显示保存文件对话框 if (i == JFileChooser.APPROVE_OPTION) { //点击对话框中保存按钮 File f = filechooser.getSelectedFile(); //得到选择的文件 try { FileOutputStream out = new FileOutputStream(f); //得到文件输出流 out.write(textPane.getText().getBytes()); //写出文件 } catch (Exception ex) { ex.printStackTrace(); //输出出错信息 } } } } class ExitAction extends AbstractAction { //退出命令 public ExitAction() { super("退出"); } public void actionPerformed(ActionEvent e) { System.exit(0); //退出程序 } } class CutAction extends AbstractAction { //剪切命令 public CutAction() { super("剪切"); } public void actionPerformed(ActionEvent e) { textPane.cut(); //调用文本窗格的剪切命令 } } class CopyAction extends AbstractAction { //拷贝命令 public CopyAction() { super("拷贝"); } public void actionPerformed(ActionEvent e) { textPane.copy(); //调用文本窗格的拷贝命令 } } class PasteAction extends AbstractAction { //粘贴命令 public PasteAction() { super("粘贴"); } public void actionPerformed(ActionEvent e) { textPane.paste(); //调用文本窗格的粘贴命令 } } class AboutAction extends AbstractAction { //关于选项命令 public AboutAction() { super("关于"); } public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(EditorDemo.this, "简单的文本编辑器演示"); //显示软件信息 } } public static void main(String[] args) { new EditorDemo(); } }
本文转自 小眼儿 博客园博客,原文链接:http://www.cnblogs.com/hujunzheng/p/5232125.html,如需转载请自行联系原作者