都說Swing是個坑,果不其然,今天在學習繪圖組件的時候,照着書上的代碼,就出現了彈出窗體,
卻沒出現繪圖組件的問題,當然,我還是菜鳥。所以還請原諒我犯這么低級的錯誤。
參考: 《Head First Java》P-364
C博客大伽: http://blog.csdn.net/u012270113/article/details/38898083
一不小心就過年了。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