【问题标题】:How to make JButtons visible on a JPanel with an image as background如何使 JButton 在以图像为背景的 JPanel 上可见
【发布时间】:2016-07-26 12:12:32
【问题描述】:

我制作了一个JPanel,并以图片为背景。但是在第一次加载 JPanel 时,其余添加的组件但图像不可见。在图像上滚动鼠标后,按钮变得可见。如何在加载面板时使JButtons 与作为背景的图像一起可见。

这是我的一段代码:

    contentPane = new JPanel();
    contentPane.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    homePanel.setBounds(10, 11, 959, 620);
    homePanel.setLayout(null);

    JPanel wizardPanel = new JPanel();
    wizardPanel.setBounds(10, 295, 545, 336);
    wizardPanel.setLayout(null);
    homePanel.add(wizardPanel);

    JLabel backgroundLabel;
    try {
        backgroundLabel = new JLabel(new ImageIcon(ImageIO.read(new File("images/nature.jpg"))));
        backgroundLabel.setBounds(0, 0, 545, 336);
        wizardPanel.add(backgroundLabel);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


    JButton btnNewButton = new JButton("New button");
    btnNewButton.setBounds(309, 95, 89, 23);
    wizardPanel.add(btnNewButton);

    JButton btnNewButton_1 = new JButton("New button");
    btnNewButton_1.setBounds(309, 150, 89, 23);
    wizardPanel.add(btnNewButton_1);

    JButton btnNewButton_2 = new JButton("New button");
    btnNewButton_2.setBounds(309, 212, 89, 23);
    wizardPanel.add(btnNewButton_2);

【问题讨论】:

  • 添加完所有组件后,尝试在内容窗格中调用 revalidate()repaint()
  • 如果可能,然后发布整个代码。
  • 最好有Minimal, Complete, and Verifiable example。这将使您的问题更容易回答。
  • revalidate() & repaint() 没有成功@vishal.. 让我展示我的完整代码
  • This 是为什么我不会使用 JLabel 来显示背景图像,我会使用 JPanel 或您可以更好地控制的其他组件,对于 example 和 @ 987654325@

标签: java swing jpanel


【解决方案1】:

将按钮放在标签上是个坏主意。更好的方法是将图像绘制为面板背景或使用 JLayer。这是第一个解决方案的示例:

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.LayoutManager;
import java.util.Objects;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class JImagePanel extends JPanel {

    private final Image image;

    private boolean scale;

    public JImagePanel(Image anImage) {
        image = Objects.requireNonNull(anImage);
    }

    public JImagePanel(Image anImage, LayoutManager aLayout) {
        super(aLayout);
        image = Objects.requireNonNull(anImage);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        final Image toDraw = scale? image.getScaledInstance(getWidth(), getHeight(), Image.SCALE_SMOOTH) : image;
        g.drawImage(toDraw, 0, 0, this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        } else {
            return new Dimension(image.getWidth(this), image.getHeight(this));
        }
    }

    public boolean isScale() {
        return scale;
    }

    public void setScale(boolean scale) {
        this.scale = scale;
    }


    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    final JImagePanel p = 
                            new JImagePanel(ImageIO.read(JImagePanel.class.getResource("myImage.png")), new FlowLayout());
                    p.setScale(true);
                    p.add(new JButton("Button"));
                    final JFrame frm = new JFrame("Image test");
                    frm.add(p);
                    frm.pack();
                    frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                    frm.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

}

【讨论】:

  • “将按钮放在标签上是个坏主意” - 为什么?至少出于一个特定原因,这不是我的首选方法,但如果您要提出索赔,那么 OP 知道原因会很有用
  • image.getWidth(null) 应该是 image.getWidth(this)getHeightg.drawImage(toDraw, 0, 0, null) 应该是 g.drawImage(toDraw, 0, 0, this)The Perils of Image.getScaledInstance() 因为我不会使用 getScaledInstance 的原因:P
  • 您还应该从 EDT 的上下文中加载您的 UI 以解决许多其他潜在问题,请查看 Initial Threads 了解更多详细信息
  • @MadProgrammer 我做得很快;)。但你是对的。我已经更正了这个例子。
【解决方案2】:

