java简单文本编辑器

一、前言

  聚天地之灵气,集日月之精华!一个简单的java文本编辑器由此而生。毕设所需,很是无奈!

二、界面预览

   

三、实现思路

  1.字体选择器的实现

  (1).字体类

class MyFont{
    private Font font;
    private Color color;

    public Font getFont() {
        return font;
    }

    public void setFont(Font font) {
        this.font = font;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }
    //字体名称索引
    private int familyIndex = -1;
    //字体大小索引
    private int sizeIndex = -1;
    //字体颜色索引
    private int colorIndex = -1;
    //字体风格索引
    private int styleIndex = -1;

    public int getFamilyIndex() {
        return familyIndex;
    }

    public int getSizeIndex() {
        return sizeIndex;
    }

    public int getColorIndex() {
        return colorIndex;
    }

    public int getStyleIndex() {
        return styleIndex;
    }

    public void setFamilyIndex(int familyIndex) {
        this.familyIndex = familyIndex;
    }

    public void setSizeIndex(int sizeIndex) {
        this.sizeIndex = sizeIndex;
    }

    public void setColorIndex(int colorIndex) {
        this.colorIndex = colorIndex;
    }

    public void setStyleIndex(int styleIndex) {
        this.styleIndex = styleIndex;
    }

    @Override
    public String toString() {
        return familyIndex + " " + sizeIndex + " " + styleIndex + " " + colorIndex + " \n" +
                font + " " + color;
    }

}

  (2).字体选择器

public class JFontChooser extends JPanel {

    //定义变量
    private String current_fontName = "宋体";//当前的字体名称,默认宋体.
    private int current_fontStyle = Font.PLAIN;//当前的字样,默认常规.
    private int current_fontSize = 9;//当前字体大小,默认9号.
    private Color current_color = Color.BLACK;//当前字色,默认黑色.
    private Component parent;//弹出dialog的父窗体.
    private JDialog dialog;//用于显示模态的窗体
    private MyFont myfont;//带有Color的字体.
    private JLabel lblFont;//选择字体的LBL
    private JLabel lblStyle;//选择字型的LBL
    private JLabel lblSize;//选择字大小的LBL
    private JLabel lblColor;//选择Color的label
    private JTextField txtFont;//显示选择字体的TEXT
    private JTextField txtStyle;//显示选择字型的TEXT
    private JTextField txtSize;//显示选择字大小的TEXT
    private JList lstFont;//选择字体的列表.
    private JList lstStyle;//选择字型的列表.
    private JList lstSize;//选择字体大小的列表.
    private JComboBox cbColor;//选择Color的下拉框.
    private JButton ok, cancel;//"确定","取消"按钮.
    private JScrollPane spFont;
    private JScrollPane spSize;
    private JLabel lblShow;//显示效果的label.
    private JPanel showPan;//显示框.
    private Map sizeMap;//字号映射表.
    private Map colorMap;//字着色映射表.

