如何在 JPanel 中设置背景图片

Posted

技术标签:

【中文标题】如何在 JPanel 中设置背景图片【英文标题】:How to set a background picture in JPanel 【发布时间】:2014-04-05 10:10:38 【问题描述】:

你好,我正在使用 JPanel 作为我框架的容器,然后我真的想在我的面板中使用背景图片我真的需要帮助这是我到目前为止的代码。这是更新请检查这里是我的代码现在

 import java.awt.*;
import javax.swing.*;
import java.awt.event.*;


public class imagebut extends JFrame


public static void main(String args [])

    imagebut w = new imagebut();
    w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    w.setSize(300,300);
    w.setVisible(true);


public imagebut()
   

    setLayout(null); // :-)
    PicPanel mainPanel = new PicPanel("picturename.jpg");
    mainPanel.setBounds(0,0,500,500);
    add(mainPanel);




class PicPanel extends JPanel

    private BufferedImage image;
    private int w,h;
    public PicPanel(String fname)

        //reads the image
        try 
            image = ImageIO.read(new File(fname));
            w = image.getWidth();
            h = image.getHeight();

         catch (IOException ioe) 
            System.out.println("Could not read in the pic");
            //System.exit(0);
        

    

    public Dimension getPreferredSize() 
        return new Dimension(w,h);
    
    //this will draw the image
    public void paintComponent(Graphics g)
        super.paintComponent(g);
        g.drawImage(image,0,0,this);
    



【问题讨论】:

picturename.jpg 位于何处?您不能简单地复制和粘贴代码并期望它能够工作,您需要进行一些修改以满足您的需求 我创建了图片名称.jpg 然后我把我的 src 文件夹里面 ImageIO.read(new File(fname)) 正在执行程序的当前目录中查找文件,您已将图像嵌入为嵌入资源,它们需要以不同方式加载。尝试改用ImageIO.read(getClass().getResource("/picturename.jpg")) 之类的东西(假设picturename.jpgsrc 的根)。另外,不要使用null 布局,它们会回来在你的后端留下齿痕 我需要使用什么 if 而不是 null ? 对于您粘贴的(新)示例,去掉 setLayout(null);,去掉 mainPanel.setBounds(0,0,500,500);add(mainPanel); 并简单地使用 setContentPane(mainPanel) 【参考方案1】:

有很多方法可以实现。

你可以...

免责声明

Cavet,为此使用 JLabel 可能会导致内容溢出容器,请参阅下文了解更多详情

创建一个JLabel,将图像应用到它的icon 属性并将其设置为框架内容窗格。然后您需要适当地设置布局管理器,因为JLabel 没有默认布局管理器

JFrame frame = ...;
JLabel background = new JLabel(new ImageIcon(ImageIO.read(...)));
frame.setContentPane(background);
frame.setLayout(...);
frame.add(...);

更新完整示例

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class LabelBackground 

    public static void main(String[] args) 
        new LabelBackground();
    

    public LabelBackground() 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                try 
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                 catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) 
                

                try 
                    // Load the background image
                    BufferedImage img = ImageIO.read(new File("/path/to/your/image/on/disk"));

                    // Create the frame...
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                    // Set the frames content pane to use a JLabel
                    // whose icon property has been set to use the image
                    // we just loaded                        
                    frame.setContentPane(new JLabel(new ImageIcon(img)));
                    
                    // Supply a layout manager for the body of the content
                    frame.setLayout(new GridBagLayout());
                    GridBagConstraints gbc = new GridBagConstraints();
                    gbc.gridwidth = GridBagConstraints.REMAINDER;
                    // Add stuff...
                    frame.add(new JLabel("Hello world"), gbc);
                    frame.add(new JLabel("I'm on top"), gbc);
                    frame.add(new JButton("Clickity-clackity"), gbc);

                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                 catch (IOException exp) 
                    exp.printStackTrace();
                
            
        );
    

问题在于 JLabel 在调整框架大小时不会调整图像大小

警告 - 如果子组件的所需空间超过背景图像的大小,使用 JLabel 可能会导致问题,因为 JLabel 不会根据其内容计算其首选大小,而是基于在其 icontext 属性上

你可以...

创建一个自定义组件,从 JPanel 之类的东西扩展并覆盖它的 paintComponent 方法,按照您认为合适的方式绘制背景。

查看Performing Custom Painting了解更多详情。

