在使用Nimbus外观时,如果有背景图片,JFrame中的JButton会完全消失。

4
我有一个JFrame窗口,其中使用了以下内容:
  1. JTabbedPane标签页。
  2. JButton按钮。
  3. JPanel中添加了带背景图片的JLabel标签。
  4. Nimbus外观。
我的问题是:当我使用Nimbus外观时,只要添加了背景图片,JButton按钮就会消失,而其他外观则不会发生这种情况。请问有谁能帮我让按钮可见?
以下是我的代码:
import javax.swing.ImageIcon;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JFrame; 
import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIManager.LookAndFeelInfo;

import java.awt.*;
import java.awt.event.*;

class ImageTest 
{
JTabbedPane tp;
JLabel lab1;
JPanel  welcome;
JFrame frame;
ImageIcon image2;
JButton b1;
public void createUI()
{
    frame=new JFrame("JTabbedPane Example");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


    b1=new JButton();
    welcome= new JPanel(null);
    welcome.setPreferredSize(new Dimension(1366,786));
    ImageIcon icon = new ImageIcon(ImageTest.class.getResource("icloud.jpg"));

    tp=new JTabbedPane();
            Container pane = frame.getContentPane();
    pane.add(tp);
    tp.addTab("Welcome", welcome);
            lab1=new JLabel();
    lab1.setIcon(icon);

    b1.setBounds(100,100,100,100);
    lab1.setBounds(0,0,1500,700);
            welcome.add(lab1);
            welcome.add(b1);
            b1.setVisible(true);
    frame.setSize(500,500);
    frame.setVisible(true);
    frame.setTitle("I-Cloud");

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

      try {
        for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (Exception e) {

    }   
      ImageTest w = new ImageTest();
      w.createUI();   

     }
    }

EDIT:

 import javax.swing.ImageIcon;
 import javax.swing.JTabbedPane;
 import javax.swing.JTextField;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.UnsupportedLookAndFeelException;
 import javax.swing.UIManager.LookAndFeelInfo;

 import java.awt.*;
 import java.awt.event.*;

 class ImageTest 
  {
 JTabbedPane tp;
 JLabel lab1;
 JPanel  welcome,w;
 JFrame frame;
 ImageIcon image2;
 JButton b1;

public void createUI()
{
    frame=new JFrame("JTabbedPane Example");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    b1=new JButton();
    welcome= new JPanel(new GridLayout(1,1,15,15));
    w=new JPanel (new GridLayout(1, 1, 15, 15));
    welcome.setPreferredSize(new Dimension(1366,786));

    ImageIcon icon = new ImageIcon(ImageTest.class.getResource("icloud.jpg"));

    tp=new JTabbedPane();
            Container pane = frame.getContentPane();
    pane.add(tp);


    lab1=new JLabel();
    lab1.setIcon(icon);
    w.setOpaque(false);
    w.add(b1);


    b1.setVisible(true);
            welcome.add(lab1);
            welcome.add(w);
            tp.addTab("Welcome", welcome);

    frame.setSize(500,500);
    frame.pack();
    frame.setVisible(true);
    frame.setTitle("I-Cloud");

}   
public static void main(String[] args) 
{
    try {
        for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (Exception e) {

    }

        ImageTest w = new ImageTest();
        w.createUI();   

    }
  }

谢谢。

2
请不要使用setBounds()方法,而是使用适当的LayoutManager。下面这个评论完全不是针对个人的,请不要误解我的意思,但我认为有一个学院或者类似的地方教人们使用setBounds()setLocation()setSize()方法来处理Swing,这是完全错误的。每天至少有10个开发者在使用这些方法时提出问题。请不要这样做! - dic19
1
请查看**这个答案**。其中有链接,解释了为什么开发人员不应该使用那些方法的大多数常见问题和答案。 - dic19
2
@NickRippe,你认为这是这种情况吗?无论如何,Swing GUI必须能够与不同的L&F一起工作,这意味着例如不同的字体大小可能会导致问题,如此处所示:https://dev59.com/UGjWa4cB1Zd3GeqPtLXa#12532237。因此,通过`setBounds()`设置固定位置/大小是自讨苦吃的方法。 - dic19
1
@dic19 - 不,我不认为这是那些特殊情况之一。但我也不认为说从来没有使用它们的地方是正确的。如果你觉得需要使用它们,那么怎么样“当你在学习时,你不需要使用它们。” - Nick Rippe
2
@NickRippe:无论如何,他不应该将JLabel和JButton放在同一个容器中的相同位置,除非容器是JLayeredPane,并且他小心地处理z-order。我认为,如果原帖作者学习如何嵌套容器并使用布局管理器,他会更容易上手。对于那些精通布局管理器并且有非常好的理由不使用它们(例如某些动画)的人来说,偶尔使用null布局也没有问题,但这里不适用。 - Hovercraft Full Of Eels
显示剩余4条评论
2个回答

4
您使用了null布局,然后在一个组件的顶部添加另一个组件,实际上覆盖了其中一个组件(JButton)与另一个组件(带有图像的JLabel)。请不要像您所做的那样使用null布局。尽管对于新手来说,使用null布局和setBounds似乎是创建复杂GUI的最佳方法,但随着您处理Swing GUI创建的更多内容,您会发现这样做会让您的GUI处于一个死角,使其非常难以扩展或增强。请不要这样做。
不要在同一容器中将一个组件放在另一个组件上面。
相反,请为带有图像的JLabel提供布局管理器。
然后将JButton添加到JLabel中。
然后将JLabel添加到JTabbedPane中。
编辑
您的最新编辑未使用如上建议的JLabel作为容器。因此,如果您使用单独的容器,则按钮和标签将并排显示。要解决此问题,您需要为JLabel提供布局管理器,然后按照上述建议将按钮添加到其中,或者直接在JPanel的paintComponent(...)方法中进行绘制,并将按钮添加到JPanel中。
以下是后者的示例:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

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

public class MyImageTest extends JPanel {
   // public static final String SPEC = "https://duke.kenai.com/SunRIP/.Midsize/SunRIP.jpg.png";
   public static final String SPEC = "http://upload.wikimedia.org/wikipedia/commons/3/37/"
         + "Mandel_zoom_14_satellite_julia_island.jpg";
   private static final int PREF_H = 786;
   private static final int GAP = 100;
   private BufferedImage img;

