epubjs
Version:
Render ePub documents in the browser, across many devices
128 lines (119 loc) • 17 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Pluggable Look-and-Feel</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Pluggable Look-and-Feel"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-18-SECT-5"/>Pluggable Look-and-Feel</h1></div></div></div><p><a id="idx11025" class="indexterm"/>We mentioned before that Swing components can easily change
their appearance, like master spies or thespians. Generally, different
kinds of components within an application have coordinated appearances
that are similar in some way. For example, they probably use the same font
and the same basic color scheme. The collection of appearances and common
behavior of GUI components is called a <span class="emphasis"><em>look-and-feel</em></span>
(L&F).</p><p>Part of the job of designing a GUI for an operating system is
designing the L&F. Mac OS, therefore, has its own distinctive L&F,
as does Windows. Java offers several different L&F schemes for Swing
components. If you’re adept at graphic design, you can write your own
L&F schemes and easily convince Swing to use them. This chameleon-like
ability to change appearance is called <span class="emphasis"><em>pluggable
look-and-feel</em></span>, sometimes abbreviated PLAF (don’t pronounce that
out loud if others are eating).</p><p>Seeing is believing. Here’s an example that creates a handful of
Swing components. Menu items allow you to change the L&F dynamically
while the application is running:</p><a id="I_18_tt1097"/><pre class="programlisting"> <code class="c1">//file: QuickChange.java</code>
<code class="kn">import</code> <code class="nn">java.awt.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.awt.event.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.swing.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">QuickChange</code> <code class="kd">extends</code> <code class="n">JFrame</code> <code class="o">{</code>
<code class="kd">public</code> <code class="nf">QuickChange</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">super</code><code class="o">(</code><code class="s">"QuickChange v1.0"</code><code class="o">);</code>
<code class="n">createGUI</code><code class="o">();</code>
<code class="o">}</code>
<code class="kd">protected</code> <code class="kt">void</code> <code class="nf">createGUI</code><code class="o">()</code> <code class="o">{</code>
<code class="n">setSize</code><code class="o">(</code><code class="mi">300</code><code class="o">,</code> <code class="mi">200</code><code class="o">);</code>
<code class="c1">// create a simple File menu</code>
<code class="n">JMenu</code> <code class="n">file</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JMenu</code><code class="o">(</code><code class="s">"File"</code><code class="o">,</code> <code class="kc">true</code><code class="o">);</code>
<code class="n">JMenuItem</code> <code class="n">quit</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JMenuItem</code><code class="o">(</code><code class="s">"Quit"</code><code class="o">);</code>
<code class="n">file</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">quit</code><code class="o">);</code>
<code class="n">quit</code><code class="o">.</code><code class="na">addActionListener</code><code class="o">(</code><code class="k">new</code> <code class="n">ActionListener</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">actionPerformed</code><code class="o">(</code><code class="n">ActionEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code> <code class="n">System</code><code class="o">.</code><code class="na">exit</code><code class="o">(</code><code class="mi">0</code><code class="o">);</code> <code class="o">}</code>
<code class="o">});</code>
<code class="c1">// create the Look & Feel menu</code>
<code class="n">JMenu</code> <code class="n">lnf</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JMenu</code><code class="o">(</code><code class="s">"Look & Feel"</code><code class="o">,</code> <code class="kc">true</code><code class="o">);</code>
<code class="n">ButtonGroup</code> <code class="n">buttonGroup</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ButtonGroup</code><code class="o">();</code>
<code class="kd">final</code> <code class="n">UIManager</code><code class="o">.</code><code class="na">LookAndFeelInfo</code><code class="o">[]</code> <code class="n">info</code> <code class="o">=</code>
<code class="n">UIManager</code><code class="o">.</code><code class="na">getInstalledLookAndFeels</code><code class="o">();</code>
<code class="k">for</code> <code class="o">(</code><code class="kt">int</code> <code class="n">i</code> <code class="o">=</code> <code class="mi">0</code><code class="o">;</code> <code class="n">i</code> <code class="o"><</code> <code class="n">info</code><code class="o">.</code><code class="na">length</code><code class="o">;</code> <code class="n">i</code><code class="o">++)</code> <code class="o">{</code>
<code class="n">JRadioButtonMenuItem</code> <code class="n">item</code> <code class="o">=</code> <code class="k">new</code>
<code class="n">JRadioButtonMenuItem</code><code class="o">(</code><code class="n">info</code><code class="o">[</code><code class="n">i</code><code class="o">].</code><code class="na">getName</code><code class="o">(),</code> <code class="n">i</code> <code class="o">==</code> <code class="mi">0</code><code class="o">);</code>
<code class="kd">final</code> <code class="n">String</code> <code class="n">className</code> <code class="o">=</code> <code class="n">info</code><code class="o">[</code><code class="n">i</code><code class="o">].</code><code class="na">getClassName</code><code class="o">();</code>
<code class="n">item</code><code class="o">.</code><code class="na">addActionListener</code><code class="o">(</code><code class="k">new</code> <code class="n">ActionListener</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">actionPerformed</code><code class="o">(</code><code class="n">ActionEvent</code> <code class="n">ae</code><code class="o">)</code> <code class="o">{</code>
<code class="k">try</code> <code class="o">{</code> <code class="n">UIManager</code><code class="o">.</code><code class="na">setLookAndFeel</code><code class="o">(</code><code class="n">className</code><code class="o">);</code> <code class="o">}</code>
<code class="k">catch</code> <code class="o">(</code><code class="n">Exception</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">e</code><code class="o">);</code> <code class="o">}</code>
<code class="n">SwingUtilities</code><code class="o">.</code><code class="na">updateComponentTreeUI</code><code class="o">(</code><code class="n">QuickChange</code><code class="o">.</code><code class="na">this</code><code class="o">);</code>
<code class="o">}</code>
<code class="o">});</code>
<code class="n">buttonGroup</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">item</code><code class="o">);</code>
<code class="n">lnf</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">item</code><code class="o">);</code>
<code class="o">}</code>
<code class="c1">// add the menu bar</code>
<code class="n">JMenuBar</code> <code class="n">mb</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JMenuBar</code><code class="o">();</code>
<code class="n">mb</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">file</code><code class="o">);</code>
<code class="n">mb</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">lnf</code><code class="o">);</code>
<code class="n">setJMenuBar</code><code class="o">(</code><code class="n">mb</code><code class="o">);</code>
<code class="c1">// add some components</code>
<code class="n">JPanel</code> <code class="n">jp</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JPanel</code><code class="o">();</code>
<code class="n">jp</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JCheckBox</code><code class="o">(</code><code class="s">"JCheckBox"</code><code class="o">));</code>
<code class="n">String</code><code class="o">[]</code> <code class="n">names</code> <code class="o">=</code>
<code class="k">new</code> <code class="n">String</code><code class="o">[]</code> <code class="o">{</code> <code class="s">"Tosca"</code><code class="o">,</code> <code class="s">"Cavaradossi"</code><code class="o">,</code> <code class="s">"Scarpia"</code><code class="o">,</code>
<code class="s">"Angelotti"</code><code class="o">,</code> <code class="s">"Spoletta"</code><code class="o">,</code> <code class="s">"Sciarrone"</code><code class="o">,</code>
<code class="s">"Carceriere"</code><code class="o">,</code> <code class="s">"Il sagrestano"</code><code class="o">,</code> <code class="s">"Un pastore"</code> <code class="o">};</code>
<code class="n">jp</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JComboBox</code><code class="o">(</code><code class="n">names</code><code class="o">));</code>
<code class="n">jp</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JButton</code><code class="o">(</code><code class="s">"JButton"</code><code class="o">));</code>
<code class="n">jp</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JLabel</code><code class="o">(</code><code class="s">"JLabel"</code><code class="o">));</code>
<code class="n">jp</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JTextField</code><code class="o">(</code><code class="s">"JTextField"</code><code class="o">));</code>
<code class="n">JPanel</code> <code class="n">main</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JPanel</code><code class="o">(</code><code class="k">new</code> <code class="n">GridLayout</code><code class="o">(</code><code class="mi">1</code><code class="o">,</code> <code class="mi">2</code><code class="o">));</code>
<code class="n">main</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="n">jp</code><code class="o">);</code>
<code class="n">main</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JScrollPane</code><code class="o">(</code><code class="k">new</code> <code class="n">JList</code><code class="o">(</code><code class="n">names</code><code class="o">)));</code>
<code class="n">setContentPane</code><code class="o">(</code><code class="n">main</code><code class="o">);</code>
<code class="n">setDefaultCloseOperation</code><code class="o">(</code> <code class="n">JFrame</code><code class="o">.</code><code class="na">EXIT_ON_CLOSE</code> <code class="o">);</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code><code class="o">[]</code> <code class="n">args</code><code class="o">)</code> <code class="o">{</code>
<code class="k">new</code> <code class="nf">QuickChange</code><code class="o">().</code><code class="na">setVisible</code><code class="o">(</code><code class="kc">true</code><code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>The interesting part of this application is creating a menu of the
available L&Fs. First, we ask a class called <a id="I_indexterm18_id803920" class="indexterm"/><code class="literal">UIManager</code> to tell us all
about the available L&Fs on our computer:</p><a id="I_18_tt1098"/><pre class="programlisting"> <code class="kd">final</code> <code class="n">UIManager</code><code class="o">.</code><code class="na">LookAndFeelInfo</code><code class="o">[]</code> <code class="n">info</code> <code class="o">=</code>
<code class="n">UIManager</code><code class="o">.</code><code class="na">getInstalledLookAndFeels</code><code class="o">();</code></pre><p>Information about L&Fs is returned as instances of <code class="literal">UIManager.LookAndFeelInfo</code>. Despite the long
name, there’s not much to this class; it just associates a name, such as
Metal, and the name of the class that
implements the L&F, such as <code class="literal">javax</code><a id="I_indexterm18_id803961" class="indexterm"/><code class="literal">.swing.plaf.metal.MetalLookAndFeel</code>. In the
<code class="literal">QuickChange</code> example, we create
a menu item from each L&F name. If the menu item is selected, we tell
the <code class="literal">UIManager</code> to use the selected
L&F class. To make sure all the components are redrawn with the new
L&F, we call <a id="I_indexterm18_id803990" class="indexterm"/><code class="literal">updateComponentTreeUI()</code>,
a static method in the <a id="I_indexterm18_id804002" class="indexterm"/><code class="literal">SwingUtilities</code>
class.</p><p>The JDK includes several L&Fs: Windows, OS X, Motif, the
original Metal L&F, the highly customizable Synth, and the newest
edition, Nimbus. Windows, OS X, and Motif are recreations of their
corresponding native desktop environments. If you’re running Swing on Mac
OS X, the default L&F is an implementation of Aqua, the UI design for
all new Mac applications. Unfortunately, you cannot use this L&F on
any other platforms because of licensing issues (the Windows L&F has
similar restrictions).</p><p>The Metal L&F and its Ocean theme are the default on some
platforms, but at this point they appear dated compared to modern
windowing systems. The newest edition, Nimbus, is a far superior
alternative. Its aethetics are on par with modern windowing systems and
its use of scaleable vector graphics allows it to shine on high-density
displays at various sizes. Nimbus is actually a highly evolved subclass of
the Synth L&F.</p><p>Synth accommodates the new trend in skinnable user interfaces. Many
applications now allow users to customize the L&F very easily, using
only images and simple preferences files to create new appearances.
Skinnability is not the same as a full-blown pluggable L&F, but it
lets you do a lot without any programming required. Synth acts like an
ordinary L&F, but can be customized through the use of images and XML
description files to create new looks. For example, the borders of
components (such as the shiny metal look of the Metal L&F) can be
described by providing an example image and then specifying the offsets of
the interior “corners” as well as the method to use (stretch or tile) to
cover larger areas. Synth then uses the image to paint the borders of
whatever components you specify. Synth can do quite a lot and even allows
you to specify Java objects to be involved in painting, so you can resort
to programming again if your L&F gets too complex.<a id="I_indexterm18_id804051" class="indexterm"/></p></div></body></html>