views:

3608

answers:

5

I have the following situation I think would be best to show in sample program code. I have a Java class that extends JPanel. In this class are two objects which are two more JPanels. In one of the JPanel objects is a JTable object. I added a listener to this JTable that detects a double click. When it detects a double click, I want to fire a method in the top class. How do I reference this method in Java?

public class TopPanel extends JPanel {

  JPanel OnePanel;
  JPanel TwoPanel;

  public void MethodToFire;

}

public class OnePanel extends JPanel {

  JTable TheTable;

}

public class TheTable extends JTable {

  public TheTable {
    this.addMouseListener(new MouseAdapter(){
      public void mouseClicked(MouseEvent e){
          if (e.getClickCount() == 2){ SYNTAX CALLING THE METHOD IN TopPanel  }
      }
    } );
  }
}
+1  A: 

To access a method on the Outer class, you need to use the syntax of Outer.this.method().

So in this case, to access a method on the "TheTable" class from the listener, you should use TheTable.this.callMethod().

I assume that TopPanel has added to it the TheTable. In this case, you could do something like:

mouseClicked(...) {
   TopTable t = (TopTable)TheTable.this.getParent();
   t.MethodToFire();
}

This is a direct answer to the question, not necessarily the "best" way to do it. A type-safe composition approach would be a better long-term solution.

James Schek
+2  A: 

One way to solve this is to use composition instead of inheritance. You could pass the JPanel into your subclass of the JTable.


public class TopPanel extends JPanel 
{
  private TheTable table;

  public TopPanel()
  {
    table = new TheTable(this);
  }

  public void methodToFire() { }
}

public class TheTable extends JTable 
{
  private TopPanel panel;

  public TheTable(TopPanel panel)
  {
    this.panel = panel;

    this.addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent e) {
        doThing();
      }
    } );
  }

  private void doThing()
  {
    this.panel.methodToFire(); 
  }
}
David
This is definately the more safe/generalized approach to solving this problem. Using getParent() as I described assumes that TheTable will *always* be added to TopPanel.
James Schek
Always prefer composition over inheritance wherever it doesn't really make it hard to keep your code DRY
Bill K
A: 

I don't think that Java has a direct syntax for doing that, unless you start playing with reflection (which is of course possible, but I don't consider it very clean).

At the point where you want to make the call, your "this" refers to an anonymous subclass of MouseAdapter.

The cleanest approach may be to create a private method, let's call it X, in TheTable, and have the adapter call that function.

Now, because that method X is in the TheTable, it doesn't know that it is inside a panel so it doesn't have any way of activating that function. If you are sure that every table is inside a panel, then you can add a panel reference field to your Table class, initialize it when it is created (you may need to modify the constructor on OnePanel), and then make the call from the method in TheTable.

If the panel method you are ultimately trying to explore not part of JPanel, you may need to create and pass interfaces.

Uri
+2  A: 

Seems like you're going a round-about way - why not just do everything from the outermost class? This is one reason listeners exist, after all:


    public class TopPanel {
        public TopPanel() {
            // Construct everything here
            OnePanel.TheTable.addMouseListener(new MouseAdapter(){
              public void mouseClicked(MouseEvent e){
                 if (e.getClickCount() == 2){ MethodToFire }
              }
              } );

        }

    }

Anthony Rizk
+1  A: 

You could make your TheTable fire an event when the mouse is pressed, which your TopPanel could listen for. This has the benefit of not making the Table and Panel classes both dependent on each other.

The code is a little more involved, but the decoupling may be worth it.

public class TopPanel extends JPanel 
{
  private TheTable table;

  public TopPanel()
  {
    table = new TheTable(this);
    table.addTheTableListener(new TheTableListener() {
      public void tableSelected() {  // or tableSelected(TableSelectionEvent e) if you want to make a TableSelectionEvent
        methodToFire();
      }
    });
  }

  public void methodToFire() { }
}

public class TheTable extends JTable 
{
  private TopPanel panel;
  private EventListenerList listeners;

  public TheTable(TopPanel panel)
  {
    this.panel = panel;
    listeners = new EventListenerList();

    this.addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent e) {
        fireTableSelected();
      }
    } );
  }

  public void addTheTableListener(TheTableListener l) {
    listeners.add(l);
  }

  // also write removeListener

  private void fireTableSelected()
  {
    for (TheTableListener l : listeners) {
      l.tableSelected(); 
  }
}

public interface TheTableListener extends EventListener
{
    public void tableSelected();
}
David