Java Swing的JLayeredPane未显示CardLayout的卡片和背景图像。

huangapple go评论65阅读模式
英文:

Java Swing JLayeredPane not showing CardLayout cards & background image

问题

I've translated the provided code for you. Here's the translated code:

Window.java:

public class Window extends JFrame {
    JPanel cards;
    JLayeredPane layeredPane;

    JPanel openPokédex = new OpenPokédexPanel();

    public Window() {
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                dispose();
            }
        });

        this.setSize(800, 600);

        layeredPane = new JLayeredPane();
        this.setContentPane(layeredPane);

        BackgroundImage background = new BackgroundImage();
        layeredPane.add(background, Integer.valueOf(0));

        cards = new JPanel(new CardLayout());
        layeredPane.add(cards, Integer.valueOf(1));

        cards.add(openPokédex, "openPokedex");

        Navbar bar = new Navbar(cards, this);
        this.setJMenuBar(bar);

        this.setVisible(true);
    }

    public void switchPanel(String panelName) {
        CardLayout cardLayout = (CardLayout) cards.getLayout();
        cardLayout.show(cards, panelName);
        System.out.println(panelName);
    }
}

Navbar.java:

public class Navbar extends JMenuBar {
    JPanel cards;
    Window window;

    public Navbar(JPanel cards, Window window) {
        this.cards = cards;
        this.window = window;

        JMenu pokedex = new JMenu("Pokédex");
        JMenuItem openPokedex = new JMenuItem("Open");
        pokedex.add(openPokedex);

        this.add(pokedex);

        // Events
        openPokedex.addActionListener(e -> window.switchPanel("openPokedex"));
    }
}

OpenPokédexPanel.java:

public class OpenPokédexPanel extends JPanel {

    OpenPokédexPanel() {
        // tried doing transparent background but made no difference
        // this.setOpaque(false);
        // this.setBackground(new Color(255, 255, 255, 0));

        // pretty much irrelevant. just to see if the panel is actually there
        JButton pokémonButton = new JButton("Pokémon");
        this.add(pokémonButton);
    }
}

BackgroundImage.java:

public class BackgroundImage extends JComponent {
    BufferedImage image = null;

    public BackgroundImage() {
        File bgimage = null;

        File directory = new File("src/bin/");

        if (directory.isDirectory()) {
            File[] files = directory.listFiles();

            if (files != null && files.length > 0) {
                Random rng = new Random();
                File randomFile = files[rng.nextInt(files.length)];
                bgimage = randomFile;

            } else {
                System.out.println("No images!");
            }
        } else {
            System.out.println("Not a directory!");
        }

        try {
            image = ImageIO.read(bgimage);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null) {
            g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
        }
    }
}

I hope this helps you with your project!

英文:

I'm using Java 17 for a little project. I'm doing the Layout with the AWT CardLayout and the graphical components with Swing.

I want to change my currently active JPanel in Window.java whenever I click on one of the JMenuBarItems inside my Navbar.java class but show my background image from my BackgroundImage class all the time by using a JLayeredPane.

Window.java:

public class Window extends JFrame {
JPanel cards;
JLayeredPane layeredPane;

JPanel openPokédex = new OpenPokédexPanel();

public Window() {
addWindowListener(new WindowAdapter() {
    public void windowClosing (WindowEvent e) {
	dispose();
    }
});

this.setSize(800, 600);

layeredPane = new JLayeredPane();
this.setContentPane(layeredPane);

BackgroundImage background = new BackgroundImage();
layeredPane.add(background, Integer.valueOf(0));

cards = new JPanel(new CardLayout());
layeredPane.add(cards, Integer.valueOf(1));

cards.add(openPokédex, "openPokedex");

Navbar bar = new Navbar(cards, this);
this.setJMenuBar(bar);

this.setVisible(true);
}

public void switchPanel(String panelName) {
    CardLayout cardLayout = (CardLayout) cards.getLayout();
    cardLayout.show(cards, panelName);
    System.out.println(panelName);
}
}

Navbar.java:

