Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад]

Библиотека примеров приложений Java

Оглавление
Выбор файлов
Простейший редактор текста
Копирование файлов UNICODE
Сохранение объекта Java в файле
Произвольные классы и файлы
Буферизация потоков
Разбор конфигура-
ционного файла

Работа с консолью
Работа с классом PrintWriter
Разбор строк класса String
Загрузка и просмотр изображений
Потоки в оперативной памяти
Конвейерные потоки
Комбинирование двух потоков
Комбинирование нескольких потоков
Поиск слова в текстовом файле
Произвольный доступ к файлу
Информация о файле
Работа с каталогами
Просмотр содержимого каталога
Просмотр каталога с фильтром
Панель для выбора каталога
Список системных свойств
Сохранение списка системных свойств
Контрольная сумма файла
Копирование, переименование, удаление файлов
Архивы ZIP
Создание архива ZIP
Распаковка архива ZIP
Обход дерева каталогов

Назад Вперед

7.22. Панель для выбора каталога

Стандартная диалоговая панель класса FileDialog позволяет выбирать файлы, расположенные внутри каталогов, но, к сожалению, непригодна для выбора каталогов. В примере реализован класс DirDialog, с помощью которого можно выбирать каталоги, расположенные на текущем рабочем диске.

Исходный текст примера

Архив проекта для Java WorkShop 2.0

Немного теории

В библиотеке классов java.awt.* определен класс FileDialog, с помощью которого приложения могут выводить на экран стандартную диалоговую панель выбора файлов. Но если вам нужно организовать выбор не файлов, а каталогов, то в решении этой задачи класс FileDialog никак вам не поможет.

Вы, однако, можете создать свой собственный класс на базе класса Dialog, расположить там список и заполнить его содержимым нужного вам каталога при помощи метода list класса File. Для того чтобы в этом списке присутствовали только каталоги, необходимо определить фильтр.

Описание примера

Пример представляет собой автономное приложение Java, создающее свое главное окно на базе класса Frame. В окне имеется меню File, состоящее из строк Open и Exit. Если из этого меню выбрать строку Open, на экране появится диалоговая панель, показанная на рис. 1.

pic1.gif (3238 bytes)

Рис. 1. Диалоговая панель для выбора каталога

Эта панель позволяет перемещаться по дереву каталога в пределах текущего рабочего диска. Путь к выделенному каталогу отображается в заголовке панели.

Если выделить каталог и нажать кнопку OK, полный путь к каталогу появится в главном окне приложения (рис. 2).

pic2.gif (2893 bytes)

Рис. 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 только в том случае, если переданное ему имя соответствует каталогу.


Назад Вперед

[Назад]