2016-10-24 10 views
0

TableViewとその項目に問題があります。 Dialog私のアプリケーションに関する警告を表示する小さなウィンドウを作成しました。Dialogには、警告の名前とボタンをクリックするとその情報が表示されるTableViewがあります。JavaFX:ダイアログ内のTableViewに重複した項目があります

Dialogを開く/閉じるだけで、WarningUtilクラス(Singletonパターン)を作成しました。関連するコードは次のとおりです。

(一度だけ呼ばれる)WarningUtilクラスのコンストラクタ:

private WarningUtil(RootCtrl rootCtrl) { 
    this.rootCtrl = rootCtrl; 
    warnings = new HashMap<>(); 

    setupWarningCallbacks(); // not relevant 
    setupTable(); 
    setupColumns(); // not relevant 
    setupDialog(); 
} 

Dialogの建設を管理する機能:

private void setupTable() { 
    // create the content pane 
    content = new AnchorPane(); // class variable - reference needed for further uses 
    content.setPrefSize(480, 240); 

    // create the root nodes of the view (table + 2 columns) 
    warningTable = new TableView<>(); // class variable - reference needed for further uses 
    warnDescriptionCol = new PTableColumn<>(); // class variable - reference needed for further uses 
    warnDetailsCol = new PTableColumn<>(); // class variable - reference needed for further uses 

    // settings anchors to keep the ration between dialog <-> table 
    AnchorPane.setBottomAnchor(warningTable, 15.0); 
    AnchorPane.setTopAnchor(warningTable, 15.0); 
    AnchorPane.setLeftAnchor(warningTable, 15.0); 
    AnchorPane.setRightAnchor(warningTable, 15.0); 

    // setting up the columns 
    warnDescriptionCol.setText(i18n("label.desc")); 
    warnDetailsCol.setText(i18n("label.details")); 
    warnDescriptionCol.setPercentageWidth(0.7); 
    warnDetailsCol.setPercentageWidth(0.3); 
    warnDescriptionCol.setResizable(false); 
    warnDetailsCol.setResizable(false); 

    // adding nodes to containers 
    warningTable.getColumns().addAll(warnDescriptionCol, warnDetailsCol); 
    content.getChildren().add(warningTable); 
} 

Dialogを作成し、contentを設定するために使用される関数:

private void setupDialog() { 
    // creation and saving of the dialog in a variable reused later 
    warningDialog = DialogFactory.getInstance(rootCtrl.getPrimaryStage()).createWarningDialog(); 
    warningDialog.getDialogPane().setContent(content); 
    warningDialog.getDialogPane().getScene().getWindow().sizeToScene(); 
} 

// The DialogFactory function creating the dialog 

public Dialog createWarningDialog(){ 
    CustomDialog dialog = new CustomDialog(rootStage); 

    dialog.setTitle(i18n("warning.description")); 

    ButtonType cancelBt = new ButtonType(i18n("button.close"), ButtonData.OK_DONE); 
    dialog.getDialogPane().getButtonTypes().add(cancelBt); 

    return dialog.setupLayout(); 
} 

Mainクラスは、警告の読み込みを担当します(.jsonファイルに格納され、アプリの起動時に逆シリアル化されます)。今のところファイルには1つのエントリしか含まれていません。

私は私の警告]ボタンをクリックし

は、以下の関数が呼び出されます:私は私の.jsonファイルで唯一のエントリ、最初の時間を持っているとき、私はをクリックしてください:

public void showWarnings() { 
    warningTable.getItems().clear(); // BP 
    warningTable.setItems(FXCollections.observableArrayList(warnings.values())); 
    warningDialog.showAndWait(); 
} 

は何が起こることは以下のとおりです。ボタン、only one warning is shown

  • ロジック制約:私は二度目、a second entry appears (the same)をクリックすると、次の理由による可能にすべきではないどのwarnings.values()は鍵がすることはできません警告(WarningTypeクラス)>のタイプであるHashMapから来ています二つの同一のキー
  • デバッグを持っている:私は「// BP」にブレークポイントを設定すると、私ははっきりwarningTableは一つのアイテムを持っていることがわかり、そして明確な後のアイテムの数がゼロ
  • デバッグです:それでも同じブレークポイントでまた、warnings.values()には1つのアイテムしかないことが確認されます。その場合は
  • です

ボタンを5回クリックした後、the Dialog clearly shows something is bugging

驚くべきことに、2番目の警告(最初のタイプ、別のタイプと異なる)を追加すると、問題は発生しません。重複はなく、警告は正しく表示されます。

私の質問は:この警告ダイアログを作成する方法が珍しいエラーにつながることでしょうか?もしそうなら、なぜ2つの警告があるのでしょうか?

