javaSwing学习笔记

说起来好久没写了…大概算算…也就四个月

嗐,四个月而已,问题不大(

这次是关于Java Swing。上次写GUI是高中学VB应付会考,这次还是学点看上去有用点的吧。学这玩意是为了啥我也不知道,估计是为了填上初中时代对java swing的回忆。那会觉得这玩意挺高端的,最近在晋t群见到一位用java swing写安卓stg的老哥,感觉挺有趣的。虽说我不会试图用这个过气物件写stg,不过学一学就当是入门GUI。

年后可能的话会有js的学习笔记,嗯,希望吧。

Hello World

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import javax.swing.*;

public class hello {
public static void createShow() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Hello World Swing!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JLabel label = new JLabel("Hello world");
frame.getContentPane().add(label);

frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createShow();
}
});
}
}

首先我们需要知道,swing里相关类的继承关系。

java.awt分成两个部分,第一部分是java.awt.Component,另一部分是java.awt.MenuComponent。后者主要用于处理菜单,而前者主要处理其他各种各样的界面元素。

Component有两类子类,第一类是各种图形界面元素,比如JButton,JTextField之类的;而第二类为Container子类。Container类的子类进一步分作Window和Panel。

Window类里的主要子类是Frame。Frame是各种图形界面的载体,作为程序的主页面。而Panel则是一个长方形区域,用以容纳其他组件。一般,我们把各种组件放到Panel中去。

上面的Hello World中,setDefaultLookAndFeelDecorated()方法据说可以让出来的更美观,不过我倒是没觉得。JFrame的构造方法使用的是JFrame(Stirng name),后面的name会作为窗体的名称。getContentPane()可以理解成得到当前的Panel,而setVisible()函数用来显示出来。主函数中新建了一个进程来防止死锁,听说是。

JLabel是一个容器。

布局设计

我们以一个计算器的例子来考虑布局设计的问题。

布局管理器是Swing实现的一种自动布局的模式,其相对位置可以自己计算。常见的布局管理器有边框布局管理器、流式布局管理器、卡片布局管理器、网格布局管理器
网格包布局管理器、盒布局管理器。我个人感觉网格包布局管理器非常好用,所以这里仅仅介绍这种管理器。

网格包布局管理器形成的对象是GridBadLayout对象,需要一个GridBagConstraints对象来对其进行约束。这一管理器可以看成网格,但是我们可以赋给不同的网格行列以权重,来自由的调整各行各列的比例。同时,我们可以控制一个对象在表格中占据的位置、需要占据的长度和宽度来分配。

其常见的函数有:

  • gridx/gridy 改变左上角的行和列
  • gridwidth/gridheight 改变所占的单元格
  • fill 填充网格的方式
  • weightx/weighty 改变某一行的权重

我们以一个计算器来说明。

首先新建一个Cauculator类,由于这个类是一个swing框架,可以直接继承JFrame类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Component createComponent(String info, GridBagConstraints constraint, 
int gridx, int gridy, int gridwidth, int gridheight,
double weightx, double weighty) {
Component component;
if(info == "")
component = new JTextField(info);
else
component = new JButton(info);
// adjust the restrictions
constraint.gridx = gridx;
constraint.gridy = gridy;
constraint.gridheight = gridheight;
constraint.gridwidth = gridwidth;
constraint.weightx = weightx;
constraint.weighty = weighty;
// add the button to the panel with constraint
mypanel.add(component, constraint);
return component;
}

上面的方法可以造一个Component。constraint传入一个对布局的约束条件,mypanel调用add方法将这一component压入,所采用的规则是constrint.

在类的构造函数中,我们进行元素的添加过程,如下:

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
public calculator() {
// Basic settings
setTitle("Calculator");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 400, 500);
mypanel = new JPanel();

// Adjust the layout type
setLayout(new BorderLayout());
add(mypanel, BorderLayout.CENTER);

// To set the constraints
mypanel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;

// To make the textField
JTextField textField = (JTextField)createComponent("", gbc, 0, 0, 4, 1, 1.0, 0.1);
JTextField showOut = (JTextField)createComponent("", gbc, 0, 1, 4, 1, 1.0, 0.3);
number = new JButton[10];
for(int i = 7; i <= 9; ++i) {
number[i] = (JButton)createComponent(String.valueOf(i), gbc, i - 7, 2, 1, 1, 0.25, 0.15);
}
plus = (JButton)createComponent("+", gbc, 3, 2, 1, 1, 0.25, 0.15);
for(int i = 4; i <= 6; ++i) {
number[i] = (JButton)createComponent(String.valueOf(i), gbc, i - 4, 3, 1, 1, 0.25, 0.15);
}
minus = (JButton)createComponent("-", gbc, 3, 3, 1, 1, 0.25, 0.15);
for(int i = 1; i <= 3; ++i) {
number[i] = (JButton)createComponent(String.valueOf(i), gbc, i - 1, 4, 1, 1, 0.25, 0.15);
}
multiply = (JButton)createComponent("*", gbc, 3, 4, 1, 1, 0.25, 0.15);
point = (JButton)createComponent(".", gbc, 0, 5, 1, 1, 0.25, 0.15);
number[0] = (JButton)createComponent("0", gbc, 1, 5, 1, 1, 0.25, 0.15);
equal = (JButton)createComponent("=", gbc, 2, 5, 1, 1, 0.25, 0.15);
divide = (JButton)createComponent("/", gbc, 3, 5, 1, 1, 0.25, 0.15);

