#swt #eclipse-rcp #jface
#swt #eclipse-rcp #jface
Вопрос:
В настоящее время я использую FilteredTree с PatternFilter для отображения данных в виде дерева.
Моя проблема в том, что он показывает только элементы, соответствующие шаблону, и скрывает их дочерние элементы (за исключением того, что они также соответствуют шаблону).
Пример:
Дерево:
A
-B
—1
—2
-C
—1
—2
Шаблон «B» дает мне:
A
-B
Но мне нужно:
A
-B
—1
—2
Я попробовал несколько вещей, но не нашел хорошего / простого способа сделать это. Есть идеи?
Ответ №1:
Это поведение по умолчанию. Переопределите PatternFilter.isParentMatch() и PatternFilter.isLeafMatch() для получения правильных результатов.
Комментарии:
1. Я уже точно не помню, но я думаю, что соответствующие методы не могли быть переопределены. Поэтому мне пришлось скопировать весь класс и изменить их.
Ответ №2:
У меня была та же проблема: элемент был отфильтрован правильно, но дочерние элементы узла дерева не отображались. Пользователь должен был выбрать найденный узел (в надежде, что это был только один результат), затем сбросить фильтр и посмотреть, где появился выбор вместе с дочерними элементами.
Для решения этой проблемы требуется перезапись PatternFilter#isLeafMatch()
и извлечение кэша (частного) поля из PatternFilter
с помощью JavaReflection:
public class MyPatternFilter extends PatternFilter {
private final Map<Object, Object> patternFilterCache;
public MyPatternFilter () {
this.patternFilterCache = getCache();
}
@Override
protected boolean isLeafMatch(final Viewer viewer, final Object element) {
boolean result = super.isLeafMatch(viewer, element);
if (result) { // element matches, now add all its children
traverseChildren(((MyTreeNode) element).getChildren());
}
return resu<
}
// this is to traverse the children of the element found before
// these children need to be added to the Map 'cache' to be displayed
void traverseChildren(List<MyTreeNode> children) {
// assuming that child.getChildren() is never null!
for(MyTreeNode child : children) {
this.patternFilterCache.put(child, child.getChildren().stream().toArray(MyTreeNode[]::new));
traverseChildren(child.getChildren());
}
}
private Map<Object, Object> getCache() {
try {
Field cacheField = this.getClass().getSuperclass().getDeclaredField("cache"); //$NON-NLS-1$
cacheField.setAccessible(true);
@SuppressWarnings("unchecked")
Map<Object, Object> cache = (Map<Object, Object>) cacheField.get(this);
cacheField.setAccessible(false);
return cache;
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
e.printStackTrace();
}
return null;
}
}
Очевидным недостатком является то, что Map ‘cache’ не является API, поэтому — теоретически — при изменении имени это решение завершится неудачей.
Ответ №3:
Так приятно опубликовать мой первый ответ!
Переопределите isElementVisible()
и добавьте условие возврата.
public class FilePatternFilter extends PatternFilter {
@Override
public boolean isElementVisible(Viewer viewer, Object element) {
File file = (File) element;
return isParentMatch(viewer, element) || isLeafMatch(viewer, element) || isLeafMatch(viewer, file.getParent());
}
}