Материал: Портянкин И. Swing

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

470

ГЛАВА 15

tree.setEditable(true);

//"настоящий" редактор

JComboBox combo = new JComboBox(

new String[] {"Красный", "Зеленый"}); DefaultCellEditor editor = new DefaultCellEditor(combo);

//специальный редактор для дерева

DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); DefaultTreeCellEditor treeEditor =

new DefaultTreeCellEditor(tree, renderer, editor);

//присоединяем редактор к дереву tree.setCellEditor(treeEditor);

//выводим окно на экран

add(new JScrollPane(tree)); setSize(400, 300); setVisible(true);

}

// создание несложной модели дерева private TreeModel createTreeModel() {

//корень нашего дерева

DefaultMutableTreeNode root =

new DefaultMutableTreeNode("Цвета");

//основные ветви

DefaultMutableTreeNode basic =

new DefaultMutableTreeNode("Основные"); DefaultMutableTreeNode extended =

new DefaultMutableTreeNode("Дополнительные"); root.add(basic);

root.add(extended);

// присоединяем листья

for (int i=0; i<basics.length; i++) { basic.add(new DefaultMutableTreeNode(basics[i])); extended.add(

new DefaultMutableTreeNode(extendeds[i]));

}

// создаем стандартную модель return new DefaultTreeModel(root);

}

public static void main(String[] args) { SwingUtilities.invokeLater(

new Runnable() {

Уход за деревьями

471

public void run() { new TreeDefaultEditing(); } });

}

}

В примере мы создаем дерево JTree, основанное на простой модели, описывающей взаимоотношения цветов. Модель создается в методе createTreeModel(). Процесс наполнения модели данными нам уже прекрасно знаком.

Гораздо интереснее посмотреть, как настраиваются стандартные редакторы для нашего дерева. Прежде всего необходимо создать «настоящий» редактор DefaultCellEditor, тот самый, который можно затем будет передать в редактор DefaultTreeCellEditor. В качестве компонента, заведующего процессом редактирования, мы выбрали раскрывающийся список JComboBox, который создали на основе массива из двух строк. Настроенный список затем надо передать в конструктор класса DefaultCellEditor. После этого уже можно приступать ко второму редактору DefaultTreeCellEditor, он позволит нам проводить редактирование ячеек, не отказываясь от значков. Конструктор второго редактора требует сразу три параметра: дерево, стандартный отображающий объект и редактор для дерева. В дереве будет проводиться редактирование, стандартный отображающий объект7 потребуется для получения значков, ассоциированных с узлами, а редактор, естественно, будет выполнять редактирование. Настроенный редактор DefaultTreeCellEditor можно присоединять к дереву.

Запустив программу с примером, вы увидите, как стандартные редакторы позволяют организовать редактирование на основе раскрывающегося списка. Начать редактирование позволяет тройной щелчок мыши или двойной щелчок, выполненный с паузой. Кстати, с помощью специальных методов стандартных редакторов вы можете задать число щелчков мыши, необходимых для начала редактирования. Обратите внимание, что во время редактирования значок узла остается на экране — это «заслуга» редактора DefaultTreeCellEditor, используй мы сразу редактор DefaultCellEditor, значок во время редактирования с экрана исчезал бы. Помимо списка JComboBox вы также можете задействовать для редактирования текстовое поле JTextField или флажок JCheckBox, хотя последний применяется редко8. Однако редактирование с помощью стандартных редакторов все же довольно ограничено:

7 Редактор DefaultTreeCellEditor может работать только со стандартным отображающим объектом, что, конечно же, ограничивает область его применения.

8 Лучше обратиться к созданному нами недавно специальному дереву с флажками, позволяющему менять их состояние.

472

ГЛАВА 15

редактировать можно все узлы «без разбора», и для редактирования всех узлов всегда применяется один и тот же компонент. Для деревьев, отображающих сложные данные различных типов, зачастую приходится писать собственные редакторы.

Создание собственного редактора

Как мы уже упоминали, создание собственного редактора для узлов дерева может вылиться в приличную работу: методов в интерфейсе TreeCellEditor (большая часть которых находится в его базовом интерфейсе CellEditor) немало. Однако библиотека предлагает нам помощника — абстрактный класс AbstractCellEditor реализует большую часть методов интерфейса CellEditor, и в том числе предоставляет нам поддержку слушателей CellEditorListener. Эти слушатели оповещаются при окончании или отмене редактирования, чтобы компонент (дерево) знал, когда работа редактора оканчивается. Для того чтобы наш собственный редактор для дерева смог заработать, нужно будет определить всего два метода: метод getCellEditorValue() должен возвращать значение, в данный момент находящееся в редакторе, а уже знакомый нам метод getTreeCellEditorComponent() — компонент, который и задействуется деревом как редактор. Остальные методы реализованы классом AbstractCellEditor и их требуется переопределять только в том случае, если вам понадобятся дополнительные возможности.