setVisible(true);

}

setLayout改变了布局,在后面分别把不同的控件添加进去。最后形成的如图:

事件响应器

在awt中,有不同的事件响应器。这里用的响应器是ActionEvent类,是最常见的响应器。

在实现时,我们一般对不同类型的事件,新建不同的类,这些类都实现了ActionListener接口。这一接口需要实现actionPerformed方法,来表示事件发生之后所做的事情。下面两个例子分别实现了这一接口,用来维护上面的计算器所需要进行的操作。numberController类用来响应数字键的点击,operatorController方法用来响应其他键的点击。最后写出来的大概就是这个样子:

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
private class numberController implements ActionListener {
private int value;

numberController() {
value = 0;
}

numberController(int value) {
this.value = value;
}

public void actionPerformed(ActionEvent e) {
if(currstr == "0" && value == 0)
return;
if(currstr == "0") currstr = "";
if(uppershow == "NULL") uppershow = "";
currstr += String.valueOf(value);
uppershow += String.valueOf(value);
showOut.setText(currstr);
textField.setText(uppershow);
}

}
private class operatorController implements ActionListener {
private String type;

operatorController(){
type = "";
}

operatorController(String type) {
this.type = type;
}

public void actionPerformed(ActionEvent e) {
if(type == "-") {
s1 = currstr;
currstr = "0";
uppershow += " - ";
} else if(type == "+") {
s1 = currstr;
currstr = "0";
uppershow += " + ";
} else if(type == "*") {
s1 = currstr;
currstr = "0";
uppershow += " * ";
} else if(type == "/") {
s1 = currstr;
currstr = "0";
uppershow += " / ";
} else if(type == "mod") {
s1 = currstr;
currstr = "0";
uppershow += " mod ";
} else if(type == "=") {
s2 = currstr;
currstr = String.valueOf(getAns());
} else if(type == ".") {
currstr += ".";
uppershow += ".";
}
showOut.setText(currstr);
textField.setText(uppershow);
}

private double getAns() {
if(uppershow.indexOf("-") != -1) {
return Double.parseDouble(s1) - Double.parseDouble(s2);
} else if(uppershow.indexOf("+") != -1) {
return Double.parseDouble(s1) + Double.parseDouble(s2);
} else if(uppershow.indexOf("*") != -1) {
return Double.parseDouble(s1) * Double.parseDouble(s2);
} else if(uppershow.indexOf("/") != -1) {
return Double.parseDouble(s1) / Double.parseDouble(s2);
} else if(uppershow.indexOf("mod") != -1) {
return Double.parseDouble(s1) % Double.parseDouble(s2);
}
return 0;
}

}

在调用的时候,只需要number[i].addActionListener(new numberController(i))即可。

最后完整的代码如下。在上面的基础上又改了一些字号之类的东西,没什么太大差别。

当然,因为我比较懒,很多应该加上去的东西实在懒得加了,大概就这样吧x

感觉写界面好难啊QAQ

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import javax.swing.*;
import javax.swing.border.*;

import java.awt.*;
import java.awt.event.*;

