setOpaque() in java

user489041 picture user489041 · Nov 3, 2010 · Viewed 10.3k times · Source

Can anyone explain why Nimbius treats the setOpaque() differently than other java LaF's. Its breaking my code because components that are normally transparent no longer are.

EDIT: The problem seems to only deal with JTextAreas (which is what I need) or similar components.

EDIT EDIT: This is a screen of the actual application. When applying trashgod's solution, the background still does not show through.

alt text

EDIT EDIT EDIT:
I tried trashgod's suggestion to override the paint(). I toiled with this for hours, and could not get it to work. I was able to get the background to show through, but the JinternalFrame was unable to be moved, resized, and have its text selected. Calling super.paint(g) failed to solve the solution. Is there an easy way to do this that I might be missing?
Ive taken a new approach to this. Inside the JInternalFrame is a JLayeredPane.
Layer 0 - JLabel
Layer 1 - JTextArea

When the JInternalFrame is moved or resized:

  1. Makes itself invisible
  2. Takes a screen shot of where it was in the container its contained in
  3. Paints the JLabel with the image it took
  4. Makes itself visible again.

Since I could not get the JInternalFrame to be transparent at all. I simulated its transpaency. The only issue is, there is a lot of overhead associated with this. Any thoughts?

alt text


package newpackage;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.UIManager;

/**
 * Example of how to create a transparent internal frame.
 * @author dvargo
 */
public class TransparentInternalFrame extends JInternalFrame {

    JLayeredPane container;


    /**
     * Defualt constructor to set the frame up
     * @param container The container for the frame
     * @param opacity The opacity of the frame
     */
    public TransparentInternalFrame(JLayeredPane container, int opacity) {
        super("", true, true, true, true);
        this.container = container;
        initComponents();
        setSize(200, 200);
        putClientProperty("JInternalFrame.isPalette", Boolean.TRUE);
        scrollPane.setBackground(new Color(0, 0, 0, opacity));
        scrollPane.getViewport().setBackground(new Color(0, 0, 0, opacity));
        textArea.setBackground(new Color(0, 0, 0, opacity));
        setBG();
    }

    /**
     * Builds the GUI
     */
    private void initComponents() {

        layeredPane = new javax.swing.JLayeredPane();
        imageLabel = new javax.swing.JLabel();
        scrollPane = new javax.swing.JScrollPane();
        textArea = new javax.swing.JTextArea();

        imageLabel.setBounds(0, 0, 360, 260);
        layeredPane.add(imageLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        scrollPane.setBorder(null);

        textArea.setColumns(20);
        textArea.setRows(5);
        textArea.addKeyListener(new java.awt.event.KeyAdapter() {

            public void keyPressed(java.awt.event.KeyEvent evt) {
                textAreaKeyPressed(evt);
            }

            public void keyReleased(java.awt.event.KeyEvent evt) {
                textAreaKeyReleased(evt);
            }

            public void keyTyped(java.awt.event.KeyEvent evt) {
                textAreaKeyTyped(evt);
            }
        });

        addComponentListener(new java.awt.event.ComponentAdapter() {

            public void componentMoved(java.awt.event.ComponentEvent evt) {
                frameMoved();
            }

            public void componentResized(java.awt.event.ComponentEvent evt) {
                frameResized();
            }
        });

        scrollPane.setViewportView(textArea);

        scrollPane.setBounds(0, 0, 360, 260);
        layeredPane.add(scrollPane, javax.swing.JLayeredPane.PALETTE_LAYER);



        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
       getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(layeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, 362, javax.swing.GroupLayout.PREFERRED_SIZE));
        layout.setVerticalGroup(
              layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(layeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE));
    }

    /**
     * The text will be blurred with out this
     * @param evt
     */
    private void textAreaKeyTyped(java.awt.event.KeyEvent evt) {
        repaintAll();
    }

    /**
     * The text will be blurred with out this
     * @param evt
     */
    private void textAreaKeyPressed(java.awt.event.KeyEvent evt) {
        repaintAll();
    }

    /**
     * The text will be blurred with out this
     * @param evt
     */
    private void textAreaKeyReleased(java.awt.event.KeyEvent evt) {
        repaintAll();
    }

    /**
     * Capture whats behind the frame and paint it to the image label
     */
    private void setBG() {

        setVisible(false);
        Rectangle location = new Rectangle(this.getX() + container.getX(),
                this.getY() + container.getY(),
                (int) this.getSize().getWidth() + 8 + ((javax.swing.plaf.basic.BasicInternalFrameUI) getUI()).getNorthPane().getWidth(),
                (int) this.getSize().getHeight() + ((javax.swing.plaf.basic.BasicInternalFrameUI) getUI()).getNorthPane().getHeight() + 4);
        ImageIcon newIcon = new ImageIcon(createImage((JComponent) container, location));
        setVisible(true);
        imageLabel.setIcon(newIcon);
        repaint();
    }

    /**
     * Only need to update the image label if the frame is moved or resized
     */
    private void frameResized() {
        setBG();
        textArea.repaint();
    }

