0

When I add panels and objects in panels, I want the image to be set as the background and show through the panels put on top of it. I read you can do this bet setting the panel.setOpaque(false) option, however this does not seem to work.

Here is my compiler directory and how it's setup (Using Intellij)...

enter image description here

Here is the background Image...

enter image description here

Here is the code...

BackgroundPanel class > http://www.camick.com/java/source/BackgroundPanel.java

/**
 * Created by James Page on 4/16/2017.
 */
package Main;

import org.apache.commons.lang3.ArrayUtils;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;

public class TestGui extends JFrame {
    private final String[] guiCharSelDefault = {"---  Select Character ---"};
    private final String[] characters = {"charOne", "charTwo", "charThree", "charFour"};
    private final String[] GuiCharSel = (String[]) ArrayUtils.addAll(guiCharSelDefault, characters);
    private final String[] weapon = {"Weapon"};
    private final String[][] allWeapons = {
            {
                    "weakWeaponOne", "strongWeaponOne", "shortWeaponOne", "longWeaponOne"
            },
            {
                    "weakWeaponTwo", "strongWeaponTwo", "shortWeaponTwo", "longWeaponTwo"
            },
            {
                    "weakWeaponThree", "strongWeaponThree", "shortWeaponThree", "longWeaponThree"
            },
            {
                    "weakWeaponFour", "strongWeaponFour", "shortWeaponFour", "longWeaponFour"
            }
    };
    private JComboBox charCombo = new JComboBox(GuiCharSel);
    private JComboBox weaponsCombo = new JComboBox(weapon);
    private BackgroundPanel backgroundFrame = createBackgroundFrame("../images/Background.png");
    private JPanel topFrame = createTopFrame();
    private JPanel centerFrame = createCenterFrame();

    //**************************************************************************************

    private static GridBagConstraints setGbc(int gridx, int gridy, int gridWidth, int gridHeight, int ipadx, int ipady, String anchorLocation, double weightx, double weighty, Insets insets){
        GridBagConstraints gbc = new GridBagConstraints();

        if (anchorLocation.toUpperCase().equals("NORTHWEST")){
            gbc.anchor = GridBagConstraints.NORTHWEST;
        } else if (anchorLocation.toUpperCase().equals("NORTH")){
            gbc.anchor = GridBagConstraints.NORTH;
        } else if (anchorLocation.toUpperCase().equals("NORTHEAST")){
            gbc.anchor = GridBagConstraints.NORTHEAST;
        } else if (anchorLocation.toUpperCase().equals("WEST")){
            gbc.anchor = GridBagConstraints.WEST;
        } else if (anchorLocation.toUpperCase().equals("EAST")){
            gbc.anchor = GridBagConstraints.EAST;
        } else if (anchorLocation.toUpperCase().equals("SOUTHWEST")){
            gbc.anchor = GridBagConstraints.SOUTHWEST;
        } else if (anchorLocation.toUpperCase().equals("SOUTH")){
            gbc.anchor = GridBagConstraints.SOUTH;
        } else if (anchorLocation.toUpperCase().equals("SOUTHEAST")){
            gbc.anchor = GridBagConstraints.SOUTHEAST;
        } else {
            gbc.anchor = GridBagConstraints.CENTER;
        }

        gbc.gridx = gridx; // column
        gbc.gridy = gridy; // row
        gbc.gridwidth = gridWidth; // number of columns
        gbc.gridheight = gridHeight; // number of rows
        gbc.ipadx = ipadx; // width of object
        gbc.ipady = ipady; // height of object
        gbc.weightx = weightx; // shifts rows to side of set anchor
        gbc.weighty = weighty; // shifts columns to side of set anchor
        gbc.insets = insets; // placement inside cell
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.fill = GridBagConstraints.VERTICAL;

        return gbc;
    }

    private Insets setInsets(int top, int left, int bottom, int right){
        Insets insets = new Insets(top,left,bottom,right);
        return insets;
    }

    //**************************************************************************************

