30

Can JPanels background be set to transparent?

My frame is has two JPanels:

  • Image Panel and
  • Feature Panel.

Feature Panel is overlapping Image Panel. The Image Panel is working as a background and it loads image from a remote URL.

On Feature Panel I want to draw shapes. Now Image Panel cannot be seen due to Feature Panel's background color.

I need to make Feature Panel background transparent while still drawing its shapes and I want Image Panel to be visible (since it is doing tiling and cache function of images).

I'm using two JPanel's, because I need to seperate the image and shape drawing .

Is there a way the overlapping Jpanel have a transparent background?

Line
  • 1,529
  • 3
  • 18
  • 42
Imran
  • 847
  • 2
  • 9
  • 9
  • 1
    JPanel when transparent PNG image is loaded, and set `JPanel.setOpaque(false);` it will use the image transparent method, else it will show not transparent picture. –  Jul 19 '12 at 12:34

7 Answers7

31

Calling setOpaque(false) on the upper JPanel should work.

From your comment, it sounds like Swing painting may be broken somewhere -

First - you probably wanted to override paintComponent() rather than paint() in whatever component you have paint() overridden in.

Second - when you do override paintComponent(), you'll first want to call super.paintComponent() first to do all the default Swing painting stuff (of which honoring setOpaque() is one).

