zoukankan      html  css  js  c++  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 + " 
    " +
                    font + " " + color; 
        }
        
    }
    View Code

      (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;
        }
    }  
    View Code

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

      (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;  
         }  
    }  
    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();
         }
    }
    View Code
  • 相关阅读:
    AcWing 157. 树形地铁系统 (hash判断树同构)打卡
    AcWing 156. 矩阵 (哈希二维转一维查询)打卡
    AcWing 144. 最长异或值路径 01字典树打卡
    AcWing 143. 最大异或对 01字典树打卡
    AcWing 142. 前缀统计 字典树打卡
    AcWing 139. 回文子串的最大长度 hash打卡
    AcWing 138. 兔子与兔子 hash打卡
    常用C库函数功能及用法
    编程实现C库函数
    C语言面试题5
  • 原文地址:https://www.cnblogs.com/hujunzheng/p/5232125.html
Copyright © 2011-2022 走看看