Question: When adding keybindings to a JTree, Why am I forced to make each Action it's own class? Why can't I have have each action use a single Action class? To understand my question/issue, let me start off by explaining my Short Self Contained Example of the Problem below.
addKeyBindings(JTree tree) has the following 2 lines commented out.
//Action addsiblingnodeaction = new RightClickNodeAction("Add SiblingNode");
//Action addchildnodeaction = new RightClickNodeAction("Add ChildNode");
/*These use 1 action class, to do 2 different actions. (I want this because I
find the code to be less verbose)
(They're commented out because they don't work for keybindings)
(The reason I ask question, is because they DO work for JPopupMenu)*/
The Real Question is Why does the above //commented out code// not work for keybindings? (In my example I included a JPopupMenu to show that the above commented out code works for JPopupMenu, and in my mind should also work for keybindings) (The only way I was able to get the keybindings to work was to make a AbstractAction class for each Action, which you can see in the example code below)
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.KeyStroke;
public class StackExchangeQuestion2 {
public static void main(String[] args){
StackExchangeQuestion2 workaround = new StackExchangeQuestion2();
//workaround = compiler didn't like me throwing constructor code in main
}//end main
StackExchangeQuestion2(){
JTree tree = new JTree();
initRightClickMenu(tree);//purpose of existance is to show Action Code is accurate
addKeyBindings(tree);
JFrame window = new JFrame();
window.getRootPane().setContentPane(tree);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setTitle("Stack Exchange Question");
window.setSize(400,500);//variable parameters would be best
window.setVisible(true);
}//constructor
private void initRightClickMenu(JTree tree){
JPopupMenu rightclickmenu = new JPopupMenu();
Action addsiblingnodeaction = new RightClickNodeAction("Add SiblingNode");
Action addchildnodeaction = new RightClickNodeAction("Add ChildNode");
rightclickmenu.add(addsiblingnodeaction);
rightclickmenu.add(addchildnodeaction);
tree.setComponentPopupMenu(rightclickmenu);
}
private void addSiblingNode(){
System.out.println("sibling node added");}
private void addChildNode(){
System.out.println("child node added");}
private void addKeyBindings(JTree tree){
//Action addsiblingnodeaction = new RightClickNodeAction("Add SiblingNode");
Action addsiblingnodeaction = new AddSiblingNodeAction("Add SiblingNode");
tree.getActionMap().put("Add SiblingNode", addsiblingnodeaction);
tree.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "Add SiblingNode");
//Action addchildnodeaction = new RightClickNodeAction("Add ChildNode");
Action addchildnodeaction = new AddChildNodeAction("Add ChildNode");
tree.getActionMap().put("Add ChildNode", addchildnodeaction);
tree.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "Add ChildNode");
}//end addKeyBindins
private class AddSiblingNodeAction extends AbstractAction{
AddSiblingNodeAction(String name){super(name);}
public void actionPerformed(ActionEvent ae) { addSiblingNode(); }}
private class AddChildNodeAction extends AbstractAction{
AddChildNodeAction(String name){super(name);}
public void actionPerformed(ActionEvent ae) { addChildNode(); }}
private class RightClickNodeAction extends AbstractAction{
RightClickNodeAction(String name){super(name);}
public void actionPerformed(ActionEvent ae) {
if(ae.getActionCommand().equals("Add SiblingNode"))addSiblingNode();
if(ae.getActionCommand().equals("Add ChildNode"))addChildNode(); }}
}//end class
Answer: Because I'm doing it wrong, I'm not forced to do it one way.
private class RightClickNodeAction extends AbstractAction{
RightClickNodeAction(String name){super(name);
putValue(ACTION_COMMAND_KEY, name);
}//end constructor
public void actionPerformed(ActionEvent ae) {
//System.out.println("Action Command is: "+ae.getActionCommand());
//the above comment verified it worked as expected + testing
if(ae.getActionCommand().equals("Add SiblingNode"))addSiblingNode();
if(ae.getActionCommand().equals("Add ChildNode"))addChildNode(); }}