# Klassenübergreifend MouseListener verwenden



## Achtel (24. Aug 2005)

Hallo ihr Lieben,

ich habe folgendes Problem: Ich habe in einer Klasse (TickFrame) ein JPanel (main_panel), dass über einen MouseListener auf Maus-Click und Maus-Drag reagiert (zu Testzwecken erstmal nur durch Ausgabe der Koordinaten). 

Dann gibt es ein weiteres Panel (button_panel) in der selben Klasse, in dem eine Reihe von Buttons stehen... beim Click auf einen der Button wird eine andere Klasse (ClassBox) aufgerufen, die dann eine Instanz dieser Klasse erzeugt und bestimmte Abfragen über Dialoge durchführt.  Jetzt möchte ich, dass der User nach diesen Abfragen ins main_panel klickt und die Koordinaten des Klicks in der Instanz der ClassBox gespeichert werden... wie kann ich das erreichen? 

Hier der Code:
(TickFrame)

```
// The TickFrame class defines the structure of the top-level frame
public class TickFrame extends JFrame
{
  public TickFrame()
  {
    super("TickFrame");
    Container cp = getContentPane();

    [...]

    // Create the main panel containing the user's design
    JPanel main_panel = new JPanel();

    main_panel.addMouseMotionListener(new MouseMotionAdapter()
    {
      public void mouseDragged(MouseEvent evt)
      {
        mainPanelMouseDragged(evt);
      }
    });
    
    main_panel.addMouseListener(new MouseAdapter()
    {
      public void mouseClicked(MouseEvent evt)
      {
        mainPanelMouseClicked(evt);
      }
    });
    
    cp.add(main_panel, BorderLayout.CENTER);
    
    // Create the button panel at the side of the main panel
    JPanel button_panel = new JPanel();
    JButton add_class_button = new JButton("Add Class");
 
   add_class_button.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent evt)
      {
        addClassButtonActionPerformed(evt);
      }
    });
    button_panel.add(add_class_button);
    cp.add(button_panel, BorderLayout.WEST);
    
  // Methods called from Listeners
  private void addClassButtonActionPerformed(ActionEvent evt)
  {
    ClassBox cb = new ClassBox();
  }
  
  private void mainPanelMouseDragged(MouseEvent evt)
  {
    System.out.println("Mouse drag at " + evt.getX() + "" + evt.getY());
  }
  
  int clickX;
  int clickY;
  private void mainPanelMouseClicked(MouseEvent evt)
  {
    clickX = evt.getX();
    clickY = evt.getY();
    System.out.println("Mouse click at " + clickX + "" + clickY);
  }

  // Main program entry point
  public static void main(String args[])
  {
    TickFrame tf = new TickFrame();
    tf.show();
  }
}
```

(ClassBox)

```
public class ClassBox
{

   // coordinates of top right corner of box later appearing in panel
   private int c_x;
   private int c_y;

   public ClassBox()
   {
     JFrame frame = new JFrame();
     
     // dialogs

     [...]
     
     // info to tell user to click in panel & drag mouse to create rectangular
     // representing class
     JOptionPane.showMessageDialog(frame, "Click anywhere in the panel and drag the mouse 
to create a box representing your class.");

     // mouseListener to detect where mouse clicked - safe coordinates, call
     // class to draw rectangular
     c_x = TickFrame.clickX;
   }
}
```


Mit dem aktuellen Code bekomm ich den Fehler "non-static variable cannot be referenced from static context". Kann mir jemand von euch helfen?

Danke...


----------



## Sky (24. Aug 2005)

Du brauchst in ClassBox eine Referenenz auf ein Objekt vom Typ TickFrame (und zwar die, die Du in TickFrame erstellst)

btw: warum hast Du in beiden Klassen jeweils eine main-Methode?


----------



## Achtel (24. Aug 2005)

Das mit den beiden main-Methoden ist ne gute Anmerkung... 

Ich kann mir jetzt zwar vorstellen, was du meinst - aber wie ich den Hinweis umsetze, weiß ich eher nicht... kannst du das irgendwie an nem Code-Beispiel mal bitte zeigen?


----------



## Sky (24. Aug 2005)

Achtel hat gesagt.:
			
		

> Das mit den beiden main-Methoden ist ne gute Anmerkung...
> 
> Ich kann mir jetzt zwar vorstellen, was du meinst - aber wie ich den Hinweis umsetze, weiß ich eher nicht... kannst du das irgendwie an nem Code-Beispiel mal bitte zeigen?


ja klar, ist ganz trivial. Hier eine nicht getestete Version:


```
class Test {

  public static void main( String[] args ) throws Exception {
    OutputTest o = new OutputTest( ); // Instanz erzeugen
    Test test = new Test(o); // Referenz übergeben
  }

  public Test(OutputTest theOutputTest ) {
    theOutputTest.doOutput("my Output"); // Nutzen der Referenz.
    // Bei Dir wird die Referenz auch noch in anderen Methoden
    // gebraucht, daher solltest Du diese im Konstruktor einer
    // Instanzvariablen zuweisen.
  }
}

class OutputTest {
  public OutputTest() {

  }
  
  public void doOutput(String theOutput) {
    System.out.println( theOutput );
  }
}
```


----------



## Achtel (24. Aug 2005)

Sorry, aber jetzt bin ich verwirrt... wie hilft mir das jetzt die Koordinaten ausm main panel auszulesen?  ???:L


----------



## Sky (24. Aug 2005)

Achtel hat gesagt.:
			
		

