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

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

310 ГЛАВА 11

private String text; // удобный конструктор

public ImageListElement(Icon icon, String text) { this.icon = icon;

this.text = text;

}

// методы для доступа к значку и тексту public Icon getIcon() { return icon; } public String getText() { return text; }

public void setIcon(Icon icon) { this.icon = icon; } public void setText(String text) { this.text = text; }

}

Это просто композиция из значка Icon и строки String с текстом. Чтобы было проще создавать этот объект, мы добавили удобный конструктор, позволяющий быстро задать нужные значения. Теперь нам понадобится рисующий объект, который будет прорисовывать для списка элементы ImageListElement:

//com/porty/swing/ImageListCellRenderer.java

//Класс для прорисовки в списке одновременно

//значка и текста

package com.porty.swing;

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

public class ImageListCellRenderer extends DefaultListCellRenderer {

// метод, возвращающий для элемента рисующий компонент public Component getListCellRendererComponent(

JList list, Object data, int idx, boolean isSelected, boolean hasFocus) {

// проверяем, нужного ли элемент типа

if ( data instanceof ImageListElement ) { ImageListElement lie =

(ImageListElement)data;

//получаем текст и значок

Icon icon = lie.getIcon(); String text = lie.getText();

//используем возможности базового класса

JLabel label = (JLabel) super.getListCellRendererComponent(

list, text, idx, isSelected, hasFocus); label.setIcon(icon);

Списки

311

return label;

}else

return super.getListCellRendererComponent( list, data, idx, isSelected, hasFocus);

}

}

МынаследуемклассImageListCellRendererотстандартногообъектаDefaultListCellRenderer, и это дает нам возможность не беспокоиться о правильной прорисовке текста надписи с помощью установленных для списка цветов. Вместо этого мы можем сосредоточиться на обработке элементов нужного нам типа (а именно ImageListElement). Для начала мы выясняем, относится ли элемент списка к нужному типу, и если это так, начинаем его обработку. Прежде всего вызывается метод getListCellRendererComponent() базового класса DefaultListCellRenderer, но не для всего объекта ImageListElement, а только для хранящегося в нем текста (text). В результате мы получаем надпись JLabel (а мы знаем, что всегда получаем надпись от базового класса, поэтому преобразование типов безопасно) с установленным текстом. Нам остается лишь добавить к этому тексту наш значок и вернуть списку готовую надпись. Если же в списке окажется элемент незнакомого нам типа, мы просто перепоручим его обработку своему базовому классу.

Наконец, мы можем проверить работу нашего нового объекта для отображения элементов списка. Давайте попробуем:

//ImageList.java

//Список, используюший новый рисующий объект import javax.swing.*;

import com.porty.swing.*;

import java.awt.*;

public class ImageList { // данные списка

private

static Icon bullet = new ImageIcon("bullet.gif");

private

static Object[] data = {

new

ImageListElement(bullet, "Первый"),

new

ImageListElement(bullet, "Второй"),

new

ImageListElement(bullet,

 

"<html><h4><font color=green>И третий!")

};

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

new Runnable() { public void run() {

//создаем список и настраиваем его

JList list = new JList(data); list.setCellRenderer(new ImageListCellRenderer());

//добавляем в окно

312

ГЛАВА 11

JFrame frame = new JFrame("ImageList"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 200);

frame.add(new JScrollPane(list)); frame.setVisible(true);

} });

}

}

Мы создаем небольшое окно со списком в панели содержимого. Список создается на основе массива данных, и на этот раз мы записываем наши данные в виде объектов ImageListElement,одновременноуказываязначокитекст.Заметьте,чтоблагодаряиспользованию в качестве базового класса стандартного рисующего объекта DefaultListCellRenderer, возможности HTML для списка по-прежнему доступны. Остается не забыть установить в качестве рисующего объекта списка наш новый объект ImageListCellRenderer (c помощью метода setCellRenderer()) и вывести окно на экран. Вы убедитесь в том, что теперь список показывает значок и текст одновременно, а при необходимости может выводить и HTML-текст. Не забывайте только, что созданные нами классы ImageListElement и ImageListCellRenderer находятся в пакете com.porty.swing. Они могут сослужить вам хорошую службу — списки с элементами, состоящими из значка и текста, очень популярны в приложениях.

Аналогичным образом вы можете действовать, если вам понадобятся дальнейшие изменения во внешнем виде элементов списка. Унаследуйте от стандартного рисующего объекта и добавьте к надписи то, что вам необходимо, благо ее возможности нам хорошо известны и без сомнения велики. Если же вам понадобится выводить элементы списка в совершенно особом виде, вы можете написать рисующий объект ListCellRenderer «с нуля». Пример такого объекта (для создания списка с элементами-флажками) мы вскоре увидим.

