Java--GUI图形用户界面编程(计算器,贪吃蛇)
@ TOC
GUI图形用户界面编程
1. GUI简介
图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。(百度百科)
核心技术:
- AWT
- Swing
缺点:
- 界面不美观
- 需要jre环境才能使用
2. AWT(Abstract Window Toolkit)
AWT(Abstract Window Toolkit)抽象窗口工具包,该包提供了一套与本地图形界面进行交互的接口,是Java提供的用来建立和设置Java的图形用户界面的基本工具。 AWT是Java基础类 (JFC)的一部分,为Java程序提供图形用户界面(GUI)的标准API。
2.1 常用组件
AWT中包含窗口(Frame),画板(Panel),标签(Label),按钮(Button)等组件。
2.1.1 窗口组件
2.1.1.1 Frame
通过静态变量设置窗口长windowHeight和宽windowWidth以及窗口弹出的位置(startX,starty),方便整体的编程和修改。
//创建图像界面窗口并设置标题
Frame frame=new Frame("贪吃蛇");
//设置窗口可见性
frame.setVisible(true);
//设置窗口大小
frame.setSize(windowWidth,windowHeight);
//设置窗口背景颜色
frame.setBackground(new Color(68,150, 131));
//设置窗口弹出的初始位置
frame.setLocation(startX,starty);
//设置窗口大小固定
frame.setResizable(false);
//监听关闭窗口事件--如果不添加该事件,无法通过点击窗口的叉号去关闭窗口
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
});
效果如下:
2.1.1.2 自定义窗口
通过继承Frame类,自定义窗口
public class TestFrame2 {
public static void main(String[] args) {
//展示多个窗口
for (int i = 0; i < 4; i++) {
if(i%2==0){
MyFrame frame=new MyFrame(200,i*100+200,200,200,new Color(i*10,i*30,i*50));
}else {
MyFrame frame=new MyFrame(400,i*100+100,200,200,new Color(i*10,i*30,i*50));
class MyFrame extends Frame{
static int id=0;
public MyFrame(int x,int y,int w,int h,Color color){
super("MyFrame"+(++id));
setVisible(true);
setBounds(x,y,w,h);
setBackground(color);
}
效果如下:
2.1.1.3 窗口监听
设置窗口监听事件,如窗口激活(windowActivated),窗口关闭(windowClosing),窗口停用(windowDeactivated)等。
public class TestWindow {
public static void main(String[] args) {
new WindowFrame();
class WindowFrame extends Frame{
public WindowFrame(){
setBackground(Color.blue);
setBounds(100,100,200,200);
setVisible(true);
// addWindowListener(new MyWindowListener());
this.addWindowListener(new WindowAdapter() {
//关闭窗口
@Override
public void windowClosing(WindowEvent e) {
System.out.println("windowClosing");
System.exit(0);
//激活窗口
@Override
public void windowActivated(WindowEvent e) {
WindowFrame frame = (WindowFrame) e.getSource();
frame.setTitle("窗口被激活");
System.out.println("windowActivated");
}
效果如下: 鼠标未点击窗口外的位置时,窗口处于激活状态, 当鼠标点击窗口外位置时,窗口处于待激活的状态, 再次点击窗口,窗口重新被激活并设置标题为 “窗口被激活”
2.1.2 Panel画板
画板是位于窗口内的一个组件,窗口内一般包含一个或多个画板。然后将其他组件添加到画板上,到达最终效果。
Frame frame=new Frame();
//创建面板
Panel panel=new Panel();
//设置布局
frame.setLayout(null);
frame.setBounds(frameX,frameY,frameW,frameH);
frame.setBackground(new Color(0x00281F));
//panel设置坐标,相对于frame
panel.setBounds(panelX,panelY,panelW,panelH);
panel.setBackground(new Color(0x480050));
//窗口添加画板
frame.add(panel);
frame.setVisible(true);
//监听事件,实现关闭窗口 System.exit(0)
//适配器模式:
frame.addWindowListener(new WindowAdapter() {
//窗口点击关闭时需要做的事
@Override
public void windowClosing(WindowEvent e) {
//结束程序
System.exit(0);
});
效果如下:
2.2 布局
2.2.1 流式布局FlowLayout
流式布局:从左到右依次排列组件
public static void main(String[] args) {
Frame frame=new Frame();
//组件--按钮
Button button1=new Button("button1");
Button button2=new Button("button2");
Button button3=new Button("button3");
//设置流式布局
frame.setLayout(new FlowLayout());
// frame.setLayout(new FlowLayout(FlowLayout.LEFT));
// frame.setLayout(new FlowLayout(FlowLayout.RIGHT));
frame.setBounds(100,100,200,200);
frame.setVisible(true);
frame.add(button1);
frame.add(button2);
frame.add(button3);
}
效果如下:
2.2.2 东西南北中布局BorderLayout
东西南北中布局:见名知意,分为东西南北中五个位置,其中中间的位置最大,东西南北都只有很小的空间。
public class TestBorderLayout {
public static void main(String[] args) {
Frame frame=new Frame("TestBorderLayout");
Button east=new Button("east");
Button west=new Button("west");
Button south=new Button("south");
Button north=new Button("north");
Button center=new Button("center");
frame.add(east,BorderLayout.EAST);
frame.add(west,BorderLayout.WEST);
frame.add(south,BorderLayout.SOUTH);
frame.add(north,BorderLayout.NORTH);
frame.add(center,BorderLayout.CENTER);
frame.setBounds(100,100,500,500);
frame.setVisible(true);
}
效果如下:
2.2.3 网格布局GridLayout
网格布局:设置行和列的数量划分网格
public class TestGridLayout {
public static void main(String[] args) {
Frame frame=new Frame();
//组件--按钮
Button button1=new Button("button1");
Button button2=new Button("button2");
Button button3=new Button("button3");
Button button4=new Button("button4");
Button button5=new Button("button5");
Button button6=new Button("button6");
frame.setLayout(new GridLayout(3,2));
frame.setBounds(100,100,500,500);
frame.setVisible(true);
frame.add(button1);
frame.add(button2);
frame.add(button3);
frame.add(button4);
frame.add(button5);
frame.add(button6);
}
效果如下:
2.2.4 布局案例
利用上述3种布局方法,实现如下效果
public class LayoutDemo {
public static void main(String[] args) {
Frame frame=new Frame("测试布局");
frame.setBounds(300,300,400,300);
frame.setLayout(new GridLayout(2,1));
frame.setVisible(true);
Panel panel1=new Panel(new BorderLayout());
panel1.add(new Button("button1"),BorderLayout.WEST);
panel1.add(new Button("button2"),BorderLayout.EAST);
Panel panel3=new Panel(new GridLayout(2,1));
panel1.add(panel3,BorderLayout.CENTER);
panel3.add(new Button("button3"));
panel3.add(new Button("button4"));
panel1.add(panel3);
Panel panel2=new Panel(new BorderLayout());
panel2.add(new Button("button5"),BorderLayout.WEST);
panel2.add(new Button("button6"),BorderLayout.EAST);
Panel panel4=new Panel(new GridLayout(2,2));
for (int i = 0; i < 4; i++) {
panel4.add(new Button("button"+(i+7)));
panel2.add(panel4);
frame.add(panel1);
frame.add(panel2);
//监听关闭窗口事件
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
效果如下:
2.3 事件监听
2.3.1 窗口监听
如2.1.1.3所示,窗口监听包括窗口关闭,激活等。
2.3.2 按钮事件监听
2.3.2.1 一个按钮一个监听事件
实现目标:点击按钮在控制台输出aaa
public class TestActionEvent {
public static void main(String[] args) {
Frame frame=new Frame();
frame.setBounds(100,100,200,300);
Button button=new Button();
frame.add(button);
//构造一个ActionListener,去满足addActionListener()监听事件的需求
MyActionListener listener=new MyActionListener();
button.addActionListener(listener);
frame.pack();
frame.setVisible(true);
//监听关闭窗口事件
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
class MyActionListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("aaa");
}
2.3.2.2 多个按钮共享一个监听事件
实现目标:运行程序,窗口中间使用xx年xx月xx日 HH:mm:ss格式显示日期时间。点击change按钮修改日期时间显示格式xx-xx-xx HH:mm:ss,点击refresh按钮再次将日期时间显示格式修改为xx年xx月xx日 HH:mm:ss。
public class TestActionEvent2 {
public static void main(String[] args) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Frame frame=new Frame();
frame.setBounds(100,100,300,500);
//标签:显示时间
Label label=new Label();
label.setPreferredSize(new Dimension(400,300));
label.setAlignment(Label.CENTER);
label.setFont(new Font("宋体",Font.PLAIN,20));
label.setBackground(new Color(192,192,192));
label.setText(sdf.format(new Date()));
// System.out.println(String.valueOf(new Date(System.currentTimeMillis())));
//刷新按钮:用来刷新标签显示的时间
MyMonitor monitor=new MyMonitor(label);
Button button1=new Button("refresh");
button1.setPreferredSize(new Dimension(200,300));
button1.setFont(new Font("宋体",Font.PLAIN,24));
button1.setActionCommand("refresh");
button1.addActionListener(monitor);
//格式转换按钮:用来转换标签时间显示的格式
Button button2=new Button("change");
button2.setPreferredSize(new Dimension(200,300));
button2.setFont(new Font("宋体",Font.PLAIN,24));
button2.setActionCommand("change");
button2.addActionListener(monitor);
frame.add(button1,BorderLayout.EAST);
frame.add(button2,BorderLayout.WEST);
frame.add(label,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
class MyMonitor implements ActionListener{
private Label label;
public MyMonitor(Label label) {
this.label = label;
@Override
public void actionPerformed(ActionEvent e) {
try {
if(e.getActionCommand().equals("refresh")){
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
label.setText(sdf.format(new Date()));
}else if(e.getActionCommand().equals("change")){
SimpleDateFormat sdf1=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date date=sdf1.parse(label.getText());
label.setText(date.toLocaleString());
} catch (ParseException parseException) {
parseException.printStackTrace();
}
效果如下:
2.3.3 文本域事件监听
实现目标:在文本域中输入文字,点击回车键,将输入的文字打印到控制台并清空文本域。
public class TestInputText {
public static void main(String[] args) {
new MyFrame1();
class MyFrame1 extends Frame {
public MyFrame1(){
setBounds(300,300,800,300);
TextField textField=new TextField();
add(textField);
//监听文本框输入的数字
MyActionListener2 listener2=new MyActionListener2();
//按下enter就会出发事件
textField.addActionListener(listener2);
//设置替换编码
// textField.setEchoChar('*');
setVisible(true);
//监听关闭窗口事件
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
class MyActionListener2 implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
TextField field=(TextField) e.getSource();//获取一些二资源,返回一个对象
System.out.println(field.getText());//获得输入框的文本
field.setText(""); //清空输入框
}
2.3.4 键盘事件监听
实现目标:识别键盘上按下的是不是方向键中的上键,如果是在控制台中打印出”你按的是上键“。
public class TestKeyListener {
public static void main(String[] args) {
new KeyFrame();
class KeyFrame extends Frame{
public KeyFrame(){
setBounds(1,2,300,400);
setVisible(true);
this.addKeyListener(new KeyAdapter() {
//键盘按下
@Override
public void keyPressed(KeyEvent e) {
//获取当前按下的是那个键
int keyCode=e.getKeyCode();
if(keyCode==KeyEvent.VK_UP){
System.out.println("你按的是上键");
}
2.3.5 鼠标监听事件
实现目标:识别鼠标在窗口的位置,点击鼠标时在窗口的该位置留下一个点。
public class TestMouseListener {
public static void main(String[] args) {
new MyFrame3("画图");
class MyFrame3 extends Frame{
ArrayList points;
public MyFrame3(String title){
super(title);
setBounds(200,200,400,300);
//创建一个list存放鼠标点击的点
points=new ArrayList<>();
//鼠标监听器,
this.addMouseListener(new MyMouseListener());
setVisible(true);
//点击关闭按钮结束程序
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
@Override
public void paint(Graphics g) {
//画画,监听鼠标事件
Iterator iterator=points.iterator();
while (iterator.hasNext()){
Point point= (Point) iterator.next();
g.setColor(Color.blue);
g.fillOval(point.x,point.y,5,5);
//添加一个点到窗口
public void addPaint(Point point){
points.add(point);
//适配器模式
private class MyMouseListener extends MouseAdapter{
//鼠标模式:按下,弹起,按住不放
@Override
public void mousePressed(MouseEvent e) {
MyFrame3 myFrame=(MyFrame3) e.getSource();
myFrame.addPaint(new Point(e.getX(),e.getY()));
//每次点击鼠标都需要重画一遍
myFrame.repaint();
}
2.4 小结案例--计算器
package com.yang.learning.GUILearning.AWT;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
* 模拟计算器
* @Author yang97
* @Date 2022/9/29 16:36
public class TestCalc {
public static void main(String[] args) {
new Calculator().loadFrame();
//计算器类
class Calculator extends Frame{
TextField textField;
Panel panel,panel1,panel2,panel3;
MyButton button1;
public void loadFrame(){
setTitle("计算器");
setBounds(500,500,600,400);
//文本框
textField=new TextField();
textField.setPreferredSize(new Dimension(600,80));
textField.setBackground(new Color(0x30C1D2F0, true));
textField.setFont(new Font("宋体",Font.PLAIN,24));
//按钮0~9,+,-,*,/,=共15个按钮
//画板,放所有按钮
panel=new Panel(new GridLayout(1,2));
panel.setBounds(0,200,600,600);
//放1-9
panel1=new Panel(new GridLayout(3,3));
for (int i = 9; i > 0; i--) {
panel1.add(new MyButton(String.valueOf(i),this));
//放+,-,*,/,0,=,清空键C
panel2=new Panel(new GridLayout(3,2));
panel2.add(new MyButton("+",this));
panel2.add(new MyButton("-",this));
panel2.add(new MyButton("*",this));
panel2.add(new MyButton("/",this));
panel2.add(new MyButton("0",this));
panel2.add(new MyButton("=",this));
//放panel2和清空键C
panel3=new Panel(new BorderLayout());
button1=new MyButton("C",this);
button1.setPreferredSize(new Dimension(240,60));
panel3.add(button1,BorderLayout.NORTH);
panel3.add(panel2);
panel.add(panel1);
panel.add(panel3);
add(textField,BorderLayout.NORTH);
add(panel);
setVisible(true);
//点击关闭按钮结束程序
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
//按钮类,修改按钮的字体和背景,添加不同的监听器
class MyButton extends Button{
public MyButton(String label,Calculator calculator){
super(label);
setFont(new Font("宋体",Font.PLAIN,24));
setBackground(new Color(192,192,192));
setActionCommand(label);
if(label.equals("=")){
addActionListener(new MyCalcListener(calculator));
}else {
addActionListener(new InputListener(calculator));
//监听器类--监听输入
class InputListener implements ActionListener{
private Calculator calculator;
public InputListener(Calculator calculator){
this.calculator=calculator;
@Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("C")){
calculator.textField.setText("");
}else {
calculator.textField.setText(calculator.textField.getText()+e.getActionCommand());
//监听器类--监听计算
class MyCalcListener implements ActionListener{
private Calculator calculator;
public MyCalcListener(Calculator calculator) {
this.calculator = calculator;
@Override
public void actionPerformed(ActionEvent e) {
String str=calculator.textField.getText();
//获取两个操作数
String[] array=str.split("\\+|\\/|\\*|\\-");
//获取操作符
String op= str.split(array[0])[1].split(array[1])[0];
//类型转换
int n1=Integer.parseInt(array[0]);
int n2=Integer.parseInt(array[1]);
if(op.equals("+")){
calculator.textField.setText(""+(n1+n2));
}else if(op.equals("-")){
calculator.textField.setText(""+(n1-n2));
}else if(op.equals("*")){
calculator.textField.setText(""+(n1*n2));
}else if(op.equals("/")){
if(n2==0){
calculator.textField.setText("除0错误,一秒后清空输入框!");
try {
Thread.sleep(1000);
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
calculator.textField.setText("");
}else {
calculator.textField.setText(""+(n1/n2));
}
效果如下:
3. Swing
Swing是一个用于开发Java应用程序用户界面的开发工具包。Swing具有丰富、灵活的功能和模块化组件可用来创建更优美的用户界面。
3.1 JFrame窗口
相比于Frame,JFrame不需要监听窗口关闭事件,只需要设置默认关闭i操作即可。 Frame一般将组件放置于Panel中,JFrame一般将组件放置于container中
//JFrame
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//Frame
//监听关闭窗口事件
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
public class TestJFrame2 {
public static void main(String[] args) {
new MyJFrame().init();
class MyJFrame extends JFrame{
public void init(){
setBounds(100,200,300,400);
setVisible(true);
setBackground(Color.gray);
//设置默认关闭操作
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JLabel label=new JLabel("欢迎使用Swing");
//水平对齐,居中
label.setHorizontalAlignment(SwingConstants.CENTER);
//获得一个容器
Container container=this.getContentPane();
container.setBackground(Color.ORANGE);
this.add(label);
}
3.2 JPanel
public class JPanelDemo extends JFrame {
public JPanelDemo() {
Container container=getContentPane();
container.setLayout(new GridLayout(2,1,10,10));
JPanel panel1=new JPanel(new GridLayout(1,3));
JPanel panel2=new JPanel(new GridLayout(3,1));
JPanel panel3=new JPanel(new GridLayout(2,3));
JPanel panel4=new JPanel(new GridLayout(1,3));
panel1.add(new JButton("1"));
panel1.add(new JButton("2"));
panel1.add(new JButton("3"));
panel2.add(new JButton("1"));
panel2.add(new JButton("2"));
panel2.add(new JButton("3"));
panel3.add(new JButton("1"));
panel3.add(new JButton("1"));
panel3.add(new JButton("1"));
panel3.add(new JButton("2"));
panel3.add(new JButton("2"));
panel3.add(new JButton("2"));
panel4.add(new JButton("1"));
panel4.add(new JButton("2"));
panel4.add(new JButton("3"));
container.add(panel1);
container.add(panel2);
container.add(panel3);
container.add(panel4);
this.setVisible(true);
this.setBounds(100,100,400,400);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
public static void main(String[] args) {
new JPanelDemo();
}
效果如下:
3.3 按钮(图片按钮,单选按钮,多选按钮)
public class JButtonDemo extends JFrame {
public JButtonDemo(){
Container container=getContentPane();
URL res=JButtonDemo.class.getResource("1.jpg");
Icon icon=new ImageIcon(res);
//图标按钮,把图标放在按钮上
JButton button=new JButton();
button.setIcon(icon);
button.setToolTipText("图片按钮");
//单选框按钮JRadioButton
JRadioButton button1=new JRadioButton("button1");
JRadioButton button2=new JRadioButton("button2");
JRadioButton button3=new JRadioButton("button3");
//需要将多个按钮分到一个组中
ButtonGroup group=new ButtonGroup();
group.add(button1);
group.add(button2);
group.add(button3);
//多选框
JCheckBox checkBox1=new JCheckBox("checkBox1");
JCheckBox checkBox2=new JCheckBox("checkBox2");
container.setLayout(new FlowLayout());
container.add(button);
container.add(button1);
container.add(button2);
container.add(button3);
container.add(checkBox1);
container.add(checkBox2);
this.setVisible(true);
this.setBounds(100,100,400,400);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
public static void main(String[] args) {
new JButtonDemo();
}
效果如下:
3.4 文本域,滚动面板
public class JScrollDemo extends JFrame {
public JScrollDemo() {
Container container=this.getContentPane();
//文本域
JTextArea textArea=new JTextArea(20,50);
textArea.setText("欢迎学习java");
//Scroll面板
JScrollPane scrollPane=new JScrollPane(textArea);
container.add(scrollPane);
this.setVisible(true);
this.setBounds(100,100,400,400);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
public static void main(String[] args) {
new JScrollDemo();
}
效果如下:
3.5 下拉框和列表
public class ComboBoxDemo1 extends JFrame{
public ComboBoxDemo1() {
Container container=getContentPane();
JComboBox comboBox=new JComboBox();
comboBox.addItem("null");
comboBox.addItem("过去");
comboBox.addItem("现在");
comboBox.addItem("未来");
container.add(comboBox);
this.setVisible(true);
this.setBounds(100,100,400,70);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
public static void main(String[] args) {
new ComboBoxDemo1();
public class ComboBoxDemo2 extends JFrame{
public ComboBoxDemo2() {
Container container=getContentPane();
//生成列表内容
String[] content={"天","生","我","材","必","有","用",",","千","金","散","去","还","复","来"};
JList jList=new JList(content);
container.add(jList);
this.setVisible(true);
this.setBounds(100,100,400,400);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
public static void main(String[] args) {
new ComboBoxDemo2();
}
效果如下:
3.6 弹窗
public class DialogDemo extends JFrame {
public DialogDemo(){
this.setVisible(true);
this.setBounds(100,200,300,400);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//容器,用来放组件
Container container=this.getContentPane();
container.setLayout(null); //绝对布局
JButton button=new JButton("点击弹出一个对话框");
button.setBounds(30,30,200,50);
//按钮监听事件,点击按钮弹出一个对话框
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new MyDialog();
this.add(button);
public static void main(String[] args) {
new DialogDemo();
class MyDialog extends JDialog{
public MyDialog() {
this.setVisible(true);
this.setBounds(100,100,300,300);
this.setTitle("欢迎查看弹窗");
}
效果如下:
4. 小结案例--贪吃蛇
启动游戏界面
package com.yang.learning.GUILearning.SnakeGluttony;
import javax.swing.*;
* 启动游戏界面
* D0D0D0
* @Author yang97
* @Date 2022/10/20 19:34
public class StartGame {
public static void main(String[] args) {
JFrame frame=new JFrame();
frame.setBounds(10,10,900,720);
frame.setTitle("贪吃蛇");
// frame.setIconImage();
//游戏界面
frame.add(new GamePanel());
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
资源界面
package com.yang.learning.GUILearning.SnakeGluttony;
import javax.swing.*;
import java.net.URL;
* @Author yang97
* @Date 2022/10/20 20:09
public class Data {
public static URL upURL=Data.class.getResource("statics/up.png");
public static URL downURL=Data.class.getResource("statics/down.png");
public static URL leftURL=Data.class.getResource("statics/left.png");
public static URL rightURL=Data.class.getResource("statics/right.png");
public static ImageIcon up=new ImageIcon(upURL);
public static ImageIcon down=new ImageIcon(downURL);
public static ImageIcon left=new ImageIcon(leftURL);
public static ImageIcon right=new ImageIcon(rightURL);
public static URL headerURL=Data.class.getResource("statics/header.png");
public static URL bodyURL=Data.class.getResource("statics/body.png");
public static URL foodURL=Data.class.getResource("statics/food.png");
public static ImageIcon header=new ImageIcon(headerURL);
public static ImageIcon body=new ImageIcon(bodyURL);
public static ImageIcon food=new ImageIcon(foodURL);
}
游戏面板
package com.yang.learning.GUILearning.SnakeGluttony;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
* @Author yang97
* @Date 2022/10/20 19:38
public class GamePanel extends JPanel implements KeyListener, ActionListener {
//蛇的属性
int length; //蛇的长度
int[] snakeX=new int[600]; //蛇的X坐标
int[] snakeY=new int[600]; //蛇的Y坐标
String fx; //初始时蛇头朝向的方向
//食物的坐标
int foodX;
int foodY;
Random random=new Random(); //随机种子
//游戏当前状态属性
boolean isStart=false; //默认是不开始
//定义游戏状态
boolean isFail=false;
int score;
//定时器,以毫秒为单位
Timer timer=new Timer(100,this); //100毫秒一次
public GamePanel() {
init();
//获得焦点和键盘事件
this.setFocusable(true); //获得焦点事件
this.addKeyListener(this); //获得键盘监听事件
timer.start(); //游戏一开始就启动定时器
public void init(){
//初始化小蛇
length=3; //初始长度为3
snakeX[0]=100; snakeY[0]=100; //脑袋的坐标
snakeX[1]=75; snakeY[1]=100; //第一个身体的坐标
snakeX[2]=50; snakeY[2]=100; //第二个身体的坐标
fx="R";
//初始化食物,随机分布在画布上
foodX=25+25*random.nextInt(850/25);
foodY=75+25*random.nextInt(650/25);
//初始成绩
score=0;
//绘制面板,绘制游戏界面
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //清屏
//绘制静态面板
this.setBackground(new Color(73, 72, 72));
//画头部标题栏
Data.header.paintIcon(this,g,25,11);
//画成绩
g.setColor(Color.BLACK);
g.setFont(new Font("楷体",Font.BOLD,30));
g.drawString("长度:"+length,550,50);
g.drawString("分数:"+score,700,50);
//画默认游戏界面
g.setColor(Color.gray);
g.fillRect(25,75,850,600);
//画初始小蛇,初始蛇头向右
if(fx.equals("R")){
Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if(fx.equals("L")){
Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if(fx.equals("U")){
Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if(fx.equals("D")){
Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);
for(int i=1;i<length;i++){
Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
//绘制食物
Data.food.paintIcon(this,g,foodX,foodY);
//游戏状态
if(isStart==false){
g.setColor(Color.WHITE);
g.setFont(new Font("楷体",Font.BOLD,40));
g.drawString("按下空格开始游戏",300,300);
if(isFail){
g.setColor(Color.RED);
g.setFont(new Font("楷体",Font.BOLD,40));
g.drawString("游戏失败,按下空格重新开始游戏",150,300);
//键盘监听事件===通过键盘事件刷新
@Override
public void keyPressed(KeyEvent e) {
int keyCode=e.getKeyCode();
//开始暂停游戏
if(keyCode==KeyEvent.VK_SPACE){
if(isFail){
isFail=false;
init();
}else {
isStart=!isStart;
repaint();
//小蛇移动
if(keyCode==KeyEvent.VK_UP){
fx="U";
}else if(keyCode==KeyEvent.VK_DOWN){
fx="D";
}else if(keyCode==KeyEvent.VK_LEFT){
fx="L";
}else if(keyCode==KeyEvent.VK_RIGHT){
fx="R";
//事件监听===通过固定事件刷新
@Override
public void actionPerformed(ActionEvent e) {
if(isStart && isFail==false){ //如果游戏是开始状态,小蛇移动
//吃食物
if(snakeX[0]==foodX&&snakeY[0]==foodY){
length++; //长度加一
score+=10; //分数加10
//再次随机刷新食物
foodX=25+25*random.nextInt(34);
foodY=75+25*random.nextInt(24);
//小蛇移动
for(int i =length-1;i>0;i--){
snakeX[i]=snakeX[i-1]; //向前移动一节
snakeY[i]=snakeY[i-1]; //向前移动一节
if(fx.equals("R")){
snakeX[0]=snakeX[0]+25;
//边界判断,超过边界后从另一边回来
if(snakeX[0]>850){ snakeX[0]=25; }
}else if(fx.equals("L")){
snakeX[0]=snakeX[0]-25;
//边界判断,超过边界后从另一边回来
if(snakeX[0]<25){ snakeX[0]=850; }
}else if(fx.equals("U")){
snakeY[0]=snakeY[0]-25;
//边界判断,超过边界后从另一边回来
if(snakeY[0]<75){ snakeY[0]=650; }
}else if(fx.equals("D")){
snakeY[0]=snakeY[0]+25;
//边界判断,超过边界后从另一边回来
if(snakeY[0]>650){ snakeY[0]=75; }
//失败判定,撞到自己
for (int i = 1; i < length; i++) {
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
isFail=true;
repaint(); //重画页面
timer.start();
@Override