Observer Pattern JLabel ändern

_BroNKo_

Mitglied
Guten Mittag,
habe folgende Frage Danke schonmal im voraus für Hilfe. Ich versuche gerade eine Gui für eine Api Schnittstelle zu programmieren.
Ich habe zwei Klassen eine Gui Klasse und eine Klasse die als Observer fungiert. In der Observer KLasse wird eine Methode ausgeführt wenn eine neue "Nachricht" von der Api kommt und über die Methode auf der Console ein Wert ausgegeben. Auf der Gui Klasse ist ein JLabel das eben wenn das passiert mit dem Wert initialisiert werden soll den diese Methode auf der Console ausgibt. Wie sollte ich hier Grundsätzlich bestmöglich vorgehen???
Hoffe meine Frage ist soweit verständlich formuliert...
 
Deine GUI soll in dem Moment als Observer dienen und könnte daher das Interface java.util.Observer implementieren. Dadurch muss die update(Observable, Object) Methode überschrieben werden, in der du einfach den Text des JLabels updaten kannst. Dabei ist Object der String, den du in dein JLabel schreiben willst.

Deine "Oberserver-Klasse" [Name mEn schlecht gewählt] sollte dann von java.util.Observable erben damit du, in der von dir angesprochen Methode, die Methoden setChanged() und notifyObservers(<dein Wert als String>) aufrufen kannst. Natürlich muss in deiner "Observer-Klasse" noch der eigentliche Observer (was deine GUI ist) registriert werden.
 
Perfekt vielen vielen Dank´... läuft jetzt wie es soll 😀
(P.S. du meintest von der GUI KLasse erben hast dich vertan bin aber Dank deiner Erklärung am Ziel)
 
Ich habe zwei Klassen eine Gui Klasse und eine Klasse die als Observer fungiert
Nicht das du dir das falsch einprägst. Die Objekte, die über Änderungen informiert werden, sind die Observer. Das Objekt, welches ihre Observer über Änderungen informiert, ist Observable.

du meintest von der GUI KLasse erben
Meinte ich eigentlich nicht, nein.

Vielleicht einfach noch mal ein kleines Beispiel:
Java:
public class Window implements Observer {

    private JLabel labelToDisplayValue;
    private JFrame frame;

    public Window() {
        buildAndShowUI();
    }

    @Override
    public void update(Observable o, Object arg) {
        labelToDisplayValue.setText("Wert: " + arg);
    }

    private void buildAndShowUI() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,500);

        labelToDisplayValue = new JLabel("Wert: n/a");
        frame.add(labelToDisplayValue);

        frame.setVisible(true);
    }
}
Java:
public class FooObservable extends Observable {

    public FooObservable(Observer observer) {
        addObserver(observer);
        addSomeTask();
    }

    private void addSomeTask() {
        Runnable task = () -> {
            Scanner scanner = new Scanner(System.in);
            while(true) {
                String input = scanner.nextLine();
                setChanged();
                notifyObservers(input);
            }
        };
        Thread taskThread = new Thread(task);
        taskThread.start();
    }
}

Java:
public static void main(String[] args) {
    Window window = new Window();
    FooObservable observable = new FooObservable(window);
}
 
@Robat Bin etwas verwirrt jetzt hier mal Code Ausschnitte wie ich es jetzt programmiert habe. Bin offen für Verbesserungsvorschläge, ich würde es gerne so effizient wie möglich programmieren. Habe alles weggekürzt was nicht relevant ist, ist also nur Exemplarisch...Wenn die Api eine neue "Nachricht" hat dann wird die tickByTickMidPoint Methode ausgeführt die dann die Parameter übergeben bekommt die ich auch dem JLabel ausgeben will.

Java:
public class CPanel extends JPanel{

   private final JLabel lblKatze = new JLabel("Katze  ");

   JButton btnStartCurrency = new JButton("Start");
       btnStartCurrency.addMouseListener(new MouseAdapter() {
           @Override
           public void mouseClicked(MouseEvent e) {
               startReqData();
           }

   void startReqData() {
      
       final Contract katzeb = new Contract(0,"Hallo","CASH",null,0,null,null,"IDEAL","knallo",null,null);
      
       final ResultsPanel tickres_katze = new ResultsPanel(katzeb);
      
       String d_symbol = "Katze  ";
       tickres_katze.attach(lblKatze, d_symbol);
      
       Api.INSTANCE.controller().reqTickByTickData(katzeb, "MidPoint", 0, false, tickres_katze);
   }

   public void update(JLabel x,double m, String symbol) {
       x.setText(symbol + m);
   }
}
Java:
public class ResultsPanel extends CPanel{
  
   private Contract con;
   private ArrayList<JLabel> jl_helpobject;
   private String jl_symbol;
  
   public ResultsPanel(Contract u_con) {
       this.con = u_con;      
       this.jl_helpobject = new ArrayList<>();
   }
  
   @Override
   public void tickByTickMidPoint(int reqId, long time, double midPoint) {
       try
       {      
           update(jl_helpobject.get(0), midPoint, jl_symbol);
       }
           catch(Exception e) {System.out.println("ResultsPanell class Exception catched!");}
   }
   public void attach(JLabel l, String jlsymbol) {
       jl_symbol = jlsymbol;
       jl_helpobject.add(l);
   }
}
 
Ich glaub du solltest dir das Observer-Pattern noch mal genauer anschauen.

Wenn die Methode tickByTickMidPoint(int, long, double) immer dann ausgeführt wird, wenn die API eine neue Nachricht hat, dann ist die Klasse ResultsPanel dein Subject (erweitert aus Java-Sicht also java.util.Observable). Wichtig ist, dass diese Klasse kein CPanel ist, sondern vielmehr ein oder mehrere CPanel(Observer) besitzt. Das Subject hat ein oder mehrere Observer, welche es über Datenänderungen informiert. Das geschieht über die Methode notifyObservers(Object data). Zuvor muss aber die Methode setChanged() aufgerufen werden, damit dieses Observable-Objekt als "verändert" markiert wird. Dein ResultsPanel muss also einen Konstruktor verpasst bekommen, welcher ein oder mehrere Observer entgegen nimmt, und muss diese mit der Methode addObserver(Observer o) registrieren.

Beispielhaft mal die tickByTickMidPoint(int, long, double) Methode dargestellt.
Java:
public void tickByTickMidPoint(int reqId, long time, double midPoint) {
    setChanged();
    notifyObservers(midPoint);
}
Dein CPanel ist kein Subject (Observable) sondern ein Observer. Dazu kann diese Klasse das Interface java.util.Observer implementieren und damit die update(Observable o, Object data) überschreiben. Diese Methode wird immer dann von Subject aufgerufen, wenn Änderungen präsent sind. In dieser Methode musst du dann den Text des Label neu setzen.

Solltest du in der update-Methode mehrere Daten übertragen wollen, müssen die Daten in eine Klasse gewrappt werden.
 
Ok hab es geschafft zu Implementieren. Mein Problem war die ganze Zeit das es zwar in der Theorie so ist das man meist mehrere Observer hat ich aber für in meinem Fall nur einen Observer habe für mehrere Subjekte, also jedes Subject hat sozusagen als Observer den selben Abonnenten nähmilch ein und das selbe GUI Objekt. Natürlich spielt das eigentlich keine Rolle hat mich aber verwirrt. Wie auch immer jetzt ist es denke ich sauber programmiert.
@Robat Danke für deine Hilfe der Link war auch Hilfreich Top 🙂
 

Zurück
Oben