背景

  • JAVA上机大作业:qq / 代码评价系统

  • 第一次上机主题是练习JAVA自带的GUI图形化编程

  • 目的:实现一个跟window10记事本界面相同,功能相近的文本编辑器,时间有剩余的话再添加类似notepad++上的一些额外功能。

  • 记事本结构
    • 标题栏
      显示标题title

    • 菜单栏
      文件、编辑、格式、查看、帮助 - 菜单项

      • 下拉栏有:新建、新窗口、打开、保存、退出

      • 下拉栏有:撤销、恢复、剪切、复制、粘贴、删除

      • 下拉栏有:字体

      • 下拉栏有:关于

    • 文本区域
      • 底侧滚动条

设计思路

  • 菜单栏:
    • 主体就是一个JFrame,设置一些属性,然后设置菜单栏JMenuBar,add菜单项JMenu,菜单项的下拉栏add菜单子项JMenuItem
  • 文本区域:
    • 完成菜单栏之后就是一个占屏幕率超大的JTextArea,注意该文本区域需要将他设置为静态,并且写一个静态get函数得到它,因为有跨类的需要改该文本属性。由于有滚动条,后续还要加上显示行号的功能,所以用一个JScrollPane装载它。
  • 文件菜单子栏:
    • 新建:就新建一个窗口new TextEdition(),并且把当前窗口退出dispose(),退出前调用一次保存函数savefile()

    • 新窗口:
      • 新建一个窗口,并且当前窗口不退出,两窗口相互不影响,即默认退出操作使用DISPOSE_ON_CLOSE(当然可以自己写,退出时加上是否保存询问)
    • 打开:
      • 使用JFileChooser,界面为打开界面,打开跳出一个Dialog对话框,选择文件进行打开,InputStreamReader+BufferedReader
    • 保存:
      • 使用JFileChooser,界面为保存界面,跟打开操作一样,OutputStreamWriter+BufferedWriter
    • 退出:
      • 调用保存函数savefile(),并且dispose()当前窗口
  • 编辑菜单子栏:
    • 撤销:
      • 撤销与恢复都需要用到撤销管理类um = new UndoManager(),在监听器初始化时注册撤销可编辑监听器 - 文本区域getDocument().addUndoableEditListener,撤销操作就是 um.undo()
    • 恢复:
      • 恢复操作与上一致,监听器设置好以后,调用um.redo()即是恢复
    • 剪切:
      • 剪切与复制、粘贴是一起完成,需要用到系统剪切板clipboard = this.getToolkit().getSystemClipboard(),剪切就是复制+删除操作
    • 复制:
      • 先将文本区域的文本放到string里面,创建能传输指定 String 的 StringSelection,把系统剪切板的内容设置成StringSelection:clipboard.setContents(editText,null);
    • 粘贴:
      • 先将系统剪切板的内容放在一个Transferable里面,之后再将Transferable转成string,文本区域append即可
    • 删除
      • getSelectionStart,getSelectionEnd得到头尾,再replaceRange替换成空文本即可
  • 格式菜单子栏:
    • 字体
      • 新建一个窗体设置字体,用JComboBox实现下拉列表,一个JTextField放演示文本,再是确认取消按钮,三个JPanel分别装这三部分整理布局排版,确认按钮点击后就调用静态get函数得到父窗体的文本区域设置其属性。
  • 帮助菜单子栏:
    • 关于
      • 弹出一个新窗体,里面用label写文本显示

TextEdition - 主窗体类实现

<JAVA - 大作业(1)文本编辑器 >_第1张图片

主窗体属性

