# Parameter an Runnable-Objekt übergeben



## videlius (28. Nov 2010)

Hallo, 

Ich habe ein Problem. Ein Thread meiner Anwednung soll die Oberfläche meiner Anwendung verändern. 
Soviel ich weiß, geht das ja nur, in dem ich der EventQueue ein Runnable Objekt übergebe, also etwa so.


```
public class myGui extends JFrame{

[...]

public void veraendereGui(String text)
{
            EventQueue.invokeAndWait(new Runnable() {
                @Override
           public void run() {
                // gib text in einer TextArea aus 
                }
            });
}

[...]

}
```

Das Problem ist nur, das ich den Parameter "text" nicht an das Runnable-Objekt übergeben bekomme.

Ich hab mir 2 Möglichkeiten überlegt das hinzubekommen, aber ich finde diese nicht praktikabel.

1. Eine Klassen-Variable myGuiText definieren und der den parameter text übergeben. Auf myGuiText kann das Runnable-Objekt zugreifen. 
Allerdings finde ich hat diese Variable als Klassenvariable keine Berechtigung, da sie ja nur von dieser einen Methode verwendet wird.

2. Eine Innere Klasse definieren die Runnable implementiert. 

z.b. so

```
private class WriteText implements Runnable {

        String ausgabe;

        public WriteText(String text) {
            ausgabe = text;
        }

        @Override
        public void run() {
            // gib ausgabe in einer TextArea aus 
        }
    }
```

Da aber in anderem Zusammenhang noch mehr Sachen an Oberfläche verändert werden müssen (z.B. Buttons enablen/disablen) müsste ich jede Menge innere Klassen schreiben, die jeweils die run-Methode entsprechend überschreiben. Das kann es ja auch nicht sein.

Gibt es denn keine Möglichkeit nem Runnable-Object direkt nen Parameter mitzugeben?


----------



## eRaaaa (28. Nov 2010)

Mhm? Du meinst dein Problem ist, dass du 
	
	
	
	





```
text
```
 nicht innerhalb von run benutzen kannst oder wie? Dann mach den Parameter doch einfach final 

```
public void veraendereGui(final String text)
```


----------



## videlius (28. Nov 2010)

Na toll so einfach. 
prima! 

Vielen, vielen Dank! :toll:


----------



## videlius (28. Nov 2010)

Hi,

hätte da noch eine zweite Frage. Ich will keinen neuen Thread deswegen aufmachen, da sich das Problem an meine erste Frage anschließt.

Nochmal kurze Zusammenfassung:


Ich trage ein Runnable-Objekt in die Event-queue meiner Oberfläche ein.
Dies soll eine jTextArea verändern, indem es einen String der im Parameter "text" steht in die jTextArea schreibt. Dank eRaaaa weiß ich ja nun das Text final sein muss. Danke! 


```
public void veraendereGui(final String text)
{
            EventQueue.invokeAndWait(new Runnable() {
                @Override
           public void run() {
                jTextArea.append(text + "\n");
                }
            });
}
```

Das blöde ist nur, dass kein Text in der jTextArea erscheint.
Ich kann aber sicher sagen, dass der appendBefehl erfolgreich ausgeführt wird, denn
ein 
	
	
	
	





```
System.out.println(jTextArea.getText());
```
 nachdem append gibt mir den Inhalt von text korrekt auf der Konsole aus.
Das Problem scheint darin zu liegen, dass zwar die Komponente verändert, aber nicht neu gezeichnet wird. 
Aus diesem Grunde hab ich ein 
	
	
	
	





```
jTextArea.repaint();
```
 versucht, ohne Erfolg.

Woran könnte es liegen dass der Text nich auf die TextArea will?


----------



## eRaaaa (28. Nov 2010)

So etwas ist so jetzt immer schwer zu sagen(von wo und wie wird denn veraendereGui aufgerufen etc.), kannst du mal ein Beispielcode (ausführbar) posten?

Aber an sich musst du, wenn du NUR append aufrufst, das nicht in ein invokeLater oder wait verpacken, da die Methode threadsicher ist!
D.h. es würde auch schon so etwas