这使您能够决定在可用空间发生变化时图像的最佳缩放方式。虽然有多种方法可以实现这一目标,但您应该通读 The Perils of Image.getScaledInstance() 以了解它们的优缺点。

这引发了一系列新问题,您想缩放它们并保持纵横比吗?如果是这样,您是要让图像适合可用区域还是填充它(这样它总是会覆盖可用空间)?

查看Java: maintaining aspect ratio of JPanel background image了解更多详情。

其他注意事项

图像通常最好通过ImageIO API 加载,因为它能够加载范围广泛的图像,但在出现问题时也会抛出IOException

更多详情请见Reading/Loading an Image。

图片的位置也很重要。如果图像在应用程序外部(文件系统上的某个位置),您可以使用ImageIO.read(new File("/path/to/image"))。但是,如果图像嵌入在您的应用程序中(例如存储在 Jar 中),您将需要使用更像 ImageIO.read(getClass().getResource("/path/to/image")) 的东西...

例如...

Trouble Figuring Out How To Set Background Image Add an Background image to a Panel Java: JPanel background not scaling

示例

本示例演示了如何使用自定义组件作为背景组件。当组件大小超过背景图像的大小时,图像会按比例放大以填充可用的内容区域。

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SimpleBackground 

    public static void main(String[] args) 
        new SimpleBackground();
    

    public SimpleBackground() 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                try 
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                 catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) 
                

                try 
                    BackgroundPane background = new BackgroundPane();
                    background.setBackground(ImageIO.read(new File("/path/to/your/image/on/your/disk")));

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setContentPane(background);
                    frame.setLayout(new GridBagLayout());
                    GridBagConstraints gbc = new GridBagConstraints();
                    gbc.gridwidth = GridBagConstraints.REMAINDER;
                    frame.add(new JLabel("Hello world"), gbc);
                    frame.add(new JLabel("I'm on top"), gbc);
                    frame.add(new JButton("Clickity-clackity"), gbc);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                 catch (IOException exp) 
                    exp.printStackTrace();
                
            
        );
    

    public class BackgroundPane extends JPanel 

        private BufferedImage img;
        private BufferedImage scaled;

        public BackgroundPane() 
        

        @Override
        public Dimension getPreferredSize() 
            return img == null ? super.getPreferredSize() : new Dimension(img.getWidth(), img.getHeight());
        

        public void setBackground(BufferedImage value) 
            if (value != img) 
                this.img = value;
                repaint();
            
        

        @Override
        public void invalidate() 
            super.invalidate();
            if (getWidth() > img.getWidth() || getHeight() > img.getHeight()) 
                scaled = getScaledInstanceToFill(img, getSize());
             else 
                scaled = img;
            
        

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

    

    public static BufferedImage getScaledInstanceToFill(BufferedImage img, Dimension size) 

        double scaleFactor = getScaleFactorToFill(img, size);

        return getScaledInstance(img, scaleFactor);

    

    public static double getScaleFactorToFill(BufferedImage img, Dimension size) 

        double dScale = 1;

        if (img != null) 

            int imageWidth = img.getWidth();
            int imageHeight = img.getHeight();

            double dScaleWidth = getScaleFactor(imageWidth, size.width);
            double dScaleHeight = getScaleFactor(imageHeight, size.height);

            dScale = Math.max(dScaleHeight, dScaleWidth);

        

        return dScale;

    

    public static double getScaleFactor(int iMasterSize, int iTargetSize) 

        double dScale = (double) iTargetSize / (double) iMasterSize;

        return dScale;

    

    public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) 

        return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);

    

    protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) 

        BufferedImage imgScale = img;

        int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
        int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);