    private BackgroundPanel createBackgroundFrame(String imgLocName){
        Image backgroundImg = null;
        try {
            backgroundImg = ImageIO.read(getClass().getResource(imgLocName));
            System.out.println("File: " + imgLocName.toString());
        } catch (Exception e) {
            System.out.println("Cannot read file: " + e);
        }
        BackgroundPanel bgPanel = new BackgroundPanel(backgroundImg, BackgroundPanel.SCALED, 0.0f, 0.0f);
        return bgPanel;
    }

    private JPanel createTopFrame(){
        JPanel pnl = new JPanel();
        Border raisedBevel = BorderFactory.createRaisedBevelBorder();
        Color lineColor = new Color(224,224,224);
        Border lineBorder = BorderFactory.createMatteBorder(5, 5, 5, 5, lineColor);
        Border loweredBevel = BorderFactory.createLoweredBevelBorder();
        Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
        Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);
        TitledBorder topFrameTitle = BorderFactory.createTitledBorder(compoundFinal, "Character");
        topFrameTitle.setTitleJustification(TitledBorder.CENTER);

        JLabel lineSplitter = new JLabel();
        Border lineSplitterBoarder = BorderFactory.createMatteBorder(0, 0, 0, 5, new Color(224,224,224));
        lineSplitter.setBorder(lineSplitterBoarder);

        pnl.setBorder(topFrameTitle);
        pnl.setLayout(new GridBagLayout());
        pnl.setPreferredSize(new Dimension(200, 60));

        charCombo.addActionListener(
                new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        String charName = ((JComboBox)(e.getSource())).getSelectedItem().toString();
                        if (charName.equals("charOne")){
                            weaponsCombo.removeAllItems();
                            weaponsCombo.setModel(new DefaultComboBoxModel(allWeapons[1]));
                        }
                    }
                }
        );
        pnl.add(charCombo, setGbc(0,0, 1,1, 0,0, "WEST", 0, 0, setInsets(0, 0, 0, 0)));
        pnl.add(lineSplitter, setGbc(1,0, 1,1, 0,0, "WEST", 0, 0, setInsets(0, 10, 0, 0)));
        pnl.add(weaponsCombo, setGbc(2,0, 1,1, 0,0, "WEST", 1, 1, setInsets(0, 10, 0, 0)));

        pnl.setOpaque(false);
        return pnl;
    }

    private JPanel createCenterFrame() {
        JPanel pnl = new JPanel();
        Border raisedBevel = BorderFactory.createRaisedBevelBorder();
        Color lineColor = new Color(224, 224, 224);
        Border lineBorder = BorderFactory.createMatteBorder(5, 5, 5, 5, lineColor);
        Border loweredBevel = BorderFactory.createLoweredBevelBorder();
        Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
        Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);
        TitledBorder topFrameTitle = BorderFactory.createTitledBorder(compoundFinal, "Stuff");
        topFrameTitle.setTitleJustification(TitledBorder.CENTER);

        pnl.setBorder(topFrameTitle);
        pnl.setLayout(new GridBagLayout());

        pnl.setOpaque(false);
        return pnl;
    }

    TestGui(){
        add(backgroundFrame);
        add(topFrame, BorderLayout.NORTH);
        add(centerFrame, BorderLayout.CENTER);

        setSize(800,600);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    //**************************************************************************************

    public static void main(String[] args) {
        new TestGui();
    }
}

I know the image background is being added to the gui, because if I comment out lines //add(topFrame, BorderLayout.NORTH); and //add(centerFrame, BorderLayout.CENTER); in the constructor, the image shows on the gui. Anyone have any idea how to make the background image show through these two panels?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Fiddle Freak
  • 1,923
  • 5
  • 43
  • 83
  • Start by calling `setOpaque(false)` on your panels, ie `pnl.setOpaque(false)`. You'll find a lot of components are opaque by default (except `JLabel`, because it had to be different) – MadProgrammer Apr 21 '17 at 00:29
  • That's what I tried doing in lines 139 and 153 `pnl.setOpaque(false);`. It didn't seem to work... – Fiddle Freak Apr 21 '17 at 00:33

1 Answers1

2

You're replacing the backgroundFrame with centerFrame

add(backgroundFrame);
add(topFrame, BorderLayout.NORTH);
add(centerFrame, BorderLayout.CENTER);

This is feature of BorderLayout, where it can only support a single component at each of it's 5 available positions

Instead, what you want to do is either add the other panels to the backgroundFrame or set backgroundFrame as the frame's contentPane, for example

