英文:
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 JMenuBarItem
s 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 JPanel
s 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)
- 非透明面板
- 非透明面板
- 非透明面板(使用CardLayout)
- BackgroundImage(使用BorderLayout)作为内容面板
基本解决方案是:
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
- non opaque panel (using CardLayout)
- BackgroundImage (using BorderLayout) as the content pane
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);
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论