Управление поиском файлов. Создание приложения на Java.

Владимир | | Java.

Создание графического интерфейса
Последним этапом создания нашей программы является создание графического интерфейса. Подробно я его описывать не буду. Он разрабатывался только для того, чтобы продемонстрировать возможности нашей библиотеки, т.е. максимально упрощенным. Кроме того, подробное описание даже этого относительно простого интерфейса потребует отдельной статьи (если не больше). Поэтому, здесь я приведу только исходный код с комментариями. А если вы захотите подробно изучить библиотеку SWING, то подробную информацию можно найти в Java Tutorial (есть даже несколько книг, посвященных разработке графического интерфейса на Java).

/*
 * Main.java
 *
 * Created on 16 Октябрь 2006 г., 20:02
 */

package filesearchswing;

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

/**
 *
 * @author Стаценко Владимир
 * http://www.vova-prog.narod.ru
 */
public class Main implements WindowListener {

    static JFrame frame = null;
    static MainPanel contentPane = null;

    /** Создает новые экземпляры Main */
    public Main() {
        frame.addWindowListener(this);
    }

    private static void createAndShowGUI() {
        //устанавливаем внешний вид интерфейса
        try {
            UIManager.setLookAndFeel(
                    UIManager.getSystemLookAndFeelClassName());
        }
        catch(Exception err) {}

        //создаем главный фрейм
        frame = new JFrame("Поиск файлов");
        //программа должна завершать работу при закрытии окна
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        Main m = new Main();

        //Создаем панель, и делаем её главной панелью окна
        contentPane = new MainPanel(frame);
        contentPane.setOpaque(true);
        frame.setContentPane(contentPane);

        //упаковываем фрейм и делаем его видимым
        frame.pack();
        frame.setVisible(true);
    }

