How to trigger an ActionListener in different class on click of a tree node

Hi guyz,

There are three panels inside my main Frame

-->TopPanel,MiddlePanel and BottomPanel. I have a tree structure inside a panel. This panel along with couple more panels is in MiddlePanel. My main class is "mainClass.java". Inside that i have an actionListener for a specific button. I need to trigger that actionListener when i click one of the tree nodes in the panel i specified before. The problem is that my MiddlePanel is itself a different ".java" file which is being called in my "mainClass" when a specific button is clicked. There are different buttons in my "mainClass" file and for each one i am creating different MiddlePanels depending on the buttons clicked.

So, if i click the tree node, i need to remove the MiddlePanel and recreate the MiddlePanel(One that will be created when a different button in the mainClass file is clicked). i.e., i need to trigger the actionListener for that corresponding button. Is there a way to do it?

[982 byte] By [Gopi_Ua] at [2007-10-2 11:04:32]
# 1

Any number of ways you can do this. However, I'd suggest you "decouple" various components from knowing about others. That is to say, if you know MVC, use and abuse the component MVC all you want. But if you want one component's action to do something to another component, you may want to look at using a simplified EventBus so that you can easily decouple components from one another. This is a slightly more complex solution to what you need, the point of me saying this is to inform you that while for small apps, it's fine to pass components around and have one class be aware of componetns from another class, for larger apps with multi-developers, it's far better to decouple your components and classes from being interdependent on one another as much as possible. By using a centralized "event" system outside of the Swing event system, you can have the action listener of one component fire an event on the centralized event bus, that any other component can listen for. By component, I mean the class a component (or components) are declared in would add a listener to the event bus and handle events it is interested in.

Regardless, if you want to get this working, another thought is using a "model" for your application. For example, declare your components in a MyAppModel class with getter methods that can get the component. Make tese public static methods so any other class in your app can grab the same singleton instance of the component and use it as needed. In your case, you have a model that returns the middle JPanel, top JPanel, etc (and setters to change it if you need be).

If you don't know, be sure to use a Runnable when updating GUI:

Runnable r = new Runnable(){

public void run(){

MyAppModel.setMiddlePanel(new JPanel());

MyAppModel.getMainWindow().revalidate();

MyAppModel.getMainWindow().repaint();

}

};

EventQueue.invokeLater(r);

This way, you are updating the GUI ON the Swing event thread, which is the only way you ever should update the UI. Even if you are setting a JLabel's text field, you should wrap it in a Runnable and stick it on the event thread.

Good luck.

buckman1a at 2007-7-13 3:38:06 > top of Java-index,Desktop,Core GUI APIs...
# 2
Thanks for the information, dude. Now, i am beginning to feel like i know nothing in Swings after reading all the information you have provided here.
Gopi_Ua at 2007-7-13 3:38:06 > top of Java-index,Desktop,Core GUI APIs...
# 3

Can you tell me how exactly can i do this? Here is the code from my file middlePanel.java in which i have the tree node.

tree.addTreeSelectionListener(new TreeSelectionListener(){

public void valueChanged( TreeSelectionEvent e ) {

if (e.getNewLeadSelectionPath() == null) return;

DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

if(node.isLeaf()){

//Here i have to call my mainClass's actionListener

}

}

});

Here is the snippet of code from my mainClass.java. The above code is in middlePanel.java which is being called in my mainClass to create a JTabbedPane(homeTab). contents is the ContentPane of my frame. And the private class listener i have provided here corresponds to a button i have talked about intially.

private class TreeElementsActionListner implements ActionListener {

public void actionPerformed(ActionEvent e) {

contents.remove(homeTab);

if(botPanel != null) {

contents.remove(botPanel);

}

homeTab = new JTabbedPane();

homeTab.setAutoscrolls(true);

homeTab.addTab("Eligibility Tree Elements", new middlePanel(sessionData));

homeTab.setBounds(0,40,800,500);

botPanel = new JPanel();

botPanel.setLayout(null);

//Continue Button

continueButton = new JButton("Create/Modify Eligibility Tree");

continueButton.addActionListener(new TreeActionListner());

continueButton.setBounds(600,5,200,20);

//Set buttons to bottom panel

botPanel.add(continueButton);

botPanel.setBounds(0,550,800,50);

botPanel.setBackground(new Color(51,77,134));

contents.add(homeTab);

contents.add(botPanel);

//.............

//.............

//.............

}

}