Попробуем написать особый редактор для дерева, которое отображает каталог телефонных номеров некоторой компании. Телефонные номера могут быть отсортированы по отделам и подразделениями, которые, как правило, находятся в иерархических отношениях, так что использование дерева вполне оправдано. Редактировать номера, отображаемые деревом, с помощью стандартных редакторов неудобно: во-первых, они не обеспечивают никаких ограничений на вводимые пользователем данные (а вводить можно будет только телефонные номера), во-вторых, они позволяют редактировать все узлы даже со вспомогательной информацией.

Новый редактор для дерева с телефонами использует для редактирования текстовое поле JFormattedTextField, позволяющее вводить данные в определенном формате. Формат вводимых данных определяется специальной текстовой маской9, которая в нашем примере задает простой телефонный номер. Кроме того, редактор следит за тем, чтобы редактировать можно было только листья дерева, в которых и хранятся телефонные номера, а не остальные узлы, служащие для упорядочения информации.

//CustomTreeEditor.java

//Создание специализированного редактора узлов import javax.swing.*;

import javax.swing.tree.*; import javax.swing.text.*; import java.awt.*;

import java.awt.event.*; import java.util.EventObject;

public class CustomTreeEditor extends JFrame { public CustomTreeEditor() {

super("CustomTreeEditor"); setDefaultCloseOperation(EXIT_ON_CLOSE);

9 Мы обсудим текстовое поле JFormattedTextField и поддерживаемые им форматы данных в главе 16, которая полностью посвящена текстовым компонентам Swing.

Уход за деревьями

473

// настраиваем дерево

JTree tree = new JTree(createTreeModel());

//включаем редактирование узлов tree.setEditable(true); DefaultTreeCellRenderer renderer =

new DefaultTreeCellRenderer(); DefaultTreeCellEditor editor =

new DefaultTreeCellEditor(tree, renderer, new MaskTreeEditor(tree));

tree.setCellEditor(editor);

//выводим окно на экран

add(new JScrollPane(tree)); setSize(400, 300); setVisible(true);

}

// список телефонов

private String[] phoneDirectory = { "123-13-13", "444-55-67", "111-23-45"};

// создает модель дерева

private TreeModel createTreeModel() { DefaultMutableTreeNode root =

new DefaultMutableTreeNode("Компания"); DefaultMutableTreeNode node =

new DefaultMutableTreeNode("Отдел кадров"); root.add(node);

// присоединяем листья

for (String phone : phoneDirectory) { node.add(new DefaultMutableTreeNode(phone));

}

return new DefaultTreeModel(root);

}

// специальный редактор узлов дерева

class MaskTreeEditor extends AbstractCellEditor implements TreeCellEditor {

// дерево

private JTree tree;

//текстовое поле, применяемое для редактирования private JFormattedTextField editor;

//конструктор редактора

public MaskTreeEditor(JTree tree) { this.tree = tree;

// создаем форматирующий объект

474 ГЛАВА 15

try {

MaskFormatter phone =

new MaskFormatter("###-##-##"); editor = new JFormattedTextField(phone);

} catch (Exception ex) { ex.printStackTrace();

}

// присоединяем к полю слушателя editor.addActionListener(new ActionListener() {

// вызывается при окончании редактирования public void actionPerformed(ActionEvent e) {

stopCellEditing();

}

});

}

// возвращает компонент, используемый как редактор public Component getTreeCellEditorComponent(

JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {

//устанавливаем новое значение editor.setText(value.toString());

//возвращаем текстовое поле return editor;

}

//возращает текущее значение в редакторе public Object getCellEditorValue() {

return editor.getText();

}

//определяет, можно ли проводить редактирование public boolean isCellEditable(EventObject event) {

MutableTreeNode node = (MutableTreeNode) tree.getLastSelectedPathComponent();

return ( (node != null) && ( node.isLeaf()) );

}

}

public static void main(String[] args) { SwingUtilities.invokeLater(

new Runnable() {

public void run() { new CustomTreeEditor(); } });

}

}

Источник: https://studfile.net/preview/15935977/