ファイルを開く/保存する

広告

最後にファイルを保存したり、既存のファイルを開いたりします。今回のような書式付きの文書はRTF形式(リッチテキストフォーマット形式)で保存します。RTFはMicrosoft社が策定した、文字の大きさやフォント、字飾りなどの情報を埋め込むことができる文書形式ということです。

このような形式の文書を操作する為にRTFEditorKitクラスが用意されています。

public class RTFEditorKit
extends StyledEditorKit
java.lang.Object
 L javax.swing.text.EditorKit
     L javax.swing.text.DefaultEditorKit
         L javax.swing.text.StyledEditorKit
             L javax.swing.text.rtf.RTFEditorKit

コンストラクタは下記の1つが用意されています。

コンストラクタの概要
RTFEditorKit()
RTFEditorKit を構築します。

このクラスには、ファイルの読み込み用としてreadメソッドが、ファイルの保存用としてwriteメソッドが用意されています。

read:

このタイプのコンテンツハンドラに適合した書式であることが要求されるストリームに、コンテンツ
を挿入します。

パラメータ:
  in - 読み込み元のストリーム
  doc - 挿入先
  pos - コンテンツを配置するドキュメント内の位置
例外: 
  IOException - 入出力エラーが発生した場合
  BadLocationException - pos がドキュメント内の無効な位置を示す場合

write:

このタイプのコンテンツハンドラに適合した書式であることが要求されるストリームに、ドキュメン
トのコンテンツを適した形式でストリームに挿入します。

パラメータ:
  out - 書き込み先のストリーム
  doc - 書き込み元
  pos - コンテンツを取得するドキュメント内の位置
  len - 書き出す量 
例外:
  IOException - 入出力エラーが発生した場合
  BadLocationException - pos がドキュメント内の無効な位置を示す場合

readメソッドについての実際の使い方は下記のようになります。

StyleContext sc = new StyleContext();
DefaultStyledDocument doc = new DefaultStyledDocument(sc);

JTextPane textPane = new JTextPane();
textPane.setDocument(doc);

RTFEditorKit rtfEditor = new RTFEditorKit();

....

File fChoosen = ....;

try{
  InputStream in = new FileInputStream(fChoosen);
  rtfEditor.read(in, doc, 0);
  in.close();
}catch(Exception ex){
  ex.printStackTrace();
}

textPane.setDocument(doc);

writeメソッドについての実際の使い方は下記のようになります。

StyleContext sc = new StyleContext();
DefaultStyledDocument doc = new DefaultStyledDocument(sc);

JTextPane textPane = new JTextPane();
textPane.setDocument(doc);

RTFEditorKit rtfEditor = new RTFEditorKit();

....

File fChoosen = ....;

try{
  OutputStream out = new FileOutputStream(fChoosen);
  rtfEditor.write(out, doc, 0, doc.getLength());
  out.close();
}catch(Exception ex){
  ex.printStackTrace();
}

これに新規ファイルのメニューを加えたものが下記となります。詳しくは説明しませんが、ファイルの選択にはJFileChooserクラスとFileFilterクラスを使っています。最終的なファイルとしては、TextPaneTest.javaとRtfFilter.javaの2つのファイルにしました。

TextPaneTest.java :

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.text.rtf.RTFEditorKit;
import java.io.*;

