Я хочу знать, как реализовать эту функцию:Как не свернуть узел в JTree после того, как узел редактируется
У меня есть редактируемые JTree, где я могу изменить имя узлов. Если у меня есть узел, который является ветвящимся узлом (в нем есть некоторые листовые узлы), и этот узел ветвления расширяется при редактировании, после редактирования этот узел будет свернут.
Я хочу оставить этот ветвь открытой, если она открыта и свернута, если она свернута, после того, как редактирование выполнено.
Я попытался посмотреть на TreeWillExpandListener, но кажется, что это не решает мою проблему, потому что нужно признать, если фактический узел находится в режиме редактирования ДО Я называю эти методы ...
Как сделать этот трюк? Это настолько очевидно, что это необходимо, но я не могу найти ответ вообще:/
Хорошо, так что это код, я попробую объяснить его. Прежде всего, у меня есть класс ContactTreeModel, который реализует TreeModel. Конструктор просто загружает адресную книгу и менеджер групп из основного фрейма приложения, я создаю новый root и загружаю данные из базы данных во втором методе.
public ContactTreeModel() {
addressBookManager = ContactManagerFrame.getAddressBookManager();
groupManager = ContactManagerFrame.getGroupManager();
root = new DefaultMutableTreeNode();
processTreeHierarchy();
}
private void processTreeHierarchy() {
DefaultMutableTreeNode group, contact;
for (Group g : addressBookManager.getGroups()) {
group = new DefaultMutableTreeNode(g);
root.add(group);
for (Contact c : addressBookManager.getContactsFromGroup(g)) {
contact = new DefaultMutableTreeNode(c);
group.add(contact);
}
}
}
Я прочитал, что метод valueForPathChanged в TreeModel обжигают, если
обменивались сообщениями, когда пользователь изменил значение для элемента, идентифицированного пути к NewValue. Если newValue означает действительно новое значение, модель должна опубликовать событие treeNodesChanged.
Так что я написал, что метод так:
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
// backup of the original group
Group oldGroup = (Group) path.getLastPathComponent();
try {
Group testGroup = (Group) path.getLastPathComponent();
testGroup.setName((String) newValue);
// validation of the group to be updated
groupManager.validateGroup(testGroup, true);
oldGroup.setName((String) newValue);
// updating of the group in db
groupManager.updateGroup(oldGroup);
} catch (ServiceFailureException | ValidationException ex) {
// if database error occured or validation exception is raised,
// update label in gui
ContactManagerFrame.getStatusPanelLabel().setText(ex.getMessage());
} finally {
fireTreeStructureChanged();
}
}
Обратите внимание на метод в блоке, наконец, этот метод всегда разжег. Похоже, что
protected void fireTreeStructureChanged() {
Object[] o = {root};
TreeModelEvent e = new TreeModelEvent(this, o);
for (TreeModelListener l : treeModelListeners) {
l.treeNodesChanged(e);
}
}
Это немного сложно, и причина, по которой это не работает (я думаю). Я просто перебираю все treeModelListeners и запускаю метод treeNodesChanged.
Я массив, указанный для дерева модели слушателей в качестве частного атрибута в ContactTreeModel и связанные с ними методы тоже:
private Vector<TreeModelListener> treeModelListeners = new Vector<>();
@Override
public void addTreeModelListener(TreeModelListener l) {
treeModelListeners.addElement(l);
}
@Override
public void removeTreeModelListener(TreeModelListener l) {
treeModelListeners.removeElement(l);
}
Последняя вещь, как делает модель слушателя я добавил к модели выглядят как? Вот оно:
public class ContactTreeModelListener implements TreeModelListener {
@Override
public void treeNodesChanged(TreeModelEvent e) {
System.out.println("nodes changed");
}
@Override
public void treeNodesInserted(TreeModelEvent e) {
System.out.println("nodes inserted");
}
@Override
public void treeNodesRemoved(TreeModelEvent e) {
System.out.println("nodes removed");
}
@Override
public void treeStructureChanged(TreeModelEvent e) {
System.out.println("structure changed");
}
}
Так оно и в принципе ничего не значит. Я зарегистрировал слушателя в другом месте, это не имеет значения прямо сейчас.
Итак, когда я его выполняю, в этом состоянии дерево НЕ сбрасывается и поведение по желанию. Но даже он действительно переписывает имя этого узла (метки), если исходная строка была около 5 символов, и я изменил ее, например, на 4 символа, на этикетке будет всего 4 символа, а также пустое место для пятого. Поэтому размер оригинальной метки не изменился после того, как я закончил редактирование этой метки. Аналогичным образом, когда я расширяю имя группы, например, я переименую его с 4 до 5 символов, метка этого узла будет содержать точки, указывающие , что весь текст слишком велик для отображения. Это странно ... Как мне сделать udpdate этого ярлыка?
Самая последняя вещь ... поскольку у меня есть пользовательские значки в JTree +, я распознаю пустую и непустую группу, мне нужно проверить фактический значок в db каждый раз, когда я делаю какое-то действие в дереве (Я проверил, что он выполнен, даже я просто открываю и закрываю узлы). Это очень неэффективно, поэтому я продлил DefaultTreeCellRenderer где я делаю фактическое кэширование:
@Override
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean sel,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
if (iconCache == null) {
throw new NullPointerException("iconCache in "
+ this.getClass().getName() + " is null");
}
super.getTreeCellRendererComponent(
tree, value, sel,
expanded, leaf, row,
hasFocus);
if (value instanceof Group) {
Group g = (Group) value;
Icon groupIcon = iconCache.get(g);
if (groupIcon == null) {
if (groupHasContacts(g)) {
groupIcon = groupNonEmpty;
} else {
groupIcon = groupEmptyIcon;
}
iconCache.put(g, groupIcon);
}
JLabel result = (JLabel) super.getTreeCellRendererComponent(tree,
g.getName(), sel, expanded, leaf, row, hasFocus);
result.setIcon(groupIcon);
return result;
}
else if (value instanceof Contact) {
Contact c = (Contact) value;
Icon icon = iconCache.get(c);
if (icon == null) {
icon = this.contactIcon;
iconCache.put(c, icon);
}
JLabel result = (JLabel) super.getTreeCellRendererComponent(
tree, c.getName() + c.getSurname(),
sel, expanded, leaf, row, hasFocus);
result.setIcon(icon);
return result;
}
JLabel defaultNode = (JLabel) super.getTreeCellRendererComponent(
tree, "?", sel, expanded, leaf, row, hasFocus);
defaultNode.setIcon(unknownNode);
return defaultNode;
}
Почему это рушится в первую очередь? Поделиться [SSCCE] (http://sscce.org/), что иллюстрирует проблему. – tenorsax
@Max Я добавил код для объяснения, надеюсь, что это поможет ... – stewenson