Опубликован: 04.12.2009 | Доступ: свободный | Студентов: 8424 / 660 | Оценка: 4.30 / 3.87 | Длительность: 27:27:00
Лекция 7:

Важнейшие объектные типы

Выбор файлов и папок с помощью файлового диалога

При работе с файлами в подавляющем большинстве приложений требуется вызов файлового диалога. В нашем приложении из палитры компонентов (правое верхнее окно среды разработки) перетащим на экранную форму JLabel ("Метка") – первый компонент в палитре Swing. А затем повторим эту операцию еще раз. В первой метке мы будем показывать имя выбранного файла, а во второй – путь к этому файлу.

Для того, чтобы вызвать файловый диалог, назначим обработчик события пункту файлового меню openMenuItem ("Открыть...") – подузел [JFrame]/menuBar[JMenu]/fileMenu[JMenu]/openMenuItem[JMenuItem]. Двойной щелчок по узлу openMenuItem приводит к автоматическому созданию заготовки обработчика openMenuItemActionPerformed и открытию редактора исходного кода.

Сначала мы создаем в приложении объект типа JFileChooser, соответствующий файловому диалогу. Если в начале записать import javax.swing.*, что желательно, то в соответствующих местах кода не потребуется квалификация javax.swing. Но в данном примере импорт не сделан намеренно для того, чтобы было видно, где используются классы данного пакета.

javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser();

Добавим в обработчик необходимый код:

private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
  if(fileChooser.showOpenDialog(null)!= fileChooser.APPROVE_OPTION){
      System.out.println("Отказались от выбора");
      return;
  };
  System.out.println("Нажали Open");
  jLabel1.setText(fileChooser.getSelectedFile().getName());
  jLabel2.setText(fileChooser.getSelectedFile().getParent());
}

В первой строке обработчика вызывается метод fileChooser.showOpenDialog(openMenuItem). Он показывает диалог на экране. В качестве параметра должен быть задан родительский компонент – в этом качестве мы используем пункт меню openMenuItem. Сравнение с переменной класса APPROVE_OPTION позволяет выяснить, была ли выбрана кнопка Open - "Открыть".

Следует обратить внимание на характерный прием – выход из подпрограммы с помощью оператора return в случае, когда не был осуществлен выбор файла. Неопытные программисты написали бы данный фрагмент кода таким образом:

if(fileChooser.showOpenDialog(openMenuItem)== fileChooser.APPROVE_OPTION){
  System.out.println("Нажали Open");
  jLabel1.setText(fileChooser.getSelectedFile().getName());
  jLabel2.setText(fileChooser.getSelectedFile().getParent());
}
else
  System.out.println("Отказались от выбора");

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

Можно было бы перенести строку

javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser()

в обработчик события. В этом случае при каждом нажатии пункта меню "Файл/Открыть…" создавался бы новый объект-диалог. Такой код был бы работоспособен. Но создание диалога является относительно долгим процессом, требующим большого количества ресурсов операционной системы. Поэтому лучше создавать в приложении глобальную переменную, которой назначен диалог. Помимо прочего это позволяет в повторно открываемом диалоге оказываться в той же папке, где происходил последний выбор файла.

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

File folder=…;
fileChooser.setCurrentDirectory(folder);

Диалог сохранения файла открывается аналогичным образом – showSaveDialog.

Практически всегда при использовании файловых диалогов требуется задавать фильтр, по которому просматриваются файлы. В подавляющем большинстве случаев требуется определенное расширение в имени файла. К сожалению, компонент JFileChooser до сих пор не поддерживает встроенной возможности настраивать фильтр – для этого требуется создание специального класса. Приведем пример простейшего такого класса:

package java_gui_example;
import java.io.*;

public class SimpleFileFilter extends javax.swing.filechooser.FileFilter {
  String ext;
  SimpleFileFilter(String ext){
  this.ext=ext;
  }
  