public class TextPaneTest extends JFrame 
  implements ActionListener, CaretListener{

  protected JTextPane textPane;

  protected DefaultStyledDocument doc;
  protected StyleContext sc;

  protected JToolBar toolBar;

  protected JComboBox comboFonts;  /* Font選択 */
  protected JComboBox comboSizes;  /* Fontサイズ */
  protected JToggleButton toggleB; /* 強調 */
  protected JToggleButton toggleI; /* 斜体 */
  protected JToggleButton toggleU; /* アンダーライン */
  protected JToggleButton toggleS; /* 取り消し線 */
  protected JComboBox comboColor;  /* 前景色 */

  protected String currentFontName = "";
  protected int currentFontSize = 0;
  protected boolean flag = false;

  protected String[] colorHTML = {"#000000", "#0000FF", "#00FF00",
    "#00FFFF", "#FF0000", "#FF00FF", "#FFFF00", "#FFFFFF"};

  protected RTFEditorKit rtfEditor;

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

    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    test.setVisible(true);
  }

  TextPaneTest(){
    setTitle("TextPaneTest Test");
    setBounds( 10, 10, 500, 300);

    textPane = new JTextPane();
    JScrollPane scroll = new JScrollPane(textPane, 
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
      JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

    getContentPane().add(scroll, BorderLayout.CENTER);

    sc = new StyleContext();
    doc = new DefaultStyledDocument(sc);

    textPane.setDocument(doc);
    textPane.addCaretListener(this);

    /* ファイル操作用RTFEditorKit */
    rtfEditor = new RTFEditorKit();

    JMenuBar menuBar = createMenuBar();
    setJMenuBar(menuBar);

    initToolbar();
    getContentPane().add(toolBar, BorderLayout.NORTH);

    /* 初期文書の読み込み */
    initDocument();
  }

  protected JMenuBar createMenuBar(){
    JMenuBar menuBar = new JMenuBar();
    JMenu fileMenu = new JMenu("File", true);
    menuBar.add(fileMenu);

    JMenuItem newItem = new JMenuItem("New");
    fileMenu.add(newItem);
    newItem.addActionListener(this);
    newItem.setActionCommand("newItem");

    JMenuItem openItem = new JMenuItem("Open");
    fileMenu.add(openItem);
    openItem.addActionListener(this);
    openItem.setActionCommand("openItem");

    JMenuItem saveItem = new JMenuItem("Save");
    fileMenu.add(saveItem);
    saveItem.addActionListener(this);
    saveItem.setActionCommand("saveItem");

    fileMenu.addSeparator();

    JMenuItem exitItem = new JMenuItem("Exit");
    fileMenu.add(exitItem);
    exitItem.addActionListener(this);
    exitItem.setActionCommand("exitItem");

    return menuBar;
  }

  protected void initDocument(){
    StringBuffer sb = new StringBuffer();
    sb.append("スタイル付きのテキストサンプルです。¥n");
    sb.append("スタイルを変えて表示しています。");

    try{
      /* 文書を挿入する */
      doc.insertString(0, new String(sb), 
        sc.getStyle(StyleContext.DEFAULT_STYLE));
    }catch (BadLocationException ble){
      System.err.println("初期文書の読み込みに失敗しました。");
    }
  }

  protected void initToolbar(){
    toolBar = new JToolBar();
    toolBar.setLayout(new FlowLayout(FlowLayout.LEFT));

    /* フォント一覧の取得 */
    GraphicsEnvironment ge = 
      GraphicsEnvironment.getLocalGraphicsEnvironment();
    String familyName[] = ge.getAvailableFontFamilyNames();

    /* フォント選択用コンボボックス */
    comboFonts = new JComboBox(familyName);
    comboFonts.setMaximumSize(comboFonts.getPreferredSize());
    comboFonts.addActionListener(this);
    comboFonts.setActionCommand("comboFonts");
    toolBar.add(comboFonts);

    /* フォントサイズ選択用コンボボックス */
    comboSizes = new JComboBox(new String[] {"8", "9", "10", 
      "11", "12", "14", "16", "18", "20", "22", "24", "26", 
      "28", "36", "48", "72"});
    comboSizes.setMaximumSize(comboSizes.getPreferredSize());
    comboSizes.addActionListener(this);
    comboSizes.setActionCommand("comboSizes");
    toolBar.add(comboSizes);

    toolBar.addSeparator();

    /* 強調 選択用トグルボタン */
    toggleB = new JToggleButton("<html><b>B</b></html>");
    toggleB.setPreferredSize(new Dimension(26, 26));
    toggleB.addActionListener(this);
    toggleB.setActionCommand("toggleB");
    toolBar.add(toggleB);

    /* 斜体 選択用トグルボタン */
    toggleI = new JToggleButton("<html><i>I</i></html>");
    toolBar.add(toggleI);
    toggleI.addActionListener(this);
    toggleI.setActionCommand("toggleI");
    toggleI.setPreferredSize(new Dimension(26, 26));

    /* アンダーライン 選択用トグルボタン */
    toggleU = new JToggleButton("<html><u>U</u></html>");
    toolBar.add(toggleU);
    toggleU.addActionListener(this);
    toggleU.setActionCommand("toggleU");
    toggleU.setPreferredSize(new Dimension(26, 26));

    /* 取り消し線 選択用トグルボタン */
    toggleS = new JToggleButton("<html><s>S</s></html>");
    toolBar.add(toggleS);
    toggleS.addActionListener(this);
    toggleS.setActionCommand("toggleS");
    toggleS.setPreferredSize(new Dimension(26, 26));

    toolBar.addSeparator();

    /* 前景色用コンボボックス */
    DefaultComboBoxModel colorModel = new DefaultComboBoxModel();
    for (int i = 0 ; i < 8; i++){
      /* 色つきのラベルを作成する */
      StringBuffer sb = new StringBuffer();
      sb.append("<html><font color=¥"");
      sb.append(colorHTML[i]);
      sb.append("¥">■</font></html>");

      colorModel.addElement(new String(sb));
    }
    comboColor = new JComboBox(colorModel);
    comboColor.setMaximumSize(comboColor.getPreferredSize());
    comboColor.addActionListener(this);
    comboColor.setActionCommand("comboColor");
    toolBar.add(comboColor);
  }

  public void actionPerformed(ActionEvent e){
    if (flag){
      /* キャレット変更に伴うActionEventの場合はパスする */
      return;
    }

    String actionCommand = e.getActionCommand();

    if (actionCommand.equals("exitItem")){
      System.exit(0);
    }else if ((actionCommand.equals("newItem")) || 
      (actionCommand.equals("openItem")) ||
      (actionCommand.equals("saveItem"))){

      fileOperation(actionCommand);
    }else{
      MutableAttributeSet attr = new SimpleAttributeSet();

      if (actionCommand.equals("comboFonts")){
        /* フォント変更 */
        String fontName = comboFonts.getSelectedItem().toString();
        StyleConstants.setFontFamily(attr, fontName);
      }else if (actionCommand.equals("comboSizes")){
        /* フォントサイズ変更 */
        int fontSize = 0;
        try{
          fontSize = Integer.parseInt(comboSizes.
            getSelectedItem().toString());
        }catch (NumberFormatException ex){
          return;
        }

        StyleConstants.setFontSize(attr, fontSize);
      }else if (actionCommand.equals("toggleB")){
        /* 強調 */
        StyleConstants.setBold(attr, toggleB.isSelected());
      }else if (actionCommand.equals("toggleI")){
        /* 斜体 */
        StyleConstants.setItalic(attr, toggleI.isSelected());
      }else if (actionCommand.equals("toggleU")){
        /* アンダーライン */
        StyleConstants.setUnderline(attr, toggleU.isSelected());
      }else if (actionCommand.equals("toggleS")){
        /* 取り消し線 */
        StyleConstants.setStrikeThrough(attr, toggleS.isSelected());
      }else if (actionCommand.equals("comboColor")){
        /* 前景色 */
        int col = comboColor.getSelectedIndex();
        int b = (col % 2) * 255;
        int g = ((col / 2) % 2) * 255;
        int r = ((col / 4) % 2) * 255;

        StyleConstants.setForeground(attr, new Color(r, g, b));
      }else{
        return;
      }

      setAttributeSet(attr);
    }

    textPane.requestFocusInWindow();
  }

  protected void fileOperation(String actionCommand){
    JFileChooser chooser = new JFileChooser();
    RtfFilter filter = new RtfFilter();
    chooser.setFileFilter(filter);

    if (actionCommand.equals("newItem")){
      /* 新規ファイル */
      doc = new DefaultStyledDocument(sc);
      textPane.setDocument(doc);
    }else if (actionCommand.equals("openItem")){
      /* ファイルを開く */
      doc = new DefaultStyledDocument(sc);

      if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION){
        return;
      }

      File fChoosen = chooser.getSelectedFile();
      try{
        InputStream in = new FileInputStream(fChoosen);
        rtfEditor.read(in, doc, 0);
        in.close();
      }catch(Exception ex){
        ex.printStackTrace();
      }

      textPane.setDocument(doc);
    }else if (actionCommand.equals("saveItem")){
      /* ファイルの保存 */
      if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION){
        return;
      }

      File fChoosen = chooser.getSelectedFile();
      try{
        OutputStream out = new FileOutputStream(fChoosen);
        rtfEditor.write(out, doc, 0, doc.getLength());
        out.close();
      }catch(Exception ex){
        ex.printStackTrace();
      }
    }else{
      return;
    }
  }

  protected void setAttributeSet(AttributeSet attr) {
    /* 選択している文字のスタイルを変更する */

    int start = textPane.getSelectionStart();
    int end = textPane.getSelectionEnd();

    doc.setCharacterAttributes(start, end - start, attr, false);
  }

  public void caretUpdate(CaretEvent e){
    flag = true;

    int p = textPane.getSelectionStart();
    AttributeSet atrr = doc.getCharacterElement(p).getAttributes();

    String name = StyleConstants.getFontFamily(atrr);
    /* 変更前と同じ場合は無視する */
    if (!currentFontName.equals(name)){
      currentFontName = name;
      comboFonts.setSelectedItem(name);
    }

    int size = StyleConstants.getFontSize(atrr);
    /* 変更前と同じ場合は無視する */
    if (currentFontSize != size){
      currentFontSize = size;
      comboSizes.setSelectedItem(Integer.toString(size));
    }

    /* 強調/斜体/アンダーライン/取り消し線 の状態表示 */
    toggleB.setSelected(StyleConstants.isBold(atrr));
    toggleI.setSelected(StyleConstants.isItalic(atrr));
    toggleU.setSelected(StyleConstants.isUnderline(atrr));
    toggleS.setSelected(StyleConstants.isStrikeThrough(atrr));

    /* 前景色の状態表示 */
    Color col = StyleConstants.getForeground(atrr);
    int r = (col.getRed() / 255) * 4;
    int g = (col.getGreen() / 255) * 2;
    int b = col.getBlue() / 255;
    comboColor.setSelectedIndex(r + g + b);

    flag = false;
  }
}

RtfFilter.java :

import java.io.File;
import javax.swing.*;
import javax.swing.filechooser.*;

public class RtfFilter extends FileFilter{
  public boolean accept(File f) {
    if (f.isDirectory()) {
      return true;
    }

    /* 拡張子を取り出す */
    String ext = "";
    String s = f.getName();
    int i = s.lastIndexOf('.');
    if (i > 0 &&  i < s.length() - 1) {
      ext = s.substring(i + 1).toLowerCase();
    }

    if (ext.equals("rtf")){
      return true;
    } else {
      return false;
    }
  }
 
  public String getDescription() {
    return "RTF Only";
  }
}

実行結果は下記となります。

起動直後:

適当に編集します:

メニューからSaveを選びます:

ファイル選択画面にて保存先と保存ファイル名を指定します:

メニューからNewを選びます:

文書がクリアされます:

メニューからOpenを選びます:

ファイル選択画面にて開きたいファイル名を指定します:

保存していた文書が表示されます:

これで一応完成です。ちなみに先ほど保存したファイルをMicrosoftWordで開いてみると、下記のようにWordで開いても同じように表示することができます。

( Written by Tatsuo Ikura )

関連記事 (一部広告含む)