public class calculator extends JFrame {
private static JPanel mypanel;
private JButton number[];
private JButton plus, minus, multiply,
divide, equal, point;
private JLabel textField, showOut;
private String currstr = "0", s1 = "", s2 = "", uppershow = "";

private class numberController implements ActionListener {
private int value;

numberController() {
value = 0;
}

numberController(int value) {
this.value = value;
}

public void actionPerformed(ActionEvent e) {
if(currstr == "0" && value == 0)
return;
if(currstr == "0") currstr = "";
if(uppershow == "NULL") uppershow = "";
currstr += String.valueOf(value);
uppershow += String.valueOf(value);
showOut.setText(currstr);
textField.setText(uppershow);
}

}

private class operatorController implements ActionListener {
private String type;

operatorController(){
type = "";
}

operatorController(String type) {
this.type = type;
}

public void actionPerformed(ActionEvent e) {
if(type == "-") {
s1 = currstr;
currstr = "0";
uppershow += " - ";
} else if(type == "+") {
s1 = currstr;
currstr = "0";
uppershow += " + ";
} else if(type == "*") {
s1 = currstr;
currstr = "0";
uppershow += " * ";
} else if(type == "/") {
s1 = currstr;
currstr = "0";
uppershow += " / ";
} else if(type == "mod") {
s1 = currstr;
currstr = "0";
uppershow += " mod ";
} else if(type == "=") {
s2 = currstr;
currstr = String.valueOf(getAns());
} else if(type == ".") {
currstr += ".";
uppershow += ".";
}
showOut.setText(currstr);
textField.setText(uppershow);
}

private double getAns() {
if(uppershow.indexOf("-") != -1) {
return Double.parseDouble(s1) - Double.parseDouble(s2);
} else if(uppershow.indexOf("+") != -1) {
return Double.parseDouble(s1) + Double.parseDouble(s2);
} else if(uppershow.indexOf("*") != -1) {
return Double.parseDouble(s1) * Double.parseDouble(s2);
} else if(uppershow.indexOf("/") != -1) {
return Double.parseDouble(s1) / Double.parseDouble(s2);
} else if(uppershow.indexOf("mod") != -1) {
return Double.parseDouble(s1) % Double.parseDouble(s2);
}
return 0;
}

}

// create a component
Component createComponent(String info, GridBagConstraints constraint,
int gridx, int gridy, int gridwidth, int gridheight,
double weightx, double weighty) {
Component component;
if(info == "")
component = new JLabel(info);
else
component = new JButton(info);
// adjust the restrictions
constraint.gridx = gridx;
constraint.gridy = gridy;
constraint.gridheight = gridheight;
constraint.gridwidth = gridwidth;
constraint.weightx = weightx;
constraint.weighty = weighty;
// add the button to the panel with constraint
mypanel.add(component, constraint);
return component;
}

public calculator() {
// Basic settings
setTitle("Calculator");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 400, 500);
mypanel = new JPanel();

// Adjust the layout type
setLayout(new BorderLayout());
add(mypanel, BorderLayout.CENTER);

// To set the constraints
mypanel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;

// To make the textField
textField = (JLabel)createComponent("", gbc, 0, 0, 4, 1, 1.0, 0.1);
showOut = (JLabel)createComponent("", gbc, 0, 1, 4, 1, 1.0, 0.3);
textField.setText("NULL");
showOut.setText("0");
showOut.setHorizontalAlignment(SwingConstants.RIGHT);
textField.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.BLACK));
showOut.setBorder(new EmptyBorder(5, 5, 5, 5));

textField.setFont(new Font("Arial", Font.PLAIN, 16));
showOut.setFont(new Font("Arial", Font.ITALIC, 32));

number = new JButton[10];
for(int i = 7; i <= 9; ++i) {
number[i] = (JButton)createComponent(String.valueOf(i), gbc, i - 7, 2, 1, 1, 0.25, 0.15);
}
plus = (JButton)createComponent("+", gbc, 3, 2, 1, 1, 0.25, 0.15);
for(int i = 4; i <= 6; ++i) {
number[i] = (JButton)createComponent(String.valueOf(i), gbc, i - 4, 3, 1, 1, 0.25, 0.15);
}
minus = (JButton)createComponent("-", gbc, 3, 3, 1, 1, 0.25, 0.15);
for(int i = 1; i <= 3; ++i) {
number[i] = (JButton)createComponent(String.valueOf(i), gbc, i - 1, 4, 1, 1, 0.25, 0.15);
}
multiply = (JButton)createComponent("*", gbc, 3, 4, 1, 1, 0.25, 0.15);
point = (JButton)createComponent(".", gbc, 0, 5, 1, 1, 0.25, 0.15);
number[0] = (JButton)createComponent("0", gbc, 1, 5, 1, 1, 0.25, 0.15);
equal = (JButton)createComponent("=", gbc, 2, 5, 1, 1, 0.25, 0.15);
divide = (JButton)createComponent("/", gbc, 3, 5, 1, 1, 0.25, 0.15);

for(int i = 0; i < 10; ++i) {
number[i].setFont(new Font("Arial", Font.PLAIN, 24));
}
plus.setFont(new Font("Arial", Font.PLAIN, 24));
minus.setFont(new Font("Arial", Font.PLAIN, 24));
multiply.setFont(new Font("Arial", Font.PLAIN, 24));
divide.setFont(new Font("Arial", Font.PLAIN, 24));
equal.setFont(new Font("Arial", Font.PLAIN, 24));
point.setFont(new Font("Arial", Font.PLAIN, 24));

for(int i = 0; i < 10; ++i) {
number[i].addActionListener(new numberController(i));
}

plus.addActionListener(new operatorController("+"));
minus.addActionListener(new operatorController("-"));
multiply.addActionListener(new operatorController("*"));
divide.addActionListener(new operatorController("/"));
point.addActionListener(new operatorController("."));
equal.addActionListener(new operatorController("="));

setVisible(true);

}

public static void main(String[] args) {
new calculator();
}
}

最终的样子如下:

image.png

Author

LittleRewriter

Posted on

2020-01-23

Updated on

2021-07-28

Licensed under

Comments