Изменение поведения JFileChooser: предотвращение "выбора" при вводе в пути к файлу JTextField
Приветствую Swing Pros, вот хороший (надеюсь) вопрос для вас.
Ниже приведены требования к задачам и возможные решения, которые я вижу. Я хотел бы, чтобы кто-то, у кого был такой тяжелый опыт, поделился некоторыми мыслями об этом.
Это не требует кодирования или чего-то подобного, мне просто нужен общий совет относительно того, какой подход является более надежным в отношении того факта, что мне нужно работать с закрытыми символами, которые находятся в пакетах sun.swing и / или javax.swing.plaf.
Задача состоит в том, чтобы изменить / изменить поведение JFileChooser (на самом деле, чуть-чуть).
когда пользователь нажимает, введите в имени файла JTextField, и поле содержит путь к каталогу, не "выбирайте" каталог, а переключайтесь на него. Да, диалог настроен на прием каталогов, но нам нужно принимать только щелчки по кнопке "Открыть" и (возможно) двойные щелчки в таблице списка файлов.
запретить пользователю выбирать каталог / файл с более чем 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(); }