Назад
Вперед
7.22. Панель для выбора каталога
Стандартная диалоговая панель класса FileDialog
позволяет выбирать файлы, расположенные внутри
каталогов, но, к сожалению, непригодна для выбора
каталогов. В примере реализован класс DirDialog, с
помощью которого можно выбирать каталоги,
расположенные на текущем рабочем диске.
Исходный текст примера
Архив проекта для Java WorkShop 2.0
Немного теории
В библиотеке классов java.awt.* определен класс
FileDialog, с помощью которого приложения могут
выводить на экран стандартную диалоговую панель
выбора файлов. Но если вам нужно организовать
выбор не файлов, а каталогов, то в решении этой
задачи класс FileDialog никак вам не поможет.
Вы, однако, можете создать свой собственный
класс на базе класса Dialog, расположить там список
и заполнить его содержимым нужного вам каталога
при помощи метода list класса File. Для того чтобы в
этом списке присутствовали только каталоги,
необходимо определить фильтр.
Описание примера
Пример представляет собой автономное
приложение Java, создающее свое главное окно на
базе класса Frame. В окне имеется меню File, состоящее
из строк Open и Exit. Если из этого меню выбрать
строку Open, на экране появится диалоговая панель,
показанная на рис. 1.
Рис. 1. Диалоговая панель для выбора каталога
Эта панель позволяет перемещаться по дереву
каталога в пределах текущего рабочего диска.
Путь к выделенному каталогу отображается в
заголовке панели.
Если выделить каталог и нажать кнопку OK, полный
путь к каталогу появится в главном окне
приложения (рис. 2).
Рис. 2. В главном окне приложения показан путь к
выбранному каталогу
Кнопка Cancel отменяет выбор каталога.
Рассмотрим исходный текст приложения.
Главный класс приложения DirOpen
Главный класс приложения DirOpen не имеет никаких
особенностей:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
public class DirOpen
{
public static void main(String args[])
{
FrameWindow frame;
frame = new FrameWindow(
"View Directory");
frame.setVisible(true);
}
}
Он создает главное окно приложения как объект
класса FrameWindow, унаследованного от класса Frame, и
отображает его.
Класс FrameWindow
В классе FrameWindow реализованы интерфейсы ActionListener
и WindowListener:
class FrameWindow extends Frame
implements ActionListener, WindowListener
{
. . .
}
Когда пользователь выбирает из меню File строку
Open, управление передается методу actionPerformed.
В ответ на выбор указанной строки метод
actionPerformed отображает на экране диалоговую панель
выбора каталога класса DirDialog:
DirDialog d = new DirDialog(
"Dir: ", this);
d.show();
Когда пользователь завершит выбор каталога,
метод actionPerformed попытается получить полный путь к
выбранному каталогу, вызвав метод getDirectory класса
DirDialog:
szSelected = d.getDirectory();
if(szSelected != null)
{
ta.append(szSelected + "\n");
}
Путь к каталогу будет добавлен в многострочное
окно редактирования текста ta, расположенное в
главном окне приложения. В том случае если
пользователь отказался от выбора, данный метод
вернет значение null.
Класс DirDialog
Этот класс создан нами на базе класса Dialog:
class DirDialog extends Dialog
implements ActionListener, WindowListener,
ItemListener
{
. . .
}
Для отслеживания событий, связанных с кнопками
OK и Cancel, а также событий, вызванных выбором
каталога из списка двойным щелчком клавиши мыши,
мы реализовали в этом классе интерфейс ActionListener.
Интерфейс ItemListener нужен нам для обработки
событий, связанных с выделением элементов списка
каталогов.
И, наконец, интерфейс WindowListener нужен для скрытия
окна диалоговой панели в ответ на попытку
пользователя уничтожить диалоговую панель с
помощью кнопки, расположенной в заголовке окна.
Рассмотрим поля, определенные в классе DirDialog.
Поле l класса List хранит ссылку на список, внутри
которого отображается содержимое каталогов:
List l;
Следующие два поля хранят ссылки на кнопки OK и
Cancel:
Button bOK;
Button bCancel;
Поле szCurrentDir используется для хранения текущего
каталога, который изменяется в процессе
просмотра дерева каталогов:
String szCurrentDir;
В поле szUserHome хранится путь к домашнему каталогу
пользователя, извлеченного из системного
свойства с именем "user.home":
String szUserHome;
Строка szParent хранит путь к родительскому (по
отношению к текущему) каталогу:
String szParent;
Поле szSelected предназначено для хранения пути к
каталогу, выбранного пользователем:
String szSelected = null;
И, наконец, в поле szBoxTitle хранится заголовок
диалоговой панели выбора файла, к которому в
процессе выбора добавляется путь к текущему
выделенному каталогу:
String szBoxTitle;
Конструктор класса DirDialog
Рассмотрим действия, выполняемые
конструктором класса DirDialog в процессе
инициализации диалоговой панели выбора
каталога.
Прежде всего мы вызываем конструктор базового
класса Dialog, передавая ему ссылку на родительскую
панель, заголовок и признак модальности:
super(parent, szTitle, true);
Наша панель создается как модальная, поэтому
пользователь не сможет продолжить работу
приложения, не закрыв панель.
Далее мы устанавливаем начальный размер
панели, сохраняем ее заголовок и подключаем
обработчик событий, связанных с окном панели:
setSize(400, 300);
szBoxTitle = szTitle;
this.addWindowListener(this);
Далее мы создаем список из пяти строк:
l = new List(5, false);
В его окне будут отображаться имена каталогов.
На следующем шаге мы определяем путь к
домашнему каталогу пользователя, получая для
этого значение системного свойства "user.home":
Properties p = System.getProperties();
szUserHome = p.getProperty("user.home");
Текущий каталог и выбранный каталог по
умолчанию совпадает с домашним:
szCurrentDir = szUserHome;
szSelected = szCurrentDir;
Теперь мы изменяем заголовок диалоговой
панели, добавляя в него выбранный каталог:
setTitle(szBoxTitle + szSelected);
Начальное заполнение списка именами каталогов,
расположенных в текущем каталоге, выполняется
методом updateList:
updateList(null);
Позже мы расскажем о параметре этого метода,
который при инициализации должен быть равен
значению null.
Далее мы создает кнопки, добавляем для них
обработчики событий:
bOK = new Button("OK");
bCancel = new Button("Cancel");
bOK.addActionListener(this);
bCancel.addActionListener(this);
Для списка также добавляются обработчики
событий, возникающих при выделении его строк
соответственно, двойным и одинарным щелчком:
l.addActionListener(this);
l.addItemListener(this);
Перед размещением списка и кнопок в окне
диалоговой панели мы устанавливаем режим
размещения компонент GridBagLayout:
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints c =
new GridBagConstraints();
setLayout(gbl);
Далее мы добавляем список:
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
c.gridheight = 1;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridx = GridBagConstraints.RELATIVE;
c.gridy = GridBagConstraints.RELATIVE;
c.insets = new Insets(10, 10, 10, 10);
c.weightx = 0;
c.weighty = 1.0;
gbl.setConstraints(l, c);
add(l);
При добавлении мы указываем, что список должен
быть выровнен на северо-восток, его размеры
должны изменяться по горизонтали и вертикали.
Список должен занимать одну ячейку таблицы по
высоте и быть единственным компонентом в первой
строке.
Вторую строку таблицы занимают кнопки OK и Cancel:
c.weightx = 0;
c.weighty = 0;
c.fill = GridBagConstraints.NONE;
c.gridwidth = 1;
c.ipadx = 32;
gbl.setConstraints(bOK, c);
add(bOK);
c.gridwidth = GridBagConstraints.REMAINDER;
c.ipadx = 10;
c.weightx = 1.0;
gbl.setConstraints(bCancel, c);
add(bCancel);
Метод getDirectory класса DirDialog
Этот метод вызывает программа, создавшая
диалоговую панель класса DirDialog. Он возвращает
полный путь к выбранному каталогу или значение
null, если пользователь отказался от выбора:
public String getDirectory()
{
return szSelected;
}
Метод itemStateChanged класса DirDialog
В задачу метода itemStateChanged входит отслеживание
действий пользователя по выделению строк списка
каталогов:
public void itemStateChanged(ItemEvent e)
{
String s = l.getSelectedItem();
if(s.equals(".."))
{
szSelected = null;
}
else
{
szSelected = szCurrentDir + s +
File.separator;
setTitle(szBoxTitle + szSelected);
}
}
Если пользователь выбрал строку "..",
являющуюся ссылкой на родительский каталог, в
поле szSelected записывается значение null. Таким
образом, если пользователь выберет указанную
строку и затем нажмет кнопку OK, результат будет
такой же, как будто он отказался от выбора.
При выборе других строк метод itemStateChanged
записывает путь к выделенному каталогу в поле
szSelected, добавляя к нему суффикс разделителя
каталогов, а затем изменяет заголовок диалоговой
панели.
Метод actionPerformed класса DirDialog
Этот метод обрабатывает события, возникающие
от кнопок и списка каталогов.
Когда пользователь нажимает кнопку OK, метод
actionPerformed прежде всего получает строку,
выделенную в списке каталогов:
if(e.getSource().equals(bOK))
{
String s = l.getSelectedItem();
. . .
}
Если эта строка непустая (то есть если
пользователь выделил любую строку), и если
выделенная строка не является ссылкой на
родительский каталог, то к ней добавляется
разделитель:
if(s != null)
{
if(!s.equals(".."))
{
szSelected = szCurrentDir + s +
File.separator;
}
else
szSelected = null;
}
else
szSelected = null;
Результат записывается в поле szSelected.
Далее метод скрывает окно диалоговой панели:
setVisible(false);
В том случае если пользователь нажал кнопку
Cancel, метод actionPerformed записывает в поле szSelected
значение null (признак отказа от выбора каталога) и
скрывает окно панели:
else if(e.getSource().equals(bCancel))
{
szSelected = null;
setVisible(false);
}
Двойной щелчок клавишей мыши по элементу
списка каталога обрабатывается следующим
образом:
else if(e.getSource().equals(l))
{
String s = l.getSelectedItem();
updateList(s);
}
Здесь мы получаем строку, по которой был
выполнен двойной щелчок, и затем передаем ее
методу updateList, обновляющий список каталогов.
Метод updateList класса DirDialog
Рассмотрим исходный текст метода updateList.
Прежде всего этот метод удаляет все строки из
списка каталогов:
l.removeAll();
Далее он анализирует значение переданного ему
параметра szSelected.
Если это значение равно null (что бывает при
вызове метода updateList на этапе инициализации
диалоговой панели), метод создает объект f класса
File для текущего каталога:
File f = null;
if(szSelected == null)
{
f = new File(szCurrentDir);
}
В том случае когда метод updateList был вызван в
результате выбора пользователем строки "..",
метод определяет путь к родительскому
(относительно текущего) каталогу и записывает
его в поле szCurrentDir:
else if(szSelected.equals(".."))
{
if(szCurrentDir.endsWith("\\"))
{
szCurrentDir =
szCurrentDir.substring(0,
szCurrentDir.length() - 1);
}
f = new File(szCurrentDir);
szParent = f.getParent();
szCurrentDir = szParent;
f = new File(szCurrentDir);
szCurrentDir += File.separator;
}
В результате мы "выходим" из каталога.
В противном случае метод updateList просто
добавляет имя выделенного каталога к текущему
через разделитель и создает объект f для нового
каталога:
else
{
szCurrentDir += (szSelected +
File.separator);
f = new File(szCurrentDir);
}
Этим мы достигаем эффекта "входа" в
каталог.
Далее метод проверяет, есть ли у текущего
каталога родительский каталог:
szParent = f.getParent();
if(szParent != null)
{
l.add("..");
}
Если таковой имеется, в список каталогов
добавляется строка "..", с помощью которой
пользователь сможет выйти из каталога.
На следующем этапе метод updateList получает список
каталогов, расположенных в текущем каталоге, и
заполняет список l соответствующими именами:
String[] sDirList;
sDirList = f.list(new MaskFilter());
for(int i = 0; i < sDirList.length; i++)
{
l.add(sDirList[i]);
}
В процессе заполнения используется фильтр
класса MaskFilter, разрешающий добавление в список
каталогов, но не файлов.
Класс MaskFilter
Класс MaskFilter, фильтрующий имена каталогов,
выглядит следующим образом:
class MaskFilter
implements FilenameFilter
{
public boolean accept(File f, String name)
{
return(new File(f, name).isDirectory());
}
}
Единственный определенный в нем метод accept
реализует интерфейс FilenameFilter. Он возвращает
значение true только в том случае, если переданное
ему имя соответствует каталогу.
Назад Вперед |