Одна из самых замечательных особенностей библиотеки Swing — возможность изменять внешний вид и поведение графических элементов приложения.

Вид (look) каждого графического компонента задают его форма, тип и цвет рамки, цвет фона, цвет, тип и размер шрифта, форма курсора мыши. Поведение компонента (feel) определяют та или иная реакция на действия мыши, набор командных клавиш, способ перемещения окон и т. д. Набор таких свойств всех компонентов приложения определяет его вид и поведение, Look and Feel, сокращенно — L&F. Всего набирается несколько сотен свойств, определяющих L&F приложения.

Самые общие методы получения и задания сведений о виде и поведении приложения Swing собраны в абстрактном классе LookAndFeel пакета javax.swing. При создании какого-то конкретного стиля L&F надо расширить этот класс, заполнив его характеристиками конкретного L&F.

В библиотеке Swing собраны все необходимые сведения о стандартном виде и поведении графического приложения на нескольких наиболее распространенных графических платформах. Часть этих сведений, общая для всех платформ, образует набор системных сведений (system defaults). Системные сведения собраны в абстрактном классе

BasicLookAndFeel, расширяющем класс LookAndFeel. Класс BasicLookAndFeel и его вспомогательные классы составляют пакет javax.swing.plaf.basic.

Конкретные сведения, специфичные для трех наиболее распространенных платформ, собраны в трех классах, расширяющих класс BasicLookAndFeel:

□ MotifLookAndFeel — вид и поведение, характерные для графической оболочки CDE (Common Desktop Environment), основанной на библиотеке графических функций Motif. Эта графическая оболочка применяется как "родная" в операционной системе Solaris.

В документации этот вид и поведение называются CDE/Motif;

□ WindowsLookAndFeel — вид и поведение Win32, характерные для платформы MS Windows;

□ MacLookAndFeel — вид и поведение, принятое на платформе Apple Macintosh.

Вид и поведение CDE/Motif можно реализовать на любой платформе, вид и поведение Windows и Macintosh, из-за лицензионных ограничений, доступны лишь на соответствующей платформе.

Технология Java определяет и свой собственный, независимый от платформы, Java Look and Feel, сокращенно — Java L&F, еще короче — JLF. Он неформально называется "Metal" за схожесть этого L&F с гравировкой по металлу. Такой стиль в русской технической литературе называется "приборным" стилем за сходство с оформлением алюминиевых панелей научных приборов. Впрочем, JLF позволяет создать различные темы оформления и получить стиль, совсем не похожий на приборную панель. Несколько тем реализованы в стандартной поставке Swing. Их отличия можно посмотреть в демо-программе SwingSet2. По умолчанию начиная с пятой версии Java SE установлена тема "Ocean", в прежних версиях была тема "Steel". Тему "Steel" можно сделать темой по умолчанию, установив системное свойство swing.metalTheme=steel.

Приложение, работающее в стиле JLF, будет выглядеть одинаково на всех платформах. Именно этот стиль использован во всех примерах, приведенных в предыдущих главах.

Сведения о виде и поведении Java L&F собраны в четвертом наследнике класса

BasicLookAndFeel — классе MetalLookAndFeel.

Дизайнерская мысль не стоит на месте, и на смену Java L&F идет Nimbus L&F, впервые появившийся в JDK 1.6.0_10. Оформление Nimbus создается средствами Java 2D и использует богатейшие возможности этой библиотеки, некоторые из них мы рассмотрели в главе 9. В частности, для рисования применяется векторная графика, что позволяет использовать Nimbus при любом разрешении экрана.

Вид и поведение Nimbus создаются классом NimbusLookAndFeel и другими классами из пакета j avax.swing.plaf.nimbus.

Сведения, собранные в каждом из этих классов, образуют платформенные сведения (look and feel defaults).

Кроме системных и платформенных сведений есть еще пользовательские сведения (user defaults), задаваемые приложением при его запуске или во время работы.

