背景 JSwing 图片加载异常

Background JSwing Image Loading Oddly

我似乎无法弄清楚如何在显示所有面板的情况下添加背景。

我尝试将 JFrame 内容窗格设置为带有 imageicon 的标签,并且框架确实显示了,只是没有像上面那样显示图像。

这是我用过的代码。

frame.setContentPane(new JLabel(new ImageIcon("res/Wallpaper.png")));

我使用的第二种尝试是将图像添加(未设置)到框架的内容窗格中。如上面第二张图片所示,这不起作用,它只显示面板但没有背景。代码在底部。

frame.getContentPane().add(new JLabel(new ImageIcon("res/Wallpaper.png")));

我尝试的第三次尝试是创建 JComponent 的子class 并覆盖 paintComponents 方法,然后将其对象设置为内容窗格。这不起作用,而是让我的屏幕变黑。

这是我使用的代码,class 代码在这个 link Setting background images in JFrame 的第一个答案中。结果就是这个post.

的第3张图
        File img = new File("res/Wallpaper.png");

    BufferedImage myImage;
    try {
        myImage = ImageIO.read(img);
        frame.setContentPane(new ImagePanel(myImage));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

我尝试的第四次尝试是将图片添加到填满屏幕的主面板中。这根本不起作用,而是将图像分成两半,因此屏幕的一半有图像,另一半没有。

这是我在第 4 次尝试中使用的代码。结果是顶部的倒数第 4 个图像。

        BufferedImage myPicture;
    try {
        myPicture = ImageIO.read(new File("res/Wallpaper.png"));
        JLabel picLabel = new JLabel(new ImageIcon(myPicture));
        pMain.add(picLabel);
    } catch (IOException e) {
        e.printStackTrace();
    }

我不确定为什么 JPanel 没有出现。

我知道在第一个示例中,当您将框架设置为 JLabel 时,它会为它提供空布局,但这是我能找到的显示图像的唯一方法。

我想以某种方式将面板添加到具有该背景的框架顶部,但在阅读了无数线程后我找不到如何做。

如果有人发现了,请 post 代码并在可能的情况下进行解释。我还有 class 获取系统 class 主题,将其设置为计算机正在使用的主题。前任。我使用的是 windows 操作系统,所以它显示的有点像我的操作系统。

此线程不是重复的。在其他线程中,它们只有一个框架,但在我的线程中,由于某些特定原因,我有几个面板没有显示。

编辑:我不知道怎么回事,我尝试使用这个线程 Setting background images in JFrame 但我没有运气。

我尝试了它给我的第一种方法,然后没有显示任何东西,它什么也没显示,没有图片,没有组件,什么都没有。如果您需要更多信息,我有:屏幕底部的 4 个 JPanel,我的 window 周围也有一个边框,但没有出现在第一个 window 中。我的面板周围也有边框。

所以我尝试在内容窗格中设置第一种方法,图像加载但所有组件都消失了。

第二种方法我试过将它添加到内容窗格中,但还是没有成功,我得到了一个没有背景的面板。

我试过的第三种方法是创建一个单独的 class 并覆盖 paintComponent 方法并将图像添加到它的构造函数然后将 class 的这个对象放入 setcontentPane()帧的参数。根本不起作用,我得到的只是一个空白框。

我在框架中使用的代码:

public class LoginScreen {

JCheckBox remember_User;
JButton login, create_Account, forums, faqs;
Border whiteLine;
JTextField userField;
JFormattedTextField passField;

private void createView() {
    // Created essential details for the frame
    JFrame frame = new JFrame();
    frame.setTitle("Name of the game");
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Defining panels and a constraint on the bottomPanel.
    // More info - Total amt of panels: 5
    // pLogin and pInfo are in the bottomCompPanel and bottomCompPanel is in
    // bottomPanel
    // bottom panel is in pMain
    // Giving panels some attributes like backgrounds and borders
    JPanel pMain = new JPanel(new BorderLayout());
    pMain.setBorder(BorderFactory.createMatteBorder(3, 3, 6, 3,
            Color.DARK_GRAY));
    frame.getContentPane().add(pMain);

    whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);

    JPanel pLogin = new JPanel(new GridBagLayout());
    pLogin.setBackground(Color.cyan);
    pLogin.setPreferredSize(new Dimension(400, 250));
    pLogin.setBorder(whiteLine);

    JPanel pInfo = new JPanel(new GridBagLayout());
    pInfo.setBackground(Color.green);
    pInfo.setPreferredSize(new Dimension(200, 100));
    pInfo.setBorder(whiteLine);

    JPanel bottomCompPanel = new JPanel(new GridBagLayout());
    GridBagConstraints bGBC = new GridBagConstraints();
    bGBC.gridx = 0;
    bGBC.gridy = 0;
    bGBC.insets = new Insets(0, 20, 0, 0);
    bGBC.anchor = GridBagConstraints.PAGE_END;

    bottomCompPanel.add(pLogin, bGBC);
    bGBC.gridx++;
    bottomCompPanel.add(pInfo, bGBC);

    JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));

    bottomPanel.add(bottomCompPanel);
    pMain.add(bottomPanel, BorderLayout.SOUTH);
    frame.setVisible(true);
}