ublic class TextEditor extends JFrame implements ActionListener{
    //  其实我们这里也可以用ItemListener用于捕获带有item的组件产生的事件,
    //  而ActionListener是所有监听器的父类,可以监听到所有的事件,由于担心还会有其他的事件需要监听,
    //  所以就直接用 ActionListener 了

    //菜单栏
    private JMenuBar menuBar;
    //菜单项
    private JMenu menu_File,menu_Edit,menu_Help,menu_Format;
    //file菜单项内容
    private JMenuItem item_new,item_newwindow,item_open,item_save,item_exit;
    //edit菜单项内容
    private JMenuItem item_undo,item_redo,item_cut,item_copy,item_stick,item_delete;
    //help菜单项内容
    private JMenuItem item_about;
    //format菜单项内容
    private JMenuItem item_word_format;
    
    //文本区域
    private static JTextArea edit_text_area;    //static因为要在其他窗口对其他字体格式进行改动
    //文本滚动条
    private JScrollPane scroll_bar;
    //撤销管理
    private UndoManager um;
    //系统剪切板
    private Clipboard clipboard;
    //文件选择器
    private JFileChooser fileChooser;

主窗体构造器

public TextEditor()
    {
        initMenuBar();
        initEditText();
        initListener();
         
        this.setJMenuBar(menuBar);
        this.setSize(800,600);
        this.add(scroll_bar);
        this.setTitle("黄龙士文本编辑器");
        this.setVisible(true);
        this.setLocationRelativeTo(null);   //窗体位于正中间位置
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // EXIT_ON_CLOSE  https://www.cnblogs.com/lihaiming93/p/4752422.html 后续还要改,加上退出询问
    }

initMenuBar() - 初始化菜单栏

private void initMenuBar() {
        
        //初始化菜单栏
        menuBar = new JMenuBar();
        
        //file菜单项
        menu_File = new JMenu("文件(F)");
        menu_File.setMnemonic('f');     // 设置快捷键-alt+f:打开 - 也可以传入KeyEvent.VK_F
        item_new = new JMenuItem("新建");
        item_newwindow = new JMenuItem("新窗口");
        item_open = new JMenuItem("打开");
        item_save = new JMenuItem("保存");
        item_save.setAccelerator(KeyStroke.getKeyStroke('S',java.awt.Event.CTRL_MASK,false));//给item添加快捷键 CTRL_MASK = ctrl键
        item_exit = new JMenuItem("退出");
        menu_File.add(item_new);
        menu_File.add(item_newwindow);
        menu_File.add(item_open);
        menu_File.add(item_save);
        menu_File.add(item_exit);

        //edit菜单项
        menu_Edit = new JMenu("编辑(E)");
        menu_Edit.setMnemonic('e');
        item_undo = new JMenuItem("撤销");
        item_redo = new JMenuItem("恢复");
        item_cut = new JMenuItem("剪切");
        item_copy = new JMenuItem("复制");
        item_stick = new JMenuItem("粘贴");
        item_delete = new JMenuItem("删除");
        menu_Edit.add(item_undo);
        menu_Edit.add(item_redo);
        menu_Edit.add(item_cut);
        menu_Edit.add(item_copy);
        menu_Edit.add(item_stick);
        menu_Edit.add(item_delete);
         
        //help菜单项
        menu_Help = new JMenu("帮助(H)");
        menu_Help.setMnemonic('h');
        item_about = new JMenuItem("关于");
        menu_Help.add(item_about);

        //format菜单项
        menu_Format = new JMenu("格式(O)");
        menu_Format.setMnemonic('o');
        item_word_format = new JMenuItem("字体(F)");          //CTRL_MASK = ctrl键
item_word_format.setAccelerator(KeyStroke.getKeyStroke('F',java.awt.Event.CTRL_MASK,false));//给item添加快捷键
        menu_Format.add(item_word_format);

        //加入菜单栏
        menuBar.add(menu_File);
        menuBar.add(menu_Edit);
        menuBar.add(menu_Format);
        menuBar.add(menu_Help);
    }

initEditText() - 初始化文本区域

private void initEditText() {
        
        edit_text_area = new JTextArea();
        scroll_bar = new JScrollPane(edit_text_area);
        //垂直滚动条总是出现 - 自动出现:JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED||VERTICAL_SCROLLBAR_ALWAYS
        scroll_bar.setRowHeaderView(new LineNumberHeaderView());        //显示行号
        // 具体显示行号类:https://blog.csdn.net/wangjianyu0115/article/details/50780269
        
    scroll_bar.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
  scroll_bar.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        
        um = new UndoManager();
        clipboard = this.getToolkit().getSystemClipboard();
    }

saveFile - 保存文件

private void saveFile() {
        // TODO Auto-generated method stub

        File file =null;
        int result;     //int型值,showSaveDialog返回值用来判断用户是否选择了文件或路径。
        fileChooser = new JFileChooser("C:\\Users\\62473\\Desktop\\");  //打开用户默认目录
        result = fileChooser.showSaveDialog(rootPane); // 设置Dialog的根View根布局 显示对话框
        
        if(result == JFileChooser.APPROVE_OPTION) {
            file = fileChooser.getSelectedFile(); // 若点击了确定按钮,给file填文件路径
        }
        else return;    //按取消键后不会运行下面代码
        
        try{
            OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(file),"UTF-8"); // 对字符进行编码转换 输出流
            BufferedWriter writer = new BufferedWriter(write);
            for (String value : edit_text_area.getText().split("\n")) {     // 实现在JTextArea多行如何转换到实际文本多行
                writer.write(value);
                writer.newLine();//换行
            }
            writer.close();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
    }

openfile() - 打开文件

private void openFile() {
    
        File file =null;
        int result;
        fileChooser =new JFileChooser("C:\\Users\\62473\\Desktop\\");
        result = fileChooser.showOpenDialog(rootPane);
        
        if(result == JFileChooser.APPROVE_OPTION) {
            file = fileChooser.getSelectedFile(); // 若点击了确定按钮,给file填文件路径
        }
        else return;    //按取消键后不会运行下面代码
    
        if(file.isFile() && file.exists()) {
            try {
                edit_text_area.setText("");     //清空目前文本内容
                InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(file),"UTF-8");
                BufferedReader reader = new BufferedReader(inputStreamReader);
                String readLine;
                while ((readLine = reader.readLine()) != null) {
                    edit_text_area.append(readLine+'\n');
                }
                reader.close();
            } 
            catch (IOException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    
    }

actionPerformed(ActionEvent e) - 监听事件响应

public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        //https://zhidao.baidu.com/question/2204274734088183468.html
        
        if(e.getSource()==item_about)
        {
            new helpWindow();
        }
        else if (e.getSource()==item_word_format) {
            new aboutFormat();
        }
        else if (e.getSource()==item_new) {
            this.saveFile();        //新建文件前保存原文件
            new TextEditor();
            this.dispose();     
        }
        else if (e.getSource()==item_newwindow) {
            new TextEditor();       //添加新窗口,父窗口不会退出
        }
        else if (e.getSource()==item_exit){
            this.saveFile();
            this.dispose();         //退出询问(目前有无更改都会弹出保存窗口)
        }
        else if (e.getSource()==item_save) {
            this.saveFile();
        }
        else if (e.getSource()==item_open) {
            this.openFile();
        }
        else if (e.getSource()==item_undo&&um.canUndo()) {      //撤销可以撤销是撤销上一步文本操作
            um.undo();
        }
        else if (e.getSource()==item_redo&&um.canRedo()) {      //恢复就是恢复上一步文本操作(需要被撤销)
            um.redo();
        }
        else if (e.getSource()==item_copy) {
            String temptext = edit_text_area.getSelectedText();     //得到选取文本
            StringSelection editText = new StringSelection(temptext);   //创建能传输指定 String 的 Transferable
            clipboard.setContents(editText,null);       // 将剪贴板的当前内容设置到指定的 transferable 对象,
                                                        // 并将指定的剪贴板所有者作为新内容的所有者注册。
        }
        else if (e.getSource()==item_cut) {
            String temptext = edit_text_area.getSelectedText();
            StringSelection editText = new StringSelection(temptext);
            clipboard.setContents(editText,null);
            int start= edit_text_area.getSelectionStart();      //复制+删除
            int end  = edit_text_area.getSelectionEnd(); 
            edit_text_area.replaceRange("",start,end);
        }
        else if (e.getSource()==item_stick) {
            Transferable contents = clipboard.getContents(this);
            DataFlavor  flavor= DataFlavor.stringFlavor;
            if( contents.isDataFlavorSupported(flavor))
            {
                try
                {  
                    String str;
                    str = (String)contents.getTransferData(flavor);
                    edit_text_area.append(str);
                }
                catch(Exception ex)
                {
                    ex.printStackTrace();
                }
            }
        }
        else if (e.getSource()==item_delete) {
            int start= edit_text_area.getSelectionStart();      //删除
            int end  = edit_text_area.getSelectionEnd(); 
            edit_text_area.replaceRange("",start,end);
        }
    }

initListener() - 初始化监听器

public void initListener()
    {
        // 菜单iter监听
        item_new.addActionListener(this);
        item_newwindow.addActionListener(this);
        item_open.addActionListener(this);
        item_save.addActionListener(this);
        item_exit.addActionListener(this);
        item_undo.addActionListener(this);
        item_redo.addActionListener(this);
        item_cut.addActionListener(this);
        item_copy.addActionListener(this);
        item_stick.addActionListener(this);
        item_delete.addActionListener(this);
        item_word_format.addActionListener(this);
        item_about.addActionListener(this);
        
        //注册撤销/恢复可编辑监听器
        edit_text_area.getDocument().addUndoableEditListener(new UndoableEditListener(){        
            public void undoableEditHappened(UndoableEditEvent e) {
                um.addEdit(e.getEdit());
            }
        });
        
    }

getEdit_text_area() - 静态get函数得到文本区域

public static JTextArea getEdit_text_area() {
    //返回文本编辑区给其他窗口
        return edit_text_area;
    }

main() - main函数

public static void main(String[] args) {
        
        TextEditor test = new TextEditor();
    
    }
    
}