public class Navbar extends JMenuBar{
JPanel cards;
Window window;

public Navbar(JPanel cards, Window window) {
this.cards = cards;
this.window = window;

JMenu pokedex = new JMenu("Pokédex");
JMenuItem openPokedex = new JMenuItem("Open");
pokedex.add(openPokedex);

this.add(pokedex);

// Events
openPokedex.addActionListener(e -> window.switchPanel("openPokedex"));
}
}

OpenPokédexPanel.java:

public class OpenPokédexPanel extends JPanel {

OpenPokédexPanel() {
// tried doing transparent background but made no difference
//this.setOpaque(false);
//this.setBackground(new Color(255, 255, 255, 0));

// pretty much irrelevant. just to see if the panel is actually there
JButton pokémonButton = new JButton("Pokémon");
this.add(pokémonButton);
}
}

BackgroundImage.java:

public class BackgroundImage extends JComponent {
BufferedImage image = null;

public BackgroundImage() {
File bgimage = null;

File directory = new File("src/bin/");

if (directory.isDirectory()) {
    File[] files = directory.listFiles();
    
    if (files != null && files.length > 0) {
	Random rng = new Random();
	File randomFile = files[rng.nextInt(files.length)];
	bgimage = randomFile;
	
    } else {
	System.out.println("No images!");
    }
} else {
    System.out.println("Not a directory!");
}

try {
    image = ImageIO.read(bgimage);
} catch (IOException e) {
    e.printStackTrace();
}
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
    g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}
}

Before trying to combine the BackgroudImage with the CardLayout, the background image worked fine but the JPanels weren't showing up because they apparently spawned behind my background image. I want to have a permanent background with JPanel displaying content on top.
At the moment it only shows a white screen when starting the program

EDIT 1

I modified OpenPokédexPanel JPanel class:

public class OpenPokédexPanel extends JPanel {

OpenPokédexPanel() {

this.setOpaque(false); // added this again
//this.setBackground(new Color(255, 255, 255, 0));

JButton pokémonButton = new JButton("Pokémon");
this.add(pokémonButton);
}
}

and I modified the main Window class. I removed the JLayeredPane and added the following code as @camickr suggested:

BackgroundImage background = new BackgroundImage();
this.setLayout(new BorderLayout());
this.setContentPane(background);

cards = new JPanel(new CardLayout());
cards.setOpaque(false);
background.add(cards);

cards.add(openPokédex, "openPokedex");

The background image shows up but the JPanel card openPokédex won't show up as well on click.

答案1

得分: 3

Swing有父子关系。您将拥有如下结构:

  • 框架
    • BackgroundImage(使用BorderLayout)作为内容面板
      • 非透明面板(使用CardLayout)
        • 非透明面板
        • 非透明面板

基本解决方案是:

JPanel background = new BackgroundImage();
background.setBackground( Color.YELLOW );
background.setLayout( new BorderLayout() );
frame.setContentPane( background );

JPanel cards = new JPanel( new CardLayout() );
cards.setOpaque( false );
background.add( cards );

JPanel card1 = new JPanel();
card1.add( new JLabel("第一个卡片的标签") );
card1.setOpaque( false );
cards.add(card1, "card1");

JPanel card2 = new JPanel();
card2.add( new JLabel("第二个卡片的标签") );
card2.setOpaque( false );
cards.add(card2, "card2");

首先让上述代码工作,这样您将看到面板的背景颜色和其中一个卡片的显示。如果您遇到问题,可以发布您的代码,显示您已经完成了什么。一旦这样做成功,然后您可以将基本组件替换为您的自定义组件。如果它停止工作,您就知道您刚刚更改了什么。

英文:

Swing has a parent/child relationship. You would have a structure like:

  • frame
    • BackgroundImage (using BorderLayout) as the content pane
      • non opaque panel (using CardLayout)
        • non opaque panel
        • non opaque panel

Basic solution is:

JPanel background = new BackgroundImage();
background.setBackground( Color.YELLOW );
background.setLayout( new BorderLayout() );
frame.setContentPane( background );

JPanel cards = new JPanel( new CardLayout() );
cards.setOpaque( false );
background.add( cards );

JPanel card1 = new JPanel();
card1.add( new JLabel("Label for first card") );
card1.setOpaque( false );
cards.add(card1, "card1");

