代码之家  ›  专栏  ›  技术社区  ›  fullstacknoob

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

  •  0
  • fullstacknoob  · 技术社区  · 3 年前

    我正在为一个小项目使用Java17。我正在用AWT做布局 CardLayout 以及Swing的图形组件。

    我想更改我当前的活动 JPanel 在里面 Window.java 每当我点击其中一个 JMenuBarItem 在我的里面 Navbar.java 类,但显示我的背景图像 BackgroundImage 一直使用 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"));
    }
    }
    

    OpenPokdexPanel.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);
    }
    }
    

    背景图片.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);
    }
    }
    }
    

    在尝试组合之前 BackgroudImage 卡片布局管理器 ,背景图像运行良好,但 面板 s没有出现,因为它们显然是在我的背景图像后面产生的。我想有一个永久的背景 面板 在顶部显示内容。 目前,启动程序时只显示白色屏幕

    编辑1

    我修改了 OpenPokédexPanel JPanel类:

    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);
    }
    }
    

    我修改了主 Window 班我删除了 J分层窗格 并按照@camicker的建议添加了以下代码:

    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");
    

    背景图像显示,但 面板 卡片 openPokédex 不会在点击时也显示出来。

    2 回复  |  直到 3 年前
        1
  •  3
  •   camickr    3 年前

    Swing具有父/子关系。你会有这样的结构:

    • 框架
      • 背景图像(使用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("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");
    

    因此,首先让上面的代码发挥作用,这样你就可以看到你的面板和其中一张卡片的背景色。如果你有问题,那么你可以发布你的代码,准确地显示你所做的事情。一旦成功,就可以用自定义组件替换基本组件。如果它停止工作,你就会知道你刚刚改变了什么。

        2
  •  2
  •   MadProgrammer    3 年前

    如果你想使用 JLayeredPane 这样,您将需要对其应用合适的布局管理器,例如。。。

    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);
            }
        }
    }