2017-04-04 9 views
0

背景:私は今mp3プログラムにファイルをロードして再生できますが、テーブルビューのすべての値はnullですか? enter image description hereJavaFXテーブルビューに文字列値を設定する方法

マイ歌クラス

package application; 

//imports here 

public class Song { 
private String title; 
private String artist; 
private String album; 
private SimpleStringProperty pTitle; 
private SimpleStringProperty pArtist; 
private SimpleStringProperty pAlbum; 
private Media music; 
private MediaPlayer mp; 
private Image coverArt; 

public Song(File file) { 
    music = new Media(file.toURI().toString()); 
    music.getMetadata().addListener((Change<? extends String, ? extends Object> c) -> { 
     if (c.wasAdded()) { 
      if ("artist".equals(c.getKey())) { 
       System.out.println(c.getKey()+":"+c.getValueAdded()); 
       this.pArtist = new SimpleStringProperty(c.getValueAdded().toString()); 
       //pArtist.set(c.getValueAdded().toString()); 
       artist = c.getValueAdded().toString(); 
      } else if ("title".equals(c.getKey())) { 
       title = c.getValueAdded().toString(); 
       System.out.println(c.getKey()+":"+c.getValueAdded()); 
      } else if ("album".equals(c.getKey())) { 
       album = c.getValueAdded().toString(); 
       System.out.println(c.getKey()+":"+c.getValueAdded()); 
      } else if ("image".equals(c.getKey())) { 
       coverArt = (Image) c.getValueAdded(); 
      } 
     } 
    }); 
    mp = new MediaPlayer(music); 
    System.out.println(pArtist); 
    System.out.println(artist); 
    //artist = (String) mp.getMedia().getMetadata().get("artist"); 
    //title = (String) music.getMetadata().get("title"); 
    //album = (String) music.getMetadata().get("album"); 
    //artist = "test"; 
    //album = "test"; 
    //title = "test"; 
} 

public void play() { 
    mp.play(); 
} 

public void pause() { 
    mp.pause(); 
} 

public void stop() { 
    mp.stop(); 
} 

public String getTitle(){ 
    return title; 
} 

public void setTitle(String title){ 
    this.title = title; 
} 

public String getArtist(){ 
    return artist; 
} 

public void setArtist(String artist){ 
    this.artist = artist; 
} 

public String getAlbum(){ 
    return album; 
} 

public void setAlbum(String album){ 
    this.album = album; 
} 

public Image getCover(){ 
    return coverArt; 
} 

public MediaPlayer getMP(){ 
    return mp; 
} 





} 

最初に私は私の文字列変数が正しく設定されませんでしたし、それがコンソールにNULLとして示しているので、私はこれらのプリントを入れたときにnullに設定されたので、それが思った変なふうに十分Songオブジェクトが構築されているときにそれをテストするための行。ここで私はこれをテストするコンソールのサンプルです。ここで

null 
null 
artist:Foo Fighters 
album:Saint Cecilia EP 
title:Saint Cecilia 

は私のコントローラクラスは

