【问题标题】:JPanel background image doesn't apply to a JPanel inside itJPanel 背景图像不适用于其中的 JPanel
【发布时间】:2016-01-01 10:06:52
【问题描述】:

我正在开发一个简单的注册窗口,该窗口会在 Java 应用程序打开时出现。

这是一个JFrame,其中有一个JPanel,其中包含文本字段、标签和另一个面板,其中也包含文本字段和标签。 我的问题是外部面板有一个背景图像,但它不适用于其中的面板,如下所示:

这是整个窗口的代码:

public void start() {

    try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    frame = new JFrame("Chat");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //frame.setMaximumSize(new Dimension((int)screenSize.getWidth()-1000, (int)screenSize.getHeight()-1000));
    frame.setMinimumSize(new Dimension((int)screenSize.getWidth()/2-200,(int) screenSize.getHeight()/2));
    frame.setResizable(false);

        welcome = new LoginPanel();
        welcome.setLayout(new BoxLayout(welcome, BoxLayout.Y_AXIS));
        welcome.setBorder(BorderFactory.createEmptyBorder(50, welcome.getWidth()/2-500, 50, welcome.getWidth()/2 -500));

        //repaintThread = new Thread(new RepaintRunnable(frame, welcome));
        //repaintThread.start();


            request = new JLabel("Please fill the required fields below:");
            request.setFont(new Font("Serif", Font.BOLD, 20));
            request.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
            request.setAlignmentX(Component.CENTER_ALIGNMENT);

            userInfo = new JPanel();
            userInfo.setLayout(new BoxLayout(userInfo, BoxLayout.Y_AXIS));
            userInfo.setAlignmentX(Component.CENTER_ALIGNMENT);

                Font fieldType = new Font("Serif", Font.PLAIN, 15);

                PlainDocument doc = new PlainDocument();
                doc.setDocumentFilter(new NameDocument());

                enterFirstName = new JLabel("First name:");
                enterFirstName.setAlignmentX(Component.LEFT_ALIGNMENT);
                enterFirstName.setFont(fieldType);
                firstName = new JTextField(20);
                firstName.setMaximumSize(firstName.getPreferredSize());
                firstName.setDocument(NameDocument.getNewNameDocument(NameDocument.NO_SPACE));
                firstName.getDocument().addDocumentListener(new ChangeDocumentListener());
                firstName.addActionListener(new ConfirmListener());
                firstName.setAlignmentX(Component.LEFT_ALIGNMENT);

                enterSecName= new JLabel("Surname:");
                enterSecName.setAlignmentX(Component.LEFT_ALIGNMENT);
                enterSecName.setFont(fieldType);
                secName = new JTextField(30);
                secName.setMaximumSize(secName.getPreferredSize());
                secName.setDocument(NameDocument.getNewNameDocument(NameDocument.HAS_SPACE));
                secName.getDocument().addDocumentListener(new ChangeDocumentListener());
                secName.addActionListener(new ConfirmListener());
                secName.setAlignmentX(Component.LEFT_ALIGNMENT);

                enterNickname = new JLabel("Nickname (how other people will see you in chat):");
                enterNickname.setAlignmentX(Component.LEFT_ALIGNMENT);
                enterNickname.setFont(fieldType);
                nickname = new JTextField(30);
                nickname.setMaximumSize(nickname.getPreferredSize());
                nickname.setDocument(NameDocument.getNewNameDocument(NameDocument.NO_SPACE));
                nickname.addActionListener(new ConfirmListener());
                nickname.setAlignmentX(Component.LEFT_ALIGNMENT);

            userInfo.add(enterFirstName);
            userInfo.add(firstName);
            userInfo.add(enterSecName);
            userInfo.add(secName);
            userInfo.add(enterNickname);
            userInfo.add(nickname);

            confirm = new JButton("Submit");
            confirm.setAlignmentX(Component.CENTER_ALIGNMENT);
            confirm.setEnabled(false);
            confirm.addActionListener(new ConfirmListener());

        welcome.add(request);
        welcome.add(userInfo);
        welcome.add(new Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10)));
        welcome.add(confirm);

    frame.getContentPane().add(BorderLayout.CENTER, welcome);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
}

这里是 LoginPanel 代码(外部 JPanel):

