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

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

460

ГЛАВА 15

Таблица 15.3 (продолжение)

 

 

 

 

 

Свойства

Описание

 

 

 

closedIcon

Позволяет сменить значок, обозначающий свернутый узел

 

с потомками, например, в дереве с файлами это нераскрытая

 

папка

openIcon

Значок для раскрытого узла с потомками (в дереве файлов это

 

раскрытая папка)

leafIcon

Задает значок для узла, который является листом, то есть не

 

обладает потомками. Как вы помните из обсуждения стандарт-

 

ной модели, есть два способа определения того, какой узел

 

следует считать листом

backgroundNonSelectionColor,

Управляют цветом фона отображаемых на экране узлов. Пер-

backgroundSelectionColor

вое свойство задает цвет фона для узла, когда он не выделен,

 

второе — когда выделен

textNonSelectionColor,

Управляют цветом шрифта узлов. Первое свойство хранит

textSelectionColor

цвет шрифта невыделенного узла, второе — выделенного

 

Используя любые поддерживаемые Swing возможности HTML и перечисленные в таблице свойства, можно удивительным образом раскрасить любое дерево. Рассмотрим пример, в котором задействуем самые эффектные возможности стандартного отображающего объекта дерева JTree:

//TreeDefaultRendering.java

//Использование возможностей стандартного

//отображащего объекта DefaultTreeCellRenderer import javax.swing.*;

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

public class TreeDefaultRendering extends JFrame { public TreeDefaultRendering() {

super("TreeDefaultRendering"); setDefaultCloseOperation(EXIT_ON_CLOSE);

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

JTree tree = new JTree(createTreeModel());

//создадем и настраиваем отображающий объект

DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();

renderer.setLeafIcon(new ImageIcon("Leaf.gif")); renderer.setClosedIcon(

new ImageIcon("NodeClosed.gif")); renderer.setOpenIcon(

new ImageIcon("NodeOpened.gif"));

//передаем его дереву tree.setCellRenderer(renderer);

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

461

// добавляем дерево и выводим окно на экран add(new JScrollPane(tree));

setSize(400, 300); setVisible(true);

}

//листья дерева храним в массивах private String[] langs = {

"<html><b>Java", "<html><pre>Scala", "Ruby" }; private String[] ides = {

"IDEA", "<html><i>Eclipse", "NetBeans" };

//создание несложной модели дерева

private TreeModel createTreeModel() {

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

DefaultMutableTreeNode root = new DefaultMutableTreeNode(

"<html><font color=blue>Создание кода");

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

DefaultMutableTreeNode lang =

new DefaultMutableTreeNode("Языки"); DefaultMutableTreeNode ide =

new DefaultMutableTreeNode("Среды"); root.add(lang);

root.add(ide);

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

for (int i=0; i<langs.length; i++) { lang.add(new DefaultMutableTreeNode(langs[i])); ide.add(new DefaultMutableTreeNode(ides[i]));

}

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

}

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

new Runnable() {

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

}

}

Здесь мы создаем небольшое окно с деревом JTree. Дерево строится из стандартной модели (а та, в свою очередь, принимает данные от стандартных узлов DefaultMutableTreeNode). Нетрудно заметить, что создание модели дерева в методе createTreeModel() практически не отличается от предыдущего примера. Единственное отличие в том, что мы стали использовать для данных некоторых узлов не простой текст,

462

ГЛАВА 15

а HTML-разметку, не забыв предупредить об этом отображающий объект с помощью магических символов <html>.

Посмотрите, как одним мановением руки настраивается стандартный отображающий объект дерева DefaultTreeCellRenderer. Мы сменяем три значка, используемые для вывода узлов и листьев, не затрагивая цвета и шрифты (это, как нетрудно заметить, гораздо проще сделать с помощью встроенного языка HTML). Чаще всего именно сменой значков для узлов дерева добиваются его уникального узнаваемого вида, который к тому же в состоянии «подсказать» пользователю, данные какого типа дерево отображает. Значки, показанные в примере, были частично заимствованы из коллекции графики Java Look And Feel Graphics Repository, специально созданной для внешнего вида Metal (вы можете найти эту коллекцию по адресу java.sun.com).

