Как изменить внешний вид приложения Swing во время выполнения?

#java #swing #user-interface #jdialog

#java #swing #пользовательский интерфейс #внешний вид

Вопрос:

Я знаю, что есть SwingUtilities.updateComponentTreeUI(Component c) метод, но он работает не идеально. Например, у меня есть JFileChooser и текущий внешний вид — Windows, затем я меняю внешний вид на Nimbus с помощью SwingUtilities.updateComponentTreeUI(mainWindow) , и стиль главного окна изменяется правильно, но когда я показываю средство выбора файлов с помощью JFileChooser.showOpenDialog(Component parent) метода, оно по-прежнему выглядит как Windows. То же самое произойдет, если я покажу всплывающее диалоговое окно с JPopupMenu.show(Component invoker, int x, int y) методом.

Есть ли решение этой проблемы?

Комментарии:

1. Чтобы было понятно, вы также скорректировали текущий L amp; F с помощью UIManager.setLookAndFeel() ?

Ответ №1:

Предполагая, что value это имя класса нового внешнего вида, вот фрагмент для обновления всех окон и подкомпонентов:

 public static void updateLAF(String value) {
    if (UIManager.getLookAndFeel().getClass().getName().equals(value)) {
        return;
    }
    try {
        UIManager.setLookAndFeel(value);
        for (Frame frame : Frame.getFrames()) {
            updateLAFRecursively(frame);
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedLookAndFeelException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public static void updateLAFRecursively(Window window) {
    for (Window childWindow : window.getOwnedWindows()) {
        updateLAFRecursively(childWindow);
    }
    SwingUtilities.updateComponentTreeUI(window);
}
  

Комментарии:

1. Это не поможет, если вы кэшируете компонент Swing, который не является частью иерархии Swing, в своем собственном коде.

2. @Robin Действительно, хороший улов для кэшированных компонентов. Тем не менее, если оно встроено в другой компонент, который является иерархией, другим вариантом является переопределение updateUI , вызов super.updateUI , а также пересылка вызова на средство выбора файла.

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

4. Window[] wins = Window.getWindows(); вместо` Window window: frame.getOwnedWindows()` может быть работает для всех контейнеров, которые могут быть isDisplayable() , isDisplayable( ) возвращает контейнеры с удаленными, Rootpane или если DecorationsTyp они изменены программно

5. Обновление всех окон, возвращаемых Window.getWindows() , не влияет на мой файловый выбор, который еще не отображался в диалоговом окне.

Ответ №2:

Вызов SwingUtilities.updateComponentTreeUI(mainWindow) обновит только компоненты Swing в иерархии Swing под mainWindow .

Если вы сохраняете JFileChooser где-нибудь в своем коде (например, в поле класса), не показывая JFileChooser , средство выбора не будет обновлено SwingUtilities.updateComponentTreeUI(mainWindow) вызовом. Вы можете обойти это, UIManager самостоятельно добавив слушателя и вызывая SwingUtilities.updateComponentTreeUI(myStoredFileChooser) из этого слушателя, когда внешний вид будет изменен.

Убедитесь, что вы не создаете утечку памяти с помощью этого, например, пусть у этого слушателя есть только WeakReference к JFileChooser (поскольку время жизни UIManager равно времени жизни JVM)

Комментарии:

1. Как добавить слушателя в UIManager ?

2. Отличная работа по выделению WeakReference .

3. @ZhaoYi ты вообще потрудился открыть javadoc UIManager класса. В этом случае я уверен, что вы бы нашли addPropertyChangeListener метод

4. Как я уже говорил ниже, некоторые компоненты могут быть созданы сторонними библиотеками, поэтому я не могу получить их ссылки.