aboutFormat - 字体窗口实现

<JAVA - 大作业(1)文本编辑器 >_第2张图片

字体窗口属性

public class aboutFormat extends JFrame implements ItemListener,ActionListener {

    private JComboBox choose_word_style;    //下拉列表
    private JComboBox choose_word_big;
    private JComboBox choose_word_pattern;
    private JComboBox choose_word_color;
    
    private String[] styles = {"宋体","黑体","楷体","微软雅黑","隶书"};
    private String[] colors = {"黑色","蓝色","绿色","红色","白色","黄色"};
    private String[] word_big = {"2","4","8","16","24","32","64","72"};
    private String[] pattern = {"常规","倾斜","粗体"};
    
    private JPanel paneNorth;//用于装四个ComboBox
    private JPanel paneCenter;//用来装演示区
    private JPanel paneSouth;//用来装按钮
    
    private JTextField showText;//演示文本
    
    private JButton btn_ok;     
    private JButton btn_cancel;
    
    private Font selectedFont = TextEditor.getEdit_text_area().getFont();   //用来封装改变的属性
    private String selectedStyle = "宋体";        //默认字体属性
    private int selectedBig = 32;
    private int selectedPattern = Font.PLAIN;
    private Color selectedColor = TextEditor.getEdit_text_area().getForeground();   //颜色要单独加上改

字体窗口构造器

public aboutFormat() {
          initBox();
          initText();
          initButton();
          initLocation();
          initListener();
          addBtnListener();
          
          this.setSize(550,240);
          this.setTitle("文字格式");
          this.setVisible(true);
          this.setLocationRelativeTo(null);
          this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      }

addBtnListener() - 注册监听

private void addBtnListener() {
        // TODO Auto-generated method stub      //注册按钮监听
        btn_cancel.addActionListener(this);
        btn_ok.addActionListener(this);
    }

initListener() - 初始化监听器

private void initListener() {       //注册下拉框监听
        // TODO Auto-generated method stub
        choose_word_style.addItemListener(this);
        choose_word_big.addItemListener(this);
        choose_word_pattern.addItemListener(this);
        choose_word_color.addItemListener(this);
    }

initButton() - 初始化按钮

private void initButton() {
        // TODO Auto-generated method stub
        btn_ok = new JButton("OK");
        btn_cancel = new JButton("CANCEL");
    }

initText() - 初始化演示文本

private void initText() {
        // TODO Auto-generated method stub
        showText = new JTextField("字体展示");
        showText.setHorizontalAlignment(JTextField.CENTER); //文本居中
        showText.setFont(selectedFont);
        showText.setEditable(false);    //不可编辑
        showText.setSize(200,200);
//      showText.setForeground(Color.green);//字体颜色
    }

initLocation() - 初始化布局

/**
       * 初始化布局
       * 将每个控件按照一定得布局排在this窗口中
       */
      public void initLocation() {
          paneNorth = new JPanel();
          paneNorth.add(new JLabel("字体:")); //添加下拉区
          paneNorth.add(choose_word_style);
          paneNorth.add(new JLabel("字号:"));
          paneNorth.add(choose_word_big);
          paneNorth.add(new JLabel("字形:"));
          paneNorth.add(choose_word_pattern);
          paneNorth.add(new JLabel("颜色:"));
          paneNorth.add(choose_word_color);
          paneNorth.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); //让add的组件不置顶
          this.add(paneNorth,BorderLayout.NORTH);
          