public static void main(String[] args) {
    LoginScreen login = new LoginScreen();
    login.createView();
}

}

POST 更新 2:这是我使用 @peeskillet 的第一种方法使用的代码。它有点工作,但它给了我与第三张照片相同的结果,一张截断的照片。 P.S 我最后将底部的面板添加到我的 JLabel。

private void createView() {

    //Created essential details for the frame
    JFrame frame = new JFrame();
    frame.setTitle("Name of the game");
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);

    JLabel background = new JLabel(new ImageIcon("res/Wallpaper.png"));
    background.setLayout(new BorderLayout());
    frame.setContentPane(background);


    //Defining panels and a constraint on the bottomPanel. 
    //More info - Total amt of panels: 5
    //pLogin and pInfo are in the bottomCompPanel and bottomCompPanel is in bottomPanel
    //bottom panel is in pMain
    //Giving panels some attributes like backgrounds and borders

    whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);

    JPanel pLogin = new JPanel(new GridBagLayout());
    pLogin.setBackground(Color.cyan);
    pLogin.setPreferredSize(new Dimension(400,250));
    pLogin.setBorder(whiteLine);

    JPanel pInfo = new JPanel(new GridBagLayout());
    pInfo.setBackground(Color.green);
    pInfo.setPreferredSize(new Dimension(200,100));
    pInfo.setBorder(whiteLine);

    JPanel bottomCompPanel = new JPanel(new GridBagLayout());

    GridBagConstraints bGBC = new GridBagConstraints();
    bGBC.gridx = 0;
    bGBC.gridy = 0;
    bGBC.insets = new Insets(0,20,0,0);
    bGBC.anchor = GridBagConstraints.PAGE_END;

    bottomCompPanel.add(pLogin, bGBC);
    bGBC.gridx++;
    bottomCompPanel.add(pInfo, bGBC);

    JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));

    bottomPanel.add(bottomCompPanel);
    background.add(bottomPanel, BorderLayout.SOUTH);

您可以试试 JLayeredPane 和 setOpaque(boolean) 方法。
代码:

public class BackgroundImageTest{
    private JFrame frame;

    public BackgroundImageTest() {
        frame = new JFrame("Background Image Frame");

        // set frame properties

        JPanel panel = new JPanel(new FlowLayout());
        panel.setOpaque(false);
        JButton btn = new JButton("Change Background");
        panel.add(btn);

        btn.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae) {
                setBackgroundImage(getImage(new File("Wallpaper2.png")));
            }
        });

        JPanel main = (JPanel) frame.getContentPane();
        main.setLayout(new FlowLayout());
        main.add(panel);
        main.setOpaque(false);

        setBackgroundImage(getImage(new File("Wallpaper.png")));

        frame.setVisible(true);
    }

    private Image getImage(File imageFile) {
        BufferedImage image = null;

        try {
            image = ImageIO.read(imageFile);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return image;
    }

    private void setBackgroundImage(Image img) {
        if(img == null) return;

        ImageIcon ii = new ImageIcon(img);
        JLabel lblBG = new JLabel(ii);
        lblBG.setName("BackgroundImageLabel");

        JLayeredPane layeredPane = frame.getLayeredPane();

        Component[] comps = layeredPane.getComponentsInLayer(new Integer(Integer.MIN_VALUE));
        for (int i = 0; i < comps.length; i++) {
            System.out.println(comps[i].getName());

            if (comps[i] instanceof JLabel && comps[i].getName().equals("BackgroundImageLabel")){
                layeredPane.remove(comps[i]);
                break;
            }
        }

        layeredPane.add(lblBG, new Integer(Integer.MIN_VALUE));
        lblBG.setBounds(0,0,ii.getIconWidth(), ii.getIconHeight());
    }
}

"I tried to set the JFrame content pane as a label with an imageicon"

您需要在 JLabel 上设置布局。默认情况下将为空。

import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;

public class BackgroundImage {

