2016-03-01 38 views
0

所以我有3列,其中一个表视图是组合框的一列,我创建组合框的列中的方法是作为这样在表视图刷新组合框的一列,JavaFX的

Source = new TableColumn<>("Configure Interface as.."); 
    Source.setCellValueFactory(i -> { 
     final StringProperty value = i.getValue().optionProperty(); 
     // binding to constant value 
     return Bindings.createObjectBinding(() -> value); 
    }); 

    Source.setCellFactory(col -> { 
     TableCell<TableViewTest, StringProperty> c = new TableCell<>(); 
     ComboBox<String> comboBox = new ComboBox<>(options); 
     c.itemProperty().addListener((observable, oldValue, newValue) -> { 
      if (oldValue != null) { 
       comboBox.valueProperty().unbindBidirectional(oldValue); 
      } 
      if (newValue != null) { 
       comboBox.valueProperty().bindBidirectional(newValue); 
      } 
     }); 
     c.graphicProperty().bind(Bindings.when(c.emptyProperty()).then((Node) null).otherwise(comboBox)); 
     return c; 
    }); 

该列从驻留在我的TableViewTest类中的getter方法optionProperty()中获取其值。

所以我遇到的问题是我有另一个combobox(comboBoxA)就是我上面的tableview表在我的GUI,并当过我改变comboBoxA的价值,我想与列来改变组合框的值。

我可以通过调用被监听comboboxA

Source.setCellValueFactory(i -> { 
    final StringProperty value = i.getValue().optionTwoProperty(); 
    // binding to constant value 
    return Bindings.createObjectBinding(() -> value); 
}); 

的选择变化的方法中的下列代码做到这一点,但值不改变,除非是开始向下滚动到附近的底部表。有没有办法强制组合框更改为getter方法optionTwoProperty()中的新值,而不必向下滚动?

编辑

好了,行了

 final StringProperty value = i.getValue().optionTwoProperty(); 

犯规actaully被调用,直到我开始向下滚动。

+1

后的代码更改值。因为你在这里使用我的代码的修改版本http://stackoverflow.com/a/35134148/2991525我测试了这个'comboBoxA.valueProperty()。addListener((a,b,c) - > { for(TableViewTest item:tableview.getItems()){ item.setOption(c); } });',但无法重现错误。 – fabian

+0

事情是我正在使用一个fxml文件,我的代码是在fxml控制器文件中,所以我不必为comboBoxA设置一个侦听器,而只是在选择更改时命名我想调用的方法。用于更改值的代码是'Source.setcellValueFactory'部分 – noobCoder

+0

您可以显示您的声明,以便我们知道事物的类型? (你的模型类也可能有帮助。)为什么你的单元格值是一个绑定的属性?难道你不能把它变成一个'TableColumn '而不是'TableColumn ',这看起来是什么? –

回答

1

所以,在fabian的帮助下,我想我理解您希望表格上方的组合框更改表格列中单元格中表示的模型类中的属性。

做到这一点的一种方法是制作将模型类映射到属性的组合框函数的类型,并使用映射到每个所需属性的函数来填充它。

然后,您可以使用绑定来表示表格列的单元格值工厂,该绑定会观察可能表示的所有可能属性以及组合框中选定的值,并返回通过应用函数计算的值组合框到模型实例(并检索其包装值)。

对于列的单元格工厂,您可以观察单元格组合框中的选定值。更改时,使用表格上方组合框中的选定项目来确定要更新哪个属性。

这里有一个SSCCE:

import java.util.function.Function; 

