1. GUI編程引言
以前的學習當中,我們都使用的是命令交互方式:
例如:在DOS命令行中通過javac java命令啟動程序.
軟件的交互的方式:
1. 命令交互方式
圖書管理系統
2. 圖形交互方式
ava提供了專業的API用於開發圖形用戶界面
GUI--> Graphic User Interface
將要了解GUI API的框架結構,以及GUI組件以及組件之間的關系,容器和布局管理器,顏色,字體等.
2. GUI的分類
2.1. AWT
Java1.0版本的圖形用戶界面庫,設計目標是幫助程序員編寫在所有平台上都能良好表現的GUI程序。為了實現這個目標Java1.0提供了抽象窗口工具集(AWT),但是這個目標並沒有達到。AWT在所有的系統上表現都不好。因為:最初版本的AWT是在一個月內構思,設計和實現的(Think in Java )。
Abstract Window Toolkit 抽象窗口工具集
Java將圖形用戶界面相關的類捆綁在了一起,放在了一個稱之為抽象窗口工具集的庫中.AWT適合開發簡單的圖形用戶界面,並不適合開發復雜的GUI項目.
位於: java.awt.* 中,定義了很多的組件類,開發者可以直接創建對象加以使用
缺點: 所有的圖形界面都依賴於底層的操作系統,容易發生於特定平台相關的故障.
AWT調用本地系統資源生成圖形化界面, 依賴本地平台. 1.0
2.2. Swing
SUN公司對AWT進行了升級,基於AWT,推出了一種更穩定,更通用和更靈活的庫.稱之為Swing組件庫(Swing component)。
既然都是用於GUI設計的組件庫,那么為了區分Swing組件類和對應的AWT組件類,Swing組件類都已字母J為前綴.位於:javax.swing.* 中,提供了和AWT中等同的所有的組件類,但是類名的前面多加了一個J.
SWING可以跨平台. 1.2
我們主要學習Swing GUI組件.
3. Java GUI API
GUI API包含的類分為三個部分:組件類(component class) 容器類(container class),和輔助類(helper class)
- 組件類是用來創建用戶圖形界面的,例如JButton,JLabel,JTextField.
- 容器類是用來包含其他組件的,例如JFrame,JPanel
- 輔助類是用來支持GUI組件的,例如Color,Font
3.1. 組件類
在圖形用戶界面程序中當我們想要創建按鈕、復選框和滾動條等這些可以顯示在屏幕上的對象,該如何創建。其實這些都屬於一類叫做組件類。
AWT中的組件根類
類 Component
java.lang.Object
java.awt.Component
Swing中的組件根類
javax.swing
類 JComponent
java.lang.Object
java.awt.Component
java.awt.Container
javax.swing.JComponent
組件類的實例可以顯示在屏幕上.Component類是包括容器類的所有用戶界面類的根類是java.awt中的類,對應的Swing中的是Jcomponent.了解了Component和JComponent都是抽象類.所以不能使用new關鍵字創建對象.所以需要使用它們的具體的實現類來創建對象.
在AWT中典型圖形用戶界面中的按鈕(Button)、復選框(Checkbox)和滾動條(Scrollbar)都是組件類,都是Component類的子類.
在Swing中的GUI組件,有對應的JButton,JCheckBox,JscrollBar
繼承關系圖(AWT)
3.2. 容器類
容器(Container),是一個特殊的組件,該組件可以通過add()添加其他組件。
容器類適用於盛裝其他GUI組件的GUI組件.例如 Panel Frame Dialog都是AWT組件的容器類.
對應的Swing組件的容器類是JPanel JFrame JDialog
3.3. GUI輔助類
用來描述GUI組件的屬性,例如圖像的顏色,字體等. 注意:輔助類是在java.awt中的
3.4. GUI運行原理
在JDK的bin目錄中有javaw.exe .javaw.exe是java在window中專門用於執行GUI程序.
4. 體驗GUI
import javax.swing.JFrame; import javax.swing.JOptionPane; public class Demo { public static void main(String[] args) { // 創建JFrame JFrame frame = new JFrame("hello,world"); // 設置尺寸 frame.setSize(200, 100); // JFrame在屏幕居中 frame.setLocationRelativeTo(null); // JFrame關閉時的操作 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 顯示JFrame frame.setVisible(true); } }
5. Jframe框架
JFrame(框架)是一個容器
創建一個用戶界面需要創建一個JFrame來存放用戶界面組件.例如存放按鈕,文本框。
javax.swing
類 JFrame
java.lang.Object
java.awt.Component
java.awt.Container
java.awt.Window
java.awt.Frame
javax.swing.JFrame
5.1. 創建一個框架
public class Demo1 { public static void main(String[] args) { // 創建JFrame JFrame frame = new JFrame("我的frame"); // 顯示JFrame frame.setVisible(true); } }
注意:需要調用setVisible(true)方法后才會顯示框架
運行程序會在窗口的左上角顯示一個窗口,但是只能顯示標題欄,而且關閉JFrame時,程序程序沒有停止.
所以需要完成如下需求:
1: 設置Jframe的寬度和高度
2: 讓Jframe顯示在屏幕中間
3: 關閉Jframe時,程序會停止
5.1.1. 設置JFrame的寬度和高度
java.awt.Window.setSize(int width, int height)
查找API文檔,查看 setSize方法,可以指定框架的寬度和高度.參數類型是int,注意是以像素為單位,普通的筆記本的屏幕分辨率為1280*800或者1366*768.注意:分辨率表示每平方英寸的像素數.屏幕分辨率越高,屏幕的像素越多.所以分辨率越高看到的細節就越多.
setSize方法被定義在java.awt.Component類中,被Component 的子類java.awt.Window 重寫.而Jframe以繼承了Windiws類所以也具備該方法.
5.1.2. JFrame顯示在屏幕中間
setLocationRelativeTo()方法
java.awt.Window.setLocationRelativeTo(Component c) 設置窗口相對於指定組件的位置。 如果 c 為 null,則此窗口將置於屏幕的中央。
setLocationRelativeTo(null)方法可以在屏幕上居中顯示框架.
如果不想要設置在中間,可以使用
setLocation(200, 100);
5.1.3. 關閉JFrame程序停止
setDefaultCloseOperation(int operation)方法
javax.swing.JFrame.setDefaultCloseOperation(int operation)
該方法告訴程序,當框架關閉時結束程序.方法的參數是JFrame 的常量EXIT_ON_CLOSE
添加完畢
public class Demo1 { public static void main(String[] args) { // 創建JFrame JFrame frame = new JFrame("我的frame"); // 設置尺寸 frame.setSize(200, 100); // JFrame在屏幕居中 frame.setLocationRelativeTo(null); // JFrame關閉時的操作 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 顯示JFrame frame.setVisible(true); } }
5.2. 框架中添加組件
上述案例中的框架是空的.可以通過add方法在框架中添加組件
java.awt.Container.add(Component comp)
代碼:
public static void main(String[] args) { // 創建JFrame JFrame frame = new JFrame("我的frame"); // 創建按鈕 JButton button = new JButton("OK"); // 向frame中添加一個按鈕 frame.add(button); // 設置尺寸 frame.setSize(200, 100); // JFrame在屏幕居中 frame.setLocationRelativeTo(null); // JFrame關閉時的操作 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 顯示JFrame frame.setVisible(true); }
運行程序,會顯示上圖所示窗口.調整窗口的大小,按鈕都是顯示在窗口的中央,並且占滿整個框架.
這是因為組件(本例就是按鈕)是被布局管理器放到框架中的.默認布局管理器就是將按鈕放到中央.
備注: 可以通過f.setVisible(false); 隱藏窗體f.dispose();關閉窗口
設置圖片:
setIconImage(Toolkit.getDefaultToolkit().createImage("png-0015.png"));
6. JoptionPane對話框
顯示一個帶有OK 按鈕的模態對話框。
下面是幾個使用showMessageDialog 的例子:
Java代碼
JOptionPane.showMessageDialog(null, "錯誤信息提示", "標題", JOptionPane.INFORMATION_MESSAGE);
效果如下:
Java代碼
JOptionPane.showMessageDialog(jPanel, "提示消息", "標題",JOptionPane.WARNING_MESSAGE);
Java代碼
JOptionPane.showMessageDialog(null, "提示消息.", "標題",JOptionPane.ERROR_MESSAGE);
Java代碼
JOptionPane.showMessageDialog(null, "提示消息.", "標題",JOptionPane.PLAIN_MESSAGE);
1.2 showOptionDialog
這個函數可以改變顯示在按鈕上的文字。你還可以執行更多的個性化操作。
常規的消息框:
Java代碼
int n = JOptionPane.showConfirmDialog(null, "你高興嗎?", "標題",JOptionPane.YES_NO_OPTION);//i=0/1
輸入框 :
String inputValue = JOptionPane.showInputDialog("請輸入你給我金額");
7. 面板(Panel)
面板也是一個容器的組件,可以在上面添加
注意:面板不能單獨使用,必須在頂層窗口中使用。
8. 常見組件
一些常用的組件例如:
JLabel,
JButton ,
JTextField
JPassworldField
JRadioButton
JCheckBox
JTextArea
JList
JMenuBar
JMenu
JMenultem
8.1. Button按鈕
Java中的Swing提供了常規按鈕,單選按鈕,復選按鈕和菜單按鈕
8.1.1. JButtion普通按鈕
按鈕Button是點擊時觸發動作事件的組件.
8.1.2. JRadioButton單選按鈕
單選按鈕,可以讓用戶從一組選項中選擇一個單一條目.例如性別.
使用單選按鈕時注意將,單選按鈕放在一組,需要使用java.swing.ButtonGroup. 的add方法,添加到一個組中,位於同一個組的單選按鈕就是互斥的. 如果沒有將單選按鈕放在一個組中,就是獨立的..我們讓然需要把按鈕添加在容器中.因為ButtonGroup添加到容器中..
8.1.3. JCheckBox復選框
多選
8.2. JLabel標簽
8.3. JTextField文本域
8.4. JTextArea文本區域
8.5. JComboBox組合框
8.6. JList 列表框
例如: String[] data = { "one", "two", "three" };
JList list = new JList(data);
p1.add(list);
8.7. JmenuBar菜單條
JMenu菜單
JMenultem菜單項
菜單條(MenuBar)中包含菜單(Menu),菜單中中包含菜單項(MenuItem)
注意添加的順序。例如:記事本的菜單條中包含文件、編輯、格式、查看、幫助菜單。其中文件菜單中包含新建、打開、保存、另存為等菜單項
案例綜合。
public class CommonComponent extends JFrame { public CommonComponent() { // 面板 JPanel p1 = new JPanel(); add(p1); // 標簽 JLabel name = new JLabel("用戶名:"); p1.add(name); // 文本域 JTextField field = new JTextField(8); p1.add(field); // 標簽 JLabel passwd = new JLabel("密碼"); p1.add(passwd); // 密碼域 JPasswordField pass = new JPasswordField(8); p1.add(pass); // 單選按鈕 JLabel gender = new JLabel("性別"); p1.add(gender); JRadioButton male = new JRadioButton("男"); JRadioButton female = new JRadioButton("女"); // 單選按鈕組,同一個單選按鈕組的互斥. ButtonGroup group = new ButtonGroup(); group.add(male); group.add(female); // 注意,單選按鈕組不能添加進容器 p1.add(male); p1.add(female); // 復選框 JLabel like = new JLabel("愛好:"); p1.add(like); JCheckBox eat = new JCheckBox("吃飯"); JCheckBox movie = new JCheckBox("看電影"); JCheckBox sleep = new JCheckBox("睡覺"); p1.add(eat); p1.add(movie); p1.add(sleep); // 文本域 JLabel info = new JLabel("個人簡介"); p1.add(info); JTextArea area = new JTextArea(20, 20); p1.add(area); // 列表 String[] data = { "one", "two", "three" }; JList list = new JList(data); p1.add(list); // 普通按鈕 JButton button = new JButton("注冊"); p1.add(button); // 菜單條 JMenuBar bar = new JMenuBar(); // 菜單 JMenu menu = new JMenu("文件"); // 菜單選項 JMenuItem myNew = new JMenuItem("新建"); JMenuItem myOpen = new JMenuItem("打開"); bar.add(menu); menu.add(myNew); menu.add(myOpen); add(bar, BorderLayout.NORTH); } public static void main(String[] args) { CommonComponent frame = new CommonComponent(); frame.setTitle("常用組件"); frame.setSize(400, 400); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 自適應 frame.pack(); frame.setVisible(true); } }
因為面板默認是流式布局.
9. 布局管理器
Java的GUI組件都放置在容器中,他們的位置是由容器的布局管理器來管理的.在前面的程序中,並沒有指定將OK按鈕放置在框架的什么位置,但是,Java知道應該把它放置在哪里,因為在后台工作的布局管理器能夠將組件放到正確的位置.布局管理器是使用布局管理器類創建的.
我們可以使用setLayout() 方法在容器中設置布局管理器.
我們將要了解FlowLayout GridLayout BorderLayout
9.1. FlowLayout流式布局
FlowLayout(流式布局)是最簡單布局管理器. Jpanel容器默認的布局管理器
流式布局,按照組件添加的順序,從左到到右將組件排列在容器中.當放滿一行,就開始新的一行.在FlowLayout有3個常量FlowLayout可以指定組件的對齊方式.
LEFT 每一行組件都應該是左對齊的
RIGHT 每一行組件都應該是右對齊的
CENTER 每一行組件都應該是居中的
還可以指定組件之間的以像素為單位的間隔.
int getHgap() 獲取組件之間以及組件與 Container 的邊之間的水平間隙。 int getVgap() 獲取組件之間以及組件與 Container 的邊之間的垂直間隙。 void setHgap(int hgap) 設置組件之間以及組件與 Container 的邊之間的水平間隙。 void setVgap(int vgap) 設置組件之間以及組件與 Container 的邊之間的垂直間隙。
這個布局管理器的對其方式默認值是CENTER
這個布局管理器的水平間隔默認值是 5個像素
這個布局管理器的垂直間隔默認是是5個像素
創建該布局管理器
FlowLayout() 構造一個新的 FlowLayout,它是居中對齊的,默認的水平和垂直間隙是 5 個單位。 FlowLayout(int align) 構造一個新的 FlowLayout,它具有指定的對齊方式,默認的水平和垂直間隙是 5 個單位。 FlowLayout(int align, int hgap, int vgap) 創建一個新的流布局管理器,它具有指定的對齊方式以及指定的水平和垂直間隙。
案例:創建框架,使用流失布局管理器.向該框架添加三個標簽和文本域.
public class ShowFlowLayout extends JFrame { public ShowFlowLayout() { super.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 20)); add(new JLabel("姓名:")); add(new JTextField(8)); add(new JLabel("郵箱:")); add(new JTextField(8)); add(new JLabel("電話:")); add(new JTextField(8)); } public static void main(String[] args) { ShowFlowLayout frame = new ShowFlowLayout(); frame.setTitle("FlowLayout"); frame.setSize(500, 200); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
該案例在本類main方法中創建了一個本類對象. 該類的構造函數中創建並且添加組件.
該案例使用了FlowLayout管理器在框架放置組件.如果改變框架的大小.組建會自動的重新排列,以適應框架.
如果將同一個按鈕在框架中添加10次,那么該框架只會出現一次,將一個按鈕向容器中添加多以和一次是一樣的.
9.2. GridLayout網格布局
GridLyaout是以網格形式管理組件的.組件按照他們添加的順序從左到右排列,顯示第一行,接着是第二行,一次類推.
Gridlayout可以指定網格中的行數和列數
規則如下:
行數和列數可以是0但是不能兩者都為0.
如果一個為0另外一個不為0,那么不為0的行或列的大小就是固定的,為0的行或者列有布局管理器動態決定.
例如:如果指定一個網格有0行3列10個組件,GirdLayout會創建3個固定的列和行,最后一行只有一個組件.如果指定一個網格有3行0列10個組件,GridLayout就會創建3行4列,最后一行包含2個組件.
如果行數和列數都不為0,那么以行數為依據.所以行數是固定的,布局管理器會動態的計算列數.例如,如果指定一個網格有3行3列10個組件,GridLayout會創建3個固定的行和4列,最后一行包含2個組件.
構造方法
GridLayout() 創建具有默認值的網格布局,即每個組件占據一行一列。 GridLayout(int rows, int cols) 創建具有指定行數和列數的網格布局。 GridLayout(int rows, int cols, int hgap, int vgap) 創建具有指定行數和列數,水平間隔,垂直間隔的網格布局。
方法:
int getRows() 獲取此布局中的行數。 默認值是1 int getColumns() 獲取此布局中的列數。 默認值是1 int getHgap() 獲取組件之間的水平間距。 默認值是0 int getVgap() 獲取組件之間的垂直間距。默認值是0 設置 void setRows(int rows) 將此布局中的行數設置為指定值。默認值是1 void setColumns(int cols) 將此布局中的列數設置為指定值。 默認值是1 void setHgap(int hgap) 將組件之間的水平間距設置為指定值。 默認值是0 void setVgap(int vgap) 將組件之間的垂直間距設置為指定值。默認值是0
案例:該案例依然添加3個標簽和3個文本域,只不過布局管理器是GrigLayout
public class ShowGridLayout extends JFrame { public ShowGridLayout() { setLayout(new GridLayout(3, 2, 5, 5)); add(new JLabel("姓名:")); add(new JTextField(8)); add(new JLabel("郵箱:")); add(new JTextField(8)); add(new JLabel("電話:")); add(new JTextField(8)); } public static void main(String[] args) { ShowGridLayout frame = new ShowGridLayout(); frame.setTitle("GridLayout"); frame.setSize(200, 125); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
如果使用setLayout(new GridLayout(3,10))替換setlayout語句,還是會得到3行2列,因為行的參數非零,所以列的參數會被忽略.列的實際參數是由布局管理器計算出來的.
9.3.BorderLayout邊框布局
邊框布局,JFrame 容器默認的布局管理器是邊框布局.該管理器將容器非為東西南北中5個區域.
我們使用add(Component,index)方法可以將組件添加進到BorderLayout中,index是一個常量,有5個值
EAST
東區域的布局約束(容器右邊)。
WEST
西區域的布局約束(容器左邊)。
SOUTH
南區域的布局約束(容器底部)。
NORTH
北區域的布局約束(容器頂部)。
CENTER
中間區域的布局約束(容器中央)。
構造函數
BorderLayout() 構造一個組件之間沒有間距的新邊框布局。 BorderLayout(int hgap, int vgap) 構造一個具有指定組件間距的邊框布局。
方法:
int getHgap() 返回組件之間的水平間距。 int getVgap() 返回組件之間的垂直間距。 void setHgap(int hgap) 設置組件之間的水平間距。 默認值是0 void setVgap(int vgap) 設置組件之間的垂直間距。默認值是0
組件會根據他們最合適的尺寸和在容器中的位置來放置,南北組件可以水平拉伸,東西組件可以垂直拉伸,中央組件既可以水平拉伸也可以垂直拉伸.
案例:演示邊框布局管理器
public class ShowBorderLayout extends JFrame { public ShowBorderLayout() { setLayout(new BorderLayout(5, 10)); add(new JButton("東"), BorderLayout.WEST); add(new JButton("西"), BorderLayout.EAST); add(new JButton("南"), BorderLayout.SOUTH); add(new JButton("北"), BorderLayout.NORTH); add(new JButton("中"), BorderLayout.CENTER); } public static void main(String[] args) { ShowBorderLayout frame = new ShowBorderLayout(); frame.setTitle("BorderLayout"); frame.setSize(300, 200); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
注意: 如果布局管理器為Border管理器,調用add方法,沒有說明組件的位置(東西南北中)默認是center.
所以
add(new JButton("ok"))和add(new JButton("ok"), BorderLayout.CENTER )
效果是一樣的.
如果在Border容器中添加2個組件,都沒有指定位置,那么只會顯示最后一個組件
add(new JButton("ok1"))和add(new JButton("ok2")) 只會顯示ok2
使用布局管理器
代碼:
public class CommonComponent extends JFrame { public CommonComponent() { // 菜單條 JMenuBar bar = new JMenuBar(); // 菜單 JMenu menu = new JMenu("文件"); // 菜單選項 JMenuItem myNew = new JMenuItem("新建"); JMenuItem myOpen = new JMenuItem("打開"); bar.add(menu); menu.add(myNew); menu.add(myOpen); add(bar, BorderLayout.NORTH); // 面板 JPanel p1 = new JPanel(); p1.setLayout(new GridLayout(2, 2, 5, 5)); add(p1); // 標簽 JLabel name = new JLabel("用戶名:"); p1.add(name); // 文本域 JTextField field = new JTextField(8); p1.add(field); // 標簽 JLabel passwd = new JLabel("密碼"); p1.add(passwd); // 密碼域 JPasswordField pass = new JPasswordField(8); p1.add(pass); JPanel p2 = new JPanel(); // 單選按鈕 JLabel gender = new JLabel("性別"); p2.add(gender); JRadioButton male = new JRadioButton("男"); JRadioButton female = new JRadioButton("女"); // 單選按鈕組,同一個單選按鈕組的互斥. ButtonGroup group = new ButtonGroup(); group.add(male); group.add(female); // 注意,單選按鈕組不能添加進容器 p2.add(male); p2.add(female); JPanel p3 = new JPanel(); // 復選框 JLabel like = new JLabel("愛好:"); p3.add(like); JCheckBox eat = new JCheckBox("吃飯"); JCheckBox movie = new JCheckBox("看電影"); JCheckBox sleep = new JCheckBox("睡覺"); p3.add(eat); p3.add(movie); p3.add(sleep); JPanel p4 = new JPanel(new GridLayout(1, 0, 5, 5)); // 文本域 JLabel info = new JLabel("個人簡介:"); p4.add(info); JTextArea area = new JTextArea(50, 10); p4.add(area); JPanel p5 = new JPanel(new BorderLayout()); // 列表 String[] data = { "one", "two", "three" }; JList list = new JList(data); p5.add(list, BorderLayout.WEST); JPanel p6 = new JPanel(); // 普通按鈕 JButton button = new JButton("注冊"); p6.add(button); JButton button2 = new JButton("取消"); p6.add(button2); setLayout(new GridLayout(7, 1, 5, 5)); add(p1); add(p2); add(p3); add(p4); add(p5); add(p6); } public static void main(String[] args) { CommonComponent frame = new CommonComponent(); frame.setTitle("常用組件"); frame.setSize(400, 600); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 自適應 // frame.pack(); frame.setVisible(true); } }
public class TestPanel extends JFrame { public TestPanel() { // 創建面板,默認是流式布局 JPanel p1 = new JPanel(); // 指定為網格布局,4行3列 p1.setLayout(new GridLayout(4, 3)); for (int i = 1; i <=9; i++) { p1.add(new JButton("" + i)); } p1.add(new JButton("0")); p1.add(new JButton("OK")); p1.add(new JButton("EXIT")); // 創建面板,指定邊框布局 JPanel p2 = new JPanel(new BorderLayout()); // 面板添加文本域,邊框北部 p2.add(new JTextField("我在這里啊!!!"), BorderLayout.NORTH); // 面板添加其他面板,邊框中部. p2.add(p1, BorderLayout.CENTER); // 框架添加面板,框架的布局默認就是邊框布局,面板指定位於框架西部 add(p2, BorderLayout.EAST); // 框架添加按鈕,位於框架總部. add(new JButton("哈哈"), BorderLayout.CENTER); } public static void main(String[] args) { TestPanel frame = new TestPanel(); frame.setTitle("JPanel"); frame.setSize(400, 260); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
注意: 面板容器是一個輕量級的容器,該容器不能單獨的使用,必須依賴與外層的頂層容器(JFrame)
10. Java事件監聽機制
在上述的程序中,其中菜單條,菜單 項,按鈕等都是對象,當我們單擊對象時,應該能夠完成一些任務.例如在程序中通過鼠標操作時,單擊,雙擊,鼠標移入,鼠標移出.能夠執行一些任務,在 Java中我們可以使用事件監聽機制,在Java的事件監聽機制中 ,當事件發生時(點擊按鈕,移動鼠標等,關閉窗口)會被一類對象發現並處理.
10.1. 事件和事件源
在運行java圖形用戶界面程序時,用戶與程序交互,用戶執行了某些操作時,會發生一些事情, 那么事件(event)可以定義為程序發生了某些事情的信號.典型用戶操作就是用戶移動鼠標,點擊按鈕,敲擊鍵盤等.程序可以選擇相應事件或者忽略事件。
能夠創建一個事件並觸發該事件的組件稱為源對象。例如由於按鈕能夠點擊, 那么按鈕就是一個源對象,按鈕被點擊就是一個事件。
一個事件是事件類的實例對象。事件類的根類是java.util.EventObject。
事件對象包含事件相關的屬性,可以使用EventObject類中的實例方法getSource獲得事件的源對象。
EventObject類的子類可以描述特定類型的事件
用戶動作 |
源對象 |
觸發的事件類型 |
點擊按鈕 |
JButton |
ActionEvent |
文本域按回車 |
JTextField |
ActionEvent |
窗口打開,關閉,最小化,關閉 |
Window |
WindowEvent |
單擊,雙擊,移動,鼠標 |
Component |
MouseEvent |
點擊單選框 |
JradioButton |
ItemEvent ActionEvent |
點擊復選框 |
JcheckBox |
ItemEvent ActionEvent |
10.2. 監聽器
當源對象觸發了一個事件,誰來處理這個事件?在Java中對此感興趣的對象會處理它。對此感興趣的對象稱之為監聽器(Listener)。
舉例來說當我們點擊一個按鈕,想要按鈕執行一些動作,需要一個對象來監控按鈕,當點擊按鈕的事件發生時,該對象就會監聽到按鈕事件。進而可以執行一些動作。
例如:
Java中,對象表示的每個事件都是由java.util中EventObject類的子類,
例如: MouseEvent: 表示鼠標的動作,例如移動光標,單擊,雙擊
KeyEvent: 表示鍵盤上的按鍵.
ActionEvent表示用戶采取的用戶界面操作,例如點擊屏幕上的按鈕.
10.3. 事件處理
Java對組件都有對應的事件監聽器,和添加事件監聽器方法。
例如: 按鈕: 源對象,會觸發
體驗:當用戶點擊按鈕時,按鈕上的信息會發生變化
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class ShowButton extends JFrame { public ShowButton() { JButton button = new JButton("點我"); add(button); // 添加鼠標監聽事件 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("按鈕被點擊"); Object source = e.getSource(); JButton button = (JButton) source; String text = button.getText(); if ("按鈕被點擊".equals(text)) { button.setText("點我"); } else { button.setText("按鈕被點擊"); } } }); } public static void main(String[] args) { ShowButton frame = new ShowButton(); frame.setTitle("我的框架"); frame.setSize(400, 200); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
10.4. 窗口事件
Window類
java.awt 類 Window java.lang.Object java.awt.Component java.awt.Container java.awt.Window
Window
對象是一個頂層窗口。窗口(Window)對應的事件叫做窗口事件(WindowEvent),任何窗口(Window)以及窗口的子類都可能觸發窗口事件: 打開窗口,正在關閉窗口,激活窗口,變成非活動窗口,最小化窗口和還原窗口。
Window添加窗口事件(WindowEvent)監聽器的方法
void addWindowListener(WindowListener l) 添加指定的窗口偵聽器,以從此窗口接收窗口事件
監聽Window窗口事件(WindowEvent)的監聽器:WindowListener
java.awt.event 接口 WindowListener 用於接收窗口事件的偵聽器接口。當通過打開、關閉、激活或停用、圖標化或取消圖標化而改變了窗口狀態時,將調用該偵聽器對象中的相關方法
WindowListener接口中定義的方法
抽象方法: void windowActivated(WindowEvent e) 激活窗口 void windowClosed(WindowEvent e) 關閉窗口 void windowClosing(WindowEvent e) 正在關閉窗口 void windowDeactivated(WindowEvent e) 變為非活動窗口 void windowDeiconified(WindowEvent e) 還原窗口 void windowIconified(WindowEvent e) 最小化窗口 void windowOpened(WindowEvent e) 打開窗口
案例: 框架的事件監聽處理
javax.swing
類 JFrame
java.lang.Object
java.awt.Component
java.awt.Container
java.awt.Window
java.awt.Frame
javax.swing.JFrame
創建JFrame,Jfame是一個框架,屬於窗體(Window)體系中的一員,也可以實現窗口的最大化,最小化,關閉,點擊窗體,等一系列的操作。那么在用戶觸發這些事件發生時能夠做一些工作,就需要注冊事件監聽器。
JFrame 是通過addWindowListener 方法就注冊窗體事件監聽器,該方法需要接受一個監聽器(WindowListener)對象。查找API文檔,發現WindowListener是一個接口,
我們需要窗口監聽器(WindowListener)的實例對象,所以需要實現該接口,重寫WindowListener接口的抽象方法。然后創建該實現類對象,作為參數傳遞給addWindowListener .
例如: 當像激活窗口這樣的窗口事件發生時,windowActivated 方法就會觸發。
代碼如下:
import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JFrame; public class WindowEventDemo extends JFrame { WindowEventDemo() { // this對象時JFrame的子類,而JFrame 類是Window體系中的一員所以具備添加窗口事件的方法 this.addWindowListener(new MyWindow()); } public static void main(String[] args) { WindowEventDemo frame = new WindowEventDemo(); frame.setTitle("我的框架"); frame.setSize(400, 200); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } // 實現WindowListener class MyWindow implements WindowListener { // 激活窗口 public void windowActivated(WindowEvent e) { System.out.println("激活窗口"); } // 關閉窗口 public void windowClosed(WindowEvent e) { System.out.println("關閉窗口"); } // 正在關閉窗口 public void windowClosing(WindowEvent e) { System.out.println("正在關閉窗口"); } // 變為非活動窗口 public void windowDeactivated(WindowEvent e) { System.out.println("變為非活動窗口"); } // 還原窗口 public void windowDeiconified(WindowEvent e) { System.out.println("還原窗口"); } // 最小化窗口 public void windowIconified(WindowEvent e) { System.out.println(" 最小化窗口"); } // 打開窗口 public void windowOpened(WindowEvent e) { System.out.println("打開窗口"); } }
總結:Window類或者Window類的任何子類都可能會觸發WindowEvent。因為JFrame是Window的子類。所以也可以觸發WindowEvent。
10.5. 監聽器接口適配器
因為WindowListener接口中的方法都是抽象的,所以即使程序中不想關注某些事件,但是還是要實現所以的方法,比較麻煩,為了方便起見,Java提供了一個針對WindowListener接口的實現類,該類中把WindowListener接口中的方法全部實現,只不過方法體都為空。
例如: 加入我們只對激活窗口感興趣,那么只需要繼承該實現類重寫激活窗口的方法即可。簡化了代碼。
import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; public class AdapterDemo extends JFrame { AdapterDemo() { addWindowListener(new MyAdapter()); } public static void main(String[] args) { AdapterDemo frame = new AdapterDemo(); frame.setTitle("我的框架"); frame.setSize(400, 200); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } class MyAdapter extends WindowAdapter { public void windowActivated(WindowEvent e) { System.out.println("windowActivated...."); } } }
那么這個WindowAdapter類就叫做適配器類,是為了簡化代碼的書寫而出現的。
適配器 接口
WindowAdapter WindowListener
MouserAdapter MouserListener
KeyAdapter KeyListener
10.6. 鼠標鍵盤事件
當在一個組件上按下,釋放,點擊,移動,或者拖動鼠標時,就會產生鼠標事件。MouseEvent對象捕獲這個事件。
MouseEvent
java.awt.event.MouseEvent
Java對鼠標事件提供了MouseListener 監聽器接口,可以監聽鼠標的按下,釋放,輸入,退出和點擊動作。
MouseListener
用於接收組件上“感興趣”的鼠標事件(按下、釋放、單擊、進入或離開)的偵聽器接口
方法:
void mouseClicked(MouseEvent e) 鼠標按鍵在組件上單擊(按下並釋放)時調用。 void mouseEntered(MouseEvent e) 鼠標進入到組件上時調用。 void mouseExited(MouseEvent e) 鼠標離開組件時調用。 void mousePressed(MouseEvent e) 鼠標按鍵在組件上按下時調用。 void mouseReleased(MouseEvent e) 鼠標按鈕在組件上釋放時調用。
按鍵事件可以利用鍵盤來控制和執行一些動作,如果按下、釋放一個鍵就會觸發按鍵事件。KeyEvent對象可以捕獲按鍵的按下放開和敲擊。KeyEvent提供了getkeyChar 來獲取按鍵對應的字符。
java.awt.event.KeyEvent char getKeyChar() 返回與此事件中的鍵關聯的字符。
Java提供了KeyListener監聽器接口來監聽按鍵事件。
KeyListener接口
用於接收鍵盤事件(擊鍵)的偵聽器接口。
void keyPressed(KeyEvent e) 按下某個鍵時調用此方法。 void keyReleased(KeyEvent e) 釋放某個鍵時調用此方法。 void keyTyped(KeyEvent e) 鍵入某個鍵時調用此方法。
public class MouseEventDemo extends JFrame { MouseEventDemo() { JButton button = new JButton("ok"); JTextArea text = new JTextArea(); add(button, BorderLayout.NORTH); add(text, BorderLayout.CENTER); button.addMouseListener(new MouseListener() { // 鼠標按鈕在組件上釋放時調用。 public void mouseReleased(MouseEvent e) { System.out.println("鼠標釋放"); } // 鼠標按鍵在組件上按下時調用。 public void mousePressed(MouseEvent e) { System.out.println("鼠標按下組件"); } // 鼠標離開組件時調用。 public void mouseExited(MouseEvent e) { System.out.println("鼠標離開組件"); } // 鼠標進入到組件上時調用。 public void mouseEntered(MouseEvent e) { // 鼠標進入 System.out.println("鼠標進入組件"); } // 鼠標按鍵在組件上單擊(按下並釋放)時調用。 public void mouseClicked(MouseEvent e) { System.out.println("鼠標單擊組件"); } }); text.addKeyListener(new KeyListener() { // 鍵入某個鍵時調用此方法。 public void keyTyped(KeyEvent e) { System.out.println("鍵入某個鍵"); if (e.getKeyChar() == 'q') { System.exit(0); } } // 釋放某個鍵時調用此方法。 public void keyReleased(KeyEvent e) { System.out.println("按鍵釋放"); } // 按下某個鍵時調用此方法。 public void keyPressed(KeyEvent e) { System.out.println("鍵盤按下"); } }); } public static void main(String[] args) { MouseEventDemo frame = new MouseEventDemo(); frame.setTitle("鼠標事件"); frame.setSize(400, 200); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
10.7. 事件監聽機制小結
一:確定事件源(容器或組件)
二:注冊監聽器
通過事件源對象的addXXXListener()方法將監聽器對象注冊到該事件源上。
三:監聽器對象
注冊監聽器時,需要指定監聽器對象。
以參數的形式進監聽器對象傳遞給addXXXListener()
監聽器對象是XXXListener的子類對象或者XXXAdapter的子類對象。
監聽器對象一般用匿名內部類來表示。(簡化書寫)
在覆蓋方法的時候,方法的參數一般是XXXEvent類型的變量接收。
事件觸發后會把事件打包成對象傳遞給該變量。(其中包括事件源對象。通過getSource()或者getComponent()獲取。)
四:常見的事件監聽器
WindowListener 主要用於監聽窗口
ActionListener 主要用於用監聽組件對象的單擊動作
MouseListener 鼠標監聽器
KeyListener 監聽鍵盤
…….
五:常見的事件適配器
WindowAdapter
MouseAdapter
KeyAdapter