public class SceneController implements Initializable{ 
@FXML 
private Button stopBtn; 
@FXML 
private Slider volume; 
@FXML 
private Button loadBtn; 
@FXML 
private Button playBtn; 
@FXML 
private TableView<Song> table; 
@FXML 
private Label label; 
@FXML 
private ProgressBar proBar; 
private TableColumn songCol,artistCol,albumCol; 
ObservableList<Song> songList = FXCollections.observableArrayList(); 
List<File> list; 
FileChooser fileChooser = new FileChooser(); 
Desktop desktop; 
Song mySong; 



@Override 
public void initialize(URL arg0, ResourceBundle arg1) { 
    TableColumn songCol = new TableColumn("Song"); 
    TableColumn artistCol = new TableColumn("Artist"); 
    TableColumn albumCol = new TableColumn("Album"); 

    songCol.setCellValueFactory(
      new PropertyValueFactory<Song,String>("title")); 
    //songCol.setCellFactory(new Callback); 
    artistCol.setCellValueFactory(
      new PropertyValueFactory<Song,String>("artist")); 
    albumCol.setCellValueFactory(
      new PropertyValueFactory<Song,String>("album")); 
    volume.setMin(0); 
    volume.setMax(100); 
    volume.setValue(100); 
    volume.valueProperty().addListener(new InvalidationListener() { 
     @Override 
     public void invalidated(Observable observable) { 
      mySong.getMP().setVolume(volume.getValue()/100.0); 
     } 

    }); 

} 

// Event Listener on Button[#loadBtn].onAction 
@FXML 
public void loadFile(ActionEvent event) { 
    Node source = (Node) event.getSource(); 
    Window theStage = source.getScene().getWindow(); 
    //set fileChooser filter 
    FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("MP3 files", "*.mp3"); 
    fileChooser.getExtensionFilters().add(extFilter); 
    fileChooser.setTitle("Select MP3 files"); 
    //File file = fileChooser.showOpenDialog(theStage); 
    //mySong = new Song(file); 
    list = fileChooser.showOpenMultipleDialog(theStage); 
    if(list!=null){ 
     for(File x: list) { 
      mySong = new Song(x); 
      System.out.println(mySong.getTitle()); 
      songList.add(mySong); 
     } 
    } 
    table.setItems(songList); 
} 

@FXML 
public void playSong(ActionEvent event) { 
    mySong.play(); 
} 

@FXML 
public void stopSong(ActionEvent event) { 
    //mySong.pause(); 
    System.out.println("song title: "+mySong.getArtist()+mySong.getTitle()); 
    ImageView img = new ImageView(mySong.getCover()); 
    //img.fitWidthProperty().bind(label.widthProperty()); 
    //img.fitHeightProperty().bind(label.heightProperty()); 
    img.setFitHeight(120); 
    img.setFitWidth(200); 
    label.setGraphic(img); 
    //label.setGraphic(new ImageView(mySong.getCover())); 
} 

あるしかし、私は、コントローラクラスで私の「停止」ボタンの別のテストプリントラインを作り、すべてがロードされていると私はそれを押した後、それが出て印刷しますアーティストとタイトルの罰金。私はこれを見たother threadと私のゲッターメソッドをチェックし、彼らは正しいようですか?私は実際にこれで失われて、誰かが何かの洞察力と私の変数がnullまたは私のPropertyValueFactoryが正しく行われていないために解決策を提供することができる場合

また、私はnullsが最初に来ることに気付くコントローラークラスで新しいソングオブジェクトを作成したときに最初に実行されたプリントラインがifステートメントにあるので、最後に印刷されたものですか?

+0

あなたは 'setCellValueFactory(...)を呼び出し、'、すべて小文字を使用してみてください。私は引用符で囲まれた単語が 'Song'クラスの変数名と一致しなければならないと思います。私は、私は別の方法で私のセルの値を設定するため、私は思うと言う。 –

+0

小文字と大文字を使ってみましたが、違いはありません –

+0

'TableView'にはどこに列を追加しますか?私は 'songList'を追加する場所を見ていますが、' TableColumn'は追加していません。また、上の3つのカラムを宣言したようですが、 'initialize'でそれらを再宣言して初期化します。 'initialize'メソッドの宣言を削除し、そこで初期化してみてください。 –

答えて

1

あなたはに投稿された限られた例から明らかであるあなたがあなたの現在のコードを持っている方法と間違っていくつかのものがありますが、質問:

  1. SongクラスはありませんJavaFX properties patternに正しく従ってください。特に、各プロパティを2回、「従来型」のJavaBeanスタイルのフィールドに2回(たとえばprivate String title)、JavaFXプロパティで1回(private StringProperty pTitle;)格納します。各プロパティは一度格納する必要があります。値が変更されたときにテーブルを認識させるには、JavaFXプロパティを使用し、 "標準" getXXX()およびsetXXX()にこれらのプロパティに格納されている基本値を取得して設定する必要があります。
  2. あなたはメディアのメタデータに添付するリスナーは将来のある不定の時点で非同期と呼ばれています。ソングをテーブルのリストに追加すると、列にアタッチされたセル値ファクトリが実行され、Songインスタンスから割り当てられたプロパティが取得されます。現在のコードと同様に、メタデータのリスナーが呼び出されると、それらのプロパティインスタンスは実際に作成されます。したがって、JavaFXプロパティがインスタンス化される前に、セル値ファクトリがそのプロパティのSongインスタンスを検査し、テーブルがそのプロパティを適切に観察し、そのプロパティの変更に応答することが不可能になる可能性があります(おそらく)。 Songインスタンスが作成されたときにJavaFXプロパティをインスタンス化し、その値をメタデータのリスナーに設定する必要があります。
  3. コントローラに作成した列をテーブルに追加することはできません。あなたは(あなたが質問に投稿していなかった)FXMLファイルでそれらを作成している場合は、コントローラにそれらの列を注入し、セル値の工場とたもの列を初期化する必要があります。 (スクリーンショットは、テーブル内の列がある示しているので、私は彼らがFXMLファイルに定義され、かつ適切なfx:id Sを持っていると仮定するつもりです。)

だからあなたSongクラスは次のようになります。

お使いのコントローラの
public class Song { 

    private final StringProperty title = new SimpleStringProperty(); 
    private final StringProperty artist = new SimpleStringProperty(); 
    private final StringProperty album = new SimpleStringProperty(); 
    private Media music; 
    private MediaPlayer mp; 
    private Image coverArt; 

