Before you read, here are some clarifications on what the question is about:
- The SSCCE is designed for Java 7. It would be possible to use sun.*.AWTUtilities to adapt it to Java 6, but it does not matter to me how it works on Java 6.
- The faulting line is [...]
new JDialog(someWindow)
. Ghosting can be fixed in the SSCCE by simply changing that line to[...]new JDialog()
.
Why don't top level windows exhibit ghosting?
Expected behavior: final JDialog d = new JDialog()
(see SSCCE)
As you can see, the right window has a semitransparent background (as expected).
Actual behavior: final JDialog d = new JDialog(f)
(see SSCCE)
In this case, the right window has an opaque background. As a matter of fact, it takes 3-4 repaints due to any reason (easiest to reproduce is repaint on rollover) for the background to become completely opaque.
SSCCE:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.synth.ColorType;
import javax.swing.plaf.synth.Region;
import javax.swing.plaf.synth.SynthConstants;
import javax.swing.plaf.synth.SynthContext;
import javax.swing.plaf.synth.SynthLookAndFeel;
import javax.swing.plaf.synth.SynthPainter;
import javax.swing.plaf.synth.SynthStyle;
import javax.swing.plaf.synth.SynthStyleFactory;
public class SynthSSCCE
{
public static void main(String[] args) throws Exception
{
final SynthLookAndFeel laf = new SynthLookAndFeel();
UIManager.setLookAndFeel(laf);
SynthLookAndFeel.setStyleFactory(new StyleFactory());
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
final JFrame f = new JFrame();
{
f.add(new JButton("Works properly"));
f.setUndecorated(true);
f.setBackground(new Color(0, true));
f.setSize(300, 300);
f.setLocation(0, 0);
f.setVisible(true);
}
{
final JDialog d = new JDialog(f);
final JButton btn = new JButton("WTF?");
// uncomment and notice that this has no effect
// btn.setContentAreaFilled(false);
d.add(btn);
d.setUndecorated(true);
d.setBackground(new Color(0, true));
d.setSize(300, 300);
d.setLocation(320, 0);
d.setVisible(true);
}
}
});
}
static class StyleFactory extends SynthStyleFactory
{
private final SynthStyle style = new Style();
@Override
public SynthStyle getStyle(JComponent c, Region id)
{
return style;
}
}
static class Style extends SynthStyle
{
private final SynthPainter painter = new Painter();
@Override
protected Color getColorForState(SynthContext context, ColorType type)
{
if (context.getRegion() == Region.BUTTON && type == ColorType.FOREGROUND)
return Color.GREEN;
return null;
}
@Override
protected Font getFontForState(SynthContext context)
{
return Font.decode("Monospaced-BOLD-30");
}
@Override
public SynthPainter getPainter(SynthContext context)
{
return painter;
}
@Override
public boolean isOpaque(SynthContext context)
{
return false;
}
}
static class Painter extends SynthPainter
{
@Override
public void paintPanelBackground(SynthContext context, Graphics g, int x, int y, int w, int h)
{
final Graphics g2 = g.create();
try
{
g2.setColor(new Color(255, 255, 255, 128));
g2.fillRect(x, y, w, h);
}
finally
{
g2.dispose();
}
}
@Override
public void paintButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h)
{
final Graphics g2 = g.create();
try
{
if ((context.getComponentState() & SynthConstants.MOUSE_OVER) == SynthConstants.MOUSE_OVER)
g2.setColor(new Color(255, 0, 0, 255));
else
g2.setColor(new Color(0xAA, 0xAA, 0xAA, 255));
g2.fillRoundRect(x, y, w, h, w / 2, h / 2);
}
finally
{
g2.dispose();
}
}
}
}
And these are my questions...
- What is going on? As in, why this exhibits behavior of a custom-painted non-opaque component that forgets to call super?
- Why doesn't it happen to TL windows?
- What is the easiest way to fix it, aside from not using non-TL windows?
super("Test translucent window");
works fine, because I need non-TL windows, which unfortunately exhibit some strange behavior. – JudicativepaintText
&paintIcon
forJButton
instance': if I wanted to have my own UI and trash swing's components, such asJOptionPane
,JFileChooser
etc. which will always use the defaultJButton
/JPanel
, then I would definitely do so. 'create ownSyntButtonUI
': that is not how Synth works. Yes, I have already thought about instrumenting Synth classes (because you cannot provide your ownComponentUI
s), but I would like to do that as a last resort. – Judicative