//        System.out.println("Scale Size = " + iImageWidth + "x" + iImageHeight);
        if (dScaleFactor <= 1.0d) 

            imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);

         else 

            imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);

        

        return imgScale;

    

    protected static BufferedImage getScaledDownInstance(BufferedImage img,
            int targetWidth,
            int targetHeight,
            Object hint,
            boolean higherQuality) 

        int type = (img.getTransparency() == Transparency.OPAQUE)
                ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

        BufferedImage ret = (BufferedImage) img;
        if (targetHeight > 0 || targetWidth > 0) 
            int w, h;
            if (higherQuality) 
                // Use multi-step technique: start with original size, then
                // scale down in multiple passes with drawImage()
                // until the target size is reached
                w = img.getWidth();
                h = img.getHeight();
             else 
                // Use one-step technique: scale directly from original
                // size to target size with a single drawImage() call
                w = targetWidth;
                h = targetHeight;
            

            do 
                if (higherQuality && w > targetWidth) 
                    w /= 2;
                    if (w < targetWidth) 
                        w = targetWidth;
                    
                

                if (higherQuality && h > targetHeight) 
                    h /= 2;
                    if (h < targetHeight) 
                        h = targetHeight;
                    
                

                BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
                Graphics2D g2 = tmp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                g2.drawImage(ret, 0, 0, w, h, null);
                g2.dispose();

                ret = tmp;
             while (w != targetWidth || h != targetHeight);
         else 
            ret = new BufferedImage(1, 1, type);
        
        return ret;
    

    protected static BufferedImage getScaledUpInstance(BufferedImage img,
            int targetWidth,
            int targetHeight,
            Object hint,
            boolean higherQuality) 

        int type = BufferedImage.TYPE_INT_ARGB;

        BufferedImage ret = (BufferedImage) img;
        int w, h;
        if (higherQuality) 
            // Use multi-step technique: start with original size, then
            // scale down in multiple passes with drawImage()
            // until the target size is reached
            w = img.getWidth();
            h = img.getHeight();
         else 
            // Use one-step technique: scale directly from original
            // size to target size with a single drawImage() call
            w = targetWidth;
            h = targetHeight;
        

        do 
            if (higherQuality && w < targetWidth) 
                w *= 2;
                if (w > targetWidth) 
                    w = targetWidth;
                
            

            if (higherQuality && h < targetHeight) 
                h *= 2;
                if (h > targetHeight) 
                    h = targetHeight;
                
            

            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();

            ret = tmp;
            tmp = null;

         while (w != targetWidth || h != targetHeight);
        return ret;
    


当空间减小时,将图像也缩小是一件简单的事情,但我故意决定将图像保持在最小尺寸。

该示例还使用自定义分而治之的缩放算法来生成高质量的缩放结果。

【讨论】:

【参考方案2】:
import java.awt.*;

import javax.imageio.ImageIO;
import javax.swing.*;

import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;


public class imagebut extends JFrame


public static void main(String args [])

imagebut w = new imagebut();
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
w.setSize(300,300);
w.setVisible(true);


 public imagebut()
   

setLayout(null); // :-)
PicPanel mainPanel = new PicPanel("picturename.jpg");
mainPanel.setBounds(0,0,500,500);
add(mainPanel);


  

 class PicPanel extends JPanel

private BufferedImage image;
private int w,h;
public PicPanel(String fname)

    //reads the image
    try 
        image = ImageIO.read(getClass().getResource(fname));
        w = image.getWidth();
        h = image.getHeight();

     catch (IOException ioe) 
        System.out.println("Could not read in the pic");
        //System.exit(0);
    



public Dimension getPreferredSize() 
    return new Dimension(w,h);

//this will draw the image
public void paintComponent(Graphics g)
    super.paintComponent(g);
    g.drawImage(image,0,0,this);



 

【讨论】:

如何在我的 JPanel 中直接添加背景,在我的代码中声明例如 ping.setBackground(Color.RED);我可以设置,但只能设置颜色。所以我需要它是一张类似的照片。 将上面的代码粘贴到你的 imagebut 类中。然后制作一个 PicPanel。 PicPanel p = new PicPanel(pictureNameHere);然后添加面板。 我已经用你的代码更新了我的答案,让事情变得更容易。 ImageIO,IOexception,BufferedImage 先生出现错误 null 布局在现代 UI 中非常不推荐,最好依赖布局管理器 API 和框架的 pack 方法。【参考方案3】:
JPanel ping = new JPanel()

@Override
    protected void paintComponent(Graphics g) 
        super.paintComponent(g);

//draw hare what ever you want and it will be in the back of your components
   
;

【讨论】:

当你让新面板覆盖 paintComponent() 方法时,这是在面板上绘制的方法,在 g.drawImage(background, 0, 0, this.getWidth(), this.getHeight(), null);

以上是关于如何在 JPanel 中设置背景图片的主要内容,如果未能解决你的问题,请参考以下文章

Java在窗口中设置背景图片

如何在 reactjs 中设置背景图片?

如何在颤动中设置背景图像?

如何在 React-Native 中设置 DrawerNavigator 的背景图片?

如何在 loadView 中设置背景颜色?

在 GroupLayout 中设置 JPanel 的大小