    //定义变量_结束________________
    public JFontChooser(MyFont curFont) {
        //实例化变量
        lblFont = new JLabel("字体:");
        lblStyle = new JLabel("字型:");
        lblSize = new JLabel("大小:");
        lblColor = new JLabel("颜色:");
        lblShow = new JLabel("Sample Test!", JLabel.CENTER);
        txtFont = new JTextField("宋体");
        txtStyle = new JTextField("常规");
        txtSize = new JTextField("9");
        //取得当前环境可用字体.
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        String[] fontNames = ge.getAvailableFontFamilyNames();
        lstFont = new JList(fontNames);
        //字形.
        lstStyle = new JList(new String[]{"常规", "斜休", "粗休", "粗斜休"});
        //字号.
        String[] sizeStr = new String[]{
            "8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72",
            "初号", "小初", "一号", "小一", "二号", "小二", "三号", "小三", "四号", "小四", "五号", "小五", "六号", "小六", "七号", "八号"
        };
        int sizeVal[] = {8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72, 42, 36, 26, 24, 22, 18, 16, 15, 14, 12, 11, 9, 8, 7, 6, 5};
        sizeMap = new HashMap();
        for (int i = 0; i < sizeStr.length; ++i) {
            sizeMap.put(sizeStr[i], sizeVal[i]);
        }
        lstSize = new JList(sizeStr);
        spFont = new JScrollPane(lstFont);
        spSize = new JScrollPane(lstSize);

        String[] colorStr = new String[]{
                "黑色", "蓝色", "深灰", "灰色", "绿色", "浅灰", "洋红", "桔黄", "粉红", "红色", "白色", "黄色"
        };
        Color[] colorVal = new Color[]{
                Color.BLACK, Color.BLUE, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE, Color.YELLOW
        };
        colorMap = new HashMap();
        for (int i = 0; i < colorStr.length; i++) {
            colorMap.put(colorStr[i], colorVal[i]);
        }
        cbColor = new JComboBox(colorStr);
        showPan = new JPanel();
        ok = new JButton("确定");
        cancel = new JButton("取消");
        //实例化变量_结束

        //布局控件
        this.setLayout(null);//不用布局管理器.
        add(lblFont);
        lblFont.setBounds(12, 10, 30, 20);
        txtFont.setEditable(false);
        add(txtFont);
        txtFont.setBounds(10, 30, 155, 20);
        add(spFont);
        spFont.setBounds(10, 50, 155, 100);

        add(lblStyle);
        lblStyle.setBounds(175, 10, 30, 20);
        txtStyle.setEditable(false);
        add(txtStyle);
        txtStyle.setBounds(175, 30, 130, 20);
        lstStyle.setBorder(javax.swing.BorderFactory.createLineBorder(Color.gray));
        add(lstStyle);
        lstStyle.setBounds(175, 50, 130, 100);

        add(lblSize);
        lblSize.setBounds(320, 10, 30, 20);
        txtSize.setEditable(false);
        add(txtSize);
        txtSize.setBounds(320, 30, 60, 20);
        add(spSize);
        spSize.setBounds(320, 50, 60, 100);

        add(lblColor);
        lblColor.setBounds(13, 170, 30, 20);
        add(cbColor);
        cbColor.setBounds(10, 195, 130, 22);
        cbColor.setMaximumRowCount(5);

        showPan.setBorder(javax.swing.BorderFactory.createTitledBorder("示例"));
        add(showPan);
        showPan.setBounds(150, 170, 230, 100);
        showPan.setLayout(new BorderLayout());
        lblShow.setBackground(Color.white);
        showPan.add(lblShow);
        add(ok);
        ok.setBounds(10, 240, 60, 20);
        add(cancel);
        cancel.setBounds(80, 240, 60, 20);
        //布局控件_结束

        //事件
        lstFont.addListSelectionListener(new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent e) {
                current_fontName = (String) lstFont.getSelectedValue();
                txtFont.setText(current_fontName);
                lblShow.setFont(new Font(current_fontName, current_fontStyle, current_fontSize));
            }
        });

        lstStyle.addListSelectionListener(new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent e) {
                String value = (String) ((JList) e.getSource()).getSelectedValue();
                if (value.equals("常规")) {
                    current_fontStyle = Font.PLAIN;
                }
                if (value.equals("斜休")) {
                    current_fontStyle = Font.ITALIC;
                }
                if (value.equals("粗休")) {
                    current_fontStyle = Font.BOLD;
                }
                if (value.equals("粗斜休")) {
                    current_fontStyle = Font.BOLD | Font.ITALIC;
                }
                txtStyle.setText(value);
                lblShow.setFont(new Font(current_fontName, current_fontStyle, current_fontSize));
            }
        });

        lstSize.addListSelectionListener(new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent e) {
                current_fontSize = (Integer) sizeMap.get(lstSize.getSelectedValue());
                txtSize.setText(String.valueOf(current_fontSize));
                lblShow.setFont(new Font(current_fontName, current_fontStyle, current_fontSize));
            }
        });

        cbColor.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                current_color = (Color) colorMap.get(cbColor.getSelectedItem());
                lblShow.setForeground(current_color);
            }
        });

        ok.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                myfont = new MyFont();
                myfont.setFont(new Font(current_fontName, current_fontStyle, current_fontSize));
                myfont.setColor(current_color);
                myfont.setColorIndex(cbColor.getSelectedIndex());
                myfont.setFamilyIndex(lstFont.getSelectedIndex());
                myfont.setSizeIndex(lstSize.getSelectedIndex());
                myfont.setStyleIndex(lstStyle.getSelectedIndex());
                dialog.dispose();
                dialog = null;
            }
        });

        cancel.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                myfont = null;
                dialog.dispose();
                dialog = null;
            }
        });
        //事件_结束

        if(curFont != null){
            if(curFont.getFamilyIndex() != -1) {
                lstFont.setSelectedIndex(curFont.getFamilyIndex());
                lstFont.ensureIndexIsVisible(curFont.getFamilyIndex());
            } else {
                lstFont.setSelectedValue("宋体", true);
            }

            lstSize.setSelectedIndex(curFont.getSizeIndex());
            lstSize.ensureIndexIsVisible(curFont.getSizeIndex());

            lstStyle.setSelectedIndex(curFont.getStyleIndex());
            lstStyle.ensureIndexIsVisible(curFont.getStyleIndex());
            cbColor.setSelectedIndex(curFont.getColorIndex());
        }
    }

    public MyFont showDialog(Frame parent, String title, int dx, int dy) {
        if(title == null)
            title = "Font";
        dialog = new JDialog(parent, title,true);
        dialog.add(this);
        dialog.setResizable(false);
        dialog.setBounds(dx, dy, 400, 310);
        dialog.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                myfont = null;
                dialog.removeAll();
                dialog.dispose();
                dialog = null;
            }
        });

        dialog.setVisible(true);
        return myfont;
    }
}  

  2.编辑器的实现

  (1).字符串样式修饰类

    功能:主要是将JTextPane对应的Document的文本进行处理。使得不同类型的文本显示为不同的风格样式。由于这个编辑器是用来编辑java语言的,所以会对java中的关键字进行特殊的显示,使得关键字,注释,以及其他串的不同的显示。