    /**
     * Точка входа
     * @param args аргументы командной строки
     */
    public static void main(String[] args) {
        //создаём интерфейс и отдельный поток для работы с ним
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public void windowOpened(WindowEvent e) {
    }

    public void windowClosing(WindowEvent e) {
        contentPane.stopSearch();
        frame.dispose();
        System.exit(0);
    }

    public void windowClosed(WindowEvent e) {
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowActivated(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }
}

Класс MainPanel

/*
 * MainPanel.java
 *
 * Created on 17 Октябрь 2006 г., 16:20
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package filesearchswing;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.List;
import javax.swing.*;
import searchtools.*;

/**
 * Этот класс предеставляет собой основную панель программы,
 * на которой будут размещены элементы интерфейса.
 *
 * @author Стаценко Владимир
 * http://www.vova-prog.narod.ru
 */
public class MainPanel extends JPanel implements SearchListener,
        ActionListener, Runnable {

    //создаем указатели на элементы интерфейса
    private JTextField folderName = null;
    private JTextField patternField = null;
    private JLabel patternLabel = null;
    private JLabel filesNumberLabel = null;
    private JLabel foldersNumberLabel = null;
    private JLabel filesSizeLabel = null;
    private JButton selectFolder = null;
    private JButton startSearch = null;
    private JFileChooser fc = null;

    //создаем строковые константы (текст в JLabel)
    private final String FILES_NUMBER_LABEL = "Найдено файлов: ";
    private final String FOLDERS_NUMBER_LABEL = "Найдено папок: ";
    private final String FILES_SIZE_LABEL =
            "Размер найденных файлов (байт): ";

    //начальная папка поиска
    private File startFolder = null;
    //наш поисковик
    private FileFinder finder = null;
    //поток, в котором будет выполняться поиск
    private Thread searchThread = null;
    //указатель на главный фрейм программы (нужен для создания
    //диалогового окна)
    private JFrame frame = null;

    /**
     * Создает новые экземпляры MainPanel
     * @param frame указатель на главный фрейм программы
     */
    public MainPanel(JFrame frame) {
        //все компоненты на панели будут распологаться один
        //под другим
        setLayout(new GridLayout(0,1));

        this.frame = frame;

        //создаем компоненты
        //текстовое поле (для указания начальной папки)
        folderName = new JTextField(40);
        //надпись и текстовое поле для ввода регулярного выражения
        patternLabel = new JLabel("Регулярное выражение");
        patternField = new JTextField(40);
        //JLabel, в которых будет отображаться состояние поиска
        filesNumberLabel = new JLabel(FILES_NUMBER_LABEL);
        foldersNumberLabel = new JLabel(FOLDERS_NUMBER_LABEL);
        filesSizeLabel = new JLabel(FILES_SIZE_LABEL);
        //кнопка "Обзор..."
        selectFolder = new JButton("Обзор...");
        //кнопка "Поиск"
        startSearch = new JButton("Поиск");

        //настраиваем обработчик событий нажатий на кнопки
        selectFolder.addActionListener(this);
        selectFolder.setActionCommand("browse");
        startSearch.addActionListener(this);
        startSearch.setActionCommand("search");

        //добавляем компоненты на панель
        add(folderName);
        add(selectFolder);
        add(patternLabel);
        add(patternField);
        add(filesNumberLabel);
        add(foldersNumberLabel);
        add(filesSizeLabel);
        add(startSearch);

        //создаем диалоговое окно для выбора начальной папки
        fc = new JFileChooser();
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

        //создаем поисковик
        finder = new FileFinder();
        //регистрируем класс, который будет получать уведомления
        //о процессе поиска
        finder.addListener(this);
    }

    /**
     * Этот метод вызывается экземпляром класса FileFinder
     * в начале поиска
     */
    public void onSearchStart() {
        //обновляем интерфейс программы
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                filesNumberLabel.setText(FILES_NUMBER_LABEL + "0");
                foldersNumberLabel.setText(FOLDERS_NUMBER_LABEL + "0");
                filesSizeLabel.setText(FILES_SIZE_LABEL + "0");
            }
        });
    }

    /**
     * Этот метод вызывается экземпляром класса FileFinder
     * периодически в процессе поиска
     * @param totalLength общий размер найденных файлов
     * @param filesNumber количество найденных файлов
     * @param directoriesNumber количество найденных папок
     */
    public void onSearchProgressChange(long totalLength,
            long filesNumber, long directoriesNumber) {
        //Т.к. обновление интерфейса программы выполняется в
        //отдельном потоке, мы не можем напрямую использовать
        //параметры метода. Для того, чтобы обойти это ограничение
        //создаем константы, и присваиваем им значения параметров.
        final long fn = filesNumber;
        final long dn = directoriesNumber;
        final long fl = totalLength;
        //обновляем интерфейс
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                filesNumberLabel.setText(FILES_NUMBER_LABEL + fn);
                foldersNumberLabel.setText(FOLDERS_NUMBER_LABEL + dn);
                filesSizeLabel.setText(FILES_SIZE_LABEL + fl);
            }
        });
    }

    /**
     * Этот метод вызывается экземпляром класса FileFinder
     * один раз при завершении поиска
     */
    public void onSearchEnd() {
        //Т.к. обновление интерфейса программы выполняется в
        //отдельном потоке, мы не можем напрямую использовать
        //параметры метода. Для того, чтобы обойти это ограничение
        //создаем константы, и присваиваем им значения параметров.
        final long fn = finder.getFilesNumber();
        final long dn = finder.getDirectoriesNumber();
        final long fl = finder.getDirectorySize();
        //обновляем интерфейс
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                filesNumberLabel.setText(FILES_NUMBER_LABEL + fn);
                foldersNumberLabel.setText(FOLDERS_NUMBER_LABEL + dn);
                filesSizeLabel.setText(FILES_SIZE_LABEL + fl);
                //устанавливаем команду кнопки "Поиск" (в процессе
                //поиска устоновлено "Стоп")
                startSearch.setText("Поиск");
                startSearch.setActionCommand("search");
            }
        });
    }

    /**
     * Этот метод вызывается при нажатии на кнопки программы
     * @param e объект с информацией о возникшем событии (например,
     * о том, какая кнопка была нажата)
     */
    public void actionPerformed(ActionEvent e) {
        //обработка нажатия кнопки "Обзор..."
        if(e.getActionCommand().equals("browse")) {
            //открываем диалог выбора папки
            int retVal = fc.showOpenDialog(this);
            //если папка выбрана...
            if(retVal == JFileChooser.APPROVE_OPTION) {
                //...устанавливаем её в качестве стартовой папки
                startFolder = fc.getSelectedFile();
                //и отображаем полный путь в текстовом поле
                folderName.setText(startFolder.getAbsolutePath());
            }
        }
        //обработка нажатия кнопки "Поиск"
        if(e.getActionCommand().equals("search")) {
            //создаем и запускаем новый поток, в котором будет
            //выполняться поиск
            searchThread = new Thread(this);
            searchThread.start();
            //устанавливаем для кнопки команду "Стоп"
            startSearch.setText("Остановить");
            startSearch.setActionCommand("stop");
        }
        //обработка нажатия кнопки "Стоп"
        if(e.getActionCommand().equals("stop")) {
            stopSearch();
            //устанавливаем для кнопки команду "Поиск"
            startSearch.setText("Поиск");
            startSearch.setActionCommand("search");
        }
    }

    public void stopSearch() {
        //останавливаем поиск
        finder.stopSearch();
        //ждем завершения потока, в котором выполняется поиск
        if(searchThread != null) {
            while(searchThread.isAlive()) {
                Thread.currentThread().yield();
            }
        }
    }

    /**
     * Этот метод выполняется в отдельном потоке
     * (в нем и выполняется поиск)
     */
    public void run() {
        try {
            //читаем регулярное выражение
            String mask = patternField.getText();
            //начинаем поиск
            final List res = finder.findAll(folderName.getText(), mask);
            //после завершения поиска создаем диалоговое окно со
            //списком найденных объектов
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    ResultsDialog rd = new ResultsDialog(frame, res);
                    rd.pack();
                    rd.setVisible(true);
                }
            });
        }
        catch(Exception err) {
            //создаём окно с сообщениями об ошибках, если
            //они возникли
            final String error = err.getMessage();
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    JOptionPane.showMessageDialog(frame, error,
                            "Ошибка", JOptionPane.ERROR_MESSAGE);
                }
            });
        }
    }
}