Gopi_Ua at 2007-7-13 3:38:06 > top of Java-index,Desktop,Core GUI APIs...
# 4

How about passing the reference actionListener into the tree and call the actionListener.actionPerformed method from there when it needs to. You can create a ActionEvent like:

ActionEvent ae = new ActionEvent(tree, ActionEvent.ACTION_PERFORMED , "from-tree");

actionListener.actionPerformed(ae);

minlia at 2007-7-13 3:38:06 > top of Java-index,Desktop,Core GUI APIs...
# 5

I didn't quite understand your suggestion. Did you mean creating the action event(ActionEvent ae) in my middlePanel.java where i have the tree node whose action has to trigger other actionListener in my mainClass.java? If that is so, how do i trigger the actionListener in my mainClass? The code snippet you have shown doesn't indicate any link between them.

Gopi_Ua at 2007-7-13 3:38:06 > top of Java-index,Desktop,Core GUI APIs...
# 6

First thing, sorry to add more confusion. Having been "swinging" for several years now, I like to inform those that may not know that Swing is quite a beast to really truly learn, but its a fun ride and if you keep up at it, you'll be able to make professional quality Swing applications in short order. There are some finer points related to threads, the swing event thread, keeping the GUI smooth and not freezing and more that you'll learn along the way.

As for your dilema, if you want to allow the tree selection to fire off an action that has a listener implemented in another class, do as the other guy said, pass in the listener to your tree class via a method call, constructor, etc.

Something like:

MainClass.java:

public static void main(String[] args){

MyActionListener mal = new MyActionListener();

MyTreeClass = new MyTreeClass(mal);

showWindow();

}

MyActionListener.java:

public class MyActionListener implements ActionListener(){

public void actionPerformed(ActionEvent ae){

// do something

}

}

MyTreeClass.java:

public class MyTreeClass implements ActionListener {

private ActionListener actionHandler = null;

public MyTreeClass(ActionListener al){

actionHandler = al;

// set up tree, listeners, etc

}

public void actionPerformed(ActionEvent ae){

if (null != actionHandler){

actionHandler.actionPerformed(ae);

}

}

}

I think where you may be getting confused is how to pass the one action listener instance to another. You can use the constructor,a setter method, or you can use what I said before.. a separate class that holds all your data objects, action listener instances, etc. Something like:

public class MyHandlers{

private static ActionListener treeListener = null;

private static ActionListener buttonListener = null;

public static ActionListener getTreeListener(){

if (null == treeListener){

treeListener = new ActionListener(){

public void actionPerformed(){

// do something

}

};

}

return treeListener;

}

public static ActionListener getButtonListener(){

if (null == buttonListener){

buttonListener = new ActionListener(){

public void actionPerformed(ActionEvent ae){

getTreeListener().actionPerformed(ae);

};

}

}

return buttonListener

}

In the above example, you use getTreeListener() in the buttonListener construction so that if your button is called first, it then calls the getTreeListener which will create it if its still null, in case something else hasn't set the tree listener instance already by calling it.

Now, to use it, in another class you'd simply do something like:

JButton myButton = new JButton("Some Test");

myButton.addActionListener(MyHandlers.getButtonListener());

and so on.

Hope that helps.

buckman1a at 2007-7-13 3:38:06 > top of Java-index,Desktop,Core GUI APIs...
# 7
Thanks buddy, that helped to some extent. I am still not able to get it. As you said, i am a little confused with all this stuff as i am not an expert in Swings. I am doing my best and hope i could finish it up.
Gopi_Ua at 2007-7-13 3:38:06 > top of Java-index,Desktop,Core GUI APIs...