EDITthe documentationで説明したように、セルが空の場合は、セルの工場であなたの細胞をクリアする必要がありcellFactories/cellValueFactories

private void setupColumns() { 
    warnDescriptionCol.setCellFactory(new Callback<TableColumn<CustomWarning, String>, TableCell<CustomWarning, String>>() { 
     @Override 
     public TableCell<CustomWarning, String> call(TableColumn<CustomWarning, String> param) { 
      TableCell<CustomWarning, String> cell = new TableCell<CustomWarning, String>() { 
       @Override 
       protected void updateItem(String item, boolean empty) { 
        super.updateItem(item, empty); 

        if (item != null) { 
         Label label = new Label(item); 
         setGraphic(label); 
        } 
       } 
      }; 

      return cell; 
     } 
    }); 

    warnDetailsCol.setCellFactory(new Callback<TableColumn<CustomWarning, CustomWarning>, TableCell<CustomWarning, CustomWarning>>() { 
     @Override 
     public TableCell<CustomWarning, CustomWarning> call(TableColumn<CustomWarning, CustomWarning> param) { 
      TableCell<CustomWarning, CustomWarning> cell = new TableCell<CustomWarning, CustomWarning>() { 
       @Override 
       protected void updateItem(CustomWarning item, boolean empty) { 
        super.updateItem(item, empty); 

        if (item != null) { 
         Button button = new Button(i18n("button.view")); 
         button.getStyleClass().add("save"); 
         button.setOnAction(new EventHandler<ActionEvent>() { 
          @Override 
          public void handle(ActionEvent event) { 
           showWarning(item); 
          } 
         }); 

         setGraphic(button); 
        } 
       } 
      }; 

      return cell; 
     } 
    }); 

    warnDescriptionCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<CustomWarning, String>, ObservableValue<String>>() { 
     TableViewObjectWrapper<CustomWarning, String> wrapper = new TableViewObjectWrapper<CustomWarning, String>() { 
      @Override 
      public String getData() { 
       return getModel().getTitle(); 
      } 
     }; 

     @Override 
     public ObservableValue<String> call(TableColumn.CellDataFeatures<CustomWarning, String> param) { 
      return new ReadOnlyObjectWrapper<>(wrapper.setModel(param.getValue()).getData()); 
     } 
    }); 

    warnDetailsCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<CustomWarning, CustomWarning>, ObservableValue<CustomWarning>>() { 
     TableViewObjectWrapper<CustomWarning, CustomWarning> wrapper = new TableViewObjectWrapper<CustomWarning, CustomWarning>() { 
      @Override 
      public CustomWarning getData() { 
       return getModel(); 
      } 
     }; 

     @Override 
     public ObservableValue<CustomWarning> call(TableColumn.CellDataFeatures<CustomWarning, CustomWarning> param) { 
      return new ReadOnlyObjectWrapper<>(wrapper.setModel(param.getValue()).getData()); 
     } 
    }); 
} 
+0

'TableView'のセルファクトリとセル値ファクトリを設定する部分を含めてください。 – Itai

+0

@sillyfly編集 – Jacks

答えて

2

のinclude:

それは非常に重要ですCellのサブクラスはupdateItemメソッドを適切にオーバーライドします。失敗すると、空のセルや予期しないコンテンツがセル内に表示されるなどの問題が発生します。このサンプルコードで二つの重要な点

protected void updateItem(T item, boolean empty) { 
    super.updateItem(item, empty); 

    if (empty || item == null) { 
     setText(null); 
     setGraphic(null); 
    } else { 
     setText(item.toString()); 
    } 
} 

注:ここで適切updateItemメソッドをオーバーライドする方法の例である我々が呼ぶ

  1. はsuper.updateItem(T、ブーリアン)方法。これが行われないと、アイテムと空のプロパティが正しく設定されず、グラフィカルな問題が発生する可能性があります。
  2. 空の条件をテストし、trueの場合、textプロパティとgraphicプロパティをnullに設定します。これを行わなければ、エンドユーザーは予期せずセル内のグラフィックアーチファクトを見ることがほとんど保証されます。

細胞が再利用されているので、あなたはそれが空になった場合、それがない場合はそれを設定し、グラフィックをクリアする必要がありません。

+0

をご覧ください。私はこの習慣を知っていましたが、テーブルをクリアしてアイテムを設定するとこれを回避できると思っていました。私のテーブルに2つのアイテムがある場合、その動作が同じでない理由は何ですか? – Jacks

+1

再利用のアルゴリズムは指定されていないので、内部の作業については何かを推測していますが、それに頼るべきではありません。 – Itai

+0

さて、あなたの答えとあなたの時間に感謝します。@sillyfly – Jacks

関連する問題