ПослетогокакмызадаемнашновыйотображающийобъектметодомsetCellRenderer(), остается включить дерево JTree в панель прокрутки и поместить его в окно, после чего вывести окно на экран. Заметьте, насколько мало кода нам понадобилось написать (если не считать кода, создающего модель дерева) и какой совершенно уникальный облик обрело наше дерево. Обратите внимание, как показаны узлы, названия которых написаны с помощью HTML. Одним словом, фантазия ваша в отображении узлов дерева ничем не ограничена, нужно лишь следить за тем, чтобы узлы дерева имели более или менее одинаковую высоту, иначе дерево теряет стройность и начинает запутывать пользователя.

Дерево с флажками

Конечно, вам не обязательно использовать стандартный отображающий объект DefaultTreeCellRenderer, который при всех своих преимуществах все же довольно ограничен в возможностях: значки и стиль текста задаются для всего дерева сразу, вы не сможете задать разные значки для разных узлов, а это требуется не так уж и редко. Поэтому иногда приходится создавать собственные отображающие объекты. Сделать это несложно — нам уже известно, что в интерфейсе отображающего объекта TreeCellRenderer всего один метод, который должен вернуть для узла дерева компонент, призванный отображать данные узла на экране.

Создадим теперь специализированный компонент пользовательского интерфейса — дерево, способное отображать флажки. В некоторых ситуациях применение подобного компонента делает пользовательский интерфейс значительно удобнее (к примеру, там, где имеется некая иерархия множества доступных свойств приложения). Для создания

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

463

такого дерева нам понадобится как-то хранить данные узлов (текст и признак выбора флажка) и написать отображающий объект для таких данных. В главе 11 мы написали класс CheckBoxListElement для списка, состоящего из флажков; используем его и здесь (данный класс хранит именно текст и признак выделения элемента). Чтобы новое дерево было удобно задействовать в ваших программах, мы разместим его в библиотечном пакете com.porty.swing. Отображающий объект будет сразу же присоединяться в конструкторе дерева:

//com/porty/swing/CheckBoxTree.java

//Дерево, способное отображать в качестве узлов флажки package com.porty.swing;

import java.awt.*; import java.awt.event.*; import javax.swing.*;

import javax.swing.tree.*;

public class CheckBoxTree extends JTree { // конструктор на основе модели

public CheckBoxTree(TreeModel model) { super(model);

//задаем собственный отображающий объект setCellRenderer(new CheckBoxRenderer());

//следим за щелчками мыши addMouseListener(new MouseL());

}

//стандартный объект для отображения узлов private DefaultTreeCellRenderer renderer =

new DefaultTreeCellRenderer();

//флажок для отображения узлов дерева class CheckBoxRenderer extends JCheckBox

implements TreeCellRenderer { public CheckBoxRenderer() {

// делаем флажок прозрачным setOpaque(false);

}

// данный метод должен вернуть компонент для узла public Component getTreeCellRendererComponent( JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row,

boolean hasFocus) {

// проверяем, что используется стандартная модель if (!(value instanceof DefaultMutableTreeNode)) {

464

ГЛАВА 15

// если нет, то используем стандартный объект return renderer.getTreeCellRendererComponent(

tree, value, selected, expanded, leaf, row, hasFocus);

}

Object data = ((DefaultMutableTreeNode)value). getUserObject();

// проверяем, подходит ли нам тип данных узла if ( data instanceof CheckBoxListElement ) {

CheckBoxListElement element = (CheckBoxListElement)data;

// настраиваем флажок setSelected(element.isSelected()); setText(element.getText()); return this;

}

// иначе задействуем стандартный объект

return renderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);

}

}

// класс, следящий за щелчками мыши class MouseL extends MouseAdapter {

public void mousePressed(MouseEvent e) { // получим путь к узлу

TreePath path = getClosestPathForLocation( e.getX(), e.getY());

if ( path == null ) return;

// проверим, подходят ли нам данные узла

Object _node = path.getLastPathComponent();

if (_node instanceof DefaultMutableTreeNode) { DefaultMutableTreeNode node =

(DefaultMutableTreeNode)_node; Object data = node.getUserObject();

if ( data instanceof CheckBoxListElement ) { // меняем состояние флажка

CheckBoxListElement element = (CheckBoxListElement)data;

element.setSelected(! element.isSelected()); repaint(getPathBounds(path));

}

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