    private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";

    private void init() throws Exception {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLabel background = new JLabel(new ImageIcon(new URL(IMG)));
        background.setLayout(new GridBagLayout());
        background.add(loginPanel());
        f.setContentPane(background);

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private JPanel loginPanel() {
        Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
        JPanel pLogin = new JPanel(new GridBagLayout());
        pLogin.setBackground(Color.cyan);
        pLogin.setPreferredSize(new Dimension(400, 250));
        pLogin.setBorder(whiteLine);
        return pLogin;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                new BackgroundImage().init();
            } catch (Exception ex) {}
        });
    }
}

"I've tried is to create a subclass of JComponent and Override the paintComponents method then setan object of it as the contentpane"

应该是paintComponent(不是"s"),但是就像JLabel一样,你需要设置布局。 JComponent 默认布局为空。绘画时还需要给它一个偏好的尺寸。

import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;

public class BackgroundImage {

    private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";

    private void init() throws Exception {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JComponent background = new BackgroundComponent(new ImageIcon(new URL(IMG)));
        background.setLayout(new GridBagLayout());
        background.add(loginPanel());
        f.setContentPane(background);

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private JPanel loginPanel() {
        Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
        JPanel pLogin = new JPanel(new GridBagLayout());
        pLogin.setBackground(Color.cyan);
        pLogin.setPreferredSize(new Dimension(400, 250));
        pLogin.setBorder(whiteLine);
        return pLogin;
    }

    class BackgroundComponent extends JComponent {
        public ImageIcon background;
        public BackgroundComponent(ImageIcon background) {
            this.background = background;
        }
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(background.getIconWidth(), background.getIconHeight());
        }
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(background.getImage(),
                        0, 0,
                        background.getIconWidth(), 
                        background.getIconHeight(), this);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                new BackgroundImage().init();
            } catch (Exception ex) {}
        });
    }
}

使用(扩展)JPanel 而不是 JComponent 会很相似,除了 JPanel 有默认布局 FlowLayout.


更新

要获得所需的布局,您需要使用不同的布局管理器。我使用的组合是

Outer (main panel)     -- BorderLayout
Bottom (bottom panel)  -- BoxLayout inside (south) of outer layout

对于 BorderLayout,您需要确保面板不透明 属性 设置为 false,因为 BorderLayout 会拉伸面板并覆盖背景。

对于 BoxLayout,您需要确保设置最大尺寸和首选尺寸

import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;

public class BackgroundImage {

    private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";
    private final Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);


    private void init() throws Exception {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JComponent background = new BackgroundComponent(new ImageIcon(new URL(IMG)));
        background.setLayout(new BorderLayout());
        background.add(bottomPanel(), BorderLayout.SOUTH);
        f.setContentPane(background);

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private JPanel bottomPanel() {
        JPanel bottomPanel = new JPanel();
        bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        BoxLayout layout = new BoxLayout(bottomPanel, BoxLayout.X_AXIS);
        bottomPanel.setLayout(layout);
        bottomPanel.setOpaque(false);
        bottomPanel.add(Box.createHorizontalGlue());
        bottomPanel.add(loginPanel());
        bottomPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        bottomPanel.add(infoPanel());
        return bottomPanel;
    }

    private JPanel infoPanel() {
        JPanel pInfo = new JPanel(new GridBagLayout());
        pInfo.setAlignmentY(Component.BOTTOM_ALIGNMENT);
        pInfo.setBackground(Color.green);
        pInfo.setMaximumSize(new Dimension(200, 100));
        pInfo.setPreferredSize(new Dimension(200, 100));
        pInfo.setBorder(whiteLine);
        return pInfo;
    }

    private JPanel loginPanel() {
        JPanel pLogin = new JPanel(new GridBagLayout());
        pLogin.setAlignmentY(Component.BOTTOM_ALIGNMENT);
        pLogin.setBackground(Color.cyan);
        pLogin.setPreferredSize(new Dimension(400, 250));
        pLogin.setMaximumSize(new Dimension(400, 250));
        pLogin.setBorder(whiteLine);
        return pLogin;
    }

    class BackgroundComponent extends JComponent {

        public ImageIcon background;

        public BackgroundComponent(ImageIcon background) {
            this.background = background;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(background.getIconWidth(), background.getIconHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(background.getImage(),
                    0, 0,
                    background.getIconWidth(),
                    background.getIconHeight(), this);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                new BackgroundImage().init();
            } catch (Exception ex) {
            }
        });
    }
}

有关使用不同布局管理器的详细信息,请参阅

  • Laying Out Components Within a Container