import javafx.application.Application; 
import javafx.beans.binding.Bindings; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.geometry.Insets; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.ComboBox; 
import javafx.scene.control.ListCell; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class TableWithSetAllComboBox extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TableView<Item> table = new TableView<>(); 
     TableColumn<Item, String> itemCol = new TableColumn<>("Item"); 
     itemCol.setCellValueFactory(cellData -> Bindings.createStringBinding(() -> cellData.getValue().getName())); 
     table.getColumns().add(itemCol); 

     TableColumn<Item, String> choiceCol = new TableColumn<>("Choice"); 

     ComboBox<Function<Item, StringProperty>> option = new ComboBox<>(); 

     option.getItems().add(Item::choiceProperty); 
     option.getItems().add(Item::choice2Property); 

     option.setCellFactory(lv -> createListCell()); 
     option.setButtonCell(createListCell()); 

     option.getSelectionModel().select(0);   


     ObservableList<String> choices = FXCollections.observableArrayList("First choice", "Second choice", "Third choice"); 

     choiceCol.setCellFactory(col -> { 
      TableCell<Item, String> cell = new TableCell<>(); 
      ComboBox<String> combo = new ComboBox<>(choices); 
      cell.graphicProperty().bind(Bindings.when(cell.emptyProperty()).then((Node)null).otherwise(combo)); 
      combo.valueProperty().addListener((obs, oldValue, newValue) -> { 
       if (! cell.isEmpty() && newValue != null) { 
        Item item = table.getItems().get(cell.getIndex()) ; 
        StringProperty property = option.getValue().apply(item); 
        property.set(newValue); 
       } 
      }); 
      cell.itemProperty().addListener((obs, oldItem, newItem) -> combo.setValue(newItem)); 
      return cell ; 
     }); 

     choiceCol.setPrefWidth(150); 

     table.getColumns().add(choiceCol); 

     choiceCol.setCellValueFactory(cellData -> Bindings.createStringBinding( 
       () -> option.getValue().apply(cellData.getValue()).get(), 
       cellData.getValue().choiceProperty(), 
       cellData.getValue().choice2Property(), 
       option.valueProperty())); 

     choiceCol.setGraphic(option); 

     choiceCol.setPrefWidth(200); 

     for (int i = 1; i <= 30 ; i++) table.getItems().add(new Item("Item "+i ,choices.get(0))); 

     Button debug = new Button("Debug"); 
     debug.setOnAction(e -> table.getItems().stream(). 
       map(item -> String.format("%s (%s, %s)", item.getName(), item.getChoice(), item.getChoice2())). 
       forEach(System.out::println)); 

     BorderPane root = new BorderPane(table); 
     BorderPane.setMargin(debug, new Insets(5)); 
     root.setBottom(debug); 

     primaryStage.setScene(new Scene(root, 600, 600)); 
     primaryStage.show(); 
    } 

    private ListCell<Function<Item, StringProperty>> createListCell() { 
     return new ListCell<Function<Item, StringProperty>>() { 
      @Override 
      public void updateItem(Function<Item, StringProperty> item, boolean empty) { 
       super.updateItem(item, empty); 
       setText(empty ? null : item.apply(new Item("", "")).getName()); 
      } 
     }; 
    } 

    public static class Item { 
     private final String name ; 
     private final StringProperty choice ; 

     private final StringProperty choice2 ; 

     public Item(String name, String choice) { 
      this.choice = new SimpleStringProperty(this, "Choice", choice); 
      this.choice2 = new SimpleStringProperty(this, "Choice 2", "Second choice"); 
      this.name = name ; 
     } 

     public final StringProperty choiceProperty() { 
      return this.choice; 
     } 

     public final java.lang.String getChoice() { 
      return this.choiceProperty().get(); 
     } 

     public final void setChoice(final java.lang.String choice) { 
      this.choiceProperty().set(choice); 
     } 

     public String getName() { 
      return name; 
     } 
     public final StringProperty choice2Property() { 
      return this.choice2; 
     } 

     public final java.lang.String getChoice2() { 
      return this.choice2Property().get(); 
     } 

     public final void setChoice2(final java.lang.String choice2) { 
      this.choice2Property().set(choice2); 
     } 

    } 

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

我不是100%确定的,但是如果我理解了这个问题,它基本上是关于改变列中显示的属性('i.getValue()。optionTwoProperty()' <=>'i.getValue()。optionProperty()'),这应该可以通过替换整列来完成......'TableView'外部的'ComboBox'选择使用的属性......(我猜)如果我是对的,即使单元格只是显示文本内容而不是这个“ComboBox”设置... – fabian

+0

好的,这是有道理的。通过替换'cellValueFactory',它*应该*真的可能,但更新'cellValueFactory'似乎(尽管我需要测试)导致在单元上调用updateItem(这看起来像一个bug) 。从理论上讲,你应该能够使组合框成为ComboBox ,TableCell <...> >>,并将'cellValueFactoryProperty'绑定到它的值,但是立即测试它并不适合我。你可能可以创建一个自定义绑定... –

+0

自定义绑定会有问题,但是,因为这里写访问似乎是必需的。 – fabian

0

很难说给出的代码片段。在更新时可能你不在javaFX线程上?在这种情况下,使用Platform.runLater(...),或者分享一些最少的代码来重现问题。

0

问题是TableView未收听对其列的元素的cellValueFactory属性的修改。因此TableView不知道它应该重画它的单元格。在JavaFX 8u60被用于此目的添加refresh()方法(出于某种原因,我不能在网上找到的javadoc它虽然),它允许你改变你的方法的代码改变cellValueFactory这样的:

Source.setCellValueFactory(i -> { 
    final StringProperty value = i.getValue().optionTwoProperty(); 
    // binding to constant value 
    return Bindings.createObjectBinding(() -> value); 
}); 
tableview.refresh(); 

在旧版本中,你必须使用设置列值的解决方法,以触发列表中的一个变化:

List<TableColumn<TableViewTest, ?>> columns = tableview.getColumns(); 
columns.set(columns.indexOf(Source), Source); 

但这种解决办法可能会停止在未来的版本中的工作,因为名单实际上与此修改合同不要求操作和触发列表更改事件(但用新实例替换TableColumn(并复制属性)应始终有效)。

+0

但所有这些变通办法应该如果事情设置正确,就不必要了...... –