#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. Как я уже говорил ниже, некоторые компоненты могут быть созданы сторонними библиотеками, поэтому я не могу получить их ссылки.