getContentPane().add(……);
然后有的人就产生了疑问,为什么要这么写呢?
好像我直接写 add(……); 也可以啊?
的确,现在直接写 add(……); 是可以的,但是在 java 1.4 还是更早的年代,
这一句 getContentPane() 却是必不可少的,现在不用了add与getContentPane都是向着contentPane上画的
这里我就不得不吐槽一下当年的 Swing 的开发人员,
明明重载一下 JFrame 的 add 方法就能解决的问题,非要我们多写这么一句……
好在后来他们终于醒悟,重载了一下 JFrame 的 addImpl 方法:
protected void addImpl(Component comp, Object constraints, int index)
{
if(isRootPaneCheckingEnabled()) {
getContentPane().add(comp, constraints, index);
}
else {
super.addImpl(comp, constraints, index);
}
}
终于,我们不用再去 getContentPane() 了……
那这个神奇的 ContentPane 究竟是什么呢?
从视觉效果来看(从 View 层来看),一个 JFrame 的结构是这样的:
Java JFrame中从里到外由frame-rootpane-layeredPane-contentPane-menuBar(optional)-glassPane构成
下面是类之间的关系,及类中包含引用关系
可以看出,
Frame 的最底层是 RootPane,
然后是 LayeredPane
再上面就是 ContentPane
最顶层是 GlassPane
最顶层的 GlassPane 默认是透明的,
关于 GlassPane 这个层次,其实有很多可以利用的技巧,以后我再慢慢告诉大家,
今天说我们的重点:ContentPane
可以看出,这个 ContentPane 就是默认盛放控件的那个层次,
那 ContentPane 在默认的情况下又是什么呢?
我们来看两个方法:
JFrame 中的 getContentPane:
public Container getContentPane() {
return getRootPane().getContentPane();
}
JRootPane 中的 createContentPane:
protected Container createContentPane() {
JComponent c = new JPanel();
……
……
return c;
}
可以明显的看出,默认的 ContentPane 就是一个 JPanel,
现在我们再来看另一张图,从模型的角度来看 JFrame 的层次:
可以看出,其实 ContentPane 是添加在 LayeredPane 上的一个控件。
而 LayeredPane 和 GlassPane 是直接添加在 RootPane 上的,
RootPane 直接添加在 JFrame 上。
其实你只要记住:
1、你现在不再需要去 getContentPane(),
2、ContentPane 默认是一个 JPanel ,
这两个结论就可以了……
终于成功实现了如何为jframe窗口设置背景图片了。下面是示例,请初学swring的朋友们参考学习!
- import java.awt.FlowLayout;
- import javax.swing.ImageIcon;
- import javax.swing.JButton;
- import javax.swing.JFrame;
- import javax.swing.JLabel;
- import javax.swing.JPanel;
- public class JFrameBackground {
- private JFrame frame = new JFrame("背景图片测试");
- private JPanel imagePanel;
- private ImageIcon background;
- public static void main(String[] args) {
- new JFrameBackground();
- }
- public JFrameBackground() {
- background = new ImageIcon("003.jpg");// 背景图片
- JLabel label = new JLabel(background);// 把背景图片显示在一个标签里面
- // 把标签的大小位置设置为图片刚好填充整个面板
- label.setBounds(0, 0, background.getIconWidth(),
- background.getIconHeight());
- // 把内容窗格转化为JPanel,否则不能用方法setOpaque()来使内容窗格透明
- imagePanel = (JPanel) frame.getContentPane();
- imagePanel.setOpaque(false);
- // 内容窗格默认的布局管理器为BorderLayout
- imagePanel.setLayout(new FlowLayout());
- imagePanel.add(new JButton("测试按钮"));
- frame.getLayeredPane().setLayout(null);
- // 把背景图片添加到分层窗格的最底层作为背景
- frame.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE));
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setSize(background.getIconWidth(), background.getIconHeight());
- frame.setResizable(false);
- frame.setVisible(true);
- }
- }
- public static void main (String[] args) {
- JFrame frame=new JFrame("背景图设置");
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- ImageIcon img = new ImageIcon("bg\\1.gif");//这是背景图片
- JLabel imgLabel = new JLabel(img);//将背景图放在标签里。
- frame.getLayeredPane().add(imgLabel, new Integer(Integer.MIN_VALUE));//注意这里是关键,将背景标签添加到jfram的LayeredPane面板里。
- imgLabel.setBounds(0,0,img.getIconWidth(), img.getIconHeight());//设置背景标签的位置
- Container cp=frame.getContentPane();
- cp.setLayout(new BorderLayout());
- JButton but=new JButton("anniu");//创建按钮
- cp.add(but,"North");//将按钮添加入窗口的内容面板
- ((JPanel)cp).setOpaque(false); //注意这里,将内容面板设为透明。这样LayeredPane面板中的背景才能显示出来。
- frame.setSize(500,300); frame.setVisible(true);
- }
(1)jframe窗口的组成部分,最底层是jrootpane面板。(这一点恐怕很多初学者都没有注意吧!)
(2)jframe的组成如下: jrootpane中包含glasspane和layeredpane两个面板。而layeredpane面板包含contentpane和jmenubar。(没想到吧contentpane是放在contentpane中的?)
(3)在jframe上添加组件,往往是添加在contentpane中。。但是在contentpane的下面还有两层面板,那就是layeredpane和jrootpane。
(4)任何一本关于java的书中都会介绍contentpane,却很少提到layeredpane和jrootpane,因此使得很多的初学者产生:jframe中只要一个contentpane的错误认识。 通过解决背景设置的问题,让我对jframe中容器的“层”结构,
更多参考:
从网上搜索了有关设置背景图片的文章,但是因为我每次设计窗口程序的时候,喜欢利用“Degsin”按钮,将所有的窗口进行布局后,在进行相关源代码的填写,因此,网页提供的答案是直接在主函数中编写,而我选择了在构造函数中编写,故有一定的不同。相关代码如下:
主函数:
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
HAPPY frame = new HAPPY();
//frame.setVisible(true); 这行代码,可加可不加,并不会影响最终结果,但是在构造函数中一定要添加;
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
构造函数(关键代码):
JFrame frame=new JFrame("\设\置\背\景\图\片 ");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImageIcon img = new ImageIcon("src/images/1.jpg");//这是背景图片
JLabel imgLabel = new JLabel(img);//将背景图放在标签里。
frame.getLayeredPane().add(imgLabel, new Integer(Integer.MIN_VALUE));//注意这里是关键,将背景标签添加到jfram的 LayeredPane面板里。
imgLabel.setBounds(0,0,img.getIconWidth(), img.getIconHeight());//设置背景标签的位置
Container cp=frame.getContentPane();
cp.setLayout(null); //这里选择绝对布局管理器,对于边界布局管理器,放入控件后,无法显示背景图片;因为将整个面板都填充满了;
((JPanel)cp).setOpaque(false); //这样就能显示出背景图片出来了。
剩下的就是在面板中添加相关的控件,添加语句可以用:
(1)frame.getContentPane().add(panel); (2)cp.add(panel)
效果一样;
另一种方法则是直接为面板设置背景图片,源代码如下:
contentPane = new JPanel(){
private static final long serialVersionUID=-1588458291133087637L;
public void paint(Graphics g){
ImageIcon icon=new ImageIcon("src/images/5.jpg");
Image image=icon.getImage();
g.drawImage(image, 0, 0, null);
}
};
但在实验中发现,显示效果不如前一种方法,不知为何,面板上设置的标签文字显示不出来,所以,后一种方法虽然更简便,但似乎前一种方法效果更好!
第三种方法:
contentPane.setOpaque(false);
JLabel backgroundLabel = new JLabel("");
ImageIcon background = new ImageIcon(BalloonMove.class.getResource("/images/background.jpg"));
backgroundLabel.setBounds(0, 0, background.getIconWidth(),background.getIconHeight());
backgroundLabel.setIcon(background);
getLayeredPane().add(backgroundLabel, new Integer(Integer.MIN_VALUE));
窗口中的标签,可以直接添加到contentPane面板中,很显然,最后一种方法显示效果很好,且代码简便。