setContentPane(backgroundFrame);
add(topFrame, BorderLayout.NORTH);
add(centerFrame, BorderLayout.CENTER);

Background

Also, as a general suggestion, avoid using setPreferredSize, there are simply too many things that can make that go wrong

Sorry to bother you again, it looks like it is not showing through the JScrollPane. Should I open this up as a new question?

The JScrollPane is a more complex component, which is made up of two components which are used to provide the functionality of scrolling

JScrollPane

You need to make the JScrollPane and it's JViewport transparent as well (as well as the view you wrap into it)

So, this is a modified version of your createCenterFrame method which creates a JTextArea, wraps into a JScrollPane and adds it to the pnl

private JPanel createCenterFrame() {
    JPanel pnl = new JPanel();
    Border raisedBevel = BorderFactory.createRaisedBevelBorder();
    Color lineColor = new Color(224, 224, 224);
    Border lineBorder = BorderFactory.createMatteBorder(5, 5, 5, 5, lineColor);
    Border loweredBevel = BorderFactory.createLoweredBevelBorder();
    Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
    Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);
    TitledBorder topFrameTitle = BorderFactory.createTitledBorder(compoundFinal, "Stuff");
    topFrameTitle.setTitleJustification(TitledBorder.CENTER);

    pnl.setBorder(topFrameTitle);
    pnl.setLayout(new BorderLayout());

    JScrollPane scrollPane = new JScrollPane();
    scrollPane.setOpaque(false);
    scrollPane.getViewport().setOpaque(false);

    JTextArea ta = new JTextArea();
    ta.setOpaque(false);
    ta.setText("This is an example of a transparent text area inside a transparent scroll pane, but you could just as easily wrap a transparent panel into it and get the same result");
    ta.setWrapStyleWord(true);
    ta.setLineWrap(true);

    scrollPane.setViewportView(ta);

    pnl.add(scrollPane);

    pnl.setOpaque(false);
    return pnl;
}

Transparent scroll pane and text area

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • YAY! Thanks again (MadProgrammer to the rescue!!!). The swing library has so many methods I have to learn, geez :) – Fiddle Freak Apr 21 '17 at 00:45
  • Sorry to bother you again, it looks like it is not showing through the JScrollPane. Should I open this up as a new question? – Fiddle Freak Apr 21 '17 at 00:58
  • @FiddleFreak That's more complicated, see [this](http://stackoverflow.com/questions/15422854/jscrollpane-with-transparent-background-and-content/15423000#15423000) and [this](http://stackoverflow.com/questions/30339103/transparent-jlist-in-jscrollpane-all-in-one-class/30339125#30339125) for more details – MadProgrammer Apr 21 '17 at 01:01
  • I think the best solution was to have the image set as it's own background in scrollpane `JScrollPane scrollPane = new JScrollPane(backgroundFrame);`. Then add the panel inside of the scroll pane with the following lines `scrollPane.setOpaque(false);`, `scrollPane.getViewport().setOpaque(false);`, and `scrollPane.getViewport().setView(topFrame);`. I'm not sure if this was the best way to do it, but it's showing exactly how I want it. – Fiddle Freak Apr 21 '17 at 01:27
  • If you wrap the `backgroundFrame` in the scrollpane, then you don't need to set it as transparent. Call `setView` will replace the `backgroundFrame` with the `topFrame` ... so not really working as you might expect. The solution will depend on what you hope to achieve – MadProgrammer Apr 21 '17 at 01:30
  • [Here's another example](http://stackoverflow.com/questions/13677850/add-background-image-in-jtable/13678077#13678077), which either makes the component responsible for managing the background, which allows it to scroll, or the `JViewport` to make it sticky, but in you case, just make the `JScrollPane` (and `viewport`) transparent and adding it to the current container will do the same thing – MadProgrammer Apr 21 '17 at 01:33
  • Yeah, I think removing the extra panel and just transferring all the settings to the scroll pane is the better call. – Fiddle Freak Apr 21 '17 at 03:30
  • Actually nevermind, I can't use GridBagLayout with JScrollPane. So I'll just stick with JPanel inside the JScrollPane. – Fiddle Freak Apr 21 '17 at 03:36