class DecorateKeyWords{
    //java中的关键字
    private static final String KEYWORDS[]={"abstract","assert","boolen","break","byte","case","catch","char","class","const",
         "continue","default","do","double","else","enum","extends","final","finally","float","for",
         "if","implements","import","instanceof","int","interface","long","native","new","package",
         "private","protected","public","return","short","static","strictfp","super","switch","synchrpnized",
         "this","throw","throws","transient","try","void","volatile","while"
    };
     // 准备关键字
    private static HashSet<String> keywords = new HashSet<String>(); 

    public static void decorateStyleConstants(SimpleAttributeSet attr, Font font){
        StyleConstants.setFontFamily(attr, font.getFamily());
        StyleConstants.setFontSize(attr, font.getSize());
        switch(font.getStyle()) {
            case Font.BOLD :
                StyleConstants.setBold(attr, true);
                break;
            case Font.ITALIC :
                StyleConstants.setItalic(attr, true);
                break;
            case Font.PLAIN :
                StyleConstants.setItalic(attr, false);
                StyleConstants.setBold(attr, false);
                break;
            case Font.BOLD | Font.ITALIC :
                StyleConstants.setItalic(attr, true);
                StyleConstants.setBold(attr, true);
                break;
            default :
                break;
        }
    }

    public static void decorateKeyWords(JTextPane tp, MyFont myFont) {
      //初始化关键字
      for(int i = 0; i<KEYWORDS.length; i++)
         keywords.add(KEYWORDS[i]);
      // 对所有关键词进行修饰颜色
      String text = tp.getText().replaceAll("\\r", "");
      StyledDocument doc = tp.getStyledDocument();
      SimpleAttributeSet keyWordAttr = new SimpleAttributeSet();
      StyleConstants.setForeground(keyWordAttr, Color.cyan);
      decorateStyleConstants(keyWordAttr, myFont.getFont());
      SimpleAttributeSet otherWordAttr = new SimpleAttributeSet();
      StyleConstants.setForeground(otherWordAttr, myFont.getColor());
      decorateStyleConstants(otherWordAttr, myFont.getFont());
      ListIterator<WordNode> iterator1 = split(text, "\\s|\\{|\\}|\\(|\\)|\\<|\\>|\\.|\\n");
      while (iterator1.hasNext()) {
          WordNode wn = iterator1.next();
          if (keywords.contains(wn.getWord())) {
              doc.setCharacterAttributes(wn.getLocation(), wn.getWord().length(), keyWordAttr, true);
          } else {
              doc.setCharacterAttributes(wn.getLocation(), wn.getWord().length(), otherWordAttr, true);
          }
      }
      // 对注释行进行修饰不同的颜色
      SimpleAttributeSet annotationAttr = new SimpleAttributeSet();
      StyleConstants.setForeground(annotationAttr, Color.green);
      decorateStyleConstants(annotationAttr, myFont.getFont());
      ListIterator<WordNode> iterator2 = split(text, "\\n");
      boolean exegesis = false; // 是否加了/*的注释
      while (iterator2.hasNext()) {
          WordNode wn = iterator2.next();
          if (wn.getWord().startsWith("//")) {
              doc.setCharacterAttributes(wn.getLocation(), wn.getWord()
                      .length(), annotationAttr, true);
          } else if (wn.getWord().startsWith("/*")  && wn.getWord().endsWith("*/")) {
              doc.setCharacterAttributes(wn.getLocation(), wn.getWord()
                      .length(), annotationAttr, true);
          } else if (wn.getWord().startsWith("/*")  && !wn.getWord().endsWith("*/")) {
              exegesis = true;
              doc.setCharacterAttributes(wn.getLocation(), wn.getWord()
                      .length(), annotationAttr, true);
          } else if (!wn.getWord().startsWith("/*") && wn.getWord().endsWith("*/") && true == exegesis) {
              doc.setCharacterAttributes(wn.getLocation(), wn.getWord()
                      .length(), annotationAttr, true);
              exegesis = false;
          } else if (true == exegesis) {
              doc.setCharacterAttributes(wn.getLocation(), wn.getWord()
                      .length(), annotationAttr, true);
          }
          }
     }  

