Skip to main content

Style Binding in Synth Look And Feel

Posted by xuanyun on February 4, 2009 at 8:43 PM PST

The style binding mechanism is another great feature of Synth
look and feel
. By using style binding, you can define several button styles
within the same look and feel (one as default button style and the others are
candidates), the final user can decide which style can be applied on which button.

How could Synth achieve this? The answer is hidden in the bind
node in XML. Let's make an example, the Synth look and feel can be customized
by an XML file like this:

<synth>
   <style id="Button">
   ......
   </style>
   <bind style="Button" type="region" key="Button" />
   <style id="Button_Search">
  ......
   </style>
   <bind style="Button_Search" type="name" key="Button.Search" />
</synth>

It is really simple and only two styles are defined, each style node will be
followed by a bind node, which specify how to apply the style. After reading
the Synth
XML format
, we understand that the type attribute in bind
node can be either "region" or "name",
these two region types are both used in the example above, but what do they
mean?

Understanding Region:

<bind style="Button" type="region" key="Button" />

This bind node is defining this rule: the style with id "Button"
will be bound to the region named "Button". But what is region? It
is really confusing at the first time, but finally I understand it is a distinct
rendering area of a Swing component, we can find the javax.swing.plaf.synth.Region
class from JRE5+ to represent the same thing, this class defines a set of constant
instances for external usage, like these:

 public static final Region ARROW_BUTTON = new Region("ArrowButton","ArrowButtonUI");
public static final Region BUTTON = new Region("Button", "ButtonUI");
public static final Region CHECK_BOX = new Region("CheckBox", "CheckBoxUI");
......

The constructor of Region class accepts two parameters, the first one is the
name of region, and the second one is the corresponding UI identification. The
name of region can be used by the bind node in Synth XML. Now
we know the first bind node exactly bind the style to the BUTTON region. BTW,
how could we know the region name (like "Button") when we are writing
the Synth XML? Oh, I am afraid we have to read the source code of javax.swing.plaf.synth.Region
class.

Each simple swing component has one region only. For example, BUTTON region
is for JButton component, so bind a style to the BUTTON region can customize
the painting of JButton. For some complex component, it is consist of several
simple components, so they will have several regions. For example, a JComboBox
component is consist of SynthArrowButton, JList, JPopupMenu, JScrollPane and
JTextField etc., so it will have several regions for customizing: ARROW_BUTTON,
LIST, POPUP_MENU, SCROLL_PANE and TEXT_FIELD etc.

If a style is bound to a region, it will become the default
style of this region. Example: if we bind a style to the BUTTON region, all
JButton objects we created will have the same style (unless we specify not to
use the default style, see below).

The Usage of Component Name:

There is a public method setName() in java.awt.Component
class , so this method is available on any swing components. That means we can
specify the name of each swing component, is it meaningful for using Synth?
Sure! Remember the type value of bind node? It can be "name", which
means the style will be bound to the component with the given name! So now we
can explain the second bind node in the example:

<bind style="Button_Search" type="name" key="Button.Search" />

It defines such a rule: the style with id "Button_Search" will be
bound to the component with the name "Button.Search". So if we have
a JButton created in this way:

final JButton searchButton = new JButton("Search");
searchButton.setName("Button.Search");

This button will have a different style than other buttons, since it has the
special name, so a non-default style will be applied on it.

Once we understand the style binding mechanism provided by
Synth, making several styles for any components will not be a problem.

PS: One name can be assigned to several components, all components with the same name will share the same style.

Related Topics >>

Comments

Hi, I am trying to skin two combos with two different ...

Hi,
I am trying to skin two combos with two different styles. Since combobox is complex and made of many subcomponents, I am not able to skin each of the combo and its subcomponents seperatly. The second subcomponets take the same look and feel as the first combo. Could you please help me on how to skin different combos and its subcomponents differently.
My combo skin tag looks like the following:

hi xuan,i got a problem with&nbsp;synth xml..how can i ...

hi xuan,i got a problem with synth xml..how can i define several ComboBox styles?ComboBox is a complex component,i know how define single style for it,but.. how several styles at the same time?pls help me..thx!!

the first style:

</p>
<p><style id="ComboBox List Renderer"><br />
        <opaque value="true" />             <br />
        <state>    <br />
            <font name="微软雅'" size="14" style="PLAIN"/><br />
            <insets top="0" left="4" bottom="0" right="0"/><br />
            <color type="BACKGROUND" value="#495bc9"/><br />
        </state><br />
    </style><br />
    <bind style="ComboBox List Renderer" type="name" key="ComboBox.listRenderer" /></p>
<p>    <style id="ComboBox Renderer"><br />
        <opaque value="false" />     <br />
        <state><br />
            <font name="微软雅'" size="14" style="PLAIN"/>    <br />
        </state>        <br />
    </style><br />
    <bind style="ComboBox Renderer" type="name" key="ComboBox.renderer" /></p>
<p>    <style id="ComboBox list">     <br />
        <opaque value="true" />    <br />
        <state><br />
            <color type="BACKGROUND" value="#3f3a3a"/><br />
            <font name="微软雅'" size="14" style="PLAIN"/>    <br />
        </state>        <br />
    </style><br />
    <bind style="ComboBox list" type="name" key="ComboBox.list" /></p>
