root pane defaultbutton not painted correclty with custom synth lnf

248 views Asked by At

i'm currently working on a custom synth lnf but can't get the root pane's defaultButton to show up correctly.

All buttons are painted correctly with following definition:

<style id="Button">
    <property key="Button.defaultButtonFollowsFocus" type="boolean" value="true"/>
    <property key="Button.textShiftOffset" type="integer" value="1"/>
    <property key="Button.margin" type="insets" value="0 10 0 10"/>
    <insets top="4" left="4" bottom="4" right="4"/>

    <state>
        <imagePainter method="buttonBackground" path="images/Button.Normal.png" sourceInsets="4 4 4 4" paintCenter="true" stretch="true"/>
    </state>

    <state value="MOUSE_OVER">
        <imagePainter method="buttonBackground" path="images/Button.Normal.MouseOver.png" sourceInsets="4 4 4 4" paintCenter="true" stretch="true"/>
    </state>

    <state value="FOCUSED">
...
    </state>
...
</style>
<bind style="Button" type="region" key="Button"/>

But if i set one button as the root pane's defaultButton it's not painted correctly.

As an example i've taken following screenshot. The left one as a normal button and the right one as the defaultButton. If i set the left one as the defaultButton the right one is painted correctly and the same problem occurs (The same problem exists for all defaultButtons for example if i show up a JFileChooseDialog).

left: normal button - right: default button

If i manually set the size of the default button it is displayed correctly so i assume there is a problem calculating the size of the button.

Maybe someone had a similar problem or could give me a hint why the defaultButton is not threaded as normal buttons.

Thanks in advance.

Edit: Added simple runnable example code. There is no special layout nor something else special. The default button is just not painted.


DefaultButtonTest.java

public class DefaultButtonTest
{
    public static void main(String[] args) throws InterruptedException, NamingException
    {
        MyLookAndFeel.install();
        JFrame testFrame = new JFrame("test");
        JButton button1 = new JButton("button1");
        JButton button2 = new JButton("button2");
        JPanel testPanel = new JPanel(); // Applying for example FlowLayout makes no difference
        testPanel.add(button1);
        testPanel.add(button2);
        testFrame.setContentPane(testPanel);
        testFrame.getRootPane().setDefaultButton(button1);
        testFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        testFrame.revalidate();
        testFrame.pack();
        testFrame.setVisible(true);
    }
}    


MyLookAndFeel.java

public final class MyLookAndFeel extends SynthLookAndFeel
{
    public final void initialize()
    {
        super.initialize();
        JFrame.setDefaultLookAndFeelDecorated(true);
        JDialog.setDefaultLookAndFeelDecorated(true);
    }

    public final void uninitialize()
    {
        super.uninitialize();
    }

    public static boolean install()
    {
        try
        {
            final long start = System.currentTimeMillis();
            MyLookAndFeel laf = new MyLookAndFeel();
            laf.load(MyLookAndFeel.class.getResourceAsStream("laf.xml"), MyLookAndFeel.class);
            UIManager.setLookAndFeel(laf);
            return true;
        }
        catch (final Exception exception)
        {
            exception.printStackTrace();
            return false;
        }
    }

    public final boolean getSupportsWindowDecorations()
    {
        return true;
    }

    public final UIDefaults getDefaults()
    {
        UIDefaults defaults = super.getDefaults();
        defaults.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, SwingUtilities2.AATextInfo.getAATextInfo(true));
        defaults.addResourceBundle("com.sun.swing.internal.plaf.metal.resources.metal");
        return defaults;
    }
}


laf.xml

<synth>
    <!-- ****************************************************************************************************************************************
    CONTROLS
    ***************************************************************************************************************************************** -->
    <style id="Button">
    <property key="Button.defaultButtonFollowsFocus" type="boolean" value="true"/>
    <property key="Button.textShiftOffset" type="integer" value="1"/>
    <property key="Button.margin" type="insets" value="0 10 0 10"/>
    <insets top="4" left="4" bottom="4" right="4"/>

    <state>
        <imagePainter method="buttonBackground" path="images/Button.Normal.png" sourceInsets="4 4 4 4" paintCenter="true" stretch="true"/>
    </state>

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

There are 2 answers

2
user1845266 On BEST ANSWER

I finally found the solution to this problem, and it's plain simple.

While states like 'MOUSE OVER' 'FOCUSED' ... inherit its font and color attributes from its parent they do not need to be given fonts and color attributes. If a button or radio button has defined states like 'DEFAULT' or 'SELECTED' they do not inherit them from their parent and font and color need to be defined explicitly (at least for size calculation, as stated above if i set the size manually the font and color is shown correctly).

For example

This does not work for the 'DEFAULT' state

<style id="Button">
    <property key="Button.textShiftOffset" type="integer" value="1"/>

    <state>
        <imagePainter method="buttonBackground" path="images/Button.Normal.png" sourceInsets="4 4 4 4" paintCenter="true" stretch="true"/>
    </state>

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


This works for 'DEFAULT' state

<style id="Button">
    <property key="Button.textShiftOffset" type="integer" value="1"/>

    <font name="Dialog" size="16"/>
    <color type="TEXT_FOREGROUND" value="#000000"/>

    <state>
        <imagePainter method="buttonBackground" path="images/Button.Normal.png" sourceInsets="4 4 4 4" paintCenter="true" stretch="true"/>
    </state>

</style>
<bind style="Button" type="region" key="Button"/>
1
trashgod On

Empirically, the button's preferred size is wrong. A simple expedient is to use the other button's size, as suggested here.

enter image description here

final JButton button2 = new JButton("button2");
JButton button1 = new JButton("button1"){

    @Override
    public Dimension getPreferredSize() {
        return button2.getPreferredSize();
    }
};
button1.setBorder(BorderFactory.createLineBorder(Color.red));