国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

用Java制作十六進制編輯器

2019-11-18 13:29:38
字體:
來源:轉載
供稿:網友

  本人在用java編制一個網絡應用測試工具的時候,迫切希望能以十六進制方式顯示和編輯socket上傳輸的數據,于是自己動手寫了一個編輯器類,實現基本的十六進制編輯功能。效果如圖一、圖二所示,可以看到,編 
  輯器可以支持常規方式和十六進制兩種方式對數據進行編輯。
  分析:對于同一段數據值,用兩種方式來顯示和編輯,則用MVC(模型-視圖-控制器)模式來作為主結構是再合適不過的了。模型的作用是保存真實的數據值,同時提供若干提取和修改數據的方法;視圖是數據在用戶界面上的表示,控制器定義用戶界面對用戶輸入的響應方式,即把用戶的鍵盤動作和鼠標動作解釋成模型中的數據操作方法。出于簡化的考慮,本例中把視圖和控制器合并到了一起。
  模型的設計:編輯器必須能處理任意字節塊,所以考慮模型內用字節數組來存儲數據;要提供在指定偏移處增加、修改和刪除字節塊的操作;當模型內的數據被改變時要及時通知視圖來刷新用戶界面或其它感愛好的對象;
   用Java制作十六進制編輯器(圖一)
  圖一
   用Java制作十六進制編輯器(圖二)
  圖二
  
  視圖和控制器的設計:
  
  對于常規編輯的視圖,只需把模型中的字節數組轉化成String,使用一個文本區域組件JTextArea來顯示即可。JTextArea本身也是一個遵循MVC模式的Swing組件,它的控制器即可被用來作為我們自己的控制器,監聽它的文本增加、修改和刪除事件,從而控制我們自己的數據模型;
  
  對于16進制編輯的視圖,同樣可以用JTextArea來顯示,只是在顯示之前,要對模型中的數據進行若干加工,如每行顯示16個字節,每行都要加表示偏移量的頭,行尾要加這一行數據的字符串表示形式。它的控制器則不能簡單的利用JTextArea的控制器了,為了保證顯示格式不被打亂,需要監視它的所有光標移動事件、鍵盤擊鍵事件等。同時,為了保持與UltraEdit的十六進制編輯器的功能一致性,對它的數據的增加、刪除功能提供兩個按鈕,詢問用戶操作的字節數,假如增加n個字節,則在輸入光標處插入n個十六進制值為20的字符(字符空格)。
  十六進制編輯器的主要結構請參見下圖,由于篇幅關系,圖中只列出了十六進制編輯部分,常規編輯部分請讀者自行設計:
  用Java制作十六進制編輯器(圖三)
  圖三
  
  下面分別就幾個主要的方法的功能和主要流程加以說明。
  
  HeXPane.displayValue方法,它主要完成數據的顯示工作:
  
  public void diplayValue() {
  
  canvas.setText("");
  
  
  byte[] data = model.getData();
  
  int dataLen = data.length;
  
  
  // 把字節數組按每16個字節為一塊進行分塊;
  
  int lines = dataLen / 16 + 1;
  
  int tails = dataLen % 16;
  
  int offset = 0;
  
  for(int i = 0; i < lines; i ++) {
  
  // 在canvas的新行上加上行標,如“000020:”,表示這是第3行;
  
  canvas.append(lineHead(i));
  
  canvas.append(" ");
  
  // 把數據塊的字節值用Integer.toHexString()轉化成長度為48的字符串,數據塊不足16個字節的,在字符串后用空格補足;把字符串加入canvas的當前行;
  
  for(offset = 0; offset < 16; offset ++) {
  
  canvas.append((i < lines - 1 offset < tails) ? byteHex(data[i * 16 + offset]) : " ");
  
  canvas.append(" ");
  
  }
  
  canvas.append(" ");
  
  
  // 把數據塊構造成字符串,添在canvas的行尾;
  
  canvas.append(bytesToStr(data, i * 16, (i == lines - 1) ? tails : 16));
  
  if(i < lines - 1) ta.append("/n");
  
  };
  
  }
  這里的bytesToStr方法有兩點非凡需要注重的地方,一是不可見字符,假如不屏蔽這些字符,則我們的編輯器的顯示格式會被搞得亂七八糟,一般可以把ASCII值0到0x1F和0x7F的33個字符全部替換成0x2E,即字符小數點。二是中文字符,因為每個中文字符是2個字節,假如數據塊的起始字節一個中文字符的一半(可以用ASCII值大于0x7F來判定)的時候,將會顯示一串亂字符,處理方法是不顯示該字節。
  為敘述方便,我們把canvas中顯示每一行的行標的區域稱為標號區,它寬度固定為8個字符(6個字符顯示標號,一個冒號和一個空格);把canvas中顯示十六進制數據的區域稱為數據區,寬度固定為48個字符(每字節用十六進制顯示為2字符寬,兩兩之間有一個空格,則總寬為16×3);把canvas中每行以字符串形式顯示數據的區域稱為字串值區,寬度不定(最短為8個字符――全中文狀態,最長為16個字符――全英文狀態)。
  
  我們的canvas是一個Swing的文本組件,我們不但用它顯示數據,還顯示標號和字串值,而只有數據才是答應被編輯的,所以我們給canvas增加了CaretListener和KeyListener,當輸入光標落在不答應編輯的區域時,我們要把光標自動移到最近的答應編輯的地方去。
  
  public void caretUpdate(CaretEvent e) { // 這個方法在輸入光標移動時被觸發
  
  int pos = canvas.getCaretPosition(); // 輸入光標相對canvas第0行第0個字符的偏移量
  
  int line = 0;
  
  int startPos = 0;
  
  try {
  
  line = canvas.getLineOfOffset(pos); // 輸入光標位于第幾行
  
  startPos = canvas.getLineStartOffset(line); // 當前行的第0個字符相對canvas第0行第0個字符的偏移量
  
  }catch(BadLocationException exception) { }
  
  if(pos - startPos < 8) // 輸入光標在標號區
  
  canvas.setCaretPosition(startPos + 8); // 移動到數據區第0個字符
  
  else if(pos - startPos > 54) // 輸入光標在字串值區
  
  canvas.setCaretPosition(startPos + 54); // 移動到數據區最后一個字節
  
  else if((pos - startPos - 8) % 3 == 2) { // 在數據區的間隙空格上
  
  canvas.setCaretPosition(pos - 1); // 往前移一個字符
  
  }
  
  }
  public void keyPRessed(KeyEvent e) { // 當鍵盤被按下時觸發
  
  int key = e.getKeyCode();
  
  switch(key) { // 假如是方向鍵則移動輸入光標
  
  case KeyEvent.VK_LEFT:
  
  setCaretPrev();
  
  break;
  
  case KeyEvent.VK_RIGHT:
  
  setCaretNext();
  
  break;
  
  case KeyEvent.VK_UP:
  
  setCaretPrevLine();
  
  break;
  
  case KeyEvent.VK_DOWN:
  
  setCaretNextLine();
  
  break;
  
  default:
  
  return;
  
  }
  
  }
  public void keyTyped(KeyEvent e) { // 在鍵盤的可見字符被輸入時觸發
  
  char ch = e.getKeyChar();
  
  if((ch >= '0' && ch <= '9') (ch >= 'a' && ch <= 'f')
  
   (ch >= 'A' && ch <= 'F')) {
  
  int pos = canvas.getCaretPosition(); // 先獲取光標位置的信息
  
  int line = 0, startPos = 0;
  
  try {
  
  line = canvas.getLineOfOffset(pos);
  
  startPos = canvas.getLineStartOffset(line);
  
  }catch(BadLocationException exception) { }
  
  char c = (char)0;
  
  if((pos - startPos - 8) % 3 == 0) { // 一個字節值的前4位
  
  c = canvas.getText(pos + 1, 1).charAt(0);
  
  model.updateBytes(line * 16 + (pos - startPos - 8) / 3, Byte.parseByte("" + (char)((ch << 4) + c), 16));
  
  }else{ // 一個字節值的后4位
  
  c = canvas.getText(pos - 1, 1).charAt(0);
  
  model.updateBytes(line * 16 + (pos - startPos - 8) / 3, Byte.parseByte("" + (char)((c << 4) + ch), 16));
  
  setCaretNext();
  
  }
  
  }
  
  }
  
  到這里為止,十六進制編輯的顯示和輸入控制已經基本完成了,下面開始解決數據Model的問題。Model是用來保存數據的,并且提供增加、修改和刪除數據的方法,還要維護一個監聽者組,在數據被改變時向監聽者發出通知。這里提供一個簡單的實現版本。
  import javax.swing.event.EventListenerList;
  
  
  public class DefaultBytesModel implements BytesModel{
  
  private EventListenerList listeners = new EventListenerList(); // 監聽者組
  
  private byte[] data = null;
  
  
  public DefaultBytesModel (byte[] bytes) {
  
  data = new byte[bytes.length];
  
  }
  
  
  public void addModelListener(BytesModelListener listener) {
  
  listeners.add(BytesModelListener.class, listener);
  
  }
  
  
  public void removeModelListener(BytesModelListener listener) {
  
  listeners.remove(BytesModelListener.class, listener);
  
  }
  
  
  /**
  
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 武宁县| 屯门区| 南江县| 无为县| 蕉岭县| 莲花县| 万源市| 洛川县| 福泉市| 怀安县| 九江县| 丰城市| 铜陵市| 衡水市| 秀山| 囊谦县| 利辛县| 平利县| 莱芜市| 哈密市| 康保县| 汝南县| 揭西县| 威远县| 聂拉木县| 绥滨县| 绥芬河市| 武陟县| 西华县| 桐庐县| 特克斯县| 衡水市| 改则县| 临沂市| 临夏县| 通化县| 中阳县| 青浦区| 泊头市| 馆陶县| 中阳县|