```
public void veraendereGui(String text)
{
                jTextArea.append(text + "\n");
}
```
ausreichen


----------



## videlius (28. Nov 2010)

Ich müsste fast die komplette Anwendung posten, da eine Vielzahl von Klassen beteilligt sind.

Deshalb hab ich versucht nur die nötigsten Strukturen, in einer externen Andwendung darzustellen und das Problem so zu reproduzieren. Ich sags gleich, ohne Erfolg! ;(

Hier die Anwendung

Klasse: MyGui (Oberfläche mit main)


```
package javaapplication9;

import java.awt.EventQueue;
import java.util.Observable;
import java.util.Observer;

public class MyGui extends javax.swing.JFrame implements Observer{

    /** Creates new form myGui */
    public MyGui() {
        initComponents();
        new Backend(this);
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jTextArea = new javax.swing.JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jTextArea.setColumns(20);
        jTextArea.setEditable(false);
        jTextArea.setRows(5);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(0, 65, Short.MAX_VALUE)
                .addComponent(jTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 269, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 66, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(0, 61, Short.MAX_VALUE)
                .addComponent(jTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 62, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>

    public static void main(String args[]) {
        new MyGui().setVisible(true);
    }
    // Variables declaration - do not modify
    private javax.swing.JTextArea jTextArea;
    // End of variables declaration

    public void veraendereGui(final String text) {
        try {
            EventQueue.invokeAndWait(new Runnable() {

                @Override
                public void run() {
                    jTextArea.append(text + '\n');
                }
            });
        } catch (Exception ex) {
        }
    }

    public void update(Observable o, Object arg) {
       veraendereGui((String) arg);
    }
}
```

und die Klasse Backend, die sozusagen den Rest meiner Anwendung simulieren soll.


```
import java.util.Observable;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Backend extends Observable{

    private MyGui gui;
    private BlockingQueue<String> messages = new LinkedBlockingQueue<String>();

    public Backend(MyGui gui) {
        this.gui = gui;
        addObserver(gui);
        messages.add("Erste Nachricht");
        messages.add("Zweite Nachricht");
        messages.add("Dritte Nachricht");
        messages.add("Vierte Nachricht");
        Thread t = new Thread(new externerThread());

        t.setName("extThread");
        t.start();
    }

    private class externerThread extends Thread {

        @Override
        public void run() {
            while (!interrupted()) {
                try {
                    Thread.sleep(1000);
                    String msg = messages.take();
                    setChanged();
                    notifyObservers(msg);
                } catch (Exception ex) {
                }
            }
        }
    }
}
```


Das blöde ist, Sie funktioniert bestens und das Problem, dass der Text nicht auf der Textarea erscheint bekomme ich hier nicht simuliert. ???:L :bahnhof:

Somit werde ich wohl weiter in den Untiefen meiner Anwendung nach dem Problem suchen müssen. 
Ich werde mal schreiben wenn ich den Wurm gefunden habe.

Trotzdem vielen Dank erstmal!


----------



## videlius (28. Nov 2010)

Nur der Vollständigkeit halber, ich hab den Fehler gefunden. 


Ich hatte einen Fehler in der Implementation des Observer-Patterns.

kurze Erläuterung: 

Die Klasse MyGui ist ein Observer


```
public class MyGui extends javax.swing.JFrame implements Observer{...}
```

Die Klasse Backend ist vom Typ Observable


```
public class Backend extends Observable{...}
```

und meldet sich beim Observer von MyGui an:


```
...
addObserver(gui);
...
```

Hier lag mein Fehler in der richtigen Anwendung habe ich das gemacht:


```
...
MyGui gui = new MyGui();
addObserver(gui);
...
```

mit anderen Worten, ich habe eine zweite Gui angelegt, die nicht Visible war und an diese hat das Observable seine Nachrichten geschickt. 
Der Code war ansonsten in Ordnung.

Tja, kleiner Fehler große Wirkung und stundenlanges Suchen. Naja jetzt gehts wenigstens.

Vielen Dank nochmal für die Hilfe. :toll:


----------