    /**
     * Only need to update the image label if the frame is moved or resized
     */
    private void frameMoved() {
        setBG();
        for(Component x : container.getComponents())
        {
            //see if its a jinternalframe
            if(x.getClass().getName().equals(this.getClass().getName()))
            {
                //cast it
                TransparentInternalFrame temp = (TransparentInternalFrame)x;
                //make sure its not the same one as this
                if(x.getBounds().equals(this.getBounds()))
                {
                    return;
                }
                //if they intersect
                if(x.getBounds().intersects(this.getBounds()))
                {
                    this.setVisible(false);
                    temp.setBG();
                    this.setVisible(true);
                }
            }
        }

        textArea.repaint();
    }

    private void repaintAll() {
        textArea.repaint();
        imageLabel.repaint();
        layeredPane.repaint();
        scrollPane.repaint();
        scrollPane.getViewport().repaint();
        textArea.repaint();
        repaint();
    }

    /**
     *  Create a BufferedImage for Swing components.
     *  All or part of the component can be captured to an image.
     *
     *  @param  component Swing component to create image from
     *  @param  region The region of the component to be captured to an image
     *  @return image the image for the given region
     */
    public static BufferedImage createImage(JComponent component, Rectangle region) {
        //  Make sure the component has a size and has been layed out.
        //  (necessary check for components not added to a realized frame)

        if (!component.isDisplayable()) {
            Dimension d = component.getSize();

            if (d.width == 0 || d.height == 0) {
                d = component.getPreferredSize();
                component.setSize(d);
            }

            layoutComponent(component);
        }

        BufferedImage image = new BufferedImage(region.width, region.height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();

        //  Paint a background for non-opaque components,
        //  otherwise the background will be black

        if (!component.isOpaque()) {
            g2d.setColor(component.getBackground());
            g2d.fillRect(region.x, region.y, region.width, region.height);
        }

        g2d.translate(-region.x, -region.y);
        component.paint(g2d);
        g2d.dispose();
        return image;
    }

    public static void layoutComponent(Component component) {
        synchronized (component.getTreeLock()) {
            component.doLayout();

            if (component instanceof Container) {
                for (Component child : ((Container) component).getComponents()) {
                    layoutComponent(child);
                }
            }
        }
    }
    private javax.swing.JLabel imageLabel;
    private javax.swing.JScrollPane scrollPane;
    private javax.swing.JLayeredPane layeredPane;
    private javax.swing.JTextArea textArea;


    public static void main(String args[])
    {
        try
        {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        JFrame container = new JFrame();
        container.setSize(800, 800);

        JLayeredPane layerPanel = new JLayeredPane();
        layerPanel.setSize(800, 800);
        container.getContentPane().add(layerPanel);
        layerPanel.setVisible(true);

        JPanel colorPanel = new JPanel();
        colorPanel.setSize(800,800);
        colorPanel.setBackground(Color.red);
        layerPanel.add(colorPanel);
        layerPanel.setLayer(colorPanel, JLayeredPane.DEFAULT_LAYER);

        TransparentInternalFrame frameA = new TransparentInternalFrame(layerPanel,0);
        frameA.setVisible(true);
        layerPanel.add(frameA);
        layerPanel.setLayer(frameA, 1);
        frameA.setSize(282,282);

        TransparentInternalFrame frameB = new TransparentInternalFrame(layerPanel, 0);
        frameB.setVisible(true);
        layerPanel.add(frameB);
        layerPanel.add(frameB,1);
        frameB.setLocation(300, 300);
        frameB.setSize(282,282);

        container.repaint();
        container.setVisible(true);

    }
}


Answer

trashgod picture trashgod · Nov 3, 2010

You may get some insight from the section on Opacity in the article Painting in AWT and Swing. In particular, setting the opaque property does not mean, "Make the component's background transparent." An sscce that demonstrates the problem may also be fruitful.

Addendum: Simplifying your example, it looks like the text area itself can be made transparent, but the Nimbus defaults are affecting the area's borders. You might try changing them accordingly.

A few notes on your code:

  • Always build you GUI on the event dispatch thread.
  • Don't draw from another thread.
  • Don't swallow exception.

Addendum: See changes to create().

Addendum: You might want to look at the isPalette property, too

jif.putClientProperty("JInternalFrame.isPalette", Boolean.TRUE);

alt text

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JInternalFrame;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.UIManager;

public class TransparentTextArea extends JTextArea {

    int alpha;

    public TransparentTextArea(int alpha) {
        super(4, 16);
        this.alpha = alpha;
        this.setBackground(new Color(0, 0, 0, alpha));
        this.setFont(new Font("Serif", Font.ITALIC, 24));
        this.setEditable(false);
        this.setText("Twas brillig and the slithy toves,\n"
            + "Did gyre and gimble in the wabe;\n"
            + "All mimsy were the borogoves,\n"
            + "And the mome raths outgrabe.");
    }

    private static void create() {
        JFrame f = new JFrame();
        f.setLayout(new FlowLayout());
        f.getContentPane().setBackground(new Color(0xffffc0));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JInternalFrame jif = new JInternalFrame();
        JPanel panel = new JPanel();
        panel.setBackground(new Color(0xffffc0));
        panel.add(new TransparentTextArea(0));
        jif.add(panel);
        jif.setVisible(true);

        f.add(jif);
        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args) {

        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (Exception e) {
            e.printStackTrace();
        }

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                create();
            }
        });
    }
}