public class LoginPanel extends JPanel {
public void paintComponent(Graphics g) {
    try {
        super.paintComponent(g);
        BufferedImage background = ImageIO.read(new File("Background.jpg"));
        g.drawImage(background, 0, 0, getWidth(), getHeight(), null);
    } catch(Exception ex) {
        ex.printStackTrace();
    }
}
}

如果有人能就如何让这段代码变得更好提供建议,那也太好了,因为我是 Java 初学者。

【问题讨论】:

  • 1) frame.setMinimumSize(new Dimension((int)screenSize.getWidth()/2-200,(int) screenSize.getHeight()/2)); 这只是基于对所需大小的猜测。添加所有组件后,我会改为调用frame.pack();,然后立即调用frame.setMinimumSize(frame.getSize()); 2) new Font("Serif", Font.PLAIN, 15); 最好是new Font(Font.SERIF, Font.PLAIN, 15); 以进行编译时检查。 3) g.drawImage(background, 0, 0, getWidth(), getHeight(), null); 最好是g.drawImage(background, 0, 0, getWidth(), getHeight(), this);(使用ImageObserver)。
  • @AndrewThompson 谢谢,我真的更需要这类建议。这是我第一次向懂java的人展示它,再次感谢。

标签: java image swing background jpanel


【解决方案1】:

记得在任何内部的 JPanel(以及其他一些组件——尽管不是全部)上调用setOpaque(false);,这些组件会覆盖您的图像显示 JPanel。这将允许背景图像显示出来。您不必对 JLabels 执行此操作,因为默认情况下它们是透明的(不透明),但您可以使用 JPanel。

所以对你来说它将是:

userInfo = new JPanel();
userInfo.setOpaque(false);

另一个问题是您应该永远不要从 paintComponent 方法中读取图像。这个方法可能会经常被调用,以及为什么在可以并且应该只读取一次的情况下重新读取图像。更重要的是,这种方法应该尽可能快,因为不必要地减慢它会减慢程序的感知响应速度。一次读取图像,并将其存储在一个变量中,然后在paintComponent中显示。

例如,

public class LoginPanel extends JPanel {
    private BufferedImage background;

    public LoginPanel(BufferedImage background) {
        this.background = background;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (background != null) {
            g.drawImage(background, 0, 0, getWidth(), getHeight(), this);
        }
    }
}

读入图像,然后将其传递给 LoginPanel 类的构造函数。

【讨论】:

  • @AndrewThompson:真的,真的。提醒我,不会在这里使用null 帮助吗?编辑:没关系,我看到你对 OP 的评论。
  • 该建议重新。对于 OP,drawImage 中的 null/this 更完整。图像可能会异步加载(在代码语句返回之后)。如果您将仍在加载的图像提供给实现ImageObserver 的组件,则更多图像加载事件将被触发给图像观察者,进而导致repaint() 被调用。但是在自定义绘画时,我们需要在drawImage(..)方法调用中显式添加图像观察者(组件)。
  • 非常感谢,您还回答了我的另一个问题,关于如何使 paintComponent() 方法运行得更快,因为当我调整窗口大小时,背景图像调整大小需要一些时间也是。
【解决方案2】:

与您的问题无关,但:

frame.getContentPane().add(BorderLayout.CENTER, welcome);

从 JDK 4 开始,您不需要使用 getContentPane() 方法,只需使用 frame.add(...),组件就会添加到内容窗格中。

您还使用了错误的 add(...) 方法。您正在使用 add(constraint, component)。如果您阅读该方法的 API,它会告诉您使用 add(component, constraint) 方法。

所以你可以使用:

frame.add(welcome, BorderLayout.CENTER);

【讨论】:

  • 我仍然喜欢通过 getContentPane() 添加组件的“旧方式”,因为它让我想起了我真正添加组件的位置,并且在向人们解释为什么他们尝试使用JFrame 上的 BoxLayout 无法正常工作(您必须将 contentPane 传递给构造函数,而不是 JFrame)。但你知道这一切。 1+(当然)为您的精彩见解!
  • @HovercraftFullOfEels, it helps when explaining to folks why their attempt to use a BoxLayout on the JFrame isn't working correctly (you must pass the contentPane into the constructor - 很公平。
猜你喜欢
  • 1970-01-01
  • 2014-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
相关资源
最近更新 更多