gpt4 book ai didi

java - 如何仅在 TreeTableView 中按叶子排序?

转载 作者:行者123 更新时间:2023-12-01 22:07:20 28 4
gpt4 key购买 nike

我正在使用 JavaFX 中的 TreeTableView 类来实现分组股票行情观察列表。排序时,我只想对股票进行排序(而不是组)。目前,当我单击“符号”列(例如)时,它会对每个组中的股票进行排序(正如我所期望的),但它也会对组进行排序。

就我而言,我只想对每个组中的股票进行排序,并保留观察列表中各组的顺序。

我尝试过使用setSortMode()方法,但它只支持以下模式:ALL_DESCENDANTS
ONLY_FIRST_LEVEL

我查看了 TreeItem 类的源代码,看起来目前不支持仅按叶子排序(但将来可能会支持)。

  private void runSort(ObservableList<TreeItem<T>> children, Comparator<TreeItem<T>> comparator, TreeSortMode sortMode) 
{
if (sortMode == ALL_DESCENDANTS) {
doSort(children, comparator);
} else if (sortMode == ONLY_FIRST_LEVEL) {
// if we are here we presume that the current node is the root node
// (but we can test to see if getParent() returns null to be sure).
// We also know that ONLY_FIRST_LEVEL only applies to the children
// of the root, so we return straight after we sort these children.
if (getParent() == null) {
doSort(children, comparator);
}
// } else if (sortMode == ONLY_LEAVES) {
// if (isLeaf()) {
// // sort the parent once
// }
// } else if (sortMode == ALL_BUT_LEAVES) {
} else {
// Unknown sort mode
}
}

是否有任何方法可以解决此限制,而无需等待 JavaFX future 更新中添加支持?

最佳答案

回复很晚了,但也许您仍然可以使用反馈。我找到了两种方法来满足您的需求。

选项 1:您可以设置自己的排序策略。在这里,我设置了一个简单的策略,仅对根节点正下方的节点的子节点进行排序。您必须为每一列以及每个列组合实现一种排序方法。

package sample;

import javafx.application.Application;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeSortMode;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;

public class SortOnlySome extends Application {

private final TreeTableColumn<Person, String> tableColumn = new TreeTableColumn<>("Person");
private final TreeTableColumn<Person, Integer> ageColumn = new TreeTableColumn<>("Age");

@Override
public void start(Stage primaryStage) {
BorderPane borderPane = new BorderPane();

TreeTableView<Person> treeTable = new TreeTableView();
borderPane.setCenter(treeTable);

setupColumns(treeTable);

TreeItem<Person> root = new TreeItem<>(new Person("Root"));

// Add some data
populate(root);

// Set the data into the treetable
treeTable.setRoot(root);
root.setExpanded(true);
root.getChildren().forEach(c -> c.setExpanded(true));


primaryStage.setScene(new Scene(borderPane));
primaryStage.setTitle("Dont sort categories");
primaryStage.show();
}

private void setupColumns(TreeTableView<Person> treeTable) {
tableColumn.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue().displayName));
ageColumn.setCellValueFactory(param -> new ReadOnlyIntegerWrapper(param.getValue().getValue().age).asObject());

treeTable.getColumns().setAll(tableColumn, ageColumn);

treeTable.setSortPolicy(new Callback<TreeTableView<Person>, Boolean>() {
@Override
public Boolean call(TreeTableView<Person> table) {
TreeItem<Person> rootItem = table.getRoot();
if (rootItem == null) return false;

TreeSortMode sortMode = table.getSortMode();
if (sortMode == null) return false;

// Collecto the column comparators and merge them into 1
List<Comparator<Person>> comparators = new ArrayList<Comparator<Person>>();
table.getSortOrder().stream().forEachOrdered(ttc -> {
Comparator<Person> columnComparator = getComparatorForColumn(ttc);
comparators.add(columnComparator);
});
Comparator<Person> merged = mergeComparators(comparators);

rootItem.getChildren().forEach(c -> {
c.getChildren().sort((o1, o2) -> merged.compare(o1.getValue(), o2.getValue()));
// TODO: Sort recursively down c.getChildren()
});

return true;
}
});
}

private Comparator<Person> getComparatorForColumn(TreeTableColumn<Person, ?> column) {
int sign = column.getSortType() == TreeTableColumn.SortType.ASCENDING ? 1 : -1;
if (column == tableColumn) {
Comparator<Person> nameCompare = new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
Comparator c = column.getComparator();
Object obj1 = o1.displayName;
Object obj2 = o2.displayName;
return sign * c.compare(obj1, obj2);
}
};
return nameCompare;
} else if (column == ageColumn) {
return new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return sign * Integer.compare(o1.age, o2.age);
}
};
} else {
// TODO: Comparators for other columns
return new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return sign * 0;
}
};
}
}

public static Comparator<Person> mergeComparators(final Collection<Comparator<Person>> multipleOptions) {
return new Comparator<Person>() {
public int compare(Person o1, Person o2) {
for (Comparator option : multipleOptions) {
int result = option.compare(o1, o2);
if (result != 0) {
return result;
}
}
return 0;
}
};
}

private void populate(TreeItem<Person> root) {
root.getChildren().add(new TreeItem<>(new Person("Group A")));
root.getChildren().add(new TreeItem<>(new Person("Category 2")));
root.getChildren().add(new TreeItem<>(new Person("Collection C")));

// Add some people
for (int i = 0; i < 17; i++) {
String name = "Person " + (i + 1);
Person someone = new Person(name);
someone.age = 16 + i * 3;
TreeItem categoryNode = root.getChildren().get(i % 3);
categoryNode.getChildren().add(new TreeItem<>(someone));
}
}

