Java: GridLayout + tic-tac-toe
這次的功課是使用 AWT(Abstract Windowing Toolkit) 寫出 3*3 的圈圈叉叉,本文將記下我撰寫途中遇到的問題
問題1:明明放在前面的 label 卻出現在整個頁面的最下面一列?
問題描述
我還在嘗試怎麼使用 grid 時,寫了以下的 Code,我先設定並 add
label 後,利用迴圈跑出9個按鈕。
理論上 Label 應出現在按鈕上方,但他卻出現在底下。
完整的 code 在這:
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
import java.awt.*;
public class hw1 extends Frame{
static Frame frm = new Frame("Tic-Tac-Toe");
static Label lab = new Label("It's \"O\" turn.");
public static void main(String args[]){
// 設定版面
GridLayout grid = new GridLayout(4, 3);
frm.setLayout(grid);
frm.setSize(600, 800);
frm.setBackground(Color.white);
frm.setLocation(200, 50);
// 設定標籤屬性
lab.setBackground(Color.gray);
lab.setFont(new Font("Serief",Font.BOLD,18));
frm.add(lab);
// 按鈕
for(int i = 0; i < 9; i++){
frm.add(new Button(), i);
}
frm.setVisible(true);
}
}
為何如此?
原來問題出在第 21 行,frm.add(new Button(), i);
。
當 add 有兩個參數時,後面的 int
將會表示顯示的位置。(你可以在這裡找到官方文件的解說)
例如我將它改為 frm.add(new Button(Integer.toString(i)), i + 1);
,會顯示這樣的結果:
所有 button 從「第一格」(左上角的灰格為第0格)開始依序往下排列
修改成果
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
import java.awt.*;
public class hw1 extends Frame{
static Frame frm = new Frame("Tic-Tac-Toe");
static Label lab1 = new Label("It's \"O\" turn.");
static Label lab2 = new Label();
static Label lab3 = new Label();
public static void main(String args[]){
// 設定版面
GridLayout grid = new GridLayout(4, 3);
frm.setLayout(grid);
frm.setSize(600, 800);
frm.setBackground(Color.white);
frm.setLocation(200, 50);
// 設定標籤屬性,預留三個標籤的空位,分別是「該O下了」、「誰贏了」、「該X下了」
lab1.setBackground(Color.gray);
lab1.setFont(new Font("Serief",Font.BOLD,18));
lab2.setBackground(Color.gray);
lab2.setFont(new Font("Serief",Font.BOLD,18));
lab3.setBackground(Color.gray);
lab3.setFont(new Font("Serief",Font.BOLD,18));
frm.add(lab1);
frm.add(lab2);
frm.add(lab3);
lab2.setVisible(false);
lab3.setVisible(false);
// 按鈕
for(int i = 0; i < 9; i++){
frm.add(new Button(Integer.toString(i)), i + 3);
}
frm.setVisible(true);
}
}
問題2:Button 無法使用 setText()?
在查資料的過程中發現,其實大家都用 JButton 而非 Button,這裡指的是 java.awt 中的 Button 喔。
問題描述
我想要實現「當按鈕被點擊時,按鈕中的文字顯示為 O」,所以將按鈕都加進 ActionListener(frm)
中,如下:
1
2
3
4
5
for(int i = 0; i < 9; i++){
btn[i] = new Button();
btn[i].addActionListener(frm);
frm.add(btn[i], i + 3);
}
我也新增了一個 function:
1
2
3
4
5
public void actionPerformed(ActionEvent e){
Button actionBtn = (Button) e.getSource();
btn[1].setText("O");
}
他卻一直顯示這個問題:
1
2
3
4
5
6
7
D:\Java\hw1 ❯ javac .\hw1.java -encoding utf-8
.\hw1.java:52: error: cannot find symbol
btn[1].setText("O");
^
symbol: method setText(String)
location: class Button
1 error
為何如此?
這世界上沒有一個叫做 setText()
,且傳入了一個 String 當參數的 function。
設定 Button 中的文字應用 setLabel()
,而不是 setText()
。
不過確實還有其他 object 是用 setText()
,這點需要多注意⚠
修改成果
按下按鈕後要觸發的 function 長這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void actionPerformed(ActionEvent e){
Button actionBtn = (Button) e.getSource();
// 下棋!
++turn;
if(turn % 2 != 0){
lab1.setVisible(false);
lab3.setVisible(true);
actionBtn.setLabel("O");
}
else{
lab1.setVisible(true);
lab3.setVisible(false);
actionBtn.setLabel("X");
}
}
成品
經過一點波折,終於完成了小小的圈圈叉叉遊戲啦~
這是我第一次用視窗來設計程式,能夠和這種 GUI 互動的感覺真的成就感爆棚!
這裡是成果 demo:
終於像個圈圈叉叉了! 這裡是完整的程式碼:
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import java.awt.*;
import java.awt.event.*;
public class hw1 extends Frame implements ActionListener{
static hw1 frm = new hw1();
static Label lab1 = new Label("It's \"O\" turn.");
static Label lab2 = new Label(); //win
static Label lab3 = new Label("It's \"X\" turn."); // X
static int turn = 0; // turn % 2 == 0 -> O, turn % 2 == 1 -> X
static Button[] btn = new Button[9];
public static void main(String args[]){
// 設定版面
GridLayout grid = new GridLayout(4, 3);
frm.setLayout(grid);
frm.setTitle("Tic-Tac-Toe");
frm.setSize(600, 800);
frm.setBackground(Color.white);
frm.setLocation(200, 50);
// 設定標籤屬性
lab1.setBackground(Color.gray);
lab1.setFont(new Font("Serief",Font.BOLD,18));
lab2.setBackground(Color.gray);
lab2.setFont(new Font("Serief",Font.BOLD,18));
lab3.setBackground(Color.gray);
lab3.setFont(new Font("Serief",Font.BOLD,18));
frm.add(lab1);
frm.add(lab2);
frm.add(lab3);
lab2.setVisible(false);
lab3.setVisible(false);
// 按鈕
for(int i = 0; i < 9; i++){
btn[i] = new Button();
btn[i].addActionListener(frm);
frm.add(btn[i], i + 3);
}
frm.setVisible(true);
// 關閉視窗鍵被點下就結束程式
frm.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
});
}
public void actionPerformed(ActionEvent e){
Button actionBtn = (Button) e.getSource();
// 下棋!
++turn;
if(turn % 2 != 0){
lab1.setVisible(false);
lab3.setVisible(true);
actionBtn.setLabel("O");
}
else{
lab1.setVisible(true);
lab3.setVisible(false);
actionBtn.setLabel("X");
}
// 判斷輸贏
String[] game = new String[9];
for(int i = 0; i < 9; ++i){
game[i] = btn[i].getLabel();
}
boolean win = false;
for(int i = 0; i < 3; ++i){
// 橫列
if(game[i * 3] == game[i * 3 + 1] && game[i * 3] == game[i * 3 + 2] && game[i * 3] != ""){
win = true;
break;
}
// 直行
if(game[i] == game[i + 3] && game[i] == game[i + 6] && game[i] != ""){
win = true;
break;
}
}
// 斜線
if(game[0] == game[4] && game[0] == game[8] && game[0] != "")
win = true;
if(game[2] == game[4] && game[2] == game[6] && game[2] != "")
win = true;
// 輸出勝利訊息
if(win == true){
if(turn % 2 != 0){
lab3.setVisible(false);
lab2.setText("\"O\" win!");
lab2.setVisible(true);
}
else{
lab1.setVisible(false);
lab2.setText("\"X\" win!");
lab2.setVisible(true);
}
}
else if(turn == 9){
lab1.setVisible(false);
lab3.setVisible(false);
lab2.setText("Draw!");
lab2.setVisible(true);
}
}
}