时间:2018-06-13 19:39:14

标签: javafx javafx-8

我在表格中有两种类型的对象,为简单起见,我将其称为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;排序后:

Before sorting After sorting

正如你所看到的,索引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);
        }
    }
}

2 个答案:

答案 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);
    }

}

enter image description here

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);
    }

}

enter image description here

答案 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();
        }


    }