我在表格中有两种类型的对象,为简单起见,我将其称为Dog和Cat,这两个对象都是从Animal扩展而来的。我试图计算对象的运行次数。目前我将专注于Dog对象。
我有一个TableColumn,我已经创建了一个价值工厂,它看起来像这样:
column.setCellFactory(callback -> new TableCell<>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if(!empty) {
if (getTableView().getItems().get(getIndex()) instanceof Dog) {
int count = setDogCount(getTableView(), getIndex(), 0);
setText(String.valueOf(count));
} else {
setText("");
}
} else {
setText("");
}
}
});
我使用的递归方法是:
private int setDogCount(TableView<Animal> table, int index, int count){
if(index == 0){
if(table.getItems().get(index) instanceof Dog) {
return count + 1;
} else {
return count;
}
}
if(table.getItems().get(index) instanceof Dog){
return setDogCount(table, --index, ++count);
}else {
return setDogCount(table, --index, count);
}
}
这实际上约占95%的时间。它破坏的唯一时间是发生某种情况。它会中断,因为单元工厂只在排序时被调用,所以如果没有排序,那么它就不会更新计数。根据具体情况,这会导致狗的多次计数。
问题:
那么,有没有办法让它只更新排序中的一列?我想尽量避免刷新整个桌子,我希望有更好的方法。
谢谢!
编辑: 通过&#34;如果没有发生排序&#34;我的意思是,如果该对象没有从其当前索引移动,则它不会调用单元工厂。
编辑2: 这是一张图片,看看我面临的是什么。
排序前 - &gt;排序后:
正如你所看到的,索引0用索引3切换,因此适当地改变了计数列,但现在我没有数字1和两个数字3。这是因为它只更新已切换的行。
编辑3: 这是查看更改的小应用程序。当你运行它时,请点击一次命令已知列,看看我遇到了什么。
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
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 Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
BorderPane root = new BorderPane();
TableView<Animal> table = new TableView<>();
TableColumn<Animal, String> count = new TableColumn<>("Count");
TableColumn<Animal, String> name = new TableColumn<>("Name");
TableColumn<Animal, String> sound = new TableColumn<>("Sound");
TableColumn<Animal, String> commandsKnown = new TableColumn<>("Commands Known");
table.getColumns().addAll(count, name, sound, commandsKnown);
root.setCenter(table);
count.setCellFactory(callback -> new TableCell<>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
if (getTableView().getItems().get(getIndex()) instanceof Dog) {
int count = setDogCount(getTableView(), getIndex(), 0);
setText(String.valueOf(count));
} else {
setText("");
}
} else {
setText("");
}
}
});
name.setCellValueFactory(data -> data.getValue().nameProperty());
sound.setCellValueFactory(data -> data.getValue().soundProperty());
commandsKnown.setCellValueFactory(data -> {
if(data.getValue() instanceof Dog){
return ((Dog) data.getValue()).commandsKnownProperty();
}
return new SimpleStringProperty("");
});
ObservableList<Animal> animals = FXCollections.observableArrayList();
animals.add(new Dog("Tweeter", "Woof", "Sit, rollover, shake, drop"));
animals.add(new Dog("Sub Woofer", "Woof", "Sit, rollover, shake"));
animals.add(new Cat("Kitter Cat", "Meow"));
animals.add(new Dog("Bass", "Woof", "Sit, rollover, shake, fetch"));
table.setItems(animals);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private int setDogCount(TableView<Animal> table, int index, int count){
if(index == 0){
if(table.getItems().get(index) instanceof Dog) {
return count + 1;
} else {
return count;
}
}
if(table.getItems().get(index) instanceof Dog){
return setDogCount(table, --index, ++count);
}else {
return setDogCount(table, --index, count);
}
}
public static void main(String[] args) {
launch(args);
}
public class Animal{
StringProperty name = new SimpleStringProperty();
StringProperty sound = new SimpleStringProperty();
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getSound() {
return sound.get();
}
public StringProperty soundProperty() {
return sound;
}
public void setSound(String sound) {
this.sound.set(sound);
}
}
public class Dog extends Animal{
StringProperty commandsKnown = new SimpleStringProperty();
public Dog(String name, String sound, String commandsKnown){
setName(name);
setSound(sound);
setCommandsKnown(commandsKnown);
}
public String getCommandsKnown() {
return commandsKnown.get();
}
public StringProperty commandsKnownProperty() {
return commandsKnown;
}
public void setCommandsKnown(String commandsKnown) {
this.commandsKnown.set(commandsKnown);
}
}
public class Cat extends Animal{
public Cat(String name, String sound){
setName(name);
setSound(sound);
}
}
}
答案 0 :(得分:0)
我建议您使用static
变量来跟上Dog's
ID。
以下示例代码:
完整代码:
狗类
/**
*
* @author blj0011
*/
public class Dog extends Animal
{
static int dogCounter = 0;
private String commnads;
private final int dogId;
public Dog(String name, String sound, String commands)
{
super(name, sound);
this.commnads = commands;
dogId = ++dogCounter;
}
public String getCommnads()
{
return commnads;
}
public void setCommnads(String commnads)
{
this.commnads = commnads;
}
public int getDogId()
{
return dogId;
}
}
Cat Class
/**
*
* @author blj0011
*/
public class Cat extends Animal
{
public Cat(String name, String sound)
{
super(name, sound);
}
}
主要强>
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application
{
@Override
public void start(Stage primaryStage) throws Exception
{
BorderPane root = new BorderPane();
TableView<Animal> table = new TableView<>();
TableColumn<Animal, String> count = new TableColumn<>("Count");
TableColumn<Animal, String> name = new TableColumn<>("Name");
TableColumn<Animal, String> sound = new TableColumn<>("Sound");
TableColumn<Animal, String> commandsKnown = new TableColumn<>("Commands Known");
table.getColumns().addAll(count, name, sound, commandsKnown);
root.setCenter(table);
count.setCellValueFactory(new PropertyValueFactory("dogId"));
name.setCellValueFactory(new PropertyValueFactory("name"));
sound.setCellValueFactory(new PropertyValueFactory("sound"));
commandsKnown.setCellValueFactory(new PropertyValueFactory("commands"));
ObservableList<Animal> animals = FXCollections.observableArrayList();
animals.add(new Dog("Tweeter", "Woof", "Sit, rollover, shake, drop"));
animals.add(new Dog("Sub Woofer", "Woof", "Sit, rollover, shake"));
animals.add(new Cat("Kitter Cat", "Meow"));
animals.add(new Dog("Bass", "Woof", "Sit, rollover, shake, fetch"));
table.setItems(animals);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private int setDogCount(TableView<Animal> table, int index, int count)
{
if (index == 0) {
if (table.getItems().get(index) instanceof Dog) {
return count + 1;
}
else {
return count;
}
}
if (table.getItems().get(index) instanceof Dog) {
return setDogCount(table, --index, ++count);
}
else {
return setDogCount(table, --index, count);
}
}
public static void main(String[] args)
{
launch(args);
}
}
SortedList代码:
import java.util.Comparator;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application
{
@Override
public void start(Stage primaryStage) throws Exception
{
BorderPane root = new BorderPane();
TableView<Animal> table = new TableView<>();
TableColumn<Animal, String> count = new TableColumn<>("Count");
TableColumn<Animal, String> name = new TableColumn<>("Name");
TableColumn<Animal, String> sound = new TableColumn<>("Sound");
TableColumn<Animal, String> commandsKnown = new TableColumn<>("Commands Known");
table.getColumns().addAll(count, name, sound, commandsKnown);
root.setCenter(table);
count.setCellValueFactory(new PropertyValueFactory("dogId"));
name.setCellValueFactory(new PropertyValueFactory("name"));
sound.setCellValueFactory(new PropertyValueFactory("sound"));
commandsKnown.setCellValueFactory(new PropertyValueFactory("commands"));
ObservableList<Animal> animals = FXCollections.observableArrayList();
animals.add(new Dog("Tweeter", "Woof", "Sit, rollover, shake, drop"));
animals.add(new Dog("Sub Woofer", "Woof", "Sit, rollover, shake"));
animals.add(new Cat("Kitter Cat", "Meow"));
animals.add(new Cat("Kitter Cat 2", "Meow"));
animals.add(new Dog("Bass", "Woof", "Sit, rollover, shake, fetch"));
SortedList<Animal> sortedList = new SortedList(animals);
Comparator<Animal> comparator = (c, d) -> {
if (c instanceof Cat && d instanceof Dog) {
return -1;
}
else if (c instanceof Dog && d instanceof Cat) {
return 1;
}
return 0;
};
comparator.thenComparing((c, d) -> {
if (c instanceof Cat && d instanceof Dog) {
return -1;
}
else if (c instanceof Dog && d instanceof Cat) {
return 1;
}
else {
if (c instanceof Cat && d instanceof Cat) {
return c.getName().compareTo(d.getName());
}
else {
Dog tempDog1 = (Dog) c;
Dog tempDog2 = (Dog) d;
if (tempDog1.getDogId() > tempDog2.getDogId()) {
return 1;
}
}
return 0;
}
});
sortedList.setComparator(comparator);
table.setItems(sortedList);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
答案 1 :(得分:0)
要扩展我的评论:
一个单元格肯定是改变数据的错误位置(即使它是 meta)...在模型中做;)
作为模型,我不仅指您的数据对象/列表,还指与数据相关的所有状态,即使它也与视图相关,如f.i.一个跑步的柜台。您必须以某种方式在视图之外建模该关系。
下面是一个示例,它通过计数器的附加列表对每个所有者的一个属性建模关系。每当影响计数器的任何事情发生变化时(f.i.当列表被排序或宠物改变或任何东西时),应用程序的任务就是保持与所有者同步,如表中所示。
代码:
public class TableWithExternalCounterSO extends Application {
/**
* Updates the counter data from the given source list, assuming that
* both have the same size (if that's not true, adjust counter size
* as needed)
*/
private void updateDogCounterFrom(ObservableList<ObjectProperty<Integer>> dogCounter,
ObservableList<? extends PetOwner> owners) {
int count = 0;
for (int i = 0; i < owners.size(); i++) {
PetOwner owner = owners.get(i);
if (owner.petProperty().get() == Pet.DOG) {
dogCounter.get(i).set(++count);
} else {
dogCounter.get(i).set(-1);
}
}
}
private Parent createContent() {
// the base data
ObservableList<PetOwner> owners = PetOwner.owners();
// a list for the counters, that must be kept in sync with changes in the table
ObservableList<ObjectProperty<Integer>> dogCounter = FXCollections.observableArrayList();
owners.forEach(owner -> dogCounter.add(new SimpleObjectProperty<Integer>(-1)));
// initial sync
updateDogCounterFrom(dogCounter, owners);
SortedList<PetOwner> sorted = new SortedList<>(owners);
sorted.addListener((ListChangeListener<? super PetOwner>) c -> {
// sync after change
updateDogCounterFrom(dogCounter, c.getList());
});
TableView<PetOwner> table = new TableView<>(sorted);
sorted.comparatorProperty().bind(table.comparatorProperty());
TableColumn<PetOwner, String> name = new TableColumn<>("Name");
name.setCellValueFactory(new PropertyValueFactory<>("name"));
TableColumn<PetOwner, Pet> pet = new TableColumn<>("Pet");
pet.setCellValueFactory(new PropertyValueFactory<>("pet"));
TableColumn<PetOwner, Integer> dogIndex = new TableColumn<>("Running Dog#");
dogIndex.setSortable(false);
dogIndex.setCellValueFactory(cd -> {
// astonishingly, this is called for every cell after sorting,
// that is all cells are newly created
int index = cd.getTableView().getItems().indexOf(cd.getValue());
return dogCounter.get(index);
});
dogIndex.setCellFactory(cb -> {
return new TableCell<PetOwner, Integer>() {
@Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty || item != null && item.intValue() < 0) {
setText("");
} else {
setText(String.valueOf(item));
}
}
};
});
table.getColumns().addAll(name, pet, dogIndex);
BorderPane pane = new BorderPane(table);
return pane;
}
private enum Pet {
CAT, DOG
}
public static class PetOwner {
ObjectProperty<Pet> pet;
StringProperty name;
PetOwner(String name, Pet pet) {
this.pet = new SimpleObjectProperty<>(this, "pet", pet);
this.name = new SimpleStringProperty(this, "name", name);
}
public ObjectProperty<Pet> petProperty() {
return pet;
}
public StringProperty nameProperty() {
return name;
}
public static ObservableList<PetOwner> owners() {
ObservableList<PetOwner> owners = FXCollections.observableArrayList();
for (int i = 0; i < 20; i++) {
owners.add(new PetOwner("O " + i, i % 3 == 0 ? Pet.CAT : Pet.DOG) );
}
return owners;
}
@Override
public String toString() {
return name.get( ) + " " + pet.get();
}
}