javax.swing.text.JTextComponentのサブクラスで使える操作を確認します。
テキストコンポーネントがサポートするコマンドセットは、getActions() メソッドで取得できます。
この戻り値は、javax.swing.Actionの配列です。(実質的にはTextAction)
この配列内容を列挙、表示するためのソースコードを以下に示します。
Actionの配列の各要素は、Actionインターフェイスの実装済みオブジェクトになっています。
Actionインターフェイスは、ActionListenerンターフェイスを継承(extends)したもので、JTextComponentなどの機能設定に使われます。
つまり、列挙されたこれらの能力も持っていることになります。
import java.awt.*; import javax.swing.*; public class Test extends JFrame { JTextPane jtext = new JTextPane(); Test() {//コンストラクタ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.jtext.setPreferredSize(new Dimension(160,120)); this.getContentPane().add(jtext, BorderLayout.CENTER); this.pack(); this.setVisible(true); Action[] array = this.jtext.getActions(); for(int i = 0; i < array.length; i++){ String name = (String)array[i].getValue(Action.NAME); String sub = (String)array[i].getValue(Action.ACCELERATOR_KEY); System.out.println(name+":"+sub); } } public static void main(String[] args) { new Test(); } }
これが実行した時の画面で、Actionの配列の出力結果はコンソールにでます。
上記実行で得られるコンソール表示内容を示します。(jre 1.6.0_246を使用時)
set-read-only:null selection-down:null selection-begin-line:null delete-previous-word:null font-size-48:null select-word:null selection-page-right:null font-family-Serif:null select-all:null font-size-8:null selection-page-down:null font-size-36:null insert-content:null left-justify:null selection-previous-word:null selection-page-up:null toggle-componentOrientation:null selection-end-word:null insert-break:null caret-end-word:null center-justify:null page-up:null font-size-24:null beep:null font-family-Monospaced:null selection-page-left:null selection-begin-word:null right-justify:null delete-previous:null caret-begin-line:null font-underline:null delete-next-word:null font-size-18:null font-size-16:null selection-forward:null caret-forward:null font-size-14:null font-size-12:null font-bold:null default-typed:null font-size-10:null font-family-SansSerif:null cut-to-clipboard:null select-line:null caret-end-paragraph:null selection-up:null caret-begin:null copy-to-clipboard:null select-paragraph:null font-italic:null caret-up:null selection-end:null caret-next-word:null caret-down:null selection-next-word:null delete-next:null selection-backward:null selection-end-line:null caret-begin-paragraph:null set-writable:null selection-begin:null page-down:null caret-end:null caret-backward:null caret-end-line:null unselect:null paste-from-clipboard:null insert-tab:null dump-model:null selection-end-paragraph:null selection-begin-paragraph:null caret-begin-word:null caret-previous-word:null
つまり、上記であればJTextPaneには、以上のActionのイベント処理が登録されているわけです。
そして、JMenuItemのコンストラクタでは、このActionオブジェクトを引数にできます。
つまり、これらに関しては、特に処理を作らなくても、メニュー処理ができるということです。
以下に、その例を示します。
それは、clipboardに対するcut,copy,pasteの処理です。
目標の例を示します。
このソースコードを以下に示します。
import java.awt.*; import javax.swing.*; import javax.swing.text.*; import java.awt.event.*; public class Test extends JFrame { JTextPane jtext = new JTextPane(); Action getActionByName(String act_name){//エディタの既に使えるAction群より、引数の名前のActionを取得する。 Action[] array = jtext.getActions(); for (int i = 0; i < array.length; i++) { String name = (String)array[i].getValue(Action.NAME); if (name.equals(act_name)) return array[i]; } return null; } Test() {//コンストラクタ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.jtext.setPreferredSize(new Dimension(160,120)); this.getContentPane().add(jtext, BorderLayout.CENTER); //メニュー作成 JMenuBar menuBar = new javax.swing.JMenuBar(); this.getRootPane().setJMenuBar(menuBar);//メニューバーのセット JMenu menuEdit = new JMenu("編集(E)"); menuEdit.setMnemonic('E'); menuBar.add(menuEdit); Action actionCut=getActionByName("cut-to-clipboard"); JMenuItem itemCut = new JMenuItem(actionCut); menuEdit.add(itemCut);//メニュー項目追加 Action actionCopy=getActionByName("copy-to-clipboard"); JMenuItem itemCopy = new JMenuItem(actionCopy); menuEdit.add(itemCopy);//メニュー項目追加 Action actionPaste=getActionByName("paste-from-clipboard"); //actionPaste.putValue(Action.NAME, "貼り付け"); JMenuItem itemPaste = new JMenuItem(actionPaste); //itemPaste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK)); menuEdit.add(itemPaste);//メニュー項目追加 this.pack(); this.setVisible(true); } public static void main(String[] args) { new Test(); } }
上記コメントのactionPaste.putValue(Action.NAME, "貼り付け");
を使うことで、メニューの表示内容を次のように変更できます。
これはす既にアクセラレータ(メニューショートカット機能)が設定されていますが、
メニューで分かるように表示されていません。
上記コメントの
itemPaste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK));
を使うことで、メニューにショートカットを表示できます。
なお、Ctrl-Vは上記の代わりに次のような表現を使っても可能で、まったく同じです。
itemPaste.setAccelerator(KeyStroke.getKeyStroke("ctrl V"));
ここで使っているKeyStrokeクラスは、イベントのキー操作を一意的に指定するため使うデータを
staticで付けているクラスで、キー操作イベントを作る時に使います。
実際には、使うキー操作からgetKeyStrokeで、この一意的データ取得して使う形態です。
Ctrlを押しながらBキーを押した時に、キャレットを1文字バックさせる操作です。 ですがActionの処理自体は、DefaultEditorKitのbackwardActionオブジェクトを利用しています。
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
public class Test extends JFrame {
JTextPane jtext = new JTextPane();
Test() {//コンストラクタ
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.jtext.setPreferredSize(new Dimension(160,120));
this.getContentPane().add(jtext, BorderLayout.CENTER);
//Ctrlを押しながらBキーを押した時に、キャレットを1文字バックさせる
InputMap inputMap = jtext.getInputMap();
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK);
inputMap.put(key, DefaultEditorKit.backwardAction);
this.pack();
this.setVisible(true);
}
public static void main(String[] args) {
new Test();
}
}
キーマップを変更することで、そのキーマップ内にあるキーストローク の処理を変更できます。以下では、JTextComponent.loadKeymapメソッドで、 引数のキーマップ内に、複数のキーストロークに対するアクションを設定する例として、 切り取り処理に、Ctrl+Cを使い、 コピー処理に、Ctrl+Rを使い、 貼り付け処理に、Ctrl+Enterのキーストロークを使う設定を行っている例です。
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
public class Test extends JFrame {
JTextPane jtext = new JTextPane();
Test() {//コンストラクタ
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.jtext.setPreferredSize(new Dimension(160,120));
this.getContentPane().add(jtext, BorderLayout.CENTER);
JTextComponent.KeyBinding []defaultBindings = {
new JTextComponent.KeyBinding(
KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK),
DefaultEditorKit.cutAction
),
new JTextComponent.KeyBinding(
KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_MASK),
DefaultEditorKit.copyAction
),
new JTextComponent.KeyBinding(
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_MASK),
DefaultEditorKit.pasteAction
),
};
Keymap keymap = jtext.getKeymap();
JTextComponent.loadKeymap(keymap, defaultBindings, jtext.getActions());
Action[] array = keymap.getBoundActions();//設定の確認表示
for(int i = 0; i < array.length; i++){
String name = (String)array[i].getValue(Action.NAME);
String sub = (String)array[i].getValue(Action.ACCELERATOR_KEY);
System.out.println(name+":"+sub);
}
this.pack();
this.setVisible(true);
}
public static void main(String[] args) {
new Test();
}
}
cut-to-clipboard:null copy-to-clipboard:null paste-from-clipboard:null
実行で、コンソールに
キーマップkeymap内で使っているアクションの名前を上記のように列挙されますが、
このJTextComponent.loadKeymapの実行前で行うと、
なにも表示しません。
つまり、loadKeymapこの実行で、新規設定されていることが確認できます。
なお上記では、変更していない例えばCtrl-XやCtrl-Vの処理は、
jtextのコマンドリストに登録させているので、これまで通りに使えます。
Keymap keymap = jtext.getKeymap();で、取得したkeymapにaddActionForKeyStrokeで、
指定のストロークに対するActionオブジェクトを追加します。
ここで指定するActionオブジェクトは、
TextActionのサブクラスをTestTextActionの名前で作って
そのオブジェクトを指定しています。
そのactionPerformedをオーバーライドしたところにキーストロークの処理を書きます。
以下では、Enterキーのストロークに対して、"<br>\n"の文字列を挿入する処理にしています。
import java.awt.*; import javax.swing.*; import javax.swing.text.*; import java.awt.event.*; public class Test extends JFrame { JTextPane jtext = new JTextPane(); class TestTextAction extends TextAction{ public TestTextAction(String str){ super(str); } public void actionPerformed(ActionEvent e){ JTextComponent textcmp = (JTextComponent)getFocusedComponent(); Document doc = textcmp.getDocument(); try{ doc.insertString(textcmp.getCaretPosition(),"<br>\n",null); } catch(Exception err){ err.printStackTrace(); } } } Test() {//コンストラクタ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.jtext.setPreferredSize(new Dimension(160,120)); this.getContentPane().add(jtext, BorderLayout.CENTER); Keymap keymap = jtext.getKeymap(); keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), new TestTextAction("test-action")); Action[] array = keymap.getBoundActions();//設定の確認表示 for(int i = 0; i < array.length; i++){ String name = (String)array[i].getValue(Action.NAME); String sub = (String)array[i].getValue(Action.ACCELERATOR_KEY); System.out.println(name+":"+sub); } this.pack(); this.setVisible(true); } public static void main(String[] args) { new Test(); } }
下に確認用のコンソール表示内容も示します
test-action:null