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