    public Song(File file) { 
     music = new Media(file.toURI().toString()); 
     music.getMetadata().addListener((Change<? extends String, ? extends Object> c) -> { 
      if (c.wasAdded()) { 
       if ("artist".equals(c.getKey())) { 
        setArtist(c.getValueAdded().toString()); 
       } else if ("title".equals(c.getKey())) { 
        setTitle(c.getValueAdded().toString()); 
       } else if ("album".equals(c.getKey())) { 
        setAlbum(c.getValueAdded().toString()); 
       } else if ("image".equals(c.getKey())) { 
        // maybe this needs to be a JavaFX property too: it is not clear from your question: 
        coverArt = (Image) c.getValueAdded(); 
       } 
      } 
     }); 
     mp = new MediaPlayer(music); 
    } 

    public void play() { 
     mp.play(); 
    } 

    public void pause() { 
     mp.pause(); 
    } 

    public void stop() { 
     mp.stop(); 
    } 

    public StringProperty titleProperty() { 
     return title ; 
    } 

    public final String getTitle(){ 
     return titleProperty().get(); 
    } 

    public final void setTitle(String title){ 
     titleProperty().set(title); 
    } 

    public StringProperty artistProperty() { 
     return artist ; 
    } 

    public final String getArtist(){ 
     return artistProperty().get(); 
    } 

    public final void setArtist(String artist){ 
     artistProperty.set(artist); 
    } 

    public StringProperty albumProperty() { 
     return album ; 
    } 

    public final String getAlbum(){ 
     return albumProperty().get(); 
    } 

    public final void setAlbum(String album){ 
     albumProperty().set(album); 
    } 

    public Image getCover(){ 
     return coverArt; 
    } 

    public MediaPlayer getMP(){ 
     return mp; 
    } 


} 

、私はあなたのFXMLファイルはそれぞれ、fx:id"songCol"のS、"artistCol"、および"albumCol"と表の列を定義していると仮定するつもりです。他の列と同様に、これらをコントローラに注入する必要があります。また、私は強くないリフレクションを使用し、コンパイル時のチェックの方法で多くを欠いているPropertyValueFactoryクラスを使用して、コールバックを自分で実装することをお勧めします。ラムダ式を使用すると、これを簡単に行うことができます。

だからあなたのコントローラは次のようになります。

public class SceneController implements Initializable{ 

    // non-table code omitted... 

    @FXML 
    private TableView<Song> table; 
    @FXML 
    private Label label; 
    @FXML 
    private ProgressBar proBar; 
    @FXML 
    private TableColumn<Song, String> songCol ; 
    @FXML 
    private TableColumn<Song, String> artistCol ; 
    @FXML 
    private TableColumn<Song, String> albumCol; 

    ObservableList<Song> songList = FXCollections.observableArrayList(); 
    List<File> list; 
    FileChooser fileChooser = new FileChooser(); 
    Desktop desktop; 
    Song mySong; 

    @Override 
    public void initialize(URL arg0, ResourceBundle arg1) { 

     songCol.setCellValueFactory(cellData -> cellData.getValue().titleProperty()); 
     artistCol.setCellValueFactory(cellData -> cellData.getValue().artistProperty()); 
     albumCol.setCellValueFactory(cellData -> cellData.getValue().albumProperty()); 

     // ... 

    } 

    // other non-table code omitted... 

} 

あなたは、最小限の、完全な、検証可能な例を投稿していなかったので、うまく正しく表示さからテーブルを防ぐため、あなたのコード内の他のエラーがあるかもしれません。しかし、これはあなたを始めるはずです。

+0

あなたは最高です、先ほどの他の問題も私を助けてくれました。私はあなたが提案したことをやったことがありました。また、次回はmxを心に留めておきます。私はfxml文書について多くの人を混乱させるようです –

1

通常、TableColumnsはFXMLで定義され、@FXMLで注入されます。

あなたがそのようにしたくない場合は、実行する必要があります。あなたの他の列のための

table.getColumns().add(songCol); 

と同様に。

また、HypnicJerkがコメントで指摘したように、PropertyValueFactoryを使用する場合は、適切な命名規則に従う必要があります。詳細については

songCol.setCellValueFactory(
    new PropertyValueFactory<Song,String>("title") 
); 

は、以下を参照してください。

+0

私は小文字にその一部を変更しましたが、まだ[MCVE](https://stackoverflow.com/help/を参照してください(、私はまた、すべてはFXMLを設けることなく、あまりにも –

+0

定義されたFXMLドキュメントを持っているヌル として表示されますmcve))、あなたはさらに助けられません。 – jewelsea

関連する問題