<JAVA - 大作业(1)文本编辑器 >
<JAVA - 大作业(1)文本编辑器 >
背景
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); 
- 先将文本区域的文本放到string里面,创建能传输指定 String 的 StringSelection,把系统剪切板的内容设置成StringSelection:
 粘贴:
- 先将系统剪切板的内容放在一个Transferable里面,之后再将Transferable转成string,文本区域append即可
 
删除
- getSelectionStart,getSelectionEnd得到头尾,再replaceRange替换成空文本即可
 
格式菜单子栏:
- 字体
- 新建一个窗体设置字体,用JComboBox实现下拉列表,一个JTextField放演示文本,再是确认取消按钮,三个JPanel分别装这三部分整理布局排版,确认按钮点击后就调用静态get函数得到父窗体的文本区域设置其属性。
 
 
- 字体
 帮助菜单子栏:
- 关于
- 弹出一个新窗体,里面用label写文本显示
 
 
- 关于
 
TextEdition - 主窗体类实现

主窗体属性
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 - 字体窗口实现

字体窗口属性
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 - 帮助窗口实现

帮助窗口属性
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("<html><br /><h3 style='text-align:center;color:brown;'>黄龙士文本编辑器</h3>"	//JLabel里面可以嵌入html
				+ "blog:https://www.cnblogs.com/ymjun/<br />"
				+ "github:https://github.com/iym070010<br />"
				+ "email:iym070010@163.com<br />"
				+ "使用方式跟.txt文本编辑器一致<br />"
				+ "<br /><br />"
				+ "</html>",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);
    }
}
												
											<JAVA - 大作业(1)文本编辑器 >的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
		
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
 - 利用ssh反向代理以及autossh实现从外网连接内网服务器
		
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
 - 外网访问内网Docker容器
		
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
 - 外网访问内网SpringBoot
		
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
 - 外网访问内网Elasticsearch WEB
		
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
 - 怎样从外网访问内网Rails
		
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
 - 怎样从外网访问内网Memcached数据库
		
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
 - 怎样从外网访问内网CouchDB数据库
		
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
 - 怎样从外网访问内网DB2数据库
		
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
 - 怎样从外网访问内网OpenLDAP数据库
		
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
 
随机推荐
- 洛谷 P1049 装箱问题(01背包)
			
一道水题,但看到好久没有发博客了,再一看是一道noip普及组t4,就做了. 题目链接 https://www.luogu.org/problemnew/show/P1049 解题思路 一道裸的01背包 ...
 - 1233: [Usaco2009Open]干草堆tower
			
传送门 感觉正着做不太好搞,考虑倒过来搞 容易想到贪心,每一层都贪心地选最小的宽度,然后发现 $WA$ 了... 因为一开始多选一点有时可以让下一层宽度更小 然后有一个神奇的结论,最高的方案一定有一种 ...
 - NGUI的widget的使用
			
一,我们看看widget有什么属性,如下图: 二,Pivot是什么意思? 我们都知道在Untiy3D中有一个中央坐标点,而这个Pivot这个就是选择控件的某一个点与中央坐标点定位. 如下图区别: 当你 ...
 - JS的video在手机上有些手机能播放,而有些不能原因
			
一,一开始我video是这样写的,直接给地址,然后有很多手机却不能播放,或者说卡在一开始的页面,是什么原因呢? <video id='video' > <source src='xx ...
 - [JavaScript深入系列]JavaScript深入之执行上下文栈(转载)
			
顺序执行? 如果要问到 JavaScript 代码执行顺序的话,想必写过 JavaScript 的开发者都会有个直观的印象,那就是顺序执行,毕竟: var foo = function () { co ...
 - ubuntu下安装c man文档
			
http://www.mirrorservice.org/sites/sourceware.org/pub/gcc/libstdc%2b%2b/doxygen/ 下载 http://www.mirro ...
 - 微信小程序(13)--页面滚动到某个位置添加类效果
			
微信小程序页面滚动到某个位置添加类,盒子置顶效果. <!-- vh,是指CSS中相对长度单位,表示相对视口高度(Viewport Height),1vh = % * 视口高度 --> &l ...
 - ubuntu16.04的一系列安装
			
1.安装ubuntu https://blog.csdn.net/weixin_40494464/article/details/81010256 2.ubuntu里选择简体中文 https://bl ...
 - 两个对象值相同(x.equals(y)==true),hashcode也相同
			
不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同.Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同( ...
 - Mongodb使用shell实现与javascript的动态交互
			
关于利用mongodb的shell执行脚本,这点在以前的文章中有点遗漏:现在在此篇博客中做个补充: 一.在命令行中传入脚本文件 定义一个javasciprt文件,名称为:script1.js,内容如下 ...