Класс ResultsDialog

/*
 * ResultsDialog.java
 *
 * Created on 18 Октябрь 2006 г., 20:20
 */

package filesearchswing;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.List;
import javax.swing.*;

/**
 * Этот класс предназначен для создания окна со списком результатов
 * поиска
 *
 * @author Стаценко Владимир
 * http://www.vova-prog.narod.ru
 */
public class ResultsDialog extends JDialog implements ActionListener {

    //кнопка закрытия окна
    JButton closeButton = null;
    //текстовая область с результатами
    JTextArea res = null;

    /** Создает новые экземпляры ResultsDialog */
    public ResultsDialog(JFrame owner, List searchResults) {
        //Передаем параметры конструктору родительского класса.
        //Первый параметр - указатель на главное окно программы,
        //второй - указывает, что мы создаем модальное окно
        super(owner, true);

        //создаем текстовую область
        res = new JTextArea(20, 80);
        //создаем окно просмотра (прокрутки) и размещаем в
        //нем текстовую область
        JScrollPane sp = new JScrollPane(res);
        //устанавливаем желательный размер окна просмотра
        sp.setPreferredSize(new Dimension(400, 300));
        //добвляем результаты поиска в текстовую область
        for(int i = 0; i < searchResults.size(); i++) {
            res.append(((File)searchResults.get(i)).getAbsolutePath()
                + "n");
        }
        //устанавливаем курсор в начале окна
        res.setCaretPosition(0);
        //устанавливаем шрифт
        res.setFont(new Font("Monospaced", Font.PLAIN, 14));
        //заголовок окна
        setTitle("Результаты поиска");
        //размещаем окно просмотора с текстовой областью по
        //центру диалогового окна
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(sp, BorderLayout.CENTER);

        //создаем и размещаем внизу окна кнопку "Закрыть"
        closeButton = new JButton("Закрыть");
        closeButton.setActionCommand("close");
        //настраиваем обработчик событий кнопки
        closeButton.addActionListener(this);
        getContentPane().add(closeButton, BorderLayout.SOUTH);
    }

    /**
     * Этот метод вызывается при нажатии на кнопку
     * @param e объект с информацией о возникшем событии (например,
     * о том, какая кнопка была нажата)
     */
    public void actionPerformed(ActionEvent e) {
        //если нажата кнопка "Закрыть"
        if(e.getActionCommand().equals("close")) {
            //закрываем диалоговое окно
            setVisible(false);
        }
    }
}

Скачать

исходники класса поиска с тестами (FileFinding_src.zip — 17 кБ)

исходники программы поиска (SearchProgram_src.zip — 15 кБ)

программу поиска (SearchProgram.zip — 65 кБ)

Постовой

Готовитесь к свадьбе. Прекрасно! Свадебный форум ответит на все вопросы.

Страница: 1 2 3 4 5