public class Person {
public String displayName;
public int age;

public Person(String name) {
this.displayName = name;
}
}

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

选项2:替代方法...让我们看看treetableview 的作用。为了比较元素,它创建一个(新的)TableColumnComparatorBase。在调用堆栈中的某个时刻,类 TableColumnComparatorBase 将获取列的值并使用它们进行比较:

@Override public int compare(S o1, S o2) {
for (TableColumnBase<S,T> tc : columns) {
if (! isSortable(tc)) continue;

T value1 = tc.getCellData(o1);
T value2 = tc.getCellData(o2);

int result = doCompare(tc, value1, value2);

if (result != 0) {
return result;
}
}
return 0;
}

检查如何比较它们的 TableColumnBase 类:

public static final Comparator DEFAULT_COMPARATOR = (obj1, obj2) -> {
if (obj1 == null && obj2 == null) return 0;
if (obj1 == null) return -1;
if (obj2 == null) return 1;

if (obj1 instanceof Comparable && (obj1.getClass() == obj2.getClass() || obj1.getClass().isAssignableFrom(obj2.getClass()))) {
return (obj1 instanceof String) ? Collator.getInstance().compare(obj1, obj2) : ((Comparable)obj1).compareTo(obj2);
}

return Collator.getInstance().compare(obj1.toString(), obj2.toString());
};

我找不到设置每列比较器的方法。但我们可以做的是,确保单元格中的值实现 Comparable,并在不应移动时返回 0。请注意,不是 TreeItem 的项目,而是 CellValueFactory 生成的项目应该实现 Comparable。不幸的是,这也意味着我们需要添加自定义 CellFactories 或 toStrings。它一点也不漂亮,但在下面您将找到一个有效的示例:

import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import java.text.Collator;

public class SortOnlySome extends Application {

@Override
public void start(Stage primaryStage) {
BorderPane borderPane = new BorderPane();

TreeTableView<Person> treeTable = new TreeTableView();
borderPane.setCenter(treeTable);

setupColumns(treeTable);

TreeItem<Person> root = new TreeItem<>(new Person("Root", false));

// Add some data
populate(root);

// Set the data into the treetable
treeTable.setRoot(root);
root.setExpanded(true);
root.getChildren().forEach(c -> c.setExpanded(true));


primaryStage.setScene(new Scene(borderPane));
primaryStage.setTitle("Dont sort categories");
primaryStage.show();
}

private void setupColumns(TreeTableView<Person> treeTable) {
TreeTableColumn<Person, NameSortWrapper> treeColumn = new TreeTableColumn<>("Person");
treeColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(new NameSortWrapper(param.getValue().getValue())));
TreeTableColumn<Person, AgeSortWrapper> ageColumn = new TreeTableColumn<>("Age");
ageColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(new AgeSortWrapper(param.getValue().getValue())));
treeTable.getColumns().setAll(treeColumn, ageColumn);
}

private void populate(TreeItem<Person> root) {
root.getChildren().add(new TreeItem<>(new Person("Group A", false)));
root.getChildren().add(new TreeItem<>(new Person("Category 2", false)));
root.getChildren().add(new TreeItem<>(new Person("Collection C", false)));

// Add some people
for (int i = 0; i < 17; i++) {
String name = "Person " + (i + 1);
Person someone = new Person(name, true);
someone.age = 16 + i * 3;
TreeItem categoryNode = root.getChildren().get(i % 3);
categoryNode.getChildren().add(new TreeItem<>(someone));
}
}

// The class to show in the treetable
// Problem 1: The data class defines whether sorting is allowed
// Problem 2: Category nodes in the tree will also be TreeItem<Person>
public class Person {
public String displayName;
public int age;
boolean allowSorting = true;

public Person(String name, boolean allowSort) {
this.allowSorting = allowSort;
this.displayName = name;
}
}

// A class that implements Comparable and determines whether sorting should be done
// To be extended for each column
public abstract class SortWrapper implements Comparable {
public final Person theRealData;

public SortWrapper(Person theData) {
this.theRealData = theData;
}

@Override
public int compareTo(Object o) {
if (theRealData.allowSorting) {
return this.customCompare(o);
} else {
return 0;
}
}

protected abstract int customCompare(Object o);

@Override
public String toString() {
return super.toString();
}
}

// A sort helper for the Person's name
public class NameSortWrapper extends SortWrapper {
public NameSortWrapper(Person theData) {
super(theData);
}

@Override
protected int customCompare(Object o) {
return Collator.getInstance().compare(theRealData.displayName, ((NameSortWrapper) o).theRealData.displayName);
}

@Override
public String toString() {
if (theRealData == null) {
return null;
} else {
return theRealData.displayName;
}
}
}

// A sort helper for the Person's age
public class AgeSortWrapper extends SortWrapper {
public AgeSortWrapper(Person theData) {
super(theData);
}

@Override
protected int customCompare(Object o) {
return Integer.compare(theRealData.age, ((AgeSortWrapper) o).theRealData.age);
}

@Override
public String toString() {
// Note that null is returned when !allowSorting, this makes sure
// that the rows do not show an age for the categories
if (theRealData == null || !theRealData.allowSorting) {
return null;
} else {
return Integer.toString(theRealData.age);
}
}
}

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

关于java - 如何仅在 TreeTableView 中按叶子排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32445625/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com