Поддерживает ли Swing средства выбора файлов в стиле Windows 7?

Я только что добавил стандартное диалоговое окно «Открыть файл» в небольшое настольное приложение, которое я пишу, на основе JFileChooser запись учебного пособия по Swing. Он генерирует окно, которое выглядит так:

скриншот нежелательного окна/окна в стиле XP

но я бы предпочел иметь окно, которое выглядит так:

скриншот желаемого окна в стиле 7

Другими словами, я хочу, чтобы у моего средства выбора файлов был стиль Windows Vista/Windows 7, а не Windows XP. Возможно ли это в Swing? Если да, то как это делается? (Для целей этого вопроса предположим, что код будет работать исключительно на компьютерах с Windows 7.)


person Pops    schedule 18.04.2011    source источник


Ответы (10)


Похоже, это не поддерживается в Swing в Java 6.

В настоящее время самый простой способ открыть это диалоговое окно — через SWT, а не через Swing. SWT FileDialog (javadoc) открывает это диалоговое окно. Ниже приведена модификация фрагмент FileDialog для использования диалогового окна открытия вместо сохранения. Я знаю, что это не совсем то, что вы ищете, но вы можете выделить это в служебный класс и добавить swt.jar в свой путь к классам для этой функциональности.

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class SWTFileOpenSnippet {
    public static void main (String [] args) {
        Display display = new Display ();
        Shell shell = new Shell (display);
        // Don't show the shell.
        //shell.open ();  
        FileDialog dialog = new FileDialog (shell, SWT.OPEN | SWT.MULTI);
        String [] filterNames = new String [] {"All Files (*)"};
        String [] filterExtensions = new String [] {"*"};
        String filterPath = "c:\\";
        dialog.setFilterNames (filterNames);
        dialog.setFilterExtensions (filterExtensions);
        dialog.setFilterPath (filterPath);
        dialog.open();
        System.out.println ("Selected files: ");
        String[] selectedFileNames = dialog.getFileNames();
        for(String fileName : selectedFileNames) {
            System.out.println("  " + fileName);
        }
        shell.close();
        while (!shell.isDisposed ()) {
            if (!display.readAndDispatch ()) display.sleep ();
        }
        display.dispose ();
    }
} 
person John McCarthy    schedule 28.05.2011
comment
Это работает, и хотя технически это не Swing, кажется, что он прекрасно работает бок о бок со Swing. - person Pops; 31.05.2011
comment
Сколько МБ добавится к приложению SWING при использовании средства выбора файлов SWT? — Насколько медленнее будет запускаться приложение с добавленным в него SWT? — У меня возникает соблазн проголосовать за все показушные ответы «мой графический интерфейс лучше вашего». - person Martin; 12.12.2011
comment
@Martin: я не понимаю твоей враждебности. Я пытался ответить на вопрос, а не хвастаться. Был задан вопрос, можно ли это сделать в Swing. Мой ответ: это невозможно сделать в Swing и предоставить жизнеспособную альтернативу. Я согласен с тем, что профилирование этого решения важно, но я считаю, что это выходит за рамки этого вопроса. Кроме того, вероятно, было бы лучше профилировать это решение как часть приложения. Я сомневаюсь, что это решение приводит к значительным накладным расходам приложения, но лучше всего профилировать приложение в целом. - person John McCarthy; 14.12.2011

Даже собственные приложения Windows могут отображать этот тип диалогового окна в Windows 7. Обычно это контролируется флагами в OPENFILENAME и ее размер, передаваемые при вызове функции WinAPI GetOpenFileName. Swing (Java) использует ловушки для получения событий из диалогового окна «Открыть файл»; эти события передаются по-разному между версиями Windows XP и Windows 7.

Итак, ответ: вы не можете контролировать внешний вид FileChooser из Swing. Однако, когда Java получит поддержку этого нового вида, вы получите новый стиль автоматически.

Другой вариант — использовать SWT, как это предлагается в этом ответе. . В качестве альтернативы вы можете использовать JNA для вызова Windows API или написать собственный метод для этого.

person Alexey Ivanov    schedule 31.05.2011
comment
За исключением захватывающего ответа в последнюю минуту, это получит награду за его полноту. - person Pops; 31.05.2011
comment
Диалоговое окно Swing полностью основано на Java (с XP-клоном LAF), а не родное диалоговое окно. Это не просто побочный эффект того, как Java использует собственные вызовы (хотя они также могут генерировать файловый диалог, подобный XP). - person Michael Brewer-Davis; 13.02.2012
comment
@ Майкл Брюэр-Дэвис Вы правы. Я проигнорировал тот факт, что Swing — это чистая Java. Использование Spy++ подтверждает это: класс диалогового окна — SunAwtDialog, и у него нет дочерних окон, в отличие от стандартного системного диалога. Более того, он очень похож на диалог открытия файла XP, но это не то же самое: есть различия в поведении и внешнем виде. - person Alexey Ivanov; 16.02.2012
comment
Решение JNI, похоже, реализовано в code.google.com/p/xfiledialog, это может быть также жизнеспособным вариантом. - person Suma; 09.01.2015

