5

コントローラーがあり、電子メールサーバーから INBOX フォルダーを取得しようとしています。ダウンロードすればすべてOKです。このデータ(メールの件名、送信者、日付)をTableViewに入れることができますが...このデータをTableViewに設定するスレッドを待っているときだけです。コード:

// The table and columns
@FXML
TableView<MainModel.Item> itemTbl;
@FXML
TableColumn itemNameCol;
@FXML
TableColumn itemQtyCol;
@FXML
TableColumn itemTitleCol;
// The table's data
static ObservableList<MainModel.Item> data;

public void dataSet(){
    // Set up the table data
    itemNameCol.setCellValueFactory(
        new PropertyValueFactory<MainModel.Item,String>("name")
    );
    itemQtyCol.setCellValueFactory(
        new PropertyValueFactory<MainModel.Item,String>("qty")
    );
    itemTitleCol.setCellValueFactory(
        new PropertyValueFactory<MainModel.Item,String>("title")
    );

    data = FXCollections.observableArrayList();
    itemTbl.setItems(data);
}

public void setEnemyEvent() {
    itemTbl.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            if (event.getClickCount() == 2) {
                if(itemTbl.getSelectionModel().getSelectedItem()!=null){
                    System.out.println(itemTbl.getSelectionModel().getSelectedItem().name);
                }
            }
        }
    });
}

@Override
public void initialize(URL url, ResourceBundle rb) { 
    setEnemyEvent();
    dataSet();
    Thread t = new Thread(new MessageLoop());
    //HERE:
    t.start();
    //of course normally here is try and catch
    t.join();
}

//staric nested class "for loop"
private static class MessageLoop implements Runnable {
    public void run() {
        try {
            EmailConnetion con = new EmailConnetion();
            MainModel MainModel = new MainModel();
            for(int i=0;i<con.message.length;i++){
                try{
                    MainModel.Item item = MainModel.new Item();
                    item.name.setValue(i+""+con.message[i].getFrom()[0].toString());
                    item.qty.setValue(con.message[i].getSentDate().toString());
                    item.title.setValue(con.message[i].getSubject().toString());
                    //Here is a problem.
                    data.add(item);//This indicate my IDE  
                    //*****************
                } catch(AddressException e) {
                    System.out.println("Error : " + "AddressException:"+i);
                }
            }
        } catch (NoSuchProviderException ex) {
            Logger.getLogger(SimpleController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MessagingException ex) {
            Logger.getLogger(SimpleController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

t.join() を削除すると、この NullPointerException がスローされます。

Exception in thread "Thread-3" java.lang.NullPointerException
    at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:291)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:48)
    at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:74)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel$3.onChanged(TableView.java:1725)
    at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:134)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:48)
    at com.sun.javafx.collections.ObservableListWrapper.callObservers(ObservableListWrapper.java:97)
    at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:184)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel.quietClearSelection(TableView.java:2154)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel.updateSelection(TableView.java:1902)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel.access$2600(TableView.java:1681)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel$8.onChanged(TableView.java:1802)
    at com.sun.javafx.scene.control.WeakListChangeListener.onChanged(WeakListChangeListener.java:71)
    at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:291)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:48)
    at com.sun.javafx.collections.ObservableListWrapper.callObservers(ObservableListWrapper.java:97)
    at com.sun.javafx.collections.ObservableListWrapper.add(ObservableListWrapper.java:154)
    at com.sun.javafx.collections.ObservableListWrapper.add(ObservableListWrapper.java:144)
    at javasplitpane.SimpleController$MessageLoop.run(SimpleController.java:95)
    at java.lang.Thread.run(Thread.java:722)

これは、14 通のメール、30 通のメールという異なる位置に表示されます。アイデアはありますか?

ps このダウンロードには 20 秒かかるので待ちきれません。50通のメールで-初期化中にそれをしなければなりません。

4

1 に答える 1

10

あなたの間違い

JavaFX アプリケーション スレッド以外のスレッドからアクティブなシーン グラフに接続されているものは変更しないでください。

背景情報

このルールの説明については、 JavaFX Concurrency TutorialおよびJavaFX Platform.runLater の使用と別のスレッドからの UI へのアクセスを参照してください。

データ リストは、アクティブなシーン グラフに表示される TableView をサポートするObservableListあるため、ObservableList を変更すると、JavaFX アプリケーション スレッドではなくユーザー スレッドからそれを変更する TableView への変更イベントが発生します。これにより、競合状態と一貫性のないプログラムが発生します。失敗。

修正方法

問題を解決するには、呼び出しをラップしてPlatform.runLater内のデータ項目を更新します。

Platform.runLater(new Runnable() {
  @Override public void run() {
    data.add(item);
  }
});

runに送信されたメソッドの内容はPlatform.runLater、JavaFX アプリケーション スレッドで実行されます。

于 2013-03-09T01:56:03.797 に答える