          paneCenter = new JPanel();    //添加展示区
          paneCenter.add(showText);
          
          this.add(paneCenter, BorderLayout.CENTER);    //添加按钮去
          paneSouth = new JPanel();
          paneSouth.add(btn_ok);
          paneSouth.add(btn_cancel);
          this.add(paneSouth, BorderLayout.SOUTH);
          
      }

initBox() - 初始化下拉栏

/**
     * 初始化几个comboBox 
     * 把相应的选项加入
     */
  public void initBox() {
      choose_word_style = new JComboBox(styles);    //数组传入就不用addItem
      choose_word_big = new JComboBox(word_big);
      choose_word_pattern = new JComboBox(pattern);
      choose_word_color = new JComboBox(colors);
  }

actionPerformed(ActionEvent e) - 监听事件响应

@Override
    public void actionPerformed(ActionEvent e) {    //对按钮的监听
        // TODO Auto-generated method stub
        if (e.getSource() == btn_cancel) {
              this.dispose();//销毁当前窗口
        }else if (e.getSource() == btn_ok) { // 调用父窗体的实例,拿到text_area并对其setFont
        
            TextEditor.getEdit_text_area().setFont(selectedFont);   //改字体
            TextEditor.getEdit_text_area().setForeground(selectedColor);    //改字体颜色
            this.dispose();
        }
    }

