13

In Java2D when you use setOpaque I am a little confused on what the true and false does.

For example I know that in Swing Opaque means that when painting Swing wont paint what is behind the component. Or is this backwards? Which one is it?

Thanks

3 Answers3

51

The short answer to your question is that "opaque" is defined in English as completely non-transparent. Therefore an opaque component is one which paints its entire rectangle, and every pixel is not at all translucent to any degree.

However, the Swing component opacity API is one of those mis-designed and therefore often mis-used APIs.

What's important to understand is that isOpaque is a contract between the Swing system and a particular component. If it returns true, the component guarantees to non-translucently paint every pixel of its rectangular area. This API should have been abstract to force all component writers to consider it. The isOpaque API is used by Swing's painting system to determine whether the area covered by a given component must be painted for components which overlap it and which are behind it, including the component's container and ancestors. If a component returns true to this API, the Swing system may optimize painting to not paint anything in that area until invoking the specific component's paint method.

Because of contractual implication of isOpaque, the API setOpaque should not exist, since it is actually incorrect for anything external to call setOpaque since, in turn, the external thing can't know whether the component in question will (or even can) honor it. Instead, isOpaque should have been overridden by each concrete component to return whether it actually is, in fact, opaque given its current properties.

Because the setOpaque API does exist, many components have mis-implemented it (quite understandably) to drive whether or not they will paint their "background" (for example JLabel and JPanel filling with their background color). The effect of this is to create an impression with users of the API to think that setOpaque drives whether or not that background should paint, but it doesn't.

Furthermore, if, say, you wish to paint a JLabel with a translucent background you need to set a background color with an alpha value, and do setOpaque(true), but it's not actually opaque - it's translucent; the components behind it still need to paint in order for the component to render properly.

This problem was exposed in a significant way with the Java 6's new Nimbus Look & Feel. There are numerous bug reports regarding transparent components filed against Nimbus (see stack overflow question Java Nimbus LAF with transparent text fields). The response of the Nimbus development team is this:

This is a problem [in] the orginal design of Swing and how it has been confusing for years. The issue is setOpaque(false) has had a side effect in [existing] LAFs which is that of hiding the background which is not really what it is [meant] for. It is [meant] to say that the component may have transparent parts and [Swing] should paint the parent component behind it.

So, in summary, you should not use setOpaque. If you do use it, bear in mind that the combination of some Look & Feels and some components may do "surprising" things. And, in the end, there is actually no right answer.

Ti Strga
  • 1,353
  • 18
  • 40
Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
  • Late to the party here, but thanks for explaining the relationship between isOpaque and alpha channel. I've been stumped because they seem to cover the same area -- it's helpful to know that's because isOpaque is goofy. :) – KathyA. Apr 28 '14 at 14:20
  • Should change it to something like `setPaintBackground(boolean)`....Or change the parameter to be a float factor from 0 to 1, to set the degree of the opacity....`0` is transparent, `1` is totally not. – WesternGun Feb 22 '17 at 09:00
  • @FaithReaper: The API would have to be deprecated and replaced with something properly spec'd and `protected`. – Lawrence Dol Feb 22 '17 at 19:54
1

javadoc says : If true the component paints every pixel within its bounds. Otherwise, the component may not paint some or all of its pixels, allowing the underlying pixels to show through.

try this example program too... http://www.java2s.com/Code/JavaAPI/javax.swing/JPanelsetOpaquebooleanisOpaque.htm

raj
  • 3,769
  • 4
  • 25
  • 43
  • 2
    when true, the components behind are not shown.. when false, its shown.. *we needn't see javadoc for this, an english dictionary is enough* :) :) – raj Mar 16 '10 at 03:49
  • Yes that is what I thought but after reading many things I was getting confused. Thanks :) –  Mar 16 '10 at 03:50
0

I think that the following also needs to be added:

The term opaque has different meanings in Java 2D and in Swing.

In Java 2D opacity is a rendering concept. It is a combination of an alpha value and the Composite mode. It is a degree to which the pixel colours being drawn should be blended with pixel values already present. For instance, we draw a semi-transparent rectangle over an existing oval shape. The oval is therefore partially visible. This concept is often compared to light going trough glass or water.

In Swing, an opaque component paints every pixel within its rectangular bounds. A non-opaque component paints only a subset of its pixels or none at all, allowing the pixels underneath it to show through. The opaque property was set for efficiency reasons; Swing does not have to paint areas behind opaque components.

Source: Java docs and Filthy Rich Clients

package com.zetcode;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import static javax.swing.SwingConstants.CENTER;
import net.miginfocom.swing.MigLayout;

class DrawingPanel extends JPanel {

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        doDrawing(g);
    }

    private void doDrawing(Graphics g) {

        Graphics2D g2d = (Graphics2D) g;

        g2d.setColor(Color.green);
        g2d.fillOval(20, 20, 100, 100);
        g2d.setColor(Color.blue);
        g2d.setComposite(AlphaComposite.getInstance(
                AlphaComposite.SRC_OVER, 0.1f));
        g2d.fillRect(0, 0, 150, 150);
    }
}

class MyLabel extends JLabel {

    public MyLabel(String text) {
        super(text, null, CENTER);
    }

    @Override
    public boolean isOpaque() {
        return true;
    }
}

public class OpaqueEx2 extends JFrame {

    public OpaqueEx2() {

        initUI();
    }

    private void initUI() {

        JLabel lbl1 = new JLabel("Java 2D opacity");
        JLabel lbl2 = new JLabel("Swing opaque");

        DrawingPanel dpanel = new DrawingPanel();

        MyLabel mylbl = new MyLabel("isOpaque()");
        mylbl.setBackground(Color.decode("#A9A9A9"));

        createLayout(lbl1, lbl2, dpanel, mylbl);

        setTitle("Opaque");
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private void createLayout(JComponent... arg) {

        JPanel pnl = new JPanel(new MigLayout("ins 10"));

        pnl.add(arg[0], "w 150");
        pnl.add(arg[1], "w 150, wrap");
        pnl.add(arg[2], "w 150, h 150");
        pnl.add(arg[3], "w 150, h 150");

        add(pnl);
        pack();
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                OpaqueEx2 ex = new OpaqueEx2();
                ex.setVisible(true);
            }
        });
    }
}

In the code example, we have two components. The component on the left is a panel which uses AlphaComposite to paint a highly translucent rectangle over an oval. The component on the right is a label. Labels are non-opaque in most look and feels. We overwrite the label's isOpaque() method to set a gray background.

Opaque explained

Jan Bodnar
  • 10,969
  • 6
  • 68
  • 77