Наивысший приоритет имеют пользовательские сведения. Если они не заданы, то исполняющая система Swing отыскивает платформенные сведения. Не найдя их, она берет нужные значения из системных сведений.

Итак, на каждой платформе можно установить четыре стандартных L&F: "родной" для данной платформы, CDE/Motif, Nimbus и Java L&F. Они выглядят как на рис. 17.1.

Окно верхнего уровня класса JFrame или JDialog, зарегистрированное в оконном менеджере графической подсистемы операционной системы, оформляется по правилам этого оконного менеджера.

Его внешний вид можно изменить только специальными ухищрениями, а именно статическими методами

JFrame.setDefaultLookAndFeelDecorated(true);

JDialog.setDefaultLookAndFeelDecorated(true);

JFrame newLAFWin = new JFrame();

После выполнения этих методов, если оконный менеджер может создавать окна без оформления и если текущий L&F способен оформлять окна, все создаваемые окна класса JFrame и JDialog будут оформлены текущим L&F, как показано на рис. 17.4.

Рис. 17.1. Стандартные L&F

Чтобы оформить отдельное окно верхнего уровня текущим L&F, надо сначала отключить его оформление оконным менеджером, а затем установить новый стиль оформления методом setWindowDecorationStyle(int) класса JRootPane:

JFrame fr = new JFrame(); fr.setUndecorated(true);

fr.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);

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

Это свойство графических элементов библиотеки Swing получило название Pluggable Look and Feel, сокращенно — PL&F, PLAF или plaf.

Получение свойств L&F

Для получения свойств текущего L&F и установки нового L&F нужно заменить классы XxxLookAndFeel на класс UIManager из пакета javax.swing. Он содержит массу статических методов, позволяющих получить сведения об элементах L&F, изменить некоторые элементы или вообще сменить L&F.

Объект класса UIManager ищет название L&F сначала как значение системного свойства swing.defaultlaf, созданного, например, при запуске приложения из командной строки с ключом -d:

j ava -Dswing.defaultlaf=com.sun.j ava.swing.plaf.motif.MotifLookAndFeel

SomeSwingApplication

Если такое системное свойство не определено, объект ищет файл swing.properties, обычно лежащий в каталоге $JAVA_HOME/lib. Если он существует, то в нем отыскивается значение ключа swing.defaultlaf, например:

swing.defaultlaf=com.sun.j ava.swing.plaf.motif.MotifLookAndFeel

Если такого ключа нет или вообще отсутствует файл swing.properties, то устанавливается Java L&F.

Вы всегда можете создать или изменить файл swing.properties, записав в него другой L&F, например:

swing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel

После этого по умолчанию будет установлен Nimbus.

Для хранения свойств текущего L&F класс UIManager использует модель данных — объект класса UIDefaults. Класс UIDefaults расширяет класс Hashtable, следовательно, является хеш-таблицей, состоящей из пар "ключ — значение" (key — value). Кроме обычного для хеш-таблицы метода get(Object key), возвращающего значение value ключа key, и метода put(Object key, Object value), устанавливающего значение value с ключом key, класс UIDefaults содержит специализированные методы для определенных типов данных, хранящихся в таблице. Они позволяют избавиться от приведения типов, так надоедающего при вызове метода get(Object).

Например, метод getBoolean(Object key) возвращает значение ключа key, если оно имеет

тип boolean. Аналогично действуют методы getBorder(Object), getColor(Object), getDimension(Object), getFont(Object), getIcon(Object), getInsets(Object), getInt(Object), getString(Object). У каждого из них есть парный метод getXxx (Object, Locale), возвращающий значение ключа для данной локали.

Экземпляр класса UIDefaults, используемый в классе UIManager, — это закрытое (private) поле. Поэтому методы класса UIDefaults дублируются статическими методами класса UIManager с теми же именами.

Например, текущий шрифт, которым делаются надписи класса Jlabel, можно получить так:

