今回は前回のやつをちょっと整理する。キャレットのところを除けばほぼパッケージをわけたぐらい。それで、キャレットに関する変更を説明する。まず、描画専用のHighlighterというクラスを作った。実際、これはinterfaceで、これを実装したクラスが描画を行う。決まりきった処理を行うメソッドはAbstractHighlighterで実装して、デフォルトのHighlighterであるDefaultHighlighterを作り、特に設定がなければこのクラスで描画を行う。次に変更したのは色の指定の仕方。プロパティファイルを用意して、そこから読み込まれるように変更。とはいっても、これを行ってるクラスはテスト用クラスなので、内容は適当だ。それらの変更を加えたクラスのソースを載せておく。
まずはCaretクラス。キャレットの位置とHighlighterを持つクラス。drwはHighlighterのdrawをそのまま呼んでるだけ
package hexedit.caret; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Color; public class Caret{ private int row; private int column; private int width; private boolean isHigh; private Highlighter highlighter; public Caret(int width){ row = 0; column = 0; this.width = width; isHigh = true; highlighter = new DefaultHighlighter(); highlighter.setBackgroundColor(new Color(0x60ffCC80, true)); highlighter.setRoundColor(new Color(0x60ffCC80, true)); } public void nextRow(){ row++; } public void beforeRow(){ if(row > 0) row--; } public void nextColumn(){ column++; if(column >= width){ column = 0; nextRow(); } } public void beforeColumn(){ column--; if(column < 0){ if(row == 0) column = 0; else column = width - 1; beforeRow(); } } public int getRow(){ return row; } public void setRow(int row){ this.row = row; } public int getColumn(){ return column; } public void setColumn(int column){ this.column = column; isHigh = true; } public boolean isHigh(){ return isHigh; } public void setHigh(boolean isHigh){ isHigh = isHigh; } public void setBackgroundColor(Color color){ highlighter.setBackgroundColor(color); } public void setRoundColor(Color color){ highlighter.setRoundColor(color); } public void draw(Graphics g, Rectangle rect){ highlighter.draw(g, rect); } }
次にHighlighter。これは、描画メソッドと色指定メソッドを定義している。
package hexedit.caret; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Color; public interface Highlighter{ void draw(Graphics g, Rectangle rect); void setBackgroundColor(Color color); void setRoundColor(Color color); }
次にAbstractHighlighter。色を表す変数を持たせ、色指定メソッドだけを実装している。
package hexedit.caret; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Color; public abstract class AbstractHighlighter implements Highlighter{ protected Color background; protected Color roundColor; public void setBackgroundColor(Color background){ this.background = background; } public void setRoundColor(Color roundColor){ this.roundColor = roundColor; } }
次にDefaultHighlighter。Graphics#setColorして、Graphics#fillRectしてるだけ。描画後に元の色に戻しておいたほうがいいのかもしれない
package hexedit.caret; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Color; public class DefaultHighlighter extends AbstractHighlighter{ public void draw(Graphics g, Rectangle rect){ g.setColor(background); g.fillRect(rect.x, rect.y, rect.width, rect.height); } }
次にHexEditor。paintComponentの内容が変わり、キャレットの描画はCaretを通してHighlighterに任せている。またキャレットの色を変更するメソッドを持たせた。
package hexedit.editor; import javax.swing.JComponent; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Point; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.event.KeyListener; import java.awt.event.KeyEvent; import hexedit.document.BinaryDocument; import hexedit.caret.Caret; public class HexEditor extends JComponent implements KeyListener{ private BinaryDocument document; private Caret caret; private static final String[] DATA_TABLE = new String[]{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" }; public HexEditor(){ this(new BinaryDocument()); } public HexEditor(BinaryDocument document){ this.document = document; caret = new Caret(16); int requireColumn = (document.getSize() / 16) + 10; setPreferredSize(new Dimension(16 * 26 + 8, requireColumn * 20)); setFocusable(true); addKeyListener(this); } public void paintComponent(Graphics g){ g.setFont(new Font("Monospaced", Font.PLAIN, 16)); g.setColor(Color.BLACK); int row = 128; int column = 16; for(int y = 0; y < row; y++){ for(int x = 0; x < column; x++){ int index = (y * column) + x; byte data = document.get(index); byte high = (byte)((data >> 4) & 0x0F); byte low = (byte)(data & 0x0F); g.drawString(DATA_TABLE[high], x * 26 + 8, (y + 1) * 20); g.drawString(DATA_TABLE[low], (x * 26) + 8 + 8, (y + 1) * 20); } } Rectangle caretRectangle = new Rectangle(caret.getColumn() * 26 + 6, caret.getRow() * 20 + 4, 22, 20); caret.draw(g, caretRectangle); } public void setCaretBackground(Color color){ caret.setBackgroundColor(color); } public void setCaretRoundColor(Color color){ caret.setRoundColor(color); } public void keyPressed(KeyEvent e){ switch(e.getKeyCode()){ case KeyEvent.VK_UP: caret.beforeRow(); break; case KeyEvent.VK_DOWN: caret.nextRow(); break; case KeyEvent.VK_LEFT: caret.beforeColumn(); break; case KeyEvent.VK_RIGHT: caret.nextColumn(); break; default: break; } repaint(); } public void keyTyped(KeyEvent e){} public void keyReleased(KeyEvent e){} }
次にBinaryDocument。ただ、パッケージ名が変わっただけ
package hexedit.document; public class BinaryDocument{ private int size; private int capacity; private byte[] contents; public BinaryDocument(){ this(0); } public BinaryDocument(int size){ this.size = size; this.capacity = (size * 13 / 10) + 10; this.contents = new byte[capacity]; } public void set(byte data, int index){ if(index >= capacity) reallocate(index); if(index > size) size = index; contents[index] = data; } public byte get(int index){ if(index >= size) return (byte)0; return contents[index]; } public byte[] gets(int index, int length){ byte[] data = new byte[length]; for(int i = 0; i < length; i++){ data[i] = get(index + i); } return data; } private void reallocate(int newSize){ capacity = (newSize * 13 / 10) + 10; byte[] newContents = new byte[capacity]; for(int i = 0; i < size; i++){ newContents[i] = contents[i]; } contents = newContents; size = newSize; } public int getSize(){ return size; } }
次にMain。XML形式のプロパティファイルを読み込んで、Caretの色を指定するようにした。
import javax.swing.JFrame; import javax.swing.JScrollPane; import java.awt.Color; import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.util.Properties; import hexedit.editor.HexEditor; import hexedit.document.BinaryDocument; import hexedit.caret.Caret; public class Main{ public static void main(String[] args) throws IOException{ BinaryDocument document = new BinaryDocument(10); int index = 0; int n; byte[] data = new byte[1024]; BufferedInputStream in = new BufferedInputStream(new FileInputStream("./Main.java")); while((n = in.read(data, 0, 1024)) > 0){ for(int i = 0; i < n; i++){ document.set(data[i], index++); } } Properties properties = new Properties(); properties.loadFromXML(new FileInputStream("config.properties")); HexEditor editor = new HexEditor(document); Color color = new Color(Integer.parseInt(properties.getProperty("HexEdit.Caret.BackgroundColor"), 16), true); editor.setCaretBackground(color); JFrame frame = new JFrame(); frame.add(new JScrollPane(editor)); frame.setSize(600, 500); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
最後にconfig.properties。XML形式のプロパティファイル。キャレットの色を16進数のARGB形式で指定する
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>HexEdit Properties</comment> <entry key="HexEdit.Caret.BackgroundColor">6066CCff</entry> <entry key="HexEdit.Caret.RoundColor">6066CCff</entry> </properties>