JPanel card2 = new JPanel();
card2.add( new JLabel("Label for second card") );
card2.setOpaque( false );
cards.add(card2, "card2");

So first get the above code working so you see the background color of your panel and one of the cards displaying. If you have problems then you can post your code showing exactly what you have done. Once that works, then you replace the basic components with your custom components. If it stops working you know what you just changed.

答案2

得分: 2

Here's the translated code without the code comments:

如果您想以这种方式使用`JLayeredPane`,那么您需要为其应用合适的布局管理器例如...

```java
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Navigatable {
        enum View {
            MENU, CONTENT;
        }
        public void show(View view);
    }

    public class MainPane extends JPanel implements Navigatable {

        private JLayeredPane layeredPane;

        private JPanel contentPane;
        private CardLayout cardLayout;

        private MenuPane menuPane;

        public MainPane() {
            setLayout(new BorderLayout());

            layeredPane = new JLayeredPane();
            add(layeredPane);

            layeredPane.setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1;
            gbc.weighty = 1;
            gbc.fill = GridBagConstraints.BOTH;

            BackgroundPane backgroundPane = new BackgroundPane();
            layeredPane.add(backgroundPane, gbc);
            layeredPane.setLayer(backgroundPane, Integer.valueOf(0));

            cardLayout = new CardLayout();
            contentPane = new JPanel(cardLayout);
            contentPane.setOpaque(false);

            layeredPane.add(contentPane, gbc);
            layeredPane.setLayer(contentPane, Integer.valueOf(1));

            contentPane.add(new MenuPane(this), Navigatable.View.MENU.name());
            JLabel label = new JLabel("This is the content");
            label.setHorizontalAlignment(JLabel.CENTER);
            contentPane.add(label, Navigatable.View.CONTENT.name());
        }

        @Override
        public void show(View view) {
            cardLayout.show(contentPane, view.name());
        }
    }

    public class MenuPane extends JPanel {
        public MenuPane(Navigatable navigatable) {
            setOpaque(false);
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(32, 32, 32, 32));

            JButton btn = new JButton("Show me the content");
            add(btn);

            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    navigatable.show(Navigatable.View.CONTENT);
                }
            });
        }       
    }

    public class BackgroundPane extends JPanel {

        private BufferedImage bgImage;

        public BackgroundPane() {
            try {
                bgImage = ImageIO.read(getClass().getResource("/images/Mando01-50.png"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            if (bgImage != null) {
                return new Dimension(bgImage.getWidth(), bgImage.getHeight());
            }
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (bgImage == null) {
                return;
            }
            int x = (getWidth() - bgImage.getWidth()) / 2;
            int y = (getHeight() - bgImage.getHeight()) / 2;
            g.drawImage(bgImage, x, y, this);
        }
    }
}

但是,一种更好的解决方案可能是直接使用背景窗格,例如...

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Navigatable {
        enum View {
            MENU, CONTENT;
        }
        public void show(View view);
    }

    public class MainPane extends JPanel implements Navigatable {

        private BackgroundPane backgroundPane;
        private CardLayout cardLayout;

        private MenuPane menuPane;

        public MainPane() {
            setLayout(new BorderLayout());

            cardLayout = new CardLayout();
            backgroundPane = new BackgroundPane();
            backgroundPane.setLayout(cardLayout);
            add(backgroundPane);

            backgroundPane.add(new MenuPane(this), Navigatable.View.MENU.name());
            JLabel label = new JLabel("This is the content");
            label.setHorizontalAlignment(JLabel.CENTER);
            backgroundPane.add(label, Navigatable.View.CONTENT.name());
        }

        @Override
        public void show(View view) {
            cardLayout.show(backgroundPane, view.name());
        }
    }

    public class MenuPane extends JPanel {
        public MenuPane(Navigatable navigatable) {
            setOpaque(false);
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(32, 32, 32, 32));

            JButton btn = new JButton("Show me the content");
            add(btn);

            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    navigatable.show(Navigatable.View.CONTENT);
                }
            });
        }       
    }

    public class BackgroundPane extends JPanel {

        private BufferedImage bgImage;

        public BackgroundPane() {
            try {
                bgImage = ImageIO.read(getClass().getResource("/images/Mando01-50.png"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            if (bgImage != null) {
                return new Dimension(bgImage.getWidth(), bgImage.getHeight());
            }
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (bgImage == null) {
                return;
            }
            int x = (getWidth() - bgImage.getWidth()) / 2;
            int y = (getHeight() - bgImage.getHeight()) / 2;
            g.drawImage(bgImage, x, y, this);
        }
    }
}
英文:

If you want to use JLayeredPane this way, then you will need to apply a suitable layout manager to it, for example...

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Navigatable {
enum View {
MENU, CONTENT;
}
public void show(View view);
}
public class MainPane extends JPanel implements Navigatable {
private JLayeredPane layeredPane;
private JPanel contentPane;
private CardLayout cardLayout;
private MenuPane menuPane;
public MainPane() {
setLayout(new BorderLayout());
layeredPane = new JLayeredPane();
add(layeredPane);
layeredPane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
BackgroundPane backgroundPane = new BackgroundPane();
layeredPane.add(backgroundPane, gbc);
layeredPane.setLayer(backgroundPane, Integer.valueOf(0));
cardLayout = new CardLayout();
contentPane = new JPanel(cardLayout);
contentPane.setOpaque(false);
layeredPane.add(contentPane, gbc);
layeredPane.setLayer(contentPane, Integer.valueOf(1));
contentPane.add(new MenuPane(this), Navigatable.View.MENU.name());
JLabel label = new JLabel("This is the content");
label.setHorizontalAlignment(JLabel.CENTER);
contentPane.add(label, Navigatable.View.CONTENT.name());
}
@Override
public void show(View view) {
cardLayout.show(contentPane, view.name());
}
}
public class MenuPane extends JPanel {
public MenuPane(Navigatable navigatable) {
setOpaque(false);
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(32, 32, 32, 32));
JButton btn = new JButton("Show me the content");
add(btn);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
navigatable.show(Navigatable.View.CONTENT);
}
});
}       
}
public class BackgroundPane extends JPanel {
private BufferedImage bgImage;
public BackgroundPane() {
try {
bgImage = ImageIO.read(getClass().getResource("/images/Mando01-50.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
if (bgImage != null) {
return new Dimension(bgImage.getWidth(), bgImage.getHeight());
}
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bgImage == null) {
return;
}
int x = (getWidth() - bgImage.getWidth()) / 2;
int y = (getHeight() - bgImage.getHeight()) / 2;
g.drawImage(bgImage, x, y, this);
}
}
}

But, a generally better solution would probably be to make use of the background pane directly, for example...

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Navigatable {
enum View {
MENU, CONTENT;
}
public void show(View view);
}
public class MainPane extends JPanel implements Navigatable {
private BackgroundPane backgroundPane;
private CardLayout cardLayout;
private MenuPane menuPane;
public MainPane() {
setLayout(new BorderLayout());
cardLayout = new CardLayout();
backgroundPane = new BackgroundPane();
backgroundPane.setLayout(cardLayout);
add(backgroundPane);
backgroundPane.add(new MenuPane(this), Navigatable.View.MENU.name());
JLabel label = new JLabel("This is the content");
label.setHorizontalAlignment(JLabel.CENTER);
backgroundPane.add(label, Navigatable.View.CONTENT.name());
}
@Override
public void show(View view) {
cardLayout.show(backgroundPane, view.name());
}
}
public class MenuPane extends JPanel {
public MenuPane(Navigatable navigatable) {
setOpaque(false);
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(32, 32, 32, 32));
JButton btn = new JButton("Show me the content");
add(btn);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
navigatable.show(Navigatable.View.CONTENT);
}
});
}       
}
public class BackgroundPane extends JPanel {
private BufferedImage bgImage;
public BackgroundPane() {
try {
bgImage = ImageIO.read(getClass().getResource("/images/Mando01-50.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
if (bgImage != null) {
return new Dimension(bgImage.getWidth(), bgImage.getHeight());
}
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bgImage == null) {
return;
}
int x = (getWidth() - bgImage.getWidth()) / 2;
int y = (getHeight() - bgImage.getHeight()) / 2;
g.drawImage(bgImage, x, y, this);
}
}
}

huangapple
  • 本文由 发表于 2023年5月22日 08:42:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76302467.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定