Список JList также использует интерфейс ListCellRenderer, чтобы определить, где и какие следует выводить всплывающие подсказки. Для этого он переопределяет метод базового класса JComponent getToolTipText() и в момент вывода подсказки узнает, на каком элементе списка находится указатель мыши. Для этого элемента списка он получает с помощью объекта ListCellRenderer рисующий его компонент и пытается выяснить текст его подсказки. Если у компонента подсказка есть, она выводится, а если текст подсказки получить не удалось, она не появляется вовсе. Созданный нами класс ImageListCellRenderer легко доработать для поддержки всеми элементами списка подсказок: надо лишь добавить в класс ImageListElement строку подсказки, а в классе ImageListCellRenderer дополнительно вызывать для надписи метод setToolTipText(). После этого каждый элемент списка сможет не только показывать текст и значок, но и при необходимости выводить подсказку. Учитывая, что и в элементах списка, и в самих подсказках может присутствовать HTML-текст, возможности для создания любого интерфейса открываются просто захватывающие.

Списки

313

События списка

У списка JList нет собственных событий (за исключением стандартных событий, подобных событиям от мыши и клавиатуры, унаследованных им от базового компонента JComponent), все особенные события происходят в его моделях. Присоединив слушателя к модели ListModel, поставляющей данные для отображения в виде элементов списка, вы сможете узнать, когда и как меняются элементы списка и какие это элементы. Чаще всего эти события от модели обрабатывает как раз список, что позволяет ему вывести верные данные вовремя и в надлежащем виде, реализую концепцию модели и вида. Впрочем, вы можете и сами использовать события модели списка, сделав из нее некий сообщающий об изменениях в себе контейнер данных, если задача того требует.

Гораздо более интересные события происходят в модели выделения списка ListSelectionModel; они сообщают об изменениях в выделении пользователем элементов списка. Конечно, никто не запрещает вам бесцеремонно вмешаться в работу модели выделения (мы уже так делали) и следить за выделением прямо из нее, но это сложнее и не так элегантно. Присоединив слушателя к модели выделения списка, вы сможете прямо на месте узнавать обо всех изменениях в выделенных элементах, которые делает пользователь, и в зависимости от его выбора предлагать ему дополнительную информацию или новые альтернативы. Давайте рассмотрим небольшой пример, в котором мы будем узнавать о выделенных элементах списка прямо «на лету»:

//ListSelectionEvents.java

//Слежение за выделением списка import javax.swing.*;

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

public class ListSelectionEvents extends JFrame { // данные списка

private String[] data =

{ "Красный", "Желтый", "Зеленый"}; private JTextArea jta;

public ListSelectionEvents() { super("ListSelectionEvents"); setDefaultCloseOperation(EXIT_ON_CLOSE);

//создаем список и текстовое поле setLayout(new FlowLayout());

JList list = new JList(data); list.setSelectionMode(

ListSelectionModel.SINGLE_SELECTION); jta = new JTextArea(5, 20);

//добавим слушателя событий выделения list.addListSelectionListener(new SelectionL());

//добавляем компоненты

add(new JScrollPane(list)); add(new JScrollPane(jta)); // выводим окно на экран

314 ГЛАВА 11

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

}

// слушатель событий от модели выделения

class SelectionL implements ListSelectionListener { public void valueChanged(ListSelectionEvent lse) {

int selected = ((JList)lse.getSource()).getSelectedIndex();

switch ( selected ) {

case 0: jta.setText("Переходить нельзя"); break; case 1: jta.setText("Будьте готовы"); break; case 2: jta.setText("Переходите улицу");

}

}

}

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

new Runnable() {

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

}

}

В примере мы добавляем в окно список на основе небольшого массива строк и текстовое поле JTextArea, которые мы будем использовать для вывода дополнительной информации. Затем к списку мы добавляем слушателя событий от модели выделения, вызывая метод addListSelectionListener(). Заметьте, что этот метод мы вызываем для самого списка JList, хотя точно такой же метод есть и в модели выделения ListSelectionModel. Разница лишь в источнике события, который будет возвращать нашему слушателю метод getSource(). При присоединении слушателя к списку (как в нашем примере) данный метод будет возвращать ссылку на него, и чаще всего это удобнее. В качестве слушателя событий будет использоваться внутренний класс SelectionL. В нем при получении извещения от модели выделения мы определяем позицию выделенного элемента списка (с помощью источника события — нашего списка) и в зависимости от этой позиции снабжаем пользователя дополнительной информацией. Запустите программу с примером и удостоверьтесь в том, что переходите улицу на нужный цвет светофора.

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