Friday, February 3, 2012

Roll your own Synth look & feel - part 2: Transparency

In this part, I'll dedicate some attention to JList element in the GUI. I want to set an image as a list background, and see how it looks. For this, I'm going to use Synth imagePainter element. Here's a code snippet from Synth style sheet:

<style id="listStyle">
        <state>
            <imagePainter method="listBackground" path="/img/duke.jpg"
                sourceInsets="0 0 0 0"/>
        </state>
    </style>
    <bind style="listStyle" type="region" key="List" />

Here, I set an Duke image to be the background of the list. This works, but I'm not quite satisfied with the result, because list contents do not shw well, since they are mixed with image. Window shapshot is shown bellow:






So, I'm gonna try to add some transparency to this image. Since that can't be done in Synth style sheet (or at least, I don't know how), I'm gonna do it in Synth painter class, overriding painListBackground method. Bellow is a code snippet that renders list background:

@Override
    public void paintListBackground(SynthContext context, Graphics g, int x, int y, int w, int h) {

        try {
            // load image
            BufferedImage bim = ImageIO.read(getClass().getResourceAsStream("/img/duke.jpg"));
            // create image to use for painting
            BufferedImage used = new BufferedImage(bim.getWidth(), bim.getHeight(), BufferedImage.TRANSLUCENT);
            // create graphics for panting from used image
            Graphics2D g2 = used.createGraphics();
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f));
            g2.drawImage(bim, null, 0, 0);
            g2.dispose();
            // now, draw transparent image
            g2 = (Graphics2D) g;
            g2.drawImage(used.getScaledInstance(w, h, Image.SCALE_FAST), 0, 0, null);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

In this code snippet, we load an image, and then create new translucent image to paint on. We then apply composite operation and fill the list background with composite image. The result is shown in a screenshot bellow:


This looks a lot better, but there's a problem: if you try to select an item from the list, nothing happens, ie. the item is not highlighted. So, we need to add selection color properties to the list. We'll do that by adding color property to the style for TEXT_BACKGROUND type:

<style id="listStyle">:
        <state >:
            <painter method="listBackground" idref="myPainter" />:
            <color value="GREEN" type="TEXT_BACKGROUND" />:
        </state>:
    </style>:

This will set green background for selected list items. The result is shown in the following image:


As it turns out, this is a bit ugly. The selction background obscures list background. Wouldn't it be prettier if selection was also transparent? To do so, we'll spacify custom UI resource with transparency applied. Here's the code, and related Synth stylesheet bellow it:

public class MyListBackgroundColor extends ColorUIResource {
    
    /**
     * 
     * @param r red
     * @param g green
     * @param b blue
     * @param alpha  transparency
     */
   public MyListBackgroundColor(int r, int g, int b, int alpha){
       super(new Color(r, g, b, alpha));
   }
   
}
<object class="com.test.MyListBackgroundColor" id="listSelectionBgColor">
<int>50</int>
<int>250</int>
<int>50</int>
<int>100</int>
</object>

<style id="listStyle">
<state >
<painter method="listBackground" idref="myPainter" />
<color idref="listSelectionBgColor" type="TEXT_BACKGROUND" />
</state>
</style>

Finally, here's the final list with transparent selection background.


Here you can find some useful resources and source code of this example.

Related posts:

No comments:

Post a Comment