创建带有背景图像的表单 (JLayeredPane)

2022-01-24 00:00:00 java swing jframe jlayeredpane

我一直在努力做一些我认为很简单的事情:

I've been struggling to do something I guess pretty simple :

我想创建一个带有背景图像的表单 (JTextField).为了使表单不覆盖背景图像,我使用了 JLayeredPane.我一直在尝试不同的东西,但似乎没有任何效果:出于某种原因,我要么只显示背景,要么只显示 JTextField,但从不同时显示两者.我的目标是拥有一个永不改变的背景图像,并在其上使用我的按钮/文本字段.

I want to create a form (JTextField) with a background image. In order for the form not to cover the background Image, I'm using a JLayeredPane. I've been trying different stuff, nothing seems to work : for some reason, I'm either displaying only the background, or only the JTextField, but never both. My goal would be to have a background image that never changes, and just use my buttons / textfields on top of it.

package gestion;

import java.awt.*;

import javax.swing.*;

@SuppressWarnings("serial")
public class Main extends JFrame{
JLayeredPane layeredPane;
JPanel board;
JPanel background;


public Main(){
    super("Test");
    background = new JPanel();
    layeredPane = new JLayeredPane();
    board = new JPanel();

    // Creating frame with LayeredPane
    Dimension boardSize = new Dimension(1280, 1024);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setResizable(false);
    this.setSize(boardSize.width, boardSize.height);
    this.setVisible(true);
    this.setLocationRelativeTo(null);

    layeredPane.setPreferredSize( boardSize );
    this.add(layeredPane);


    // Add a background to the Layered Pane
    JLabel picLabel = new JLabel(new ImageIcon("background.jpg"));
    background.add(picLabel);
    background.setPreferredSize(boardSize);
    background.setBounds(0,0,boardSize.width, boardSize.height);
    layeredPane.add(background, JLayeredPane.DEFAULT_LAYER);

    // Add a JTextField
    final JTextField jtf = new JTextField("Default Value");

    Font police = new Font("Arial", Font.BOLD, 14);
    jtf.setFont(police);
    jtf.setPreferredSize(new Dimension(600, 800));
    background.setBounds(0,0,boardSize.width, boardSize.height);
    jtf.setForeground(Color.BLUE);

    board.add(jtf);
    layeredPane.add(board, JLayeredPane.PALETTE_LAYER);

}

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

}

似乎只出现了图像,并且由于某种原因(我最好的选择是黑魔法)JTextField 不存在.任何想法或帮助将不胜感激!谢谢!

Only the image seems to appear, and for some reason (My best bet is dark magic) the JTextField is not there. Any ideas or help would be greatly appreciated ! Thank you !

推荐答案

任何时候你依赖任何使用 null 布局的东西(比如 JLayeredPane),你都会运行进入问题.

Any time you rely on anything that uses a null layout (like JLayeredPane), you will run into issues.

你应该使用类似...

board.setBounds(new Rectangle(new Point(0, 0), board.getPreferredSize()));
layeredPane.add(board, JLayeredPane.PALETTE_LAYER);

设置board的大小和位置.

null 布局还有很多其他问题,这些问题只会让它们在代码中完全痛苦,最终浪费的时间比节省的时间多...

There are also a rafter of other issues with null layouts which just make them a complete pain in the code and end up wasting more time than they save...

坦率地说,一个更简单、更实用的解决方案是创建一个可以为您绘制背景图像的自定义组件,这样您就可以使用您需要的任何布局管理器,而不会遇到这些问题.在任何人跳到我身上之前,使用你可以"使用带有 JLayeredPane 的布局管理器,但这会引入更多问题,必须让组件重叠,以便背景层可以充当背景...只是更多的混乱

Frankly, a simpler and more usable solution would be to create a custom component which could paint the background image for you, this way, you can use what ever layout manager(s) you need and not suffer from these issues. Before anyone jumps all over me, use a you "can" use a layout manager with JLayeredPane, but this then introduces more issues with having to get components to overlap so the background layer can act as the background...just more of a mess

另外,在有人跳过我之前,您可以使用 JLabel 作为背景组件,在其上设置布局管理器并将您的组件添加到其中,但 JLabelcode> 不会根据它包含的子组件计算它所需的大小,而是使用 icontext 属性.如果您的背景图像足够大,这可能不是问题,但似乎总是一个等待突破的弱点.

Also, before anyone jumps all over me, you could use a JLabel as the background component, setting a layout manager on it and adding your components to it, but the JLabel doesn't calculate it's required size based on the child components it contains, but instead, uses the icon and text properties. This might not be an issue if your background image is sufficiently big enough, but always seems like a weak point waiting to break.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class Test {

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

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

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());
            BackgroundPane bgPane = new BackgroundPane();
            bgPane.setLayout(new GridBagLayout());
            add(bgPane);

            try {
                BufferedImage bg = ImageIO.read(new File("C:\Users\shane\Dropbox\MegaTokyo\thumnails\megatokyo_omnibus_1_3_cover_by_fredrin-d4oupef.jpg"));
                bgPane.setBackgroundImage(bg);
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            JLabel show = new JLabel("Bananas are yellow");
            show.setOpaque(true);
            show.setForeground(Color.RED);
            show.setBackground(Color.YELLOW);
            show.setBorder(new EmptyBorder(20, 20, 20, 20));
            bgPane.add(show);

        }

    }

    public class BackgroundPane extends JPanel {

        private BufferedImage img;

        @Override
        public Dimension getPreferredSize() {
            BufferedImage img = getBackgroundImage();

            Dimension size = super.getPreferredSize();
            if (img != null) {
                size.width = Math.max(size.width, img.getWidth());
                size.height = Math.max(size.height, img.getHeight());
            }

            return size;
        }

        public BufferedImage getBackgroundImage() {
            return img;
        }

        public void setBackgroundImage(BufferedImage value) {
            if (img != value) {
                BufferedImage old = img;
                img = value;
                firePropertyChange("background", old, img);
                revalidate();
                repaint();
            }
        }

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

    }

}

这个实现缺少像自动缩放或重复这样的东西,但你明白了

This implementation is missing things like auto scaling or repeating, but you get the idea

相关文章