> Sorry, aber jetzt bin ich verwirrt... wie hilft mir das jetzt die Koordinaten ausm main panel auszulesen?  ???:L


Ich habe Dir ein Beispiel gezeigt, wie man mit Referenzen arbeiten kann... sorry, dass ich Dir nicht direkt deinen Code verbessert habe.

Neben einigen unschönen Dingen, hier zwei Lösungs*ansätze*: 
- ClassBox braucht das Event.
- ClassBox braucht eine Referenz auf TickFrame. TickFrame muss um eine Methode (z.B. getClickX); diese muss aufgerufen werden.

Wie das mit den Referenzen geht, siehe mein Post oben.


----------



## Achtel (24. Aug 2005)

Du solltest ja auch gar nicht Code verbessern ...  Ich glaub die Lösungsansätze helfen schon mal weiter... Was meinst du mit "unschönen Dingen"?

Und nach Nachdenken noch folgende Frage - ein Event muss ich doch über eine Komponente steuern, oder? Also ich hab z.B. n Button, Panel oder Window (oder sonst was) und kann diesen entsprechende Listener zuweisen... Die Klasse ClassBox hingegen hat ja keine Komponenten, sondern fragt nur Infos ab, die gespeichert werden sollen... womit verknüpf ich dann also den Listener?  ???:L

Ich habe jetzt mal ein paar Änderungen übernommen...

(class TickFrame - ausgewählte, geänderte Methoden)

```
private void addClassButtonActionPerformed(ActionEvent evt)
  {
    System.out.println("Add a Class");
    ClassBox cb = new ClassBox(this);
  }

// get coordinates from mouse click - kann man 2 returnwerte innerhalb
// einer Methode definieren und somit die beiden Methoden zusammenfassen?
  public int getClickX()
  {
    return clickX;
  }
  public int getClickY()
  {
    return clickY;
  }
```

(class ClassBox - Auszug aus Konstruktor)

```
public ClassBox(TickFrame tickfrm)
{
// mouseListener to detect where mouse clicked - safe coordinates, call
     // class to draw rectangular
     c_x = tickfrm.getClickX();
     c_y = tickfrm.getClickY();
     System.out.print("c_x = "+ c_x + "and c_y = "+ c_y);
}
```

Das Problem jetzt ist, dass ich schon vor dem Mausklick die Ausgabe bekomme "c_x = 0 and c_y = 0" - die Variablen werden also mit Instantierwert 0 ausgegeben und nicht upgedatet - das wird wohl daran liegen, dass ClassBox das Event nicht hat??? Wo wir wieder bei meiner obigen Frage wären...  Vielen Dank für deine Hilfe...


----------



## Sky (25. Aug 2005)

Zeile 6: ClassBox cb = new ClassBox(tickf);  ändern in ClassBox cb = new ClassBox(this);

Zeile 5 kann dann gelöscht werden


----------



## Sky (25. Aug 2005)

Achtel hat gesagt.:
			
		

> Was meinst du mit "unschönen Dingen"?



Das sind ein paar Kleinigkeiten, main_panel sollte bspw. mainPanel heißen usw. ( vgl. http://java.sun.com/docs/codeconv/ )

Dann wird bei jedem Event eine neue Instanz von ClassBox erzeugt. Ok, ich weiß nicht, was dahintersteckt, auf den ersten Blick kommt mir das nur etwas komisch vor.


----------



## Guest (25. Aug 2005)

Also es geht im Prinzip darum einen Editor zu erstellen, in dem man UML-Diagramme und deren Beziehungen abbilden kann... für jede neue Klasse, die dargestellt wird, soll eine entsprechende Box im mainPanel erscheinen - da brauch ich doch dann pro Box eine neue Instanz, oder?

Und kannst du mir gerade noch einen Hinweis geben was die Eventzuordnung zur ClassBox angeht?


----------



## Sky (25. Aug 2005)

in addClassButtonActionPerformed hast Du ein ActionEvent. Dieses musst Du der ClassBox als Parameter im Konstruktor mitgeben.


----------



## Achtel (25. Aug 2005)

Ach sooo... ich verstehe... danke! Ich probiers aus, sobald ich von der Arbeit nach Haus komme...


----------



## Achtel (25. Aug 2005)

Ich bekomm die Fehlermeldung: "cannot find symbol" bei folgendem Code:

(Methode, die Event übergeben soll)

```
private void addClassButtonActionPerformed(ActionEvent evt)
  {
    System.out.println("Add a Class");
    ClassBox cb = new ClassBox(this,evt);
  }
```

(Konstruktor)

```
public ClassBox(TickFrame tickfrm,ActionEvent evt)
```

Ist die Übergabe im Prinzip falsch, oder woran hapert's?


----------



## Sky (26. Aug 2005)

Da Du dich innerhalb des ActionListeners befindet, ist 'this' ein ActionListener und kein TickFrame. Hier die Lösung:

```
ClassBox cb = new ClassBox(TickFrame.this,evt);
```


----------



## Achtel (26. Aug 2005)

Den Fehler krieg ich aber immer noch... 



> public ClassBox(TickFrame tickfrm, ActionEvent evt)
> _cannot find symbol_



Was ist falsch?

Edit: Ich hab in ClassBox vergessen die Awt.Event Library zu importieren... [schild=1 fontcolor=000000 shadowcolor=C0C0C0 shieldshadow=1]*dumm*[/schild]

Trotzdem ändert das nichts daran, dass ich immer noch automatisch c_x = 0 und c_y = 0 bekomm - noch bevor ich geklickt habe...  :bahnhof:


----------