Font labelFont = UIManager.getFont("Label.font");

Кроме того, статическим методом getDefaults() можно получить ссылку на экземпляр класса UIDefaults, используемый классом UIManager.

Просмотреть все несколько сотен свойств, хранящихся в модели данных UIDefaults, можно так:

UIDefaults defs = UIManager.getDefaults();

Enumeration keys = defs.keys();

Enumeration elem = defs.elements();

while (keys.hasMoreElements() && elem.hasMoreElements())

System.out.println(

keys.nextElement() + ": " + elem.nextElement());

Статический метод

put(Object key, Object value);

меняет только пользовательские установки различных свойств, оставляя установки L&F без изменения. Посмотреть установки L&F можно статическим методом

geLookAndFeelDefaults (), возвращающим экземпляр класса UIDefaults.

Для того чтобы легче переключать вид и поведение приложения, класс UIManager хранит несколько L&F под произвольно данными именами в виде массива объектов вложенного класса UIManager.LookAndFeelInfo. Новый элемент заносится в этот массив статическим методом

installLookAndFeel(String name, String className);

вызывающим конструктор класса UIManager.LookAndFeelInfo, или статическим методом

installLookAndFeel(UIManager.LookAndFeelInfo);

По умолчанию хранятся платформенные L&F, CDE/Motif, Nimbus и Java L&F. Посмотреть имена всех имеющихся в массиве L&F можно так:

UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels(); for (int i = 0; i < info.length; i++)

System.out.println(info[i].getName());

Задание стандартного L&F

Очень легко задать один из стандартных PL&F, воспользовавшись одним из статических методов setLookAndFeel(LookAndFeel) или setLookAndFeel(String) класса UIManager. Аргумент второго из этих методов — строка, содержащая полное имя нужного класса XxxLoo kAnd Feel со всеми подпакетами. Например, строка "javax.swing.plaf.metal. MetalLookAndFeel" задает имя класса, определяющего Java L&F. Поскольку это имя может измениться в следующих версиях Java SE, то для получения имени класса Java L&F лучше пользоваться статическим методом getCrossPlatformLookAndFeelClassName() класса UIManager. Впрочем, Java L&F устанавливается по умолчанию, как можно видеть из многочисленных примеров, приведенных в предыдущих главах. Еще один статический метод getSystemLookAndFeelClassName () класса UIManager возвращает полное имя класса, определяющего стандартный L&F для данной платформы. Обычный способ задания платформенного L&F выглядит так:

public static void main(String[] args){ try{

UIManager.setLookAndFeel(

UIManager.getSystemLookAndFeelClassName());

}catch(Exception e){}

new SomeSwingApplication();

}

Обрабатывать исключение здесь не нужно, потому что в ответ на его выбрасывание устанавливается Java L&F.

Для получения строки с полным именем класса CDE/Motif в классе UIManager никакого метода нет, ее надо задавать прямо:

UIManager.setLookAndFeel(

"com.sun.j ava.swing.plaf.motif.MotifLookAndFeel");

В листинге 17.1 приведена программа, создавшая рис. 17.1. В ней каждое внутреннее окно строится по правилам одного из стандартных L&F.

Листинг 17.1. Внутренние окна со стандартными L&F

import java.awt.*; import javax.swing.*;

