项目驱动的Swing和Graphic类学习

JFrame窗口的构建

为了实现良好的交互效果,合适的GUI窗口是十分必要的。在Java中可以使用Swing组件和Applet组件来实现。本次主要使用Swing组件的JFrame窗口。
插入窗口需要在方法或构造体中声明

1
2
3
4
private JFrame frame = new JFrame("Let's Draw!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置默认关闭状态
frame.setVisible(true); // JFrame窗口默认是透明的,需要设置成可见状态
frame.setSize(400450); // 设置窗口的大小

单击关闭窗口操作

1
2
3
4
JFrame.EXIT_ON_CLOSE    // 退出窗口,结束程序
JFrame.DO_NOTHING_ON_CLOSE // 不做任何操作
JFrame.HIDE_ON_CLOSE // 最小化
JFrame.DISPOSE_ON_CLOSE // 关闭窗口,释放资源

JFrame容器组装

GUI组件必须装在容器中,不能独立使用。必须通过.add()组装。而JFrame下可以放2种容器,常用的是ContentPane(),需要在其后.add()。

1
2
3
4
5
6
7
8
9
10
11
frame.getContentPane().add(scrollPane);
frame.getContentPane().add(listTip);
frame.getContentPane().add(drawRectangleButton);
frame.getContentPane().add(drawCircleButton);
frame.getContentPane().add(drawTriangleBtn);
frame.getContentPane().add(drawDraft);
frame.getContentPane().add(search);
frame.getContentPane().add(inputNameTip);
frame.getContentPane().add(inputName);
frame.getContentPane().add(inputOrder);
frame.getContentPane().add(inputOrderTip);

而更为通用的JPanel此处没有使用。
此工程没有使用布局,所以需要指定组件位置、大小与布局设置,避免出现bug。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
drawRectangleButton.setBounds(10, 10, 150, 30);
drawCircleButton.setBounds(10, 60, 150, 30);
drawTriangleBtn.setBounds(10, 110, 150, 30);
drawDraft.setBounds(10,160,150,30);
search.setBounds(10,210,150,30);
inputNameTip.setBounds(10,260,150,15);
inputName.setBounds(10,290,150,15);
inputOrderTip.setBounds(10,320,150,15);
inputOrder.setBounds(10,350,150,15);
listTip.setBounds(200,10,180,30);
scrollPane.setBounds(200,60,180,280);

frame.setLayout(null); // 布局设置
frame.setLocationRelativeTo(null);

常用布局:

1
2
3
4
5
6
7
8
9
10
frame.setLayout(new FlowLayout());
// 流式布局管理器,组件从左到右,从上到下摆放,间隔5像素
frame.setLayout(new BorderLayout());
// 边界布局管理器,需要在.add()中增加方向参数,组件中没有间隙
frame.setLayout(new GridLayout());
// 网格布局管理器,将容器分成数个网格单元,每个单元可容纳一个组件
frame.setLayout(new CardLayout());
// 卡片布局管理器,可以使多个组件共享同一显示空间
frame.setLayout(new GridBagLayout());
// 网格包布局管理器

JFrame部分组件介绍

JButton是一种按钮组件,声明如下

1
2
3
4
5
private JButton drawRectangleButton = new JButton("A Rectangle");
private JButton drawCircleButton = new JButton("A Circle");
private JButton drawTriangleBtn = new JButton("A Triangle");
private JButton drawDraft = new JButton("Draw Anything");
private JButton search = new JButton("Search");

常用点击事件,重写相关方法以完成操作

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
drawRectangleButton.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
String name = inputName.getText();
int order;
boolean isException = false;
try {
order = Integer.parseInt(inputOrder.getText());
} catch (NumberFormatException ex) {
isException = true;
order = 0;
}
if((name == null || name.isEmpty()) && isException){
new construct("rectangle");
new insertList("rectangle");
} else if ((name == null || name.isEmpty())) {
new construct("rectangle",order);
new insertList("rectangle",order);
} else if (isException) {
new construct("rectangle",name);
new insertList("rectangle",name);
} else {
new construct("rectangle",name,order);
new insertList("rectangle",name,order);
}
}
scrollPane.repaint();
});

同理可重写其他按钮的相关方法。

JLabel用于文本框中显示信息,声明如下

