Как мне обрабатывать медиа-метаданные в отдельном классе? - PullRequest
0 голосов
/ 01 ноября 2018

Я создаю медиаплеер с использованием классов JavaFX Media. Я создал класс SongModel, который инкапсулирует все метаданные из файла и создает экземпляры Media и MediaPlayer.

Это выглядит примерно так:

private final StringProperty album =
            new SimpleStringProperty(this, "album");

public String getAlbum(){ return album.get(); }
public void setAlbum(String value){ album.set(value); }
public StringProperty albumProperty() { return album; }

Есть также поля Artist, Year, Title и albumCover, которые выглядят так же. Кроме того, свойство MediaPlayer доступно только для чтения:

public MediaPlayer getMediaPlayer(){ return mediaPlayer.get(); }
    public ReadOnlyObjectProperty<MediaPlayer> mediaPlayerProperty(){
        return mediaPlayer.getReadOnlyProperty();
    }

Я использую MapChangelistener, чтобы проверить, доступно ли поле, и затем передаю его методу handleMetadata:

private void initializeMedia(String url){

        try {
            final Media media = new Media(url);
            media.getMetadata().addListener(new MapChangeListener<String, Object>(){
                @Override
                public void onChanged(MapChangeListener.Change<? extends String, ? extends Object> ch) {
                    if(ch.wasAdded()){
                        handleMetadata(ch.getKey(), ch.getValueAdded());
                    }
                }                
            });

            mediaPlayer.setValue(new MediaPlayer(media));
            mediaPlayer.get().setOnError(new Runnable() {
                @Override
                public void run() {
                    String errorMessage = mediaPlayer.get().getError().getMessage();
                    System.out.println("MediaPlayer error: "+errorMessage);
                }
            });

        }catch(RuntimeException e){
            System.out.println("Construction error: "+e);
        }
    }

    private void handleMetadata(String key, Object value){
        if(key.equals("album")){
            setAlbum(value.toString());
        } else if (key.equals("artist")){
            setArtist(value.toString());
        } if (key.equals("title")){
            setTitle(value.toString());
        } if (key.equals("year")){
            setYear(value.toString());
        } if (key.equals("image")){
            setAlbumCover((Image)value);
        }
    }

Затем я создал класс AbstractView, обеспечивающий доступ к SongModel:

public abstract class AbstractView {
    protected final SongModel songModel;
    protected final Node viewNode;

    public AbstractView(SongModel songModel){
        this.songModel = songModel;
        this.viewNode = initView();
        }

        public Node getViewNode() {
            return viewNode;
        }

        protected abstract Node initView();
}

Но когда я пытаюсь создать класс MetadataView, я сталкиваюсь с некоторыми проблемами. Вот как это выглядит:

public class MetadataView extends AbstractView{
    public Label artist;
    public Label album;
    public Label title;
    public Label year;
    public ImageView albumCover;

    public MetadataView(SongModel songModel) {
        super(songModel);
    }

    @Override
    protected Node initView() {
        artist = new Label();
        artist.setId("artist");
        album = new Label();
        album.setId("album");
        title = new Label();
        title.setId("title");
        year = new Label();
        year.setId("year");

        final Reflection reflection = new Reflection();
        reflection.setFraction(0.2);

        final URL url = getClass().getResource("resources/defaultAlbum.png");
        Image image = new Image(url.toString());

        albumCover = new ImageView(image);
        albumCover.setFitWidth(240);
        albumCover.setPreserveRatio(true);
        albumCover.setSmooth(true);
        albumCover.setEffect(reflection);

        final GridPane gp = new GridPane();
        gp.setPadding(new Insets(10));
        gp.setHgap(20);
        gp.add(albumCover, 0,0,1, GridPane.REMAINING);
        gp.add(title, 1,0);
        gp.add(artist, 1,1);
        gp.add(album, 1,2);
        gp.add(year, 1,3);

        final ColumnConstraints c0 = new ColumnConstraints();
        final ColumnConstraints c1 = new ColumnConstraints();

        c1.setHgrow(Priority.ALWAYS);
        gp.getColumnConstraints().addAll(c0,c1);

        final RowConstraints r0 = new RowConstraints();
        r0.setValignment(VPos.TOP);
        gp.getRowConstraints().addAll(r0,r0,r0,r0);


        return gp;

    }

}

И вот как я это называю в методе запуска:

metaDataView = new MetadataView(songModel);

Проблема в том, что он отображает только метаданные по умолчанию, не беря их из класса songmodel. Я попытался запустить код представления метаданных вместе с обработкой данных в одном классе, и все работало, но когда я пытаюсь поместить их в отдельные классы - это не так. Музыка работает отлично, это просто данные, которые не отображаются. Кто-нибудь может сказать мне, что я скучаю? Как мне сделать так, чтобы отображались метаданные из класса SongModel? Я потратил на это много времени и не хочу, чтобы это пропало даром.

1 Ответ

0 голосов
/ 02 ноября 2018

После дня поиска я нашел ответ: связывает. Все, что мне нужно было сделать, это привязать свойство label класса SongModel к свойству label класса MetadataView:

title.textProperty().bind(songModel.titleProperty());
artist.textProperty().bind(songModel.artistProperty());
album.textProperty().bind(songModel.albumProperty());
year.textProperty().bind(songModel.yearProperty());
albumCover.imageProperty().bind(songModel.albumCoverProperty());
...