public class DiffLAF extends JFrame{

DiffLAF(){

super(" Окно с разными L&F"); setLayout(new FlowLayout());

JInternalFrame ifr1 =

new JInternalFrame(" Oкно Metal", true, true, true, true); ifr1.getContentPane().add(new JLabel(" Это окно Java L&F")); ifr1.setPreferredSize(new Dimension(200, 100)); ifr1.setVisible(true); add(ifr1);

try{

UIManager.setLookAndFeel(

UIManager.getSystemLookAndFeelClassName());

JInternalFrame ifr2 =

new JInternalFrame(" РћРєРЅРѕ Windows", true, true, true, true); i fr2.getContentPane().add(

new JLabel("Это окно Windows L&F

TeMa Classic")); ifr2.setPreferredSize(new Dimension(200, 100)); ifr2.setVisible(true) ;

add(ifr2);

UIManager.setLookAndFeel(

"com.sun.java.swing.plaf.motif.MotifLookAndFeel"); }catch(Exception e){}

JInternalFrame ifr3 =

new JInternalFrame(" РћРєРЅРѕ CDE/Motif", true, true, true, true); i fr3.getContentPane().add(

new JLabelC^TO РѕРєРЅРѕ Solaris CDE L&F")); ifr3.setPreferredSize(new Dimension(200, 100)); ifr3.setVisible(true) ; add(ifr3);

setSize(400, 400);

setDefaultCloseOperation(EXIT ON CLOSE); setVisible(true);

}

public static void main(String[] args){ new DiffLAF();

}

Дополнительные L&F

Кроме текущего L&F библиотека Swing может одновременно использовать дополнительные (auxiliary) L&F. Они являются расширениями класса MultiLookAndFeel из пакета javax.swing.plaf.multi. Полные имена их классов вида XxxLookAndFeel задаются в файле $JAVA_HOME/lib/swing.properties, в строке с ключом swing.auxiliarylaf, через запятую. При загрузке объектов L&F исполняющая система Java вначале создает и загружает объекты текущего L&F, а затем объекты дополнительных L&F в порядке их записи в строке swing.auxiliarylaf в файле swing.properties.

Дополнительные L&F обычно связаны с дополнительными устройствами ввода/вывода: клавиатурой Брайля, речевым вводом/выводом и тому подобными устройствами. Ничто не мешает дополнительному L&F выводить свои объекты на экран, но при этом могут возникнуть конфликты с текущим L&F. Поэтому рекомендуется не использовать в качестве дополнительных графических L&F классы, унаследованные от BasicLookAndFeel, а наследовать их прямо от MultiLookAndFeel.

Смена всего L&F

Разработчик GUI может сменить весь L&F своего приложения или его отдельные свойства. Для смены всего L&F сначала устанавливается новый L&F:

UIManager.setLookAndFeel(new MyCoolLookAndFeel());

Затем надо привести вид и поведение приложения в соответствие с новым L&F.

При каждом изменении какого-либо свойства, входящего в L&F, или всего L&F целиком, происходит событие класса PropertyChangeEvent. Класс UIManager присоединяет обработчик этого события обычным методом addPropertyChangeListener(PropertyChangeListener). В обработчике события следует сообщить всем компонентам приложения о смене L&F. Это удобно сделать статическим методом updateComponentTreeUI(Component) класса SwingUtilities. В аргументе данного метода достаточно указать контейнер верхнего уровня, метод передаст сообщение всем вложенным контейнерам и компонентам.

Итак, обработка изменения L&F выглядит следующим образом:

JFrame frame = JFrame("Главноe окно");

UIManager.addPropertyChangeListener( new PropertyChangeListener(){

public void propertyChange(PropertyChangeEvent e){

SwingUtilities.updateComponentTreeUI(frame);

}

});

Если при этом надо установить первоначальные размеры окна, то в обработчик события следует вставить обращение к методу frame.pack ().

Метод updateComponentTreeUI (frame) рекурсивно просматривает все вложенные контейнеры и компоненты. Для каждого компонента вызывается его метод updateUI () класса JComponent, который, в свою очередь, вызывает метод setUI(ComponentUI) с аргументом соответствующего типа, устанавливающий новый L&F для этого компонента.

В листинге 17.2 приведен пример программы, дающей возможность пользователю менять L&F во время работы приложения, выбрав нужный пункт меню. На рис. 17.2 показан вывод этой программы.

Листинг 17.2. Смена L&F во время работы приложения

import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.*; import javax.swing.*;

public class ChLAF extends JFrame{

ChLAF(){

super(" Смена L&F"); setLayout(new FlowLayout()) ;

JMenuBar mb = new JMenuBar(); setJMenuBar(mb);

JMenu serv = new JMenu("CepBHc"); mb.add(serv);

JMenu laf = new JMenu("Р’РёРґ"); serv.add(laf);

ButtonGroup bg = new ButtonGroup();

UIManager.LookAndFeelInfo[] info =

UIManager.getInstalledLookAndFeels();

for (int i = 0; i < info.length; i++){

JRadioButtonMenuItem item =

new JRadioButtonMenuItem(info[i].getName());

item.addItemListener(new LAFChange(info[i].getClassName()));

bg.add(item); laf.add(item);

}

JButton b = new JButton("РљРЅРѕРїРєР°");

add(b);

UIManager.addPropertyChangeListener( new PropertyChangeListener(){

public void propertyChange(PropertyChangeEvent e){ SwingUtilities.updateComponentTreeUI(c);

}

});

setSize(400, 400);

setDefaultCloseOperation(JFrame.EXIT ON CLOSE); setVisible(true);

}

public static void main(String[] args){ new ChLAF();

}

class LAFChange implements ItemListener{

private String className;

public LAFChange(String className){ this.className = className;

}

public void itemStateChanged(ItemEvent e){

if(e.getStateChange() == ItemEvent.SELECTED) try{

UIManager.setLookAndFeel(className); }catch(Exception ex){}

}

}

}

Рис. 17.2. Смена L&F

В составе Java SE, в каталоге $JAVA_HOME/demo/jfc/SwingSet2/, приведен пример, позволяющий менять L&F и темы во время работы приложения. Для его запуска достаточно перейти в указанный каталог и набрать в командной строке

java -jar SwingSet2.jar

Замена отдельных свойств L&F

Во время работы приложения можно заменить не весь текущий L&F, а только некоторые его свойства. Для этого надо воспользоваться статическим методом put(Object key, Object value) класса UIManager. Поскольку при этом меняется только модель данных — класс UIDefaults — к нему следует присоединить обработчик событий, получив ссылку на него методом getDefaults(). Потом нужно оповестить все заинтересованные компоненты о сделанных изменениях методом

updateComponentTreeUI(Component) .

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

Листинг 17.3. Смена размера шрифта в полях ввода

import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.*; import javax.swing.*; import javax.swing.plaf.*;

public class PropCh extends JFrame{

PropCh(){

super(" Смена размера шрифта"); setLayout(new FlowLayout());

JMenuBar mb = new JMenuBar(); setJMenuBar(mb);

JMenu serv = new JMenu("Сервис"); mb.add(serv);

JMenu laf = new JMenu("Размер шрифта"); serv.add(laf);

ButtonGroup bg = new ButtonGroup();

FontChange fch = new FontChange();

for (int i = 10; i < 22; i += 2){

JRadioButtonMenuItem item = new JRadioButtonMenuItem(""+ i); item.addItemListener(fch); bg.add(item); laf.add(item);

}

JTextArea ta = new JTextArea(5, 20);

JTextField tf = new JTextField(20);

JPasswordField pf = new JPasswordField(20);

add(ta); add(tf); add(pf);

PropertyChangeListener pcl = new PropertyChangeListener(){

public void propertyChange(PropertyChangeEvent e){ SwingUtilities.updateComponentTreeUI(c);

}

};

UIManager.addPropertyChangeListener(pcl); UIManager.getDefaults().addPropertyChangeListener(pcl);

setSize(400, 400);

setDefaultCloseOperation(EXIT ON CLOSE); setVisible(true);

}

public static void main(String[] args){ new PropCh();

}

class FontChange implements ItemListener{ public FontChange(){}

public void itemStateChanged(ItemEvent e){

if (e.getStateChange() == ItemEvent.SELECTED){

JMenuItem mi = (JMenuItem)e.getSource(); int n = Integer.parseInt(mi.getText());

Font f = UIManager.getFont("TextArea.font");

String name = f.getName(); int style = f.getStyle();

FontUIResource fr = new FontUIResource(name, style, n);

UIManager.put("TextArea.font", fr);

// UIManager.put("TextField.font", fr);

// UIManager.put("PasswordField.font", fr);

UIManager.put("EditorPane.font", fr);

UIManager.put("TextPane.font", fr);

UIManager.put("FormattedTextField.font", fr);

}

}

}

}

На рис. 17.3 показан результат работы программы из листинга 17.3. В области ввода установлен шрифт величиной 20 пунктов. Поскольку две строчки листинга закомментированы, в поле ввода и в поле пароля остался прежний системный размер шрифта.

Рис. 17.3. Поля ввода с измененным размером шрифта

Темы Java L&F

Вид и поведение Java L&F базируются на трех основных (primary) цветах и трех дополнительных (secondary) фоновых цветах, из которых образуется колорит внешнего вида приложения. Кроме того, выбран цвет для ввода текста и цвет фона текстовых полей. Выбор каких-либо шести цветов в качестве основных и дополнительных, а также шрифтов для заголовка, надписей, ввода текста образует определенную тему (theme) внешнего вида.

Методы, возвращающие цвета и шрифты выбранной темы, частично определены абстрактным классом MetalTheme из пакета javax.swing.plaf.metal. Полное определение темы, выбираемой по умолчанию, дано классом DefaultMetalTheme. В этой теме основные цвета — темно-синий, синий и голубой, точнее, цвет primary1 в модели RGB равен (102, 102, 153), цвет primary2 — (153, 153, 204), цвет primary3 — (204, 204, 255). Дополнительные цвета — это темно-серый, серый и светло-серый, точнее, secondary1 равен (102, 102, 102), secondary2 — (153, 153, 153), secondary3 — (204, 204, 204). Цвет primary1 используется рамками активного компонента, надписями на компонентах. Цвет primary2 выделяет пункты меню, цвет primary3 выделяет текст в полях ввода. Цвет secondary1 оттеняет "выпуклые" компоненты, цвет secondary2 используется рамками неактивных компонентов, цвет secondary3 — цвет фона неактивных компонентов.

Кроме перечисленных цветов тема DefaultMetalModel определяет черный цвет для текста, вводимого в текстовые поля, и белый цвет для фона текстовых полей.

В теме класса OceanTheme, расширяющего класс DefaultMetalModel, основные цвета — это светло-синий, голубой и светло-голубой, точнее, в модели RGB это цвета (99, 130, 191), (163, 184, 204) и (184, 207, 229). Дополнительные цвета — серо-голубой, светло-голубой и светло-серый, точнее, (122, 138, 153), (184, 207, 229) и (238, 238, 238).

Для создания собственной темы достаточно расширить класс MetalTheme, определив методы, устанавливающие и возвращающие цвета: getPrimary1(), getPrimary2 ( ), getPrimary3(), getSecondary1(), getSecondary2(), getSecondary3(), и методы, задающие и возвращающие шрифты: getControlTextFont(), getMenuTextFont(), getSubTextFont (), getSystemTextFont ( ), getUserTextFont (), getWindowTitleFont (). Если нужно изменить только отдельный цвет или шрифт, то достаточно расширить класс DefaultMetalTheme или класс

OceanTheme.

Методы, создающие цвета, должны возвращать объект класса ColorUIResource. Для создания такого объекта есть четыре конструктора:

ColorUIResource(Color);

ColorUIResource(int red, int green, int blue);

ColorUIResource(float red, float green, float blue);

ColorUIResource(int rgb);

Поэтому метод, возвращающий первый основной цвет, может выглядеть так:

public ColorUIResource getPrimary1(){

return new ColorUIResource(36, 124, 225);

}

Методы, формирующие вид шрифтов, должны возвращать объект класса FontUIResource, для создания которого есть два конструктора:

FontUIResource(Font);

FontUIResource(String name, int style, int size);

Метод, создающий системный шрифт, может выглядеть так:

public FontUIResource getSystemTextFont(){

return FontUIResource("Times New Roman", Font.PLAIN, 10);

}

Хотя тема определяет главным образом шрифты, их цвета и цвета фона, но она может изменить любые свойства Java L&F. Для этого в классе MetalTheme есть метод

addCustomEntriesToTable (UIDefaults ), позволяющий занести в модель данных UIDefaults не только новые цвета и шрифты, но и какие-нибудь другие свойства. Достаточно переопределить этот метод в расширении класса MetalTheme, чтобы задать изменение свойств. В листинге 17.4 приведен пример метода, устанавливающего новые рамки текстовых полей.

После того как написан класс темы, расширяющий класс MetalTheme, класс DefaultMetalTheme или класс OceanTheme, надо установить новую тему статическим методом setCurrentTheme (MetalTheme) класса MetalLookAndFeel, как показано в листинге 17.4. В нем заданы только серые цвета, что удобно для печати иллюстраций в книге. Результат показан на рис. 17.4.

Листинг 17.4. Окна, оформленные в "серой" теме

import java.awt.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.plaf.*; import javax.swing.plaf.metal.*;

public class ContTheme extends JFrame{

ContTheme(){

super(" Окно с серой темой");

JDesktopPane dp = new JDesktopPane(); setLayout(new FlowLayout()); setContentPane(dp);

JInternalFrame ifr1 = new JInternalFrame(

" РћРєРЅРѕ GrayMetalTheme", true, true, true, true); ifr1.getContentPane().setLayout(new FlowLayout()); i fr1.getContentPane().add(

new JLabelC^html^TO РѕРєРЅРѕ Java L&F

Cepan тема" )); ifr1.setBounds(0,0, 200,200); ifr1.setVisible(true); dp.add(ifr1); setSize(400, 400);

setDefaultCloseOperation(EXIT ON CLOSE); setVisible(true);

public static void main(String[] args){

JFrame.setDefaultLookAndFeelDecorated(true);

JDialog.setDefaultLookAndFeelDecorated(true); MetalLookAndFeel.setCurrentTheme(new GrayMetalTheme()); new ContTheme();

}

}

class GrayMetalTheme extends DefaultMetalTheme{

public ColorUIResource getPrimary1(){ return getSecondary1();

}

public ColorUIResource getPrimary2(){ return getSecondary2();

}

public ColorUIResource getPrimary3(){ return getSecondary3();

}

public void addCustomEntriesToTable(UIDefaults table){ super.addCustomEntriesToTable(table);

BorderUIResource b = new BorderUIResource( new CompoundBorder(

new LineBorder(Color.gray), new LineBorder(Color.white))); table.put("TextField.border", b); table.put("PasswordField.border", b); table.put("TextArea.border", b); table.put("TextPane.font", b);

}

}

Рис. 17.4. Окна, оформленные в "серой" теме

В стандартной поставке Java SE, в каталоге $JAVA_HOME/demo/jfc/MetalWorks/, лежат файлы приложения MetalWorks с примерами тем Java L&F. Запустить это приложение можно из командной строки, перейдя в этот каталог и набрав

java -jar MetalWorks.jar

Там же есть исходные тексты приложения, из которых видно, как создаются и используются темы Java L&F.

Вопросы для самопроверки

1. Что такое вид и поведение (Look and Feel) приложения?

2. Что такое тема (theme) оформления и чем она отличается от вида и поведения приложения?

3. Какие L&F входят в стандартную поставку графической библиотеки Swing?

4. Можно ли стандартными средствами Swing создать собственный L&F?

5. Какие темы предлагает Java L&F?

6. Можно ли создать свои темы в Java L&F?

ГЛАВА 18