一、事件監聽
測試代碼一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package cn.javastudy.summary; import java.awt.*; import java.awt.event.*; public class TestTextField { public static void main(String args[]) { new MyFrameTextField(); } } class MyFrameTextField extends Frame { MyFrameTextField() { TextField tf = new TextField(); add(tf); tf.addActionListener( new Monitor3()); tf.setEchoChar( '*' ); /* * 這個setEchoChar()方法是設置文本框輸入時顯示的字符,這里設置為*, * 這樣輸入任何內容就都以*顯示出來,不過打印出來時依然可以看到輸入的內容 */ setVisible(true); pack(); } } class Monitor3 implements ActionListener { /* * 接口里面的所有方法都是public(公共的) * 所以從API文檔復制void actionPerformed(ActionEvent e)時 要在void前面加上public */ public void actionPerformed(ActionEvent e) { /* 事件的相關信息都封裝在了對象e里面,通過對象e的相關方法就可以獲取事件的相關信息 */ TextField tf = (TextField) e.getSource(); /* * getSource()方法是拿到事件源,注意:拿到這個事件源的時候, * 是把它當作TextField的父類來對待 * getSource()方法的定義是:“public Object getSource()”返回值是一個Object對象, * 所以要強制轉換成TextField類型的對象 * 在一個類里面想訪問另外一個類的事件源對象可以通過getSource()方法 */ System.out.println(tf.getText()); // tf.getText()是取得文本框里面的內容 tf.setText( "" ); // 把文本框里面的內容清空 } } |
測試代碼二:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package cn.javastudy.summary; import java.awt.*; import java.awt.event.*; public class TestActionEvent2{ public static void main(String args[]){ Frame f = new Frame( "TestActionEvent" ); Button btn1 = new Button( "start" ); Button btn2 = new Button( "stop" ); Monitor2 m2 = new Monitor2(); //創建監聽對象 btn1.addActionListener(m2); /*一個監聽對象同時監聽兩個按鈕的動作*/ btn2.addActionListener(m2); btn2.setActionCommand("GameOver");//設置btn2的執行單擊命令后的返回信息 f.add(btn1,BorderLayout.NORTH); f.add(btn2,BorderLayout.CENTER); f.pack(); f.setVisible(true); } } class Monitor2 implements ActionListener{ public void actionPerformed(ActionEvent e){ System.out.println("a button has been pressed,"+"the relative info is:\n"+e.getActionCommand()); /*使用返回的監聽對象e調用getActionCommand()方法獲取兩個按鈕執行單擊命令后的返回信息 根據返回信息的不同區分開當前操作的是哪一個按鈕,btn1沒有使用setActionCommand()方法設置 則btn1返回的信息就是按鈕上顯示的文本*/ } } |
二、TextField事件監聽
測試代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package cn.javastudy.summary; import java.awt.*; import java.awt.event.*; public class TestTextField { public static void main(String args[]) { new MyFrameTextField(); } } class MyFrameTextField extends Frame { MyFrameTextField() { TextField tf = new TextField(); add(tf); tf.addActionListener( new Monitor3()); tf.setEchoChar( '*' ); /* * 這個setEchoChar()方法是設置文本框輸入時顯示的字符,這里設置為*, * 這樣輸入任何內容就都以*顯示出來,不過打印出來時依然可以看到輸入的內容 */ setVisible(true); pack(); } } class Monitor3 implements ActionListener { /* * 接口里面的所有方法都是public(公共的) * 所以從API文檔復制void actionPerformed(ActionEvent e)時 要在void前面加上public */ public void actionPerformed(ActionEvent e) { /* 事件的相關信息都封裝在了對象e里面,通過對象e的相關方法就可以獲取事件的相關信息 */ TextField tf = (TextField) e.getSource(); /* * getSource()方法是拿到事件源,注意:拿到這個事件源的時候, * 是把它當作TextField的父類來對待 * getSource()方法的定義是:“public Object getSource()”返回值是一個Object對象, * 所以要強制轉換成TextField類型的對象 * 在一個類里面想訪問另外一個類的事件源對象可以通過getSource()方法 */ System.out.println(tf.getText()); // tf.getText()是取得文本框里面的內容 tf.setText( "" ); // 把文本框里面的內容清空 } } |
使用TextField類實現簡單的計算器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
package cn.javastudy.summary; import java.awt.*; import java.awt.event.*; public class TestMath { public static void main(String args[]) { new TFFrame(); } } /* 這里主要是完成計算器元素的布局 */ class TFFrame extends Frame { TFFrame() { /* * 創建3個文本框,并指定其初始大小分別為10個字符和15個字符的大小 這里使用的是TextField類的另外一種構造方法 public TextField(int columns) */ TextField num1 = new TextField(10); TextField num2 = new TextField(10); TextField num3 = new TextField(15); /* 創建等號按鈕 */ Button btnEqual = new Button("="); btnEqual.addActionListener(new MyMonitor(num1, num2, num3)); /* 給等號按鈕加上監聽,讓點擊按鈕后有響應事件發生 */ Label lblPlus = new Label("+"); /* “+”是一個靜態文本,所以使用Label類創建一個靜態文本對象 */ setLayout(new FlowLayout()); /* 把Frame默認的BorderLayout布局改成FlowLayout布局 */ add(num1); add(lblPlus); add(num2); add(btnEqual); add(num3); pack(); setVisible(true); } } class MyMonitor implements ActionListener { TextField num1, num2, num3; /* * 為了使對按鈕的監聽能夠對文本框也起作用, * 所以在自定義類MyMonitor里面定義三個TextField類型的對象 num1,num2,num3, * 并且定義了MyMonitor類的一個構造方法 這個構造方法帶有三個TextField類型的參數, * 用于接收 從TFFrame類里面傳遞過來的三個TextField類型的參數 * 然后把接收到的三個TextField類型的參數賦值給在本類中聲明的 三個TextField類型的參數num1,num2,num3 然后再在actionPerformed()方法里面處理num1,num2,num3 */ public MyMonitor(TextField num1, TextField num2, TextField num3) { this.num1 = num1; this.num2 = num2; this.num3 = num3; } public void actionPerformed(ActionEvent e) { /* 事件的相關信息都封裝在了對象e里面,通過對象e的相關方法就可以獲取事件的相關信息 */ int n1 = Integer.parseInt(num1.getText());/* num1對象調用getText()方法取得自己顯示的文本字符串 */ int n2 = Integer.parseInt(num2.getText());/* num2對象調用getText()方法取得自己顯示的文本字符串 */ num3.setText("" + (n1 + n2));/* num3對象調用setText()方法設置自己的顯示文本 */ num1.setText(""); /* 計算結束后清空num1,num2文本框里面的內容 */ num2.setText(""); // num3.setText(String.valueOf((n1+n2))); /* 字符串與任意類型的數據使用“+”連接時得到的一定是字符串, * 這里使用一個空字符串與int類型的數連接,這樣就可以直接把(n1+n2)得到的int類型的數隱式地轉換成字符串了, * 這是一種把別的基礎數據類型轉換成字符串的一個小技巧。 * 也可以使用“String.valueOf((n1+n2))”把(n1+n2)的和轉換成字符串 */ } } |
JAVA里面的經典用法:在一個類里面持有另外一個類的引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
package cn.javastudy.summary; import java.awt.*; import java.awt.event.*; public class TestMath1 { public static void main(String args[]) { new TTMyFrame().launchFrame(); /* 創建出TTMyFrame對象后調用lauchFrame()方法把計算器窗體顯示出來 */ } } /* 做好計算器的窗體界面 */ class TTMyFrame extends Frame { /* 把設計計算器窗體的代碼封裝成一個方法 */ TextField num1, num2, num3; public void launchFrame() { num1 = new TextField(10); num2 = new TextField(15); num3 = new TextField(15); Label lblPlus = new Label("+"); Button btnEqual = new Button("="); btnEqual.addActionListener(new MyMonitorbtnEqual(this)); setLayout(new FlowLayout()); add(num1); add(lblPlus); add(num2); add(btnEqual); add(num3); pack(); setVisible(true); } } /* * 這里通過取得TTMyFrame類的引用,然后使用這個引用去訪問TTMyFrame類里面的成員變量 * 這種做法比上一種直接去訪問TTMyFrame類里面的成員變量要好得多, * 因為現在不需要知道 TTMyFrame類里面有哪些成員變量了, * 現在要訪問TTMyFrame類里面的成員變量,直接使用 TTMyFrame類對象的引用去訪問即可, * 這個TTMyFrame類的對象好比是一個大管家, 而我告訴大管家,我要訪問TTMyFrame類里面的那些成員變量, * 大管家的引用就會去幫我找,不再需要我自己去找了。 * 這種在一個類里面持有另一個類的引用的用法是一種非常典型的用法 * 使用獲取到的引用就可以在一個類里面訪問另一個類的所有成員了 */ class MyMonitorbtnEqual implements ActionListener { TTMyFrame ttmf = null ; public MyMonitorbtnEqual(TTMyFrame ttmf) { this .ttmf = ttmf; } public void actionPerformed(ActionEvent e) { int n1 = Integer.parseInt(ttmf.num1.getText()); int n2 = Integer.parseInt(ttmf.num2.getText()); ttmf.num3.setText( "" + (n1 + n2)); ttmf.num1.setText( "" ); ttmf.num2.setText( "" ); } } |
運行結果如下:
三、內部類
內部類的使用范例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package cn.javastudy.summary; import java.awt.*; import java.awt.event.*; public class TestMath3 { public static void main(String args[]) { new MyMathFrame().launchFrame(); } } class MyMathFrame extends Frame { TextField num1, num2, num3; public void launchFrame() { num1 = new TextField( 10 ); num2 = new TextField( 15 ); num3 = new TextField( 15 ); Label lblPlus = new Label( "+" ); Button btnEqual = new Button( "=" ); btnEqual.addActionListener( new MyMonitor()); setLayout( new FlowLayout()); add(num1); add(lblPlus); add(num2); add(btnEqual); add(num3); pack(); setVisible( true ); } /* * 這個MyMonitor類是內部類,它在MyFrame類里面定義 MyFrame類稱為MyMonitor類的包裝類 */ /* * 使用內部類的好處: * 第一個巨大的好處就是可以暢通無阻地訪問外部類(即內部類的包裝類)的所有成員變量和方法 * 如這里的在MyFrame類(外部類)定義的三個成員變量num1,num2,num3, * 在MyMonitor(內部類)里面就可以直接訪問 * 這相當于在創建外部類對象時內部類對象默認就擁有了一個外部類對象的引用 */ private class MyMonitor implements ActionListener { public void actionPerformed(ActionEvent e) { int n1 = Integer.parseInt(num1.getText()); int n2 = Integer.parseInt(num2.getText()); num3.setText( "" + (n1 + n2)); num1.setText( "" ); num2.setText( "" ); } } } |
內部類帶來的巨大好處是:
- 可以很方便地訪問外部類定義的成員變量和方法
- 當某一個類不需要其他類訪問的時候就把這個類聲明為內部類。
四、Graphics 類
測試代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package cn.javastudy.summary; import java.awt.*; public class TestPaint{ public static void main(String args[]){ new MyPaint().launchFrame(); /*在main()方法里面并沒有顯示調用paint(Graphics g)方法 可是當創建出Frame窗體后卻可以看到Frame窗體上畫出了 圓和矩形,這是因為paint()方法是一個比較特殊的方法 在創建Frame窗體時會自動隱式調用 當我們把Frame窗體最小化又再次打開時,又會再次調用 paint()方法重新把圓和矩形在Frame窗體上畫出來 即每次需要重畫Frame窗體的時候就會自動調用paint()方法*/ } } class MyPaint extends Frame{ public void launchFrame(){ setBounds(200,200,640,480); setVisible(true); } public void paint(Graphics g){ /*paint(Graphics g)方法有一個Graphics類型的參數g 我們可以把這個g當作是一個畫家,這個畫家手里拿著一只畫筆 我們通過設置畫筆的顏色與形狀來畫出我們想要的各種各樣的圖像*/ /*設置畫筆的顏色*/ g.setColor(Color.red); g.fillOval(100,100,100,100);/*畫一個實心橢圓*/ g.setColor(Color.green); g.fillRect(150,200,200,200);/*畫一個實心矩形*/ /*這下面的兩行代碼是為了寫程序的良好編程習慣而寫的 前面設置了畫筆的顏色,現在就應該把畫筆的初始顏色恢復過來 就相當于是畫家用完畫筆之后把畫筆上的顏色清理掉一樣*/ Color c = g.getColor(); g.setColor(c); } } |
運行結果:
五、鼠標事件適配器
測試代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package cn.galc.test; import java.awt.*; import java.awt.event.*; import java.util.*; public class MyMouseAdapter{ public static void main(String args[]) { new MyFrame( "drawing..." ); } } class MyFrame extends Frame { ArrayList points = null ; MyFrame(String s) { super (s); points = new ArrayList(); setLayout( null ); setBounds( 300 , 300 , 400 , 300 ); this .setBackground( new Color( 204 , 204 , 255 )); setVisible( true ); this .addMouseListener( new Monitor()); } public void paint(Graphics g) { Iterator i = points.iterator(); while (i.hasNext()){ Point p = (Point)i.next(); g.setColor(Color.BLUE); g.fillOval(p.x,p.y, 10 , 10 ); } } public void addPoint(Point p){ points.add(p); } } class Monitor extends MouseAdapter { public void mousePressed(MouseEvent e) { MyFrame f = (MyFrame)e.getSource(); f.addPoint( new Point(e.getX(),e.getY())); f.repaint(); } } |
六、window事件
測試代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package cn.galc.test; import java.awt.*; import java.awt.event.*; public class TestWindowClose{ public static void main(String args[]){ new WindowFrame( "關閉WindowFrame" ); } } class WindowFrame extends Frame{ public WindowFrame(String s){ super (s); setBounds( 200 , 200 , 400 , 300 ); setLayout( null ); setBackground( new Color( 204 , 204 , 255 )); setVisible( true ); this .addWindowListener( new WindowMonitor()); /*監聽本窗體的動作,把所有的動作信息封裝成一個對象傳遞到監聽類里面*/ this.addWindowListener( /*在一個方法里面定義一個類,這個類稱為局部類,也叫匿名的內部類, 這里的{……代碼……}里面的代碼很像一個類的類體,只不過這個類沒有名字,所以叫匿名類 在這里是把這個匿名類當成WindowAdapter類來使用,語法上這樣寫的本質意義是相當于這個匿名類 從WindowAdapter類繼承,現在new了一個匿名類的對象出來然后把這個對象當成WindowAdapter來使用 這個匿名類出了()就沒有人認識了*/ new WindowAdapter(){ public void windowClosing(WindowEvent e){ setVisible(false); System.exit(-1); } } ); } /*這里也是將監聽類定義為內部類*/ class WindowMonitor extends WindowAdapter{ /*WindowAdapter(Window適配器)類實現了WindowListener監聽接口 重寫了WindowListener接口里面的所有方法 如果直接使用自定義WindowMonitor類直接去 實現WindowListener接口,那么就得要重寫WindowListener接口 里面的所有方法,但現在只需要用到這些方法里面的其中一個方法 所以采用繼承實現WindowListener監聽接口的一個子類 并重寫這個子類里面需要用到的那個方法即可 這種做法比直接實現WindowListener監聽接口要重寫很多個用不到的方法要簡潔方便得多*/ /*重寫需要用到的windowClosing(WindowEvent e)方法*/ public void windowClosing(WindowEvent e){ setVisible(false);/*將窗體設置為不顯示,即可實現窗體關閉*/ System.exit(0);/*正常退出*/ } } } |
七、鍵盤響應事件——KeyEvent
測試代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package cn.galc.test; import java.awt.*; import java.awt.event.*; public class TestKeyEvent{ public static void main(String args[]){ new KeyFrame( "鍵盤響應事件" ); } } class KeyFrame extends Frame{ public KeyFrame(String s){ super (s); setBounds( 200 , 200 , 400 , 300 ); setLayout( null ); setVisible( true ); addKeyListener( new KeyMonitor()); } /*把自定義的鍵盤的監聽類定義為內部類 這個監聽類從鍵盤適配器KeyAdapter類繼承 從KeyAdapter類繼承也是為了可以簡潔方便 只需要重寫需要用到的方法即可,這種做法比 直接實現KeyListener接口要簡單方便,如果 直接實現KeyListener接口就要把KeyListener 接口里面的所有方法重寫一遍,但真正用到的 只有一個方法,這樣重寫其他的方法但又用不到 難免會做無用功*/ class KeyMonitor extends KeyAdapter{ public void keyPressed(KeyEvent e){ int keycode = e.getKeyCode(); /*使用getKeyCode()方法獲取按鍵的虛擬碼*/ /*如果獲取到的鍵的虛擬碼等于up鍵的虛擬碼 則表示當前按下的鍵是up鍵 KeyEvent.VK_UP表示取得up鍵的虛擬碼 鍵盤中的每一個鍵都對應有一個虛擬碼 這些虛擬碼在KeyEvent類里面都被定義為靜態常量 所以可以使用“類名.靜態常量名”的形式訪問得到這些靜態常量*/ if(keycode == KeyEvent.VK_UP){ System.out.println("你按的是up鍵"); } } } } /*鍵盤的處理事件是這樣的:每一個鍵都對應著一個虛擬的碼, 當按下某一個鍵時,系統就會去找這個鍵對應的虛擬的碼,以此來確定當前按下的是那個鍵 */ |
通過這篇文章和大家一起學習了GUI編程,希望大家對GUI編程有了更全面的認識,關于GUI編程遠不止這些,還需要大家繼續學習。