一个快速的解决方案可能是直接将JFrame 内容窗格设置为图像并将您的组件添加到此JFrame 的内容窗格中。假设您的代码来自 JFrame 类的主体。我的建议或多或少是这样的:

        JRootPane rootpane = new JRootPane();
        JPanel contentPane = new JPanel();
        contentPane.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
        rootpane.setContentPane(contentPane);
        contentPane.setLayout(null);

        JPanel homePanel = new JPanel();
        homePanel.setBounds(10, 11, 959, 620);
        homePanel.setLayout(null);

        JRootPane wizardPanel = new JRootPane();
        wizardPanel.setBounds(10, 295, 545, 336);
        wizardPanel.setLayout(null);

        JLabel backgroundLabel;
        try {
            File f = new File("D:\\work\\eclipse\\workspace_eclipse_4.4.1\\trialExamples\\src\\main\\images\\nature.jpg");
            backgroundLabel = new JLabel(new ImageIcon(ImageIO.read(f)));
            backgroundLabel.setBounds(0, 0, 545, 336);
            wizardPanel.setContentPane(backgroundLabel);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        JButton btnNewButton = new JButton("New button");
        btnNewButton.setBounds(309, 95, 89, 23);
        wizardPanel.getContentPane().add(btnNewButton);

        JButton btnNewButton_1 = new JButton("New button");
        btnNewButton_1.setBounds(309, 150, 89, 23);
        wizardPanel.getContentPane().add(btnNewButton_1);

        JButton btnNewButton_2 = new JButton("New button");
        btnNewButton_2.setBounds(309, 212, 89, 23);
        wizardPanel.getContentPane().add(btnNewButton_2);

        homePanel.add(wizardPanel.getContentPane());

        add(homePanel);

【讨论】:

  • 但除此之外,我还在左侧使用了两个面板!我只希望图像显示在第一个面板中。
  • @Lingaraj 我编辑它以使用 JPanel 中的 JRootPane。虽然这是正确的并且有效,但这不是一个很好的方法。您应该使用一个扩展的 JPanel,其中 paintComponent 方法被覆盖。使用Layout managers 也是一个好习惯
  • 更好的解决方案是不要依赖null 布局:P
【解决方案3】:

这太疯狂了!我通过将 JButtons 初始化代码块放在它工作的图像加载部分上方来让它工作.....

     package demo;

     import java.awt.EventQueue;
     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.JPanel;
     import javax.swing.SwingUtilities;
     import javax.swing.UIManager;
     import javax.swing.border.EmptyBorder;

public class demoframe extends JFrame {

/**
 * 
 */
private static final long serialVersionUID = 1436190962490331120L;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                demoframe frame = new demoframe();

                UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                SwingUtilities.updateComponentTreeUI(frame);

                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public demoframe() {

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 988, 678);
    JPanel contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    JPanel panel = new JPanel();
    panel.setBounds(10, 11, 501, 361);
    contentPane.add(panel);
    panel.setLayout(null);

    JButton btnNewButton = new JButton("New button");
    btnNewButton.setBounds(322, 112, 89, 23);
    panel.add(btnNewButton);

    JButton button = new JButton("New button");
    button.setBounds(322, 172, 89, 23);
    panel.add(button);

    JButton button_1 = new JButton("New button");
    button_1.setBounds(322, 244, 89, 23);
    panel.add(button_1);

    JLabel backgroundLabel;
    try {
        backgroundLabel = new JLabel(new ImageIcon(ImageIO.read(new File("images/nature.jpg"))));
        backgroundLabel.setBounds(0, 0, 501, 361);
        panel.add(backgroundLabel);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }



    JPanel panel_1 = new JPanel();
    panel_1.setBounds(521, 11, 441, 361);
    contentPane.add(panel_1);

    JPanel panel_2 = new JPanel();
    panel_2.setBounds(10, 383, 952, 246);
    contentPane.add(panel_2);

}   
 }

【讨论】:

  • 将您的组件一个接一个地放置是个坏主意。更好的方法是将图像绘制为背景。
  • @SergiyMedvynskyy ...这没有什么意义,我们总是将组件放在彼此之上,这就是整个事情的运作方式...如果您要绘制图像,你需要一个组件来绘制它(最好是JPanel)......但仍然是同一类东西
  • @MadProgrammer 你是对的。我的意思是把按钮放在标签上是个坏主意。
猜你喜欢
  • 2013-03-27
  • 1970-01-01
  • 2013-12-09
  • 1970-01-01
  • 2014-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多