<p>    <style id="combo_box_switch_language">         <br />
        <state>   <br />
            <font name="微软雅'" size="14" style="PLAIN"/><br />
            <imagePainter method="comboBoxBackground" path="uiconfs/images/language_switch_normal.png"<br />
                  sourceInsets="0 5 0 0" paintCenter="true" stretch="false"/><br />
            <insets top="0" left="5" bottom="0" right="0"/><br />
        </state><br />
        <state value="focused">   <br />
            <imagePainter method="comboBoxBackground" path="uiconfs/images/language_switch_normal.png"<br />
                  sourceInsets="0 5 0 0" paintCenter="true" stretch="false"/><br />
        </state><br />
        <property key="ComboBox.buttonWhenNotEditable" type="boolean" value="true"/><br />
        <property key="ComboBox.rendererUseListColors" type="boolean" value="false"/> <br />
    </style><br />
    <bind style="combo_box_switch_language" type="name" key="switch_language"/> </p>
<p>

the second style:

</p>
<p><style id="ComboBox List Renderer"><br />
        <opaque value="true"/><br />
        <state>            <br />
            <insets top="0" left="2" bottom="0" right="0"/><br />
            <color type="BACKGROUND" value="#d67719"/><br />
            <font name="微软雅'" size="12" style="PLAIN"/><br />
        </state><br />
    </style><br />
    <bind style="ComboBox List Renderer" type="name" key="ComboBox.listRenderer" /></p>
<p>    <style id="ComboBox Renderer"><br />
        <opaque value="false" />     <br />
        <state><br />
            <font name="微软雅'" size="12" style="PLAIN"/>    <br />
        </state>        <br />
    </style><br />
    <bind style="ComboBox Renderer" type="name" key="ComboBox.renderer" /><br />
    <style id="ComboBox list"><br />
        <opaque value="true" /><br />
        <state>            <br />
            <font name="微软雅'" size="12" style="PLAIN"/><br />
            <color type="BACKGROUND" value="#3f3a3a"/><br />
            <insets top="0" left="0" bottom="0" right="0"/><br />
        </state>        <br />
    </style><br />
    <bind style="ComboBox list" type="name" key="ComboBox.list" /></p>
<p>    <style id="combo_box">        <br />
        <state>               <br />
            <font name="微软雅'" size="12" style="PLAIN"/><br />
            <imagePainter method="comboBoxBackground" path="uiconfs/images/combo_normal.png"<br />
                  sourceInsets="0 4 0 0" paintCenter="true" stretch="false"/><br />
            <insets top="0" left="4" bottom="0" right="0"/><br />
        </state><br />
        <state value="focused">  <br />
            <imagePainter method="comboBoxBackground" path="uiconfs/images/combo_selected.png"<br />
                  sourceInsets="0 4 0 0" paintCenter="true" stretch="false"/><br />
            <insets top="0" left="4" bottom="0" right="0"/><br />
        </state><br />
        <property key="ComboBox.rendererUseListColors" type="boolean" value="false"/>   <br />
        <property key="ComboBox.buttonWhenNotEditable" type="boolean" value="true"/><br />
    </style><br />
    <bind style="combo_box" type="region" key="ComboBox"/> </p>
<p>

Internal Frame Title Pane

I have customized this pane with my own, inactive icon and title in Java. When I turn on synth, it ignores both the icon and title and puts in the system icon. I have not been able to convince synth to emulate Java here. Here's a piece of the Java:
JInternalFrame exp = new JInternalFrame();
exp.setOpaque( false );
exp.setBorder( null );
((JComponent)exp.getContentPane()).setOpaque( false );
// icon varies depending on type
ImageIcon ic = new ImageIcon(NewGui.class.getResource( EXP_ICON ));
exp.setFrameIcon( ic );
// set title to module title
exp.setTitle( TITLE );

Even if the synth.xml file has no region bindings in it, it still ignores the icon and title from Java. Any ideas?

You can write your own painter class (extended from SynthPainter) and override the paintTableHeaderBackground() method, this method will paint the background of each table header, so you can also paint the header border in this method. You can take a look at EaSynth L&F, it is open sourced.

hi guys, i have same problem to drjwsimmons. i have tried all options you given but there is still not work. table header cell border still pain. please help me about that. thx

Well, you can use the "tableHeaderBackground" method, it is for individual header. Although it is a "background", you can still paint your border on it ;-)

Thank you for the reply and the information. Actually, I already tried that. What it does is put a border around the entire header area, which is not what I want. I want a border around each individual header. More generally, I want to control the appearance of each individual header.

Hi drjwsimmons, "TableHeader.cellBorder" property is not used by Synth look and feel. You can specify the painter to draw the border of table headers. You can use the imagePainter or your own painter class, set the method to "tableHeaderBorder", like this: [imagePainter method="tableHeaderBorder" path="resource/table_header_border.png" sourceInsets="2 2 2 2" paintCenter="false" stretch="true" center="false"/]

This is a request for help. I am trying to write a look and feel using Synth. It shows table headers plain, with no border. I am trying to figure out how to add a border to the table headers. I tried creating a LineBorder object in the XML file and setting it as the TableHeader.cellBorder default property, but that did not work. Could you point me in the right direction to get help? Thanks.