  public boolean accept(File f){
    if(f==null)
      return false;
    if(f.isDirectory()){
      return true ;
    }
    else
      return (f.getName().endsWith(ext));
  }
  
  /**  
   * Описание фильтра, возникающее в строке фильтра
   * @see FileView#getName
   */
  public String getDescription(){
      return "Text files (.txt)";
  }
}

Использование приведенного класса следующее: задается глобальная переменная

javax.swing.filechooser.FileFilter fileFilter=new SimpleFileFilter(".txt");

После чего она используется в обработчике события:

fileChooser.addChoosableFileFilter(fileFilter);

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

По умолчанию показывается последний из добавленных фильтров. Если требуется показать другой фильтр, который уже был добавлен в список фильтров диалога, требуется вызвать оператор

fileChooser.setFileFilter(fileFilter);

Он делает добавленный фильтр текущим, то есть видимым при открытии диалога.

Кроме стандартных диалогов открытия и сохранения файлов имеется возможность вызова диалога с дополнительными программно задаваемыми элементами - с помощью метода showCustomDialog.

Также имеется возможность выбирать несколько файлов. Для этого до вызова диалога требуется задать разрешение на такой выбор:

fileChooser.setMultiSelectionEnabled(true);

Получение массива выбранных файлов после вызова диалога идет следующим образом:

java.io.File[] files = fileChooser.getSelectedFiles();
if (files != null && files.length > 0) {
  String filenames = "";
  for (int i=0; i<files.length; i++) {
filenames = filenames + "\n" + files[i].getPath();
  }
}

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

fileChooser.setFileSelectionMode(fileChooser.DIRECTORIES_ONLY);

либо и файлы, и папки

fileChooser.setFileSelectionMode(fileChooser.FILES_AND_DIRECTORIES);

Возврат в обычный режим:

fileChooser.setFileSelectionMode(fileChooser.FILES_ONLY);

Для того, чтобы в выбранной папке просмотреть список файлов в папке, с которой связана переменная File folder, используется вызов вида

String[] filenames= folder.list(filter);

Получается массив строк с короткими именами файлов. Используется переменная filter, тип которой является классом, реализующим интерфейс java.io.FilenameFilter. О том, что такое интерфейсы, будет рассказано в отдельном разделе. Пример простейшего такого класса SimpleFilenameFilter:

package java_gui_example;
import java.io.*;
public class SimpleFilenameFilter implements FilenameFilter{
    String ext;
    public SimpleFilenameFilter(String ext) {
      this.ext=ext;
    }
    
    public boolean accept(File dir,String fileName){
       return ext==""||fileName.endsWith(ext);
    }
}

Пример с показом файлов, содержащихся в выбранной папке, в компонент jTextArea1 (текстовая область) типа JTextArea, позволяющий показывать произвольное число строк:

String[] filenamesArray;
File folder=fileChooser.getSelectedFile();
SimpleFilenameFilter filter=new SimpleFilenameFilter("");
String filenames = "";
if(folder.isDirectory()){
    filenamesArray=folder.list(filter);
    for (int i=0; i<filenamesArray.length; i++) {
        filenames = filenames + "\n" + filenamesArray[i];
    };
    jTextArea1.setText(filenames);
}

Аналогичный пример вывода выбранных в диалоге имен в режиме "мультиселект", позволяющем отмечать несколько файлов и/или папок:

java.io.File[] files = fileChooser.getSelectedFiles();
if (files != null && files.length > 0) {
    String filenames = "";
    for (int i=0; i<files.length; i++) {
        filenames = filenames + "\n" + files[i].getPath();
    };
    jTextArea1.setText(filenames);
};
Полетаев Дмитрий
Полетаев Дмитрий
Не очень понятно про оболочечные Данные,ячейки памяти могут наверно размер менять,какое это значение те же операции только ячейки больше,по скорости тоже самое
Максим Старостин
Максим Старостин

Код с перемещением фигур не стирает старую фигуру, а просто рисует новую в новом месте. Точку, круг.