目錄
圖形用戶界面基礎
JFrame的作用
JFrame是Swing創建視窗的一個基礎類,它像一個容器一樣,可以包含其他的組件進來,是其他組件賴以生存的對象。
JFrame的使用
JFrame的使用比較簡單,主要有以下幾個步驟:
1)用new語句創建JFrame對象,可以通過構造方法傳入視窗標題參數。
2)設置窗口關閉時的行爲,一般是結束進程。
3)設置視窗的外觀,例如,尺寸、可見與否等。
4)爲窗口中添加其他的組件,例如,標籤、按鈕等。
public class HelloJFrame {
public static void main(String[] args) {
//創建JFrame對象
JFrame jf = new JFrame("hello swing");
//設置窗口關閉時,程序的響應(默認情況下,視窗關閉不會結束程序)
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//設置窗口大小
jf.setSize(200, 200);
//是否可見
jf.setVisible(true);
//爲窗口添加一個標籤
//創建JLable對象
JLabel label = new JLabel();
//設置標籤文本
label.setText("Hello this is one label");
//把標籤添加到jframe
jf.add(label);
}
}
注意:
- 以上代碼setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)方法必須要調用的,否則默認情況下,視窗關閉時是不會結束程序的。
- Swing的大多數組件類的類名都是以J字母開頭,主要是爲了與AWT的老組件相區別。
創建JButton按鈕
public class HelloJButton {
public static void main(String[] args) {
//創建JFrame對象
JFrame jf = new JFrame("hello swing");
//設置窗口在關閉時,程序響應
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//設置窗口大小
jf.setSize(200, 200);
//是否可見
jf.setVisible(true);
//設置佈局樣式
jf.setLayout(new FlowLayout());
//爲窗口添加一個按鈕
JButton btn = new JButton("my button");
jf.add(btn);
}
}
注意:
- 如果沒有設置佈局格式,JFrame是無法直接加入JButton組件的,即使調用了add()方法,界面上也是空白的。
使用文本輸入組件
Swing提供兩種文本輸入組件,一個是JTextField,它代表只能單行輸入的文本框,另一個是JTextArea,它代表可以多行輸入。它們的使用方式類似,都是通過在容器中添加組件即可。
JTextField組件在創建對象的時候,一般需要提供長度參數。JTextArea組件的創建過程則提供的是長度和高度兩個參數。
public class HelloJText {
public static void main(String[] args) {
//創建JFrame對象
JFrame jf = new JFrame("Hello Text");
//設置佈局格式
jf.setLayout(new FlowLayout());
//創建一個文本框對象
JTextField jtf = new JTextField(10);
//設置文本初始內容
jtf.setText("初始化內容");
//創建一個5行10列的文本域對象
JTextArea jta = new JTextArea(5, 10);
//設置初始化文本內容
jta.setText("初始化內容\n...");
//加到窗口中
jf.add(jtf);
jf.add(jta);
showMe(jf);
}
private static void showMe(JFrame jf){
//設置窗口在關閉時,程序的響應
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//設置窗口大小
jf.setSize(400, 400);
//是否可見
jf.setVisible(true);
}
}
捕獲事件
在Swing程序中,通過註冊監聽的方式來捕獲事件。也就是說,組件可以根據需要來添加監聽器進行某些事件的監聽,其他事件不予理睬。Swing的事件模型編程思路有以下幾項。
- 創建組件對象,如JButton。
- 創建實現了監聽器接口或繼承自適配器類的實現類,實現需要進行相應動作的抽象方法。
- 調用組件對象的addXXXListener()方法,爲該組件添加某監聽器。
public class HelloEvent {
//創建一個文本框對象
private static JTextField text = new JTextField(10);
public static void main(String[] args) {
//創建JFrame對象
JFrame jf = new JFrame("Hello Text");
//設置佈局格式
jf.setLayout(new FlowLayout());
//爲窗口添加一個文本框
jf.add(text);
//爲窗口添加一個按鈕
JButton btn = new JButton("my button");
jf.add(btn);
//添加事件
btn.addActionListener(new ActionListener() {
@Override
//定義事件回調方法
public void actionPerformed(ActionEvent e) {
HelloEvent.text.setText("按鈕被點擊了");
}
});
showMe(jf);
}
private static void showMe(JFrame jf){
//設置窗口在關閉時,程序的響應
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//設置窗口大小
jf.setSize(400, 400);
//是否可見
jf.setVisible(true);
}
}
佈局控制
BorderLayout佈局
BorderLayout是Swing容器的默認佈局管理器,它的含義是採用東西南北中5個方位來進行佈局,可以分別往這些方位上放置組件。在編程時,使用容器的add()方法即可,第一個參數爲需要添加的組件,第二個參數則是佈局的方位。
注意:
- 如果通過只有一個參數的add()方法添加組件,容器會默認地把組件放在中間位置。
變量 | 說明 |
---|---|
BorderLayout.NORTH | 上端 |
BorderLayout.SOUTH | 下端 |
BorderLayout.EAST | 右端 |
BorderLayout.WEST | 左端 |
BorderLayout.CENTER | 中部 |
public class HelloBorderLayout {
public static void main(String[] args) {
//創建JFrame對象
JFrame jf = new JFrame("BorderLayout test");
//設置佈局方式
jf.setLayout(new BorderLayout());
jf.add(new JButton("east"), BorderLayout.EAST);
jf.add(new JButton("center"), BorderLayout.CENTER);
jf.add(new JButton("south"), BorderLayout.SOUTH);
jf.add(new JButton("north"), BorderLayout.NORTH);
jf.add(new JButton("west"), BorderLayout.WEST);
jf.setSize(400, 400);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
FlowLayout佈局
FlowLayout佈局器採用一種流線型的佈局方式,把組件從左到右依次地放置,如果擺放不下,則換到下一行繼續擺放。
當某種容器需要使用該佈局管理器時,只需要調用setLayout()方法,傳入一個FlowLayout對象即可。在加入組件的時候,直接調用add()方法,不需要指定其他參數。
public class HelloFlowLayout {
public static void main(String[] args) {
JFrame jf = new JFrame("Hello FlowLayout");
jf.setLayout(new FlowLayout());
for (int i = 0; i < 10; i++) {
jf.add(new JButton(i + ""));
}
jf.setSize(640, 200);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
注意:
如果窗口的大小發生變化,就會影響到FlowLayout的排列方式。例如,本來是一排,就可能變成多排。
GridLayout佈局
GridLayout佈局管理器採用的是一種表格式的佈局方式,它把容器等分爲N*N個格子,然後把加入的組件依次放置在格子中。
當某種容器需要使用該佈局管理器時,只需要調用setLayout()方法,傳入一個GridLayout對象即可,只不過GridLayout對象在創建的時候,需要指定它的行數和列數,在加入組件時,直接調用add()方法,不需要指定其他的參數。
public class HelloGridLayout {
public static void main(String[] args) {
JFrame jf = new JFrame("GridLayout test");
//創建GridLayout,10行10列
GridLayout grid = new GridLayout(10, 10);
//設置Grid
jf.setLayout(grid);
for (int i = 0; i < 100; i++) {
jf.add(new JButton(i + ""));
}
jf.setSize(640, 480);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
注意:
當窗口變大的時候,每個格子的面積也會增大,按鈕也會隨着變大。
事件模型
通用規則
Swing的事件類型比較多,但它們都有一個通用的使用和定義規則,主要有以下幾點。
- 組件都有addXXXListener()和removeXXXListener()方法,XXX就代表了事件的類型和含義。
- XXX事件的監聽器類型叫做XXXListener。
- XXX事件的類名叫做XXXEvent,它往往作爲XXXListener接口方法中的參數類型。
監聽器、事件 | 添加和取消方法 | 支持該事件的常見組件 |
---|---|---|
ActionEvent ActionListener |
addActionListener() removeActionListener() |
JButton、JList、JMenu、JMenuItem |
KeyEvent KeyListener |
addKeyListener() removeKeyListener() |
幾乎所有的組件 |
MouseEvent MouseListener |
addMouseListener() removeMouseListener() |
幾乎所有的組件 |
WindowEvent WindowListener |
addWindowListener() removeWindowListener() |
Window及其子類,JDialog、JFrame |
TextEvent TextListener |
addTextListener() removeTextListener() |
文本輸入組件,JTextField、JTextArea |
監聽器&適配器
在Java開發領域,有一種開發模式叫做適配器開發模式,Swing的適配器正是採用這種模式開發的。爲了避免代碼冗餘,Swing監聽器的適配器就是爲一些監聽器接口的方法提供默認的空實現,這樣開發者可以直接繼承自適配器就好,不必把每一個接口方法都實現。也可以根據需要自定義一些適配器。
大家知道爲一個組件添加事件監聽器就是加入一個監聽器接口的類實例,調用addXXXListener()方法即可。但是如果這個接口方法太多,而開發中只使用其中的一些,這豈不是浪費,有接口侵入之嫌。
public class HelloKeyEvent {
public static void main(String[] args) {
JFrame jf = new JFrame("hello event");
jf.setLayout(new FlowLayout());
JTextField jtf = new JTextField(15);
jf.add(jtf);
//添加監聽器
jtf.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
//空實現
}
@Override
public void keyPressed(KeyEvent e) {
System.out.println(e.getKeyChar()+" pressed");
}
@Override
public void keyReleased(KeyEvent e) {
//空實現
}
});
showMe(jf);
}
private static void showMe(JFrame jf){
//設置窗口在關閉時,程序的響應
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//設置窗口大小
jf.setSize(400, 400);
//是否可見
jf.setVisible(true);
}
}
那麼有沒有一個類提供這些接口的基本實現呢?
這就是適配器。
public class HelloKeyEvent2 {
public static void main(String[] args) {
JFrame jf = new JFrame("hello event");
jf.setLayout(new FlowLayout());
JTextField jtf = new JTextField(15);
jf.add(jtf);
//添加監聽器
jtf.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
System.out.println(e.getKeyChar()+" pressed");
}
});
showMe(jf);
}
private static void showMe(JFrame jf){
//設置窗口在關閉時,程序的響應
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//設置窗口大小
jf.setSize(400, 400);
//是否可見
jf.setVisible(true);
}
}
效果與上圖相同。
注意:
適配器是一個類,如果事件處理類已經繼承自其他接口的話,就不能繼承自適配器類了。另外,開發者也可以自己寫一個適配器,爲一些事件方法提供一些自定義的初始化實現。例如,每次事件的觸發就記錄一次日誌。