Event Handling JavaFx - auf Event warten

handoffate

Mitglied
Hallo zusammen,
ich bräuchte Hilfe bei einem kleinen Problem mit den Media-Klassen aus der JavaFx-Version. Ich habe folgenden Code für einen Button:
Java:
addbutton.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent e) {
        FileChooser fc = new FileChooser();
        List<File> filelist =  fc.showOpenMultipleDialog(primaryStage);
        if (filelist != null) {
          for (File file : filelist)   {
            Media m = new Media(file.toURI().toString());
            MedienElement me = new MedienElement(m);
            System.out.println(me.toString());
          }
        }
      }
    });

und die dazugehörige Klasse MediaElement:
Java:
public class MedienElement {
 
  String artist;
  Media song;
 
 
  public MediaElement(Media m){
    song = m;
     
    MediaPlayer mp = new MediaPlayer(m);

    mp.setOnReady(new Runnable() {
      @Override
      public void run() {
        artist = (String)mp.getMedia().getMetadata().get("artist");
      }
    });
   
  }
  
 
  public String toString(){
    return artist;
  }
 
}

Ich möchte also lediglich eine beliebige Anzahl von beispielsweise mp3 Dateien laden und auf deren Metadaten zugreifen. Folgende Probleme habe ich bzw. Aspekte verstehe ich nicht:
  • Warum brauche ich einen MediaPlayer, um die Metadaten meiner Media auszulesen? Die Metadaten müssten doch auch unabhängig vom Player bereits existieren!?
  • Das eigentliche Problem liegt in der Zeile
    Java:
    System.out.println(me.toString());
    Hier wird null ausgegeben, da der Thread, welcher beim setOnReady gestartet wird noch nicht fertig ist bzw. noch gar nicht gestartet wurde (?).. Also müsste ich es bewerkstelligen, dass ich bevor ich die Ausgabe tätige (bzw. insgesamt mit meinem MediaElement weiter arbeite), warte bis der setOnReady-Thread vollständig abgearbeitet wurde (mal davon ausgegangen, dass es beim Laden kein Fehler gibt und der Player wirklich in den Ready-Zustand gelangt). Hierfür fehlt mir jedoch jeglicher Ansatz..
Danke..
 
Da musst du mit Futures bzw. FutureTask arbeiten.

So zum Beispiel:
Java:
class MedienElement {

  private FutureTask<String> artist;

  public MedienElement(Media m) {
    MediaPlayer mp = new MediaPlayer(m);
    artist = new FutureTask<>(new Callable<String>() {
      @Override
      public String call() throws Exception {
        return (String) mp.getMedia().getMetadata().get("artist");
      }
    });

    mp.setOnReady(new Runnable() {
      @Override
      public void run() {
        artist.run();
      }
    });
  }

  public String toString() {
    try {
      return artist.get();
    } catch (InterruptedException | ExecutionException ex) {
      ex.printStackTrace();
    }
    return "<undefined>";
  }
}
 
Hmm, klappt leider noch nicht ganz.
Ich denke das Prinzip mit den FutureTasks hab ich verstanden, und das die get-Methode ja genau das realisieren sollte, was ich wollte.. Allerdings hängt sich das Programm nun auf, weil der MediaPlayer nicht in den Ready-Status gelangt oder die Ausführung des entsprechenden Threads blockiert ist. Lasse ich den print-Aufruf in der Button-Methode weg, läuft alles einwandfrei (und wenn ich mit einem anderen Button auf das MedienElement zugreife erhalte ich genau die gewünschten Metadaten)..
 
Ist jetzt schwer zu sagen was da genau schiefläuft. Poste doch mal ein KSKB (kurzes, selbständiges und kompilierbares Beispiel), dann kann man sich das dann näher angucken
 
ok, hier die beiden Klassen:
Java:
import javafx.application.*;
import javafx.stage.Stage;
import javafx.stage.FileChooser;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.scene.media.Media;
import javafx.event.*;
import java.io.*;
import java.util.*;



public class mainV extends Application {

  Button addbutton;
  Pane gpanel;

@Override
  public void init(){
    gpanel = new Pane();
    addbutton = new Button("+");
    gpanel.getChildren().add(addbutton);
  }

@Override
  public void start(Stage primaryStage)    {
    Scene scene = new Scene(gpanel, 100, 100);
    primaryStage.setTitle("Media Player");
    primaryStage.setScene(scene);
    primaryStage.show();


    addbutton.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent e) {
        FileChooser fc = new FileChooser();
        List<File> filelist =  fc.showOpenMultipleDialog(primaryStage);
        if (filelist != null) {
          for (File file : filelist)   {
            Media m = new Media(file.toURI().toString());
            MedienElement me = new MedienElement(m);
            System.out.println(me.toString());
          }
        }
      }
    });

  }

public static void main(String[] args) {
    launch(args);
  }


}

Java:
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.collections.*;
import java.util.*;
import java.util.concurrent.*;


class MedienElement {

  private FutureTask<String> artist;

  public MedienElement(Media m) {
    MediaPlayer mp = new MediaPlayer(m);
    artist = new FutureTask<>(new Callable<String>() {
      @Override
      public String call() throws Exception {
        return (String) mp.getMedia().getMetadata().get("artist");
      }
    });

    mp.setOnReady(new Runnable() {
      @Override
      public void run() {
        artist.run();
      }
    });
  }

  public String toString() {
    try {
      return artist.get();
    } catch (InterruptedException | ExecutionException ex) {
      ex.printStackTrace();
    }
    return "<undefined>";
  }

}
 

Neue Themen


Zurück
Oben