itemStateChanged(ItemEvent e) - 下拉栏的监听

@Override
    public void itemStateChanged(ItemEvent e) { //对下拉框的监听
        // TODO Auto-generated method stub
        if (e.getItem() == "宋体") {
              selectedStyle = "宋体";
              renewFont();
          }else if (e.getItem() == "黑体") {
              selectedStyle = "黑体";
              renewFont();
          }else if (e.getItem() == "楷体") {
              selectedStyle = "楷体";
              renewFont();
          }else if (e.getItem() == "微软雅黑") {
              selectedStyle = "微软雅黑";
              renewFont();
          }else if (e.getItem() == "隶书") {
              selectedStyle = "隶书";
              renewFont();
          }else if (e.getItem() == "常规") {
              selectedPattern = Font.PLAIN;
              renewFont();
          }else if (e.getItem() == "倾斜") {
              selectedPattern = Font.ITALIC;
              renewFont();
          }else if (e.getItem() == "粗体") {
              selectedPattern = Font.BOLD;
              renewFont();
          }else if (e.getItem() == "2") {
              selectedBig = 2;
              renewFont();
          }else if (e.getItem() == "4") {
              selectedBig = 4;
              renewFont();
          }else if (e.getItem() == "8") {
              selectedBig = 8;
              renewFont();
          }else if (e.getItem() == "16") {
              selectedBig = 16;
              renewFont();
          }else if (e.getItem() == "24") {
              selectedBig = 24;
              renewFont();
          }else if (e.getItem() == "32") {
              selectedBig = 32;
              renewFont();
          }else if (e.getItem() == "64") {
              selectedBig = 64;
              renewFont();
          }else if (e.getItem() == "72") {
              selectedBig = 72;
              renewFont();
          }else if (e.getItem() == "红色") {
              selectedColor = Color.red;
              renewFont();
          }else if (e.getItem() == "黑色") {
              selectedColor = Color.black;
              renewFont();
          }else if (e.getItem() == "蓝色") {
              selectedColor = Color.blue;
              renewFont();
          }else if (e.getItem() == "黄色") {
              selectedColor = Color.yellow;
              renewFont();
          }else if (e.getItem() == "绿色") {
              selectedColor = Color.green;
              renewFont();
          }else if (e.getItem() == "白色") {
              selectedColor = Color.WHITE;
              renewFont();
          }
    }

renewFont() - 更改默认字体

private void renewFont() {
        // TODO Auto-generated method stub
        selectedFont = new Font(selectedStyle,selectedPattern,selectedBig);
        showText.setFont(selectedFont);
        showText.setForeground(selectedColor);
    }

}

helpWindow - 帮助窗口实现

<JAVA - 大作业(1)文本编辑器 >_第3张图片

帮助窗口属性