   public MyImageTest() {
      try {
         URL imgUrl = new URL(SPEC);
         img = ImageIO.read(imgUrl);
      } catch (MalformedURLException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
      setLayout(new FlowLayout(FlowLayout.LEADING));
      setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
      JButton b = new JButton();
      b.setPreferredSize(new Dimension(GAP, GAP));
      add(b);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (img != null) {
         g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      if (img == null) {
         return super.getPreferredSize();
      } else {
         int width = (img.getWidth() * PREF_H) / img.getHeight();
         return new Dimension(width, PREF_H);
         // return new Dimension(img.getWidth(), img.getHeight());
      }
   }

   private static void createAndShowGui() {
      try {
         for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
               UIManager.setLookAndFeel(info.getClassName());
               break;
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
      MyImageTest mainPanel = new MyImageTest();

      JFrame frame = new JFrame("MyImageTest");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

enter image description here


我添加了一行代码 welcome= new JPanel(new GridLayout(2,2,5,10)); 按钮是可见的,但它没有出现在图像上。而且按钮大小不符合setbounds()的要求。 - user3320152
@user3320152:请仔细阅读我所有的建议。此外,如果您更改了代码,请将新代码作为对原问题的编辑发布,但保留原有代码。让我们能够测试您的新代码。 - Hovercraft Full Of Eels
我已经按照您的步骤编辑了我的代码。但是我无法设置按钮的位置和大小。我希望它正好位于图像的中心。 - user3320152
非常感谢。但是我尝试将JLabel的布局管理器设置为lab1=new JLabel(new GridLayout(1,1,15,15));,但它说这个构造函数未定义。我该如何为JLabel做到这一点? - user3320152
@user3320152:你需要养成使用Java API的习惯,因为它会告诉你所有核心Java类可用的构造函数。像JLabel这样的类没有这样的构造函数(正如你所发现的),但是它与其父类JComponent共享一个方法。请在Java API中查看。 - Hovercraft Full Of Eels

1

我认为在JLabel中设置背景图像,然后添加按钮,即使在添加容器之后,也是一个非常复杂的问题。相信我,我尝试过了,这是一个非常复杂的任务。你可以像Hovercraft建议的那样直接绘制,但记住,这种方法不会得到很好的图像质量。 :-|


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接