都说Swing是个坑,果不其然,今天在学习绘图组件的时候,照着书上的代码,就出现了弹出窗体,
却没出现绘图组件的问题,当然,我还是菜鸟。所以还请原谅我犯这么低级的错误。
参考: 《Head First Java》P-364
C博客大伽:
一不小心就过年了。2017, 新年快乐
一、下面介绍paint/paintComponent区别的时候,会用到背景颜色,所以我们先来研究窗口的
背景颜色该如何设置?
方法1: 最常用的方法, 通过JFrame自带的子容器(ContentPane)内容窗体来设置【以下只是代码片断】
1 import javax.swing.*; 2 import java.awt.Color; 3 4 // 经典的错法 5 // Color是java.awt包的类, 所以别忘了导入java.awt.*; 6 JFrame f= new JFrame(); 7 f.setBackground(Color.pink); 8 9 // 正确的方法10 f.getContentPane().setBackground(Color.pink);
方法2: 利用JPanel类的paintComponent()方法, 设置背景颜色【Code Snippet】
1 import javax.swing.*; 2 import java.awt.*; 3 4 class MyPanel extends JPanel { 5 6 // this是调用本类的方法, 由于MyPanel类继承了JPanel类, 所以使用的是它的getWidth()和getHeight()方法 7 public void paintComponent(Graphics g) { 8 g.setColor(Color.pink); 9 g.fillRect(0, 0, this.getWidth(), this.getHeight());10 }11 }
方法3: 不推荐。上面的方法,其实就等同于直接在JFrame里面创建一个面板, 然后直接设置面板的
背景颜色,该方法的缺点就是, 由于面板是直接添加在JFrame上的, 所以它的背景颜色要受到JFrame
默认的边界布局的制约! 【完整代码】
1 import javax.swing.*; 2 import java.awt.*; 3 4 public class MyDrawPanel { 5 public static void main(String[] args) { 6 JFrame f= new JFrame(); 7 JPanel p = new JPanel(); 8 9 p.setBackground(Color.pink); 10 /* 11 * 看到了吧, 这里其实是默认把面板放在窗口的中间位置, 相当于f.add("Center", p);12 * 所以一旦这个位置放了其它组件, 面板就会被覆盖掉13 */14 f.add(p); 15 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);16 f.setSize(800, 600);17 f.setVisible(true);18 }19 }
二、paint/paintComponent
1. 我们首先来创建一个窗口/界面
1 package demo; // 导入包名 2 3 import javax.swing.JFrame; // 或import javax.swing.*; 4 5 public class MyPanel { 6 public static void main(String[] args) { 7 new MyPanel(); // 用new方法创建MyPanel对象, 执行构造函数 8 } 9 10 MyPanel() { // 构造函数——类名(){}, 在创造类的实例(使用new)时执行11 12 JFrame frame = new JFrame(); 13 // 关闭window时结束程序, 不然每运行一次代码, 就会产生一个javaw.exe进程, 占用内存 14 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 15 frame.setSize(800, 600); // 设置窗口的长和宽16 frame.setVisible(true); // 设置true才是可见, 才能弹出窗口/界面17 }18 }
2. 接着就是创建绘图组件
少了frame.getContentPane().add(this),无法显示Panel(面板)及背景颜色
因此,如果没有前面单独为label设置一个布局的话,那么lable也是无法显示的。
1 package demo; // 导入包名 2 3 import java.awt.*; 4 import javax.swing.*; // 或import javax.swing.*; 5 6 public class MyPanel extends JPanel { 7 public static void main(String[] args) { 8 new MyPanel(); // 用new方法创建MyPanel对象, 执行构造函数 9 }10 11 MyPanel() { // 构造函数——类名(){}, 在创造类的实例(使用new)时执行12 13 JFrame frame = new JFrame(); 14 JLabel label = new JLabel("标签");15 16 this.add(label); // 除了JFrame对象不可以使用add(), 像JPanael, JLabel均可17 frame.getContentPane().add(BorderLayout.NORTH, label); //把label放在面板的北边18 frame.getContentPane().add(this); //把JPanel及JPanel上的其他组件都加入顶层容器JFrame 19 this.setBackground(Color.pink);20 21 // 关闭window时结束程序, 不然每运行一次代码, 就会产生一个javaw.exe进程, 占用内存 22 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 23 frame.setSize(800, 600); // 设置窗口的长和宽24 frame.setVisible(true); // 设置true才是可见, 才能弹出界面25 }26 27 public void paintComponent(Graphics g) {28 super.paintComponent(g); // super用来调用JPanel父类的方法, "Ctrl + /"注释掉该行的话,背景颜色就会消失29 g.setColor(Color.orange);30 g.fillRect(20, 50, 100, 100);31 }32 }
1.JFrame和JPanel区别
包含Swing组件的程序必须包含一个顶级容器。但是Swing组件不可以直接加入到顶级容器中,而
JFrame是顶级容器。通常是把Swing组件先加入JFrame, JDialog, and JApplet三个顶层容器类中
的一个(Swing还包括另一个JWindow顶级容器组件),然后再放入JFrame中。
2.add()是任何JComponent都可以调用的,JPanel也可以,但是JFrame不可以。
对JFrame添加组件有两种方式
方法1: 通过 getContentPane ()方法获得JFrame自带的子容器(ContentPane: 内容窗体),再对其
加入组件,如frame. getContentPane ().add(childComponent)。
方法2: 我更喜欢用frame.add(), 其实本质还是向 ContentPane 添加组件,不信的话做个实验 >^<
frame.getContentPane().setVisible(false); 保证除了一个窗口, 什么组件都没有!
3. Swing中paint与paintComponent的区别
当Swing中的paint方法被调用时, paintComponent、paintBorder、 paintChildren 这三个方法也
会被按顺序调用,之所以要按这个顺序调用是为了保证子组件能正确地显示在目前这个组件之上。
paintComponent就是本身这个容器自己画出自己组件的方法,且在JComponent中的方法paintCom
ponent()还是保护类型的,即我们平常并不用管这个方法。只在我们需要改变绘制组件动作的时候,
类只要先继承paintComponent(一般是JFrame),然后重写这个方法即可。
总之:
(1)如果只是为了在Swing中改变组件样式,重写paintComponent就可以了,其他paintBorder和
paintChildren默认。如果还要保留容器中的原本组件就别忘了调用super.paintComponent(g)。
(2)如果要改写paint方法来改变本身这个容器组件,那么也别忘了要调用super.paint(g),不然出
来的东西是不包含Jpanel的原组件、原边框和子组件的。
今天突然发现,如果不在this上设置背景颜色。而是在printComponent()或者print()方法直接设置的
话,那么,super行就不会影响到背景颜色了。同理,如果直接在frame.getContentPane().add(label);
添加label,那么也不会受super.paint(g)的影响。
不过,两种情况下,frame.getContentPane().add(this);都是必须的,因为还是要把JPanel及其组件
添加到frame中的。 ————2017 1/30