     /**
       * 按照指定的多个字符进行字符串分割,如‘ ’或‘,’等
      * @param str
      *            被分割的字符串
      * @param regexs
      *            要分割所需的符号
      * @return 包含WordNodeList对象的iterator
      */
     private static ListIterator<WordNode> split(String str,String regex) {
         Pattern p = Pattern.compile(regex);
         Matcher m = p.matcher(str);
         List<WordNode> nodeList = new ArrayList();
         int strStart = 0; // 分割单词的首位置
         String s; // 分割的单词
         WordNode wn; // StringNode节点
         while (m.find()) {
             s = str.substring(strStart, m.start());
             if (!s.equals(new String())) {
                 wn = new WordNode(strStart, s);
                 nodeList.add(wn);
             }
             strStart = m.start() + 1;
         }
         s = str.substring(strStart, str.length());
         wn = new WordNode(strStart, s);
         nodeList.add(wn);
         return nodeList.listIterator();
     }
}

  (2).串节点

    功能:通过正则表达式,将JTextPane对应的Document的文本进行分割,记录每个分割串的起始位置,然后通过字符串修饰类(DecorateKeyWords)中的decorateStyleConstants方法根据每个分割串的起始位置对JTextPane对应的Document的文本进行不同风格样式的修饰。

class WordNode {
     private int location;
     private String word;
     public WordNode(int location, String str) {
         super();
         this.location = location;
         this.word = str;
     }
     public int getLocation() {
         return location;
     }
     public String getWord() {
         return word;
     }
}  

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

时间: 2024-10-25 23:47:11

java简单文本编辑器的相关文章

简单文本编辑器制作

对于文本编辑器,最关键的知识点,就是 插入符号 的操作了... windows中有5个基本的插入符号函数: CreateCaret:创建和窗口关联的插入符号 SetCaretPos:设置窗口内的插入符号的位置 ShowCaret:显示插入符号 HideCaret:隐藏插入符号 DestroyCaret:销毁插入符号 对于插入符号的相关函数: GetCaretPos:获得当前插入符号位置的函数 GetCaretBlinkTime SetCaretBlinkTime获得和设置插入符号闪烁的时间函数

Java实现&quot;命令式&quot;简易文本编辑器原型