Java 8 может, наконец, решить эту проблему, но, к сожалению (для приложений Swing), он поставляется только как класс JavaFX FileChooser:

Я протестировал этот код из здесь и действительно появляется современный диалог (Windows 7 здесь):

FileChooser fileChooser = new FileChooser();

//Set extension filter
FileChooser.ExtensionFilter extFilterJPG = new FileChooser.ExtensionFilter("JPG files (*.jpg)", "*.JPG");
FileChooser.ExtensionFilter extFilterPNG = new FileChooser.ExtensionFilter("PNG files (*.png)", "*.PNG");
fileChooser.getExtensionFilters().addAll(extFilterJPG, extFilterPNG);

//Show open file dialog
File file = fileChooser.showOpenDialog(null);

Чтобы интегрировать это в приложение Swing, вам нужно будет запустить его в потоке javafx через Platform.runLater (как показано здесь).

Обратите внимание, что для этого вам потребуется инициализировать поток javafx (в примере это делается при инициализации сцены в new JFXPanel()).

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

new JFXPanel(); // used for initializing javafx thread (ideally called once)
Platform.runLater(() -> {
    FileChooser fileChooser = new FileChooser();

    //Set extension filter
    FileChooser.ExtensionFilter extFilterJPG = new FileChooser.ExtensionFilter("JPG files (*.jpg)", "*.JPG");
    FileChooser.ExtensionFilter extFilterPNG = new FileChooser.ExtensionFilter("PNG files (*.png)", "*.PNG");
    fileChooser.getExtensionFilters().addAll(extFilterJPG, extFilterPNG);

    //Show open file dialog
    File file = fileChooser.showOpenDialog(null);
});
person Community    schedule 22.08.2014
comment
Совет: JavaFX относится только к Oracle Java, поэтому вам может потребоваться выбрать это явно, например. в вашем проекте Eclipse. Напротив, среда выполнения Java-1.8 правильно исключила бы JavaFX из пути к классам. - person Luke Usherwood; 22.08.2014
comment
showOpenDialog(null) не указывает родительское окно/окно владельца, поэтому всплывающее окно не модальное. Ожидается javafx.stage.Window, но я работаю с Swing java.awt.Window. Как я мог добиться модального FileChooser? - person MasterHD; 27.04.2021
comment
Возможно, вы неправильно истолковали современный диалог как модальный диалог? В любом случае, я не думаю, что вы можете создать родительские (не говоря уже о модальных) отношения между окнами JavaFX и Swing (из-за их различных моделей потоков, циклов событий, несовместимых баз кода...) См. этот ответ, который в основном взламывает его, блокируя одно окно и заставляя фокус вернуться к другому. Это ошибочно — на панели задач появляется несколько фреймов верхнего уровня, а хакерство не работает на некоторых оконных менеджерах Linux. Тем не менее, это лучшее, что я видел на сегодняшний день... - person Luke Usherwood; 01.05.2021

Что-то вроде хака и немного меньше возможностей, чем версия Swing, но не рассматривали ли вы возможность использования java.awt.FileDialog? Он должен не просто выглядеть как средство выбора файлов Windows, но и быть им.

person Andrew Thompson    schedule 18.04.2011
comment
К сожалению, это не работает; он также вызывает диалоговое окно в стиле XP. Используемый мной тестовый код взят непосредственно с сайта java2s.com/Code/JavaAPI/. java.awt/ - person Pops; 18.04.2011
comment
А как насчет этого? - person trashgod; 30.05.2011
comment
@trashgod: В ближайшие часы я начну новую тему под названием «Диспетчер файлов», посвященную расширенной версии этого кода. Когда я это сделаю, я добавлю комментарий к ветке, на которую вы ссылаетесь, и надеюсь увидеть вас в самой новой ветке. - person Andrew Thompson; 30.05.2011
comment
+1, потому что это может быть адекватным решением для некоторых сценариев. По крайней мере, вы можете удалять файлы, получать контекстное меню и т. д. Просто остерегайтесь ОСНОВНЫХ ограничений: фильтрация файлов не работает в Windows и нет поддержки выбора нескольких файлов. <rant>Java 7 немного расширил этот древний класс. Я понимаю, что фокус уходит от Swing, но я все еще не могу поверить, что они не могут сделать еще немного, для этого принципиально важного диалога! </rant> - person Luke Usherwood; 22.08.2014

