- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 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/
我正在尝试对每个条目有多个值的关联数组进行排序。 例如 [0] => stdClass Object ( [type] => node [sid] => 158 [score] => 0.059600
我在 mysql 中有“日期”列以这种格式保存日期 2014 年 9 月 17 日(日-月-年) 我需要对它们进行升序排序,所以我使用了这个命令: SELECT * FROM table ORDER
我目前正在将 MySQL 存储过程重写为 MS SQL 存储过程,但遇到了问题。 在 MySQL 存储过程中,有一个游标,它根据最近的日期 (effdate) 选择一个值并将其放入变量 (thestt
我想要 gwt r.QuestionId- 排序。但是我得到未排序的 QuestionId 尽管我提到了 QuestionId ASC 的顺序。 SELECT r.QuestionId,
我有一个关于在 scandir 函数中排序的基本问题。到目前为止,我阅读了 POSIX readdir 的手册页,但没有找到有关订购保证的具体信息。 但是当我遍历大目录(无法更改,只读)时,我在多个系
基本上我必须从 SQL 数据库中构建项目列表,但是用户可以选择对 7 个过滤器的任意组合进行过滤,也可以选择要排序的列以及按方向排序。 正如您可以想象的那样,这会以大量不同的组合进行编码,并且数据集非
我有两张 table 。想象第一个是一个目录,包含很多文件(第二个表)。 第二个表(文件)包含修改日期。 现在,我想选择所有目录并按修改日期 ASC 对它们进行排序(因此,最新的修改最上面)。我不想显
我想先根据用户的状态然后根据用户名来排序我的 sql 请求。该状态由 user_type 列设置: 1=活跃,2=不活跃,3=创始人。 我会使用此请求来执行此操作,但它不起作用,因为我想在“活跃”成员
在 C++ 中,我必须实现一个“类似 Excel/Access”(引用)的查询生成器,以允许对数据集进行自定义排序。如果您在 Excel 中使用查询构建器或 SQL 中的“ORDER BY a, b,
我面临这样的挑战: 检索按字段 A 排序的文档 如果字段 B 存在/不为空 . 否则 按字段排序 C. 在 SQL 世界中,我会做两个查询并创建一个 UNION SELECT,但我不知道如何从 Mon
我想对源列表执行以下操作: map 列表 排序 折叠 排序 展开 列表 其中一些方法(例如map和toList)是可链接的,因为它们返回非空对象。但是,sort 方法返回 void,因为它对 List
我制作了一个用于分析 Windows 日志消息编号的脚本。 uniq -c 数字的输出很难预测,因为根据数字的大小会有不同的空白。此时,我手动删除了空白。 这是对消息进行排序和计数的命令: cat n
我有以下词典: mydict1 = {1: 11, 2: 4, 5: 1, 6: 1} mydict2 = {1: 1, 5: 1} 对于它们中的每一个,我想首先按值(降序)排序,然后按键(升序)排序
我刚刚开始使用泛型,目前在对多个字段进行排序时遇到问题。 案例: 我有一个 PeopleList 作为 TObjectList我希望能够通过一次选择一个排序字段,但尽可能保留以前的排序来制作类似 Ex
有没有办法在 sql 中组合 ORDER BY 和 IS NULL 以便我可以在列不为空时按列排序,但如果它为null,按另一列排序? 最佳答案 类似于: ORDER BY CASE WHEN
我有一个包含 2 列“id”和“name”的表。 id 是常规的自动增量索引,name 只是 varchar。 id name 1 john 2 mary 3 pop 4 mary 5 j
场景 网站页面有一个带有分页、过滤、排序功能的表格 View 。 表中的数据是从REST API服务器获取的,数据包含数百万条记录。 数据库 REST API 服务器 Web 服务器 浏览器 问
假设我有一本字典,其中的键(单词)和值(分数)如下: GOD 8 DONG 16 DOG 8 XI 21 我想创建一个字典键(单词)的 NSArray,首先按分数排序,然后按字
如何在 sphinx 上通过 sql 命令选择前 20 行按标题 WEIGHT 排序,接下来 20 行按标题 ASC 排序(总共 40 个结果),但不要给出重复的标题输出。 我尝试了这个 sql 命令
我有一个奇怪的问题,当从 SQLite 数据库中选择信息并根据日期排序时,返回的结果无效。 我的SQL语句是这样的: Select pk from usersDates order by dateti
我是一名优秀的程序员,十分优秀!