Discussion:
Transparent JDesktopPane
(too old to reply)
Luke Webber
2006-06-28 14:39:52 UTC
Permalink
I was so very happy today, because I had my UI looking just really blody
flash. Then I tried moving a JInternalFrame, and the whole house of
cards tumbled down.

My whole L&F depends on having a JPanel in the background of an MDI
form. That background panel has a tiled image of a cute little
watermark. Buttons on the left, JDesktop taking up the rest of the
space, with JInternal frames popping up as required.

As I said in my opening paragraph, the problem is that moving the
JInternalFrames about leaves a mess behind on the JDesktopPane.

I've put together a simple class that shows my problem exactly. It'll
wrap, but it's also available for download at...

http://www.webber.com.au/pub/TransparentMDI.java

I'd greatly appreciate any thought on this. The sample code is below.

TIA,
Luke

------------------------------------------------------------
package test;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/*
* A sample of problems encountered with transparent JDesktopPanes
*
* If pnlLeft isn't added, the red background from pnlMain doesn't
* even show though, but that's not the biggest problem.
* Moving the JInternalFrame around (WinXP, JDK1.5.0_07), makes one
* hell of a mess. OTOH, resizing the internal frame works just fine,
* even removing the artifacts left by previous moves.
*/
public class TransparentMDI extends JFrame implements WindowListener
{
JDesktopPane desktop = new JDesktopPane();

public static void main(String[] args)
{
new TransparentMDI().setVisible(true);
}

public TransparentMDI()
{
super("Transparent Desktop Test");
Container cp = getContentPane();
JPanel pnlMain = new JPanel(new BorderLayout());
pnlMain.setBackground(Color.RED);
JPanel pnlLeft = new JPanel(new BorderLayout());
pnlLeft.setOpaque(false);
pnlLeft.add(new JLabel("JDK "+System.getProperty("java.version")),
BorderLayout.NORTH);
pnlMain.add(pnlLeft, BorderLayout.WEST);
// Make the desktop semi-transparent
Color db = new Color(0,0,0, 32);
desktop.setBackground(db);
desktop.setOpaque(false);
pnlMain.add(desktop, BorderLayout.CENTER);
JInternalFrame jif = new JInternalFrame("Internal Frame", true, true);
jif.setBounds(0, 0, 300, 300);
Container jifcp = jif.getContentPane();
jifcp.setLayout(new BorderLayout());
jifcp.add(new JLabel("Move me", JLabel.CENTER), BorderLayout.CENTER);
jif.setVisible(true);
desktop.add(jif);
cp.setLayout(new BorderLayout());
cp.add(pnlMain, BorderLayout.CENTER);
addWindowListener(this);
pack();
setExtendedState(MAXIMIZED_BOTH);
}

public void windowClosing(WindowEvent we)
{
System.exit(0);
}

public void windowActivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
}
----------------------------------------------------------
Oliver Wong
2006-06-29 15:35:07 UTC
Permalink
Post by Luke Webber
I was so very happy today, because I had my UI looking just really blody
flash. Then I tried moving a JInternalFrame, and the whole house of cards
tumbled down.
My whole L&F depends on having a JPanel in the background of an MDI form.
That background panel has a tiled image of a cute little watermark.
Buttons on the left, JDesktop taking up the rest of the space, with
JInternal frames popping up as required.
As I said in my opening paragraph, the problem is that moving the
JInternalFrames about leaves a mess behind on the JDesktopPane.
I've put together a simple class that shows my problem exactly. It'll
wrap, but it's also available for download at...
http://www.webber.com.au/pub/TransparentMDI.java
I'd greatly appreciate any thought on this. The sample code is below.
[program snipped]

It looks like a bug in the paint() method of javax.swing.JLayeredPane.
Basically, the code as written seems to assume that the background colour is
not translucent at all, and so when it needs to "repaint" an area, it simply
gets its own background colour, and paints it over the area that needs to be
updated.

What's happening in your program is that when you move your JInternalFrame,
there's now an old ghost-image of the JInternalFrame that needs to be
painted over. If you had used a fully opaque colour like (0,0,0,255) [which
is black), then the paint method would paint black pixels over the ghost
image, and you'd get a completely black background.

Unfortunately, you're using the colour (0,0,0,32) which is a translucent
black, so the ghost image is still visible undernearth the tranluscent black
paint.

You might want to file a bug report with Sun, including your demonstration
program, but I'm not sure if Sun will fix it, or just say that's the way it
was designed to work.

In the meantime, you might fix it by having it so that whenever the
JDesktopPane needs to repaint itself, it triggers a call to the JPanel
pnlMain underneath it to paint first. So what will happen is that the
pnlMain will overwrite the ghost image with red paint, and then the
JDesktopPane will apply its translucent black paint over the newly applied
red paint.

- Oliver
Luke Webber
2006-06-30 03:32:29 UTC
Permalink
Post by Oliver Wong
[program snipped]
It looks like a bug in the paint() method of javax.swing.JLayeredPane.
Basically, the code as written seems to assume that the background
colour is not translucent at all, and so when it needs to "repaint" an
area, it simply gets its own background colour, and paints it over the
area that needs to be updated.
What's happening in your program is that when you move your
JInternalFrame, there's now an old ghost-image of the JInternalFrame
that needs to be painted over. If you had used a fully opaque colour
like (0,0,0,255) [which is black), then the paint method would paint
black pixels over the ghost image, and you'd get a completely black
background.
Unfortunately, you're using the colour (0,0,0,32) which is a translucent
black, so the ghost image is still visible undernearth the tranluscent
black paint.
You might want to file a bug report with Sun, including your
demonstration program, but I'm not sure if Sun will fix it, or just say
that's the way it was designed to work.
In the meantime, you might fix it by having it so that whenever the
JDesktopPane needs to repaint itself, it triggers a call to the JPanel
pnlMain underneath it to paint first. So what will happen is that the
pnlMain will overwrite the ghost image with red paint, and then the
JDesktopPane will apply its translucent black paint over the newly
applied red paint.
Thanks for that, Oliver. Looking more closely at the source code for
JDesktopPane, I see that isOpaque is set to always return true. It looks
as if they've decided to specifically bar the programmer from making
these babies transparent, but forgot about the alpha channel
possibilities. For now, I'm getting around it by ditching the whole
JDesktopPane and just using JPanel derivatives. It works, but I would
have liked to have it the other way.

Thanks again,
Luke

Loading...