<?xml version="1.0" encoding="UTF-8" standalone="yes"?><oembed><version><![CDATA[1.0]]></version><provider_name><![CDATA[Software is Crap]]></provider_name><provider_url><![CDATA[https://davmac.wordpress.com]]></provider_url><author_name><![CDATA[davmac]]></author_name><author_url><![CDATA[https://davmac.wordpress.com/author/davmac/]]></author_url><title><![CDATA[Java&#8217;s Nimbus look-and-feel and custom&nbsp;keymaps]]></title><type><![CDATA[link]]></type><html><![CDATA[<p>I recently discovered that the Nimbus look-and-feel in Java ignores background colour that&#8217;s been set using <em>setBackground()</em> on a JEditorPane. Apparently this is not a bug; look-and-feels are allowed to ignore the colour that you specify with <em>setBackground()</em> (though this raises the question of why the method even exists). With Nimbus, it turns out, you can control background painting by setting a &#8220;client property&#8221; on the editor pane (using <em>putClientProperty()</em>) &#8211; specifically, you set the &#8220;Nimbus.Overrides&#8221; property to a UIDefaults object, which is essentially a property-value map. The &#8220;EditorPane[Enabled].backgroundPainter&#8221; property is supposed to be set to a BackgroundPainter which Nimbus will then use, though if you set it some other object type (such as a String or even a Color) it will ignore the property and instead paint the background using the colour that was set with <em>setBackground()</em> &#8211; which of course raises the question of why it couldn&#8217;t do this in the first place, but, meh, whatever; at least we have a solution. (Any properties which Nimbus needs that aren&#8217;t in your provided UIDefaults will be inherited from Nimbus&#8217; default property set).</p>
<p>There is (of course) Only One Problem.</p>
<p>Setting the &#8220;Nimbus.Overrides&#8221; client property apparently prevents any custom keymaps that you might have assigned to the JEditorPane from working. This is true <em>even when the UIDefaults table you provide is empty</em>, implying that the mere act of assigning something to the Nimbus.Overrides property is changing behaviour of the look-and-feel, which is surely broken.</p>
<p>I&#8217;ve submitted a bug to Oracle (via <a href="http://bugs.java.com">bugs.java.com</a>) though the hit rate on getting a response for them hasn&#8217;t been 100%, so we&#8217;ll see what happens. Once you submit you get the following text:</p>
<blockquote><p><b>What&#8217;s Next?</b></p>
<p>We will review your report. Depending upon the completeness of the report and our ability to reproduce the problem, either a new bug will be posted, or we will contact you for further information. You will be <strong>notified by email in either case</strong>.</p></blockquote>
<p>&#8230; (emphasis mine) &#8211; however I&#8217;ve submitted reports in the past which got no response. I will update this blog entry if/when I receive an acknowledgement. (A few minutes later &#8211; first update! I&#8217;ve received an automated email stating that &#8220;We are evaluating this report and have stored this with an Review ID: JI-9012303&#8221;).</p>
<p style="padding-left:30px;"><strong>Update 24/05/2104: </strong>I still haven&#8217;t heard anything, but today I discovered <a href="https://bugs.openjdk.java.net/browse/JDK-8043315">this.</a> So, it looks like this was recognised as a bug, but I, the initial reporter, was never notified at all &#8211; this seems like poor form. At least my report wasn&#8217;t wasted.</p>
<p>Test case below.</p>
<p><!--more--></p>
<pre>import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.text.Keymap;


public class TestFrame extends JFrame
{
    public static void main(String [] args) {
        try {
        EventQueue.invokeAndWait(new Runnable() {
           @Override
            public void run()
            {
               try {
                   UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
               }
               catch(Exception e) {
                   e.printStackTrace();
                   System.exit(1);
               }
               
               TestFrame tf = new TestFrame();                              
               tf.pack();
               tf.setVisible(true);
            } 
        });
        }
        catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
    
    public TestFrame()
    {
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        
        /* 
         * Create a frame containing a JEditorPane, and override the action for the space bar to show
         * a dialog.
         */
        
        JEditorPane pp = new JEditorPane();

        UIDefaults defaults = new UIDefaults();

        /** COMMENT THIS LINE TO SEE CORRECT BEHAVIOUR */
        pp.putClientProperty("Nimbus.Overrides", defaults);
        
        JPanel contentPanel = new JPanel();
        contentPanel.setLayout(new BorderLayout());
        setContentPane(contentPanel);
        
        contentPanel.setPreferredSize(new Dimension(400, 300));
        contentPanel.add(pp, BorderLayout.CENTER);
        
        Keymap origKeymap = pp.getKeymap();
        Keymap km = JEditorPane.addKeymap("Test keymap", origKeymap);
        
        km.addActionForKeyStroke(KeyStroke.getKeyStroke(' '), new AbstractAction("SHOW_SPACE") {
           @Override
            public void actionPerformed(ActionEvent e)
            {
               JOptionPane.showMessageDialog(TestFrame.this, "Space!");
            } 
        });
        
        pp.setKeymap(km);
    }
}

</pre>
]]></html></oembed>