Я не верю, что Swing покроет это, хотя может, если это не так, вам может понадобиться взглянуть на что-то вроде SWT, который будет использовать фактический собственный компонент или сделать собственный элемент пользовательского интерфейса, например что-то из Книга "Грязно богатые клиенты".

person mezmo    schedule 18.04.2011

хороший вопрос +1, похоже, они "забыли" внедрить что-то для Win7 (defaultLookAndFeel) в Java6, но для WinXP работает корректно, и я тоже надеюсь, что для этого должен существовать какой-то метод/свойства

в любом случае вы можете попробовать это с этим кодом,

import java.io.File;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;

class ChooserFilterTest {

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                String[] properties = {"os.name", "java.version", "java.vm.version", "java.vendor"};
                for (String property : properties) {
                    System.out.println(property + ": " + System.getProperty(property));
                }
                JFileChooser jfc = new JFileChooser();
                jfc.showOpenDialog(null);
                jfc.addChoosableFileFilter(new FileFilter() {

                    @Override
                    public boolean accept(File f) {
                        return f.isDirectory() || f.getName().toLowerCase().endsWith(".obj");
                    }

                    @Override
                    public String getDescription() {
                        return "Wavefront OBJ (*.obj)";
                    }

                    @Override
                    public String toString() {
                        return getDescription();
                    }
                });
                int result = JOptionPane.showConfirmDialog(null, "Description was 'All Files'?");
                System.out.println("Displayed description (Metal): " + (result == JOptionPane.YES_OPTION));
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    SwingUtilities.updateComponentTreeUI(jfc);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                jfc.showOpenDialog(null);
                result = JOptionPane.showConfirmDialog(null, "Description was 'All Files'?");
                System.out.println("Displayed description (System): " + (result == JOptionPane.YES_OPTION));
            }
        };
        SwingUtilities.invokeLater(r);
    }

    private ChooserFilterTest() {
    }
}
person mKorbel    schedule 25.05.2011
comment
Только что попробовал это, он все еще дает выбор, похожий на мой первый снимок экрана. Я ценю усилия, хотя. - person Pops; 25.05.2011

Однако не удалось сделать это для каталогов! DirectoryDialog возвращает нас к выбору каталога в виде дерева, который совпадает с указанным в вопросе. Проблема в том, что он не позволяет мне выбирать/выбирать/открывать скрытые папки. Он также не позволяет переходить к таким папкам, как AppData, ProgramData и т. д.

Диалоговое окно в стиле Windows 7 (swt) позволяет переходить к этим папкам, но, опять же, не позволяет выбирать папки :(

Обновить Для просмотра скрытых папок используйте JFileChooser и установите setFileHidingEnabled(false). Единственным требованием является то, что пользователям необходимо выбрать «показывать скрытые файлы, папки и диски» в

Параметры папки -> Вид

Проводника Windows

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

person Rohan    schedule 08.06.2013

Ответ Джона Маккарти кажется лучшим. Вот несколько предложений.

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.Image;

Добавьте изображение в верхний левый угол. Важно, чтобы вы использовали «getResourceAsStream», вы заметите после экспорта как Runnable jar:

Display display = new Display();
Shell shell = new Shell(display);
InputStream inputImage = getClass().getResourceAsStream("/app/launcher.png");
if (inputImage != null) {
    shell.setImage(new Image(display, inputImage));
}

Домашний каталог пользователя:

String filterPath = System.getProperty("user.home");

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

String absolutePath = dialog.open();
person User Rebo    schedule 28.07.2015

Поскольку Swing эмулирует различные L&F, я думаю, вам лучше всего обновить JRE до самой последней версии и надеяться, что пользовательский интерфейс JFileChooser был обновлен.

person qwerty    schedule 18.04.2011

JFileChooser всегда выглядел немного странно с Swing, а также немного медленным.

Попробуйте использовать средство выбора файлов SWT или вы можете обернуть вызовы C в JNA.

person meverett    schedule 24.05.2011
comment
Сколько МБ добавится к приложению SWING при использовании средства выбора файлов SWT? — Насколько медленнее будет запускаться приложение с добавленным в него SWT? — У меня возникает соблазн проголосовать за все показушные ответы «мой графический интерфейс лучше вашего». - person Martin; 12.12.2011