Изменение поведения JFileChooser: предотвращение "выбора" при вводе в пути к файлу JTextField

Приветствую Swing Pros, вот хороший (надеюсь) вопрос для вас.

Ниже приведены требования к задачам и возможные решения, которые я вижу. Я хотел бы, чтобы кто-то, у кого был такой тяжелый опыт, поделился некоторыми мыслями об этом.

Это не требует кодирования или чего-то подобного, мне просто нужен общий совет относительно того, какой подход является более надежным в отношении того факта, что мне нужно работать с закрытыми символами, которые находятся в пакетах sun.swing и / или javax.swing.plaf.

Задача состоит в том, чтобы изменить / изменить поведение JFileChooser (на самом деле, чуть-чуть).

  1. когда пользователь нажимает, введите в имени файла JTextField, и поле содержит путь к каталогу, не "выбирайте" каталог, а переключайтесь на него. Да, диалог настроен на прием каталогов, но нам нужно принимать только щелчки по кнопке "Открыть" и (возможно) двойные щелчки в таблице списка файлов.

  2. запретить пользователю выбирать каталог / файл с более чем 1 ГБ данных, нажав ввод в текстовом поле имени файла

Вот несколько основных вариантов решения:

а. прислушайтесь к изменениям, основанным на свойствах, которые предоставляет JFileChooser (которые AFAICS запускаются после факта и не обеспечат необходимую нам степень контроля).

б. повозиться с javax.swing.plaf.basic.BasicFileChooserUI (посредством рефракции, нарушения инкапсуляции частного уровня) и изменить ссылку на

private Action approveSelectionAction = new ApproveSelectionAction();

так что наше пользовательское действие выполняет дополнительные проверки для 1 и 2. Этот подход связывается с пакетом plaf и может завершиться ошибкой, если это действие каким-то образом переопределено в некотором классе ниже этого класса пользовательского интерфейса.

с. Пройдите по иерархии компонентов JFileChooser, найдите JTextField (который, по-видимому, должен встречаться в дереве компонентов только один раз), украсьте всех слушателей действий, висящих на этом JTextField, нашими пользовательскими проверками. Мой сеанс отладки показывает, что этот JTextField является некоторым анонимным подклассом JTextField, живущим в sun.swing.FilePane. Этот подход кажется более подходящим для OO, но есть вероятность, что для некоторых ОС это текстовое поле отсутствует или в иерархии также присутствует какой-то другой JTextField.

Что ж, похоже, что публичного API JFileChooser недостаточно для достижения такого поведения, в то время как другие два варианта являются либо глубокой магией, либо непереносимыми (долгосрочными), либо даже и тем, и другим.

Итак, вопрос: какой подход вы бы выбрали и почему?

2 ответа

Решение

Что касается опции 2, вам не нужно использовать отражение, чтобы настроить действие принятия. Вы можете просто переопределить метод ApproveSelection(). Что-то вроде:

JFileChooser chooser = new JFileChooser( new File(".") )
{
    public void approveSelection()
    {
        if (getSelectedFile().exists())
        {
            System.out.println("duplicate");
            return;
        }
        else
            super.approveSelection();
    }
};

Недавно я столкнулся с тем же требованием, то есть нажатие клавиши Enter в JTextField JFileChooser должно привести к тому, что отображаемое диалоговое окно пересекает каталог, а не возвращается из диалогового окна. Только нажатие на кнопку "Открыть" должно привести к окончательному выбору.

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

1 - Зарегистрируйте AWTListener для отслеживания последнего типа события, сгенерированного пользователем

class MyChooser extends JFileChooser implements java.awt.AWTEventListener {

    ...
    MyChooser(){
        Toolkit.getDefaultToolkit().addAWTEventListener(this,
        AWTEvent.MOUSE_EVENT_MASK + AWTEvent.KEY_EVENT_MASK);
        ...

    }

    int lastEventId;

    public void eventDispatched(AWTEvent e) {
        lastEventId=e.getID();
    }
}

2 - Переопределите метод ApproveSelection() в JFileChooser и проверьте, является ли запрос подтверждения результатом события мыши (вероятно, вызванного нажатием кнопки "Открыть") или событием клавиши, вызванным нажатием клавиши "Ввод". Переменная lastEventId обеспечивает доступ к этой информации. Мой собственный метод ApproveSelection выглядит следующим образом:

public void approveSelection() {
    File f=getSelectedFile();
    if (f.exists() && isTraversable(f) && lastEventId ==
        KeyEvent.KEY_PRESSED) {
        setCurrentDirectory(f);
        return;
    }
    super.approveSelection(); } 
Другие вопросы по тегам