源自早先想法, 打算从界面方向做些尝试. 找到个简单文本编辑器的实现: Simple Text Editor - Java Tutorials. 原本的菜单/按钮界面如下. 包括基本功能: 新建/打开/保存文件, 文本编辑与剪切/复制/粘贴. 把所有菜单/按钮替换为命令输入后效果如下, 源码库在: program-in-chinese/simple-text-editor-in-Java. 与其他命令行工具一样, 省去界面元素的代价是输入较繁琐. 在文本和命令两处切换也有点麻烦. 接下去试着实现

java文本编辑器5

1 package peng_jun; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 6 import javax.swing.*; 7 8 import java.io.*; 9 10 import javax.swing.filechooser.*; 11 12 import java.awt.datatransfer.*; 13 14 public class Text4 extends JFrame { 15 public sta

java文本编辑器 版本4

1 package peng_jun; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 6 import javax.swing.*; 7 8 import java.io.*; 9 10 import javax.swing.filechooser.*; 11 12 import java.awt.datatransfer.*; 13 14 public class Text3 extends JFrame { 15 public sta

Python-tkinter实现简单的文本编辑器

利用tkinter实现简单的文本编辑器.创建一个简单的文本编辑器.可以用读文件的方式在一个文本域里显示一些文字供用户编辑. 当用户退出程序时(通过 QUIT 按钮)会询问用户是否保存所作的修改. (直接上代码~有注释~) 1 # -*- encoding: utf-8 -*- 2 ''' 3 @File : 简单文本编辑器.py 4 @Time : 2020/04/05 11:35:39 5 @Author : Konggu 6 @Desc : None 7 ''' 8 import os 9

程序员最爱的的 9 款文本编辑器

这年头,几乎每个开发人员都很熟悉开源代码和代码编写工具的好处.GitHub 和 SourceForge 之类的开源代码库为那些在自行构建应用程序方面寻求帮助的人提供了宝贵资源. 1. ATPad   ATPad 为偏爱使用文本编辑器而非成熟 IDE 的开发人员而设计,它提供了选项卡式环境.行编号.书签.代码片段系统.无限制的撤销/重做及更多功能. 支持的操作系统:Windows 2. CodeMirror 基于 JavaScript 的 CodeMirror 可以将文本编辑器嵌入到 Web 浏览

Java笔记第五篇 文本编辑器初见面

#日常唠叨#从现在开始,又要开始讲理论了,小星星努力今天写完文本编辑器之后再用2天时间写完数据类型,然后上代码,另外关于HelloWorld代码的讲解小星星会在写完运算符之后写 编译厉害归厉害,但对我们打代码的流畅度.心情舒畅度有用吗?答案是没用.相信大家用记事本编写代码之后已经心生厌烦了吧?如果这么打上上千行肯定吐血.那小星星现在给大家升级一下记事本. 升级过后的记事本叫啥名字?当然是叫超级记事本文本编辑器啦!小星星在这里推荐以下三款文本编辑器: UltraEdit:是一款功能强大的文本编辑器

百度UMeditor富文本编辑器java使用

百度UMeditor富文本编辑器java使用 1.介绍 UMeditor 是一款轻量级的富文本编辑器,比UEditor要小得多,是为满足广大门户网站对于简单发帖框,或者回复框需求所定制的在线富文本编辑器 2.下载    官网地址:http://ueditor.baidu.com/website/umeditor.html 说明笔者点击官网的下载中的按钮,半天没反应,然后又去了github上down了一份,github地址:https://github.com/fex-team/umeditor/

百度富文本编辑器ueditor/jsp版的简单使用,可上传图片和附件

~~经过一上午的时间,终于把ueditor编辑器搞出来了,仅做记录 #完成的样子 1,首先在官网下载对应的插件 [附下载地址:http://ueditor.baidu.com/website/download.html]    本人使用的是Java语言 ,框架是ssm+maven 2,解压文件,在自己项目的根目录下新建文件夹 ueditor,把utf8-jsp中文件复制粘贴到ueditor文件夹下 3,新建一个ueditorTest.jsp,把文件夹中index.html中的HTML代码复制粘贴