public class helpWindow extends JFrame {

    private JButton btn_ok;
    private JLabel about_label;
 
    private JPanel panel ;
    private BoxLayout boxlayout;    //指定在容器中是否对控件进行水平或者垂直放置

帮助窗口构造器

    public helpWindow() {
        panel = new JPanel();   //轻量级面板容器
        boxlayout = new BoxLayout(panel,BoxLayout.Y_AXIS);  //Y_AXIS - 控件垂直放置
        panel.setLayout(boxlayout);
        
        btn_ok = new JButton("OK");
        btn_ok.setAlignmentX(CENTER_ALIGNMENT); //alignment对齐
//      about_label = new JLabel("https://www.cnblogs.com/ymjun/");
        about_label = new JLabel("

黄龙士文本编辑器

" //JLabel里面可以嵌入html + "blog:https://www.cnblogs.com/ymjun/
" + "github:https://github.com/iym070010
" + "email:[email protected]
" + "使用方式跟.txt文本编辑器一致
" + "

" + "",JLabel.CENTER); about_label.setAlignmentX(CENTER_ALIGNMENT); panel.add(about_label); panel.add(btn_ok); this.add(panel); this.setSize(400,300); this.setTitle("关于"); this.setVisible(true); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); btn_ok.addActionListener(e->{ //窗口关闭 this.dispose(); }); } }

LineNumberHeaderView - TextArea行数显示插件

  • 直接从网上拿的,网址:JTextArea行号显示工具类

  • 貌似就是Notepad++的行号显示实现类,效果几乎一模一样

//package com.ui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
//TEXTAREA 行号显示插件
public class LineNumberHeaderView extends javax.swing.JComponent {      //貌似就是Notepad++行号显示的实现类
 
    /**
     * JAVA TextArea行数显示插件
     */
    private static final long serialVersionUID = 1L;
    private final  Font DEFAULT_FONT = new Font(Font.MONOSPACED, Font.PLAIN, 11);
    public final Color DEFAULT_BACKGROUD = new Color(228, 228, 228);
    public final Color DEFAULT_FOREGROUD = Color.BLACK;
    public final int nHEIGHT = Integer.MAX_VALUE - 1000000;
    public final int MARGIN = 5;
    private int lineHeight;
    private int fontLineHeight;
    private int currentRowWidth;
    private FontMetrics fontMetrics;
 
    public LineNumberHeaderView() {
        setFont(DEFAULT_FONT);
        setForeground(DEFAULT_FOREGROUD);
        setBackground(DEFAULT_BACKGROUD);
        setPreferredSize(9999);
    }
 
    public void setPreferredSize(int row) {
        int width = fontMetrics.stringWidth(String.valueOf(row));
        if (currentRowWidth < width) {
            currentRowWidth = width;
            setPreferredSize(new Dimension(2 * MARGIN + width + 1, nHEIGHT));
        }
    }
 
    @Override
    public void setFont(Font font) {
        super.setFont(font);
        fontMetrics = getFontMetrics(getFont());
        fontLineHeight = fontMetrics.getHeight();
    }
 
    public int getLineHeight() {
        if (lineHeight == 0) {
            return fontLineHeight;
        }
        return lineHeight;
    }
 
    public void setLineHeight(int lineHeight) {
        if (lineHeight > 0) {
            this.lineHeight = lineHeight;
        }
    }
 
    public int getStartOffset() {
        return 4;
    }
 
    @Override
    protected void paintComponent(Graphics g) {
        int nlineHeight = getLineHeight();
        int startOffset = getStartOffset();
        Rectangle drawHere = g.getClipBounds();
        g.setColor(getBackground());
        g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height);
        g.setColor(getForeground());
        int startLineNum = (drawHere.y / nlineHeight) + 1;
        int endLineNum = startLineNum + (drawHere.height / nlineHeight);
        int start = (drawHere.y / nlineHeight) * nlineHeight + nlineHeight - startOffset;
        for (int i = startLineNum; i <= endLineNum; ++i) {
            String lineNum = String.valueOf(i);
            int width = fontMetrics.stringWidth(lineNum);
            g.drawString(lineNum + " ", MARGIN + currentRowWidth - width - 1, start);
            start += nlineHeight;
        }
        setPreferredSize(endLineNum);
    }
}

你可能感兴趣的:()