選択範囲のスタイルを変更する

広告

前のページではスタイルを色々設定してみましたが、ここでは自分で選択した範囲の文書を好きなスタイルに変更できるようにしてみます。その為には、スタイルを指定するボタンやコンボボックスを用意し、選択した範囲を取得できるようにする必要があります。

まず、選択した範囲を調べて見ます。JTextPane(実際にはその親クラスのJTextComponent)で用意されているgetSelectionStartメソッドとgetSelectionEndメソッドを使います。

getSelectionStart:

選択したテキストの開始位置を返します。ドキュメントが空の場合は 0、選択領域がない場合はドッ
トの値を返します。 

戻り値:
  開始位置 >= 0

getSelectionEnd:

選択したテキストの末尾位置を返します。ドキュメントが空の場合は 0、選択領域がない場合はドッ
トの値を返します。 

戻り値:
  末尾位置 >= 0

この2つのメソッドを使って今選択されている部分の位置を知ることができます。例えば下記のようなメソッドを用意しておき、引数に設定したいスタイル情報を持つ値を指定して呼び出すことで、現在の文書の選択されている場所のスタイルを設定することができます。

protected void setAttributeSet(AttributeSet attr) {
  int start = textPane.getSelectionStart();
  int end   = textPane.getSelectionEnd();

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

フォントとフォントサイズの指定

まず手始めにフォントとフォントサイズの変更から行ってみましょう。フォントとフォントサイズはどちらもコンボボックスで選択できるようにします。フォントの一覧はGraphicsEnvironmentクラスのgetAvailableFontFamilyNamesメソッドを使って一覧を取得しています。また指定できるフォントサイズは初期値として指定しています。

それぞれのコンボボックスの作成は下記のようになります。

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);

  toolBar.addSeparator();
  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);
}

それぞれのコンボボックスにはActionListenerを設定しています。コンボボックスが選択された処理としては下記のように記載します。

public void actionPerformed(ActionEvent e){
  String actionCommand = e.getActionCommand();
  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{
    return;
  }

  setAttributeSet(attr);
  textPane.requestFocusInWindow();
}

ここでは呼び出されたコンボボックスによって、スタイル情報を持つSimpleAttributeSetクラスのオブジェクト作成し、その後で実際に選択されている範囲の文書に対してスタイルを設定するめのメソッドを呼び出しています。

では、ここまでの分をまとめて試してみましょう。

import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.awt.*;

public class TextPaneTest extends JFrame implements ActionListener{

  protected JTextPane textPane;

  protected DefaultStyledDocument doc;
  protected StyleContext sc;

  protected JToolBar toolBar;

  protected JComboBox comboFonts;
  protected JComboBox comboSizes;

  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, 200);

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

    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);

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

  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);

    toolBar.addSeparator();
    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);
  }

  public void actionPerformed(ActionEvent e){
    String actionCommand = e.getActionCommand();
    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{
      return;
    }

    setAttributeSet(attr);
    textPane.requestFocusInWindow();
  }

  protected void setAttributeSet(AttributeSet attr) {
    int start = textPane.getSelectionStart();
    int end = textPane.getSelectionEnd();

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

実行結果は下記のようになります。

起動直後:

文書の一部を選択して

フォントを選択すると

フォントが変更されます

他の文書の一部を選択して

フォントサイズを選ぶと

フォントサイズが変更されます

一応これでスタイルの変更が少しできましたが、今変更しようとしている位置の文字が、現在どのフォントを使っていて何ポイントなのかが分かりません。次のページでは対応します。

( Written by Tatsuo Ikura )

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