1
2
3
private JLabel inputNameTip = new JLabel("Input Name");
private JLabel inputOrderTip = new JLabel("Inout Order");
private JLabel listTip = new JLabel("History");

JTextArea用于文本框中输入信息,显示信息也可,声明如下

1
2
private JTextArea inputName = new JTextArea();
private JTextArea inputOrder = new JTextArea();

可以使用变量来接受获得的数据

1
String name = inputName.getText();
1
2
int order;
boolean isException = false;

但获得的不一定是自己想要的数据,一般情况下是使用滑条,不过此处使用了异常处理。

1
2
3
4
5
6
try {
order = Integer.parseInt(inputOrder.getText());
} catch (NumberFormatException ex) {
isException = true;
order = 0;
}

尝试捕捉相关异常,当获得异常时不报错,而是执行相关操作。此处暴躁地直接附0。而对于字符串而言,可以使用if判断字符串的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
if((name == null || name.isEmpty()) && isException){
new construct("rectangle");
new insertList("rectangle");
} else if ((name == null || name.isEmpty())) {
new construct("rectangle",order);
new insertList("rectangle",order);
} else if (isException) {
new construct("rectangle",name);
new insertList("rectangle",name);
} else {
new construct("rectangle",name,order);
new insertList("rectangle",name,order);
}

Jlist与JScrollPane是一类较难用的组件。其声明如下

1
2
3
private DefaultListModel<String> listModel = new DefaultListModel<>();  // 先定义一个列表
private JList<String> history = new JList<>(listModel); // 再定义JList,关联到列表上
private JScrollPane scrollPane = new JScrollPane(history); // 再将滚轮组件包络到列表上

设置滚动条(此处横向滚动条在显示不下时才显示,纵向滚动条一直显示)

1
2
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

添加相关操作,此处是双击操作

1
2
3
4
5
6
7
8
9
10
11
12
history.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if(e.getClickCount() == 2){
int index = history.locationToIndex(e.getPoint());
if(index >= 0 && index < Main.getData().size()){
Main.getData().get(index).drawFigure();
}
}
}
});

Graghics类的使用

在此处,该类通过重写JPanel.paint()方法来实现Graphics类的使用,理由很简单,Graghics类不能直接引用。以rectangle的绘制为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private Random ram = new Random();
private final int x1 = ram.nextInt(250);
private final int x2 = ram.nextInt(250);
private final int y1 = ram.nextInt(200);
private final int y2 = ram.nextInt(200);
@Override
public void drawFigure() {
var window = new JFrame(this.getName() + " Rectangle " + this.getOrder());
var draw = new myJPanels();

window.setContentPane(new myJPanels());
draw.setSize(500, 400);
window.setSize(500,400);

window.setVisible(true);
window.setLayout(null);
window.setLocationRelativeTo(null);
}
private class myJPanels extends JPanel {
public void paint(Graphics gr) {
gr.setColor(Color.BLACK);
gr.drawRect(x1,y1,x2,y2);
}
}

自由绘制模式的另类实现

为了提供自由选择多边形绘画的功能,本人干脆搞了个自由画板,虽然获取鼠标位置的方法精准度基本没有,但还能用。此处直接粘贴,不做解释。
注意,每一次画完后需要重绘画板。

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
private DrawCraft.myJPanels draw = new DrawCraft.myJPanels();
private ArrayList<coordinatePoint> array = new ArrayList<>();

@Override
public void drawFigure() {

draw.setSize(500, 400);
window.setSize(500,400);
window.setContentPane(new DrawCraft.myJPanels());
window.setVisible(true);

window.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
array.add(new coordinatePoint(e.getX(), e.getY()));
window.repaint();
}
});

window.setLayout(null);
window.setLocationRelativeTo(null);
}
static class coordinatePoint{
private int x;
private int y;
private coordinatePoint(int x, int y){
this.x = x;
this.y = y;
}
int getX(){
return this.x;
}
int getY(){
return this.y;
}
}

再加上一些堆料,和search框的绘制,一个前端工程就画好了!


项目驱动的Swing和Graphic类学习
http://example.com/2024/04/23/java-SwingLearning/
作者
Ivan Chen
发布于
2024年4月23日
许可协议
IVAN