Example -

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class TwoPanels {
    public static void main(String[] args) {

        JPanel p = new JPanel();
        // setting layout to null so we can make panels overlap
        p.setLayout(null);

        CirclePanel topPanel = new CirclePanel();
        // drawing should be in blue
        topPanel.setForeground(Color.blue);
        // background should be black, except it's not opaque, so 
        // background will not be drawn
        topPanel.setBackground(Color.black);
        // set opaque to false - background not drawn
        topPanel.setOpaque(false);
        topPanel.setBounds(50, 50, 100, 100);
        // add topPanel - components paint in order added, 
        // so add topPanel first
        p.add(topPanel);

        CirclePanel bottomPanel = new CirclePanel();
        // drawing in green
        bottomPanel.setForeground(Color.green);
        // background in cyan
        bottomPanel.setBackground(Color.cyan);
        // and it will show this time, because opaque is true
        bottomPanel.setOpaque(true);
        bottomPanel.setBounds(30, 30, 100, 100);
        // add bottomPanel last...
        p.add(bottomPanel);

        // frame handling code...
        JFrame f = new JFrame("Two Panels");
        f.setContentPane(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(300, 300);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    // Panel with a circle drawn on it.
    private static class CirclePanel extends JPanel {

        // This is Swing, so override paint*Component* - not paint
        protected void paintComponent(Graphics g) {
            // call super.paintComponent to get default Swing 
            // painting behavior (opaque honored, etc.)
            super.paintComponent(g);
            int x = 10;
            int y = 10;
            int width = getWidth() - 20;
            int height = getHeight() - 20;
            g.drawArc(x, y, width, height, 0, 360);
        }
    }
}
Nate
  • 16,748
  • 5
  • 45
  • 59
  • I did , but it did not work,should I call this function in the constructor or in the paint() method? – Imran Mar 30 '10 at 13:44
  • @Imran - In the constructor or in the paint() method of what? The panel itself? see updated answer... – Nate Mar 30 '10 at 16:45
  • Alright thanks Nate, that worked. before calling super.paint() I set Opaque to false and then before drawing my shape I set Opaque to true. thanks buddy – Imran Mar 31 '10 at 06:01
  • 1
    You shouldn't have to set it on and off... basically all `setOpaque()` handles is whether the "background" should be painted or not - you can just call it on the panel right after you create it and it will stay set. If you have an overridden `paintComponent()` on that panel, you can paint on the component (and be sure to call super.paintComponent() so default Swing painting can occur) and anything you draw will be treated as "foreground" and will show up without calling `setOpaque(true)`. – Nate Mar 31 '10 at 14:22
  • Ok I think i spoke too soon, now the problem is upside down. The contents of the overlapping Jpanel are erased when the Jpanel which is below redraws. Its some kind of a round robin. I draw the overlapping Jpanel without background, but when as soon as the overlapped jpanel redraws the overlapping jpanel looses its contents, hmmmm..now what. – Imran Apr 01 '10 at 10:37
  • Post some code representative of what you're doing... I'll post a short example, too. – Nate Apr 01 '10 at 13:12
  • hey thanks for your response. I got it working but the overlapping JPanel is expereincing a lot of Flickering. The overlapped panel does a fade in on new image load. Both panels are being painted through seperate threads. Now the overlapped thread draws xml response. Xml response loads and draws before the image is loaded in the overlapped Jpanel. During the fadeIn function of overlapped JPanel, the already drawn overlapping Japenl starts flickering and looks very ugly. just for your info. I`m trying to write a rich client for a web-mapping application that shows satellite image and features – Imran Apr 01 '10 at 14:19
  • The threading part - are you using SwingUtilities.invokeLater(), SwingWorker, or anything similar to handle updating only in the EDT? How often are you updating - the "flickery" description sounds like you're trying to update the component faster than it can really repaint, so it's repainting "as available" and not at a set rate. Or it could be many other things... threading issues, doing too much processing on the EDT, etc. – Nate Apr 04 '10 at 02:44
  • thanks, this worked for me. Much less complicated compared to the accepted answer. – braden May 01 '12 at 21:12
11

Alternatively, consider The Glass Pane, discussed in the article How to Use Root Panes. You could draw your "Feature" content in the glass pane's paintComponent() method.

Addendum: Working with the GlassPaneDemo, I added an image:

//Set up the content pane, where the "main GUI" lives.
frame.add(changeButton, BorderLayout.SOUTH);
frame.add(new JLabel(new ImageIcon("img.jpg")), BorderLayout.CENTER);

and altered the glass pane's paintComponent() method:

protected void paintComponent(Graphics g) {
    if (point != null) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setComposite(AlphaComposite.getInstance(
            AlphaComposite.SRC_OVER, 0.3f));
        g2d.setColor(Color.yellow);
        g2d.fillOval(point.x, point.y, 120, 60);
    }
}

enter image description here

As noted here, Swing components must honor the opaque property; in this variation, the ImageIcon completely fills the BorderLayout.CENTER of the frame's default layout.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 3
    Using a glasspane won't work (correctly) without setOpaque() (as described in my post) working. – Nate Apr 04 '10 at 02:37
  • and you can only have one glass pane. If say you wanted to move a JFrame or even better, a JPanel around for example and it held an object who's' sides are irregular, you want that part to be clear. Then you can blend it with the panel below to have overlapping objects. – George Xavier May 15 '19 at 20:04
8

In my particular case it was easier to do this:

 panel.setOpaque(true);
 panel.setBackground(new Color(0,0,0,0,)): // any color with alpha 0 (in this case the color is black
Ordiel
  • 2,442
  • 3
  • 36
  • 52
  • 1
    that's invalid - with opaque to true, the panel guarantees filling filling its background completely (which it doesn't with a transparent background) – kleopatra Sep 30 '12 at 12:47
  • what you say is true, but for the desired purpose of design, set any color with alpha 0 will to de job, besides he din't specified if he need to have access to the background panel components, as I understood the panel which is on the lower level is just to set a background image. – Ordiel Sep 30 '12 at 17:39
7
(Feature Panel).setOpaque(false);

Hope this helps.

Juan Mellado
  • 14,973
  • 5
  • 47
  • 54
Edesa
  • 581
  • 7
  • 16
4

To set transparent you can set opaque of panel to false like

   JPanel panel = new JPanel();
   panel.setOpaque(false);

But to make it transculent use alpha property of color attribute like

   JPanel panel = new JPanel();
   panel.setBackground(new Color(0,0,0,125));

where last parameter of Color is for alpha and alpha value ranges between 0 and 255 where 0 is full transparent and 255 is fully opaque

Shrinivasan
  • 261
  • 4
  • 9
2
 public void paintComponent (Graphics g)
    { 
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.0f)); // draw transparent background
     super.paintComponent(g);
    ((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1.0f)); // turn on opacity
    g.setColor(Color.RED);
    g.fillRect(20, 20, 500, 300);
     } 

I have tried to do it this way, but it is very flickery

Imran
  • 847
  • 2
  • 9
  • 9
1

As Thrasgod correctly showed in his answer, the best way is to use the paintComponent, but also if the case is to have a semi transparent JPanel (or any other component, really) and have something not transparent inside. You have to also override the paintChildren method and set the alfa value to 1. In my case I extended the JPanel like that:

public class TransparentJPanel extends JPanel {

private float panelAlfa;
private float childrenAlfa;

public TransparentJPanel(float panelAlfa, float childrenAlfa) {
    this.panelAlfa = panelAlfa;
    this.childrenAlfa = childrenAlfa;
}

@Override
public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(getBackground());
    g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setComposite(AlphaComposite.getInstance(
            AlphaComposite.SRC_OVER, panelAlfa));
    super.paintComponent(g2d);

}

@Override
protected void paintChildren(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(getBackground());
    g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setComposite(AlphaComposite.getInstance(
            AlphaComposite.SRC_ATOP, childrenAlfa));
  
    super.paintChildren(g); 
}
 //getter and setter
}

And in my project I only need to instantiate Jpanel jp = new TransparentJPanel(0.3f, 1.0f);, if I want only the Jpanel transparent. You could, also, mess with the JPanel shape using g2d.fillRoundRect and g2d.drawRoundRect, but it's not in the scope of this question.

Community
  • 1
  • 1
emportella
  • 323
  • 4
  • 9
  • Does the paintChildren method actually work? 1. You're passing g, not g2d and 2. I experience issues with setComposite, then passing g2d to paintChildren. It just doesn't work, while g2d.translate(x,y) perfectly makes the children be drawn with an offset. It seems the composite gets somehow lost or is simply overwritten within the paintChildren method. – Timmos Jun 30 '21 at 20:16