1、简介
Gui的核心技术: Swing和AWT
1.因为界面不美观。
2.需要jre环境!
为什么我们要学习?
1.可以写出自己心中想要的一-些小工具
2.工作时候,也可能需要维护到swing界面,概率极小!
3.了解MVC架构,了解监听!
2、AWT
2.1 Awt介绍
1.包含了很多类和接口! GUI!
2.元素:窗口,按钮,文本框
3. java.awt
2.2 面板panel
frame 包含 面板
关闭事件用适配器adapter解决
2.3 布局管理器
- 流式布局
- 东西南北中
- 表格布局 grid
总结:
Frame是顶级窗口
Panel无法单独显示, 必须添加到容器中
注意大小,定位,背景颜色,可见性,监听
2.4 事件监听
某个事情发生的时候,做什么。
2.5 计算器(输入框监听)TextField
面向过程写法:
package com.GUI;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
// 面向过程写法
public class calculator {
public static void main(String[] args) {
cal c = new cal();
windowClose(c);
}
// 关闭窗体的事件
private static void windowClose(Frame frame){
// 监听事件,监听窗口关闭事件
frame.addWindowListener(new WindowAdapter(){
// 窗口关闭时要做的事情
@Override
// 通过继承监听器的父抽象类,重新实现窗口关闭事件
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
// 计算类
class cal extends Frame{
// 加入监听后 似乎就处于一个循环的过程
public cal(){
//3个文本框
TextField T1 = new TextField(10); //
TextField T2 = new TextField(10); //
TextField T3 = new TextField(20); //
//1个按钮
Button B1 = new Button("=");
B1.addActionListener(new MyActionListener_cal(T1, T2, T3)); //按下按钮,便触发了事件
//1个标签
Label L1 = new Label("+");
//布局
setLayout(new FlowLayout());
add(T1); //T1
add(L1); //+
add(T2); //T2
add(B1); //=
add(T3); //T3
//最后
pack();
setVisible(true);
}
}
// 监听器类
class MyActionListener_cal implements ActionListener{
// 获取三个变量
private TextField num1, num2, num3;
// 传进外面的变量
public MyActionListener_cal(TextField num1, TextField num2, TextField num3) {
this.num1 = num1;
this.num2 = num2;
this.num3 = num3;
}
// 重写监听事件
@Override
public void actionPerformed(ActionEvent e) {
// 1.获得加数和被加数
int i1 = Integer.parseInt(num1.getText()); // 文本String转Int类型
int i2 = Integer.parseInt(num2.getText());
// int i3 = Integer.parseInt(num3.getText());
// 2. 加法运算后 值放入第三个框
num3.setText(""+(i1+i2));
// 3. 清除前两个框
num1.setText("");
num2.setText("");
// TextField field = (TextField) e.getSource(); // 获得一些资源, 返回了一个对象。 用类对象强制转换
// System.out.println(field.getText()); // 获得输入框的文本
// field.setText(""); // enter触发后 自动将文本置为空
}
}
面向对象写法
package com.GUI;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
// 面向对象写法
public class calculator_advanced {
public static void main(String[] args) {
cal c = new cal();
windowClose(c);
}
// 关闭窗体的事件
private static void windowClose(Frame frame){
// 监听事件,监听窗口关闭事件
frame.addWindowListener(new WindowAdapter(){
// 窗口关闭时要做的事情
@Override
// 通过继承监听器的父抽象类,重新实现窗口关闭事件
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
// 计算类
class cal_ad extends Frame{
// 属性
TextField T1, T2, T3;
// 方法
public void loadFrame(){
//3个文本框
//1个标签
//1个按钮
T1 = new TextField(10); //
T2 = new TextField(10); //
T3 = new TextField(20); //
Label L1 = new Label("+");
Button B1 = new Button("=");
B1.addActionListener(new MyActionListener_cal_ad(this)); //按下按钮,便触发了事件
//布局
setLayout(new FlowLayout());
add(T1); //T1
add(L1); //+
add(T2); //T2
add(B1); //=
add(T3); //T3
//最后
pack();
setVisible(true);
}
}
// 监听器类
class MyActionListener_cal_ad implements ActionListener{
// 直接获取计算器的对象
cal_ad calculator = null; // 初始化一个对象 this.calculator
public MyActionListener_cal_ad(cal_ad calculator) {
this.calculator = calculator; //对象传入
}
// 重写监听事件
@Override
public void actionPerformed(ActionEvent e) {
// 1.获得加数和被加数
// 2. 加法运算后 值放入第三个框
// 3. 清除前两个框
int i1 = Integer.parseInt(calculator.dT1.getText());
int i2 = Integer.parseInt(calculator.T2.getText());
calculator.T3.setText(""+(i1+i2));
calculator.T1.setText("");
calculator.T2.setText("");
}
}
内部类
更好的包装
内部类最大的好处, 就是可以畅通无阻的访问外部类
如果将监听器写入内部类,就不需要重新new一个计算器类对象
可以直接调用计算器的属性
package com.GUI;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
// 面向对象写法
public class calculator_advanced {
public static void main(String[] args) {
cal c = new cal();
windowClose(c);
}
// 关闭窗体的事件
private static void windowClose(Frame frame){
// 监听事件,监听窗口关闭事件
frame.addWindowListener(new WindowAdapter(){
// 窗口关闭时要做的事情
@Override
// 通过继承监听器的父抽象类,重新实现窗口关闭事件
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
// 计算类
class cal_ad extends Frame{
// 属性
TextField T1, T2, T3;
// 方法
public void loadFrame(){
//3个文本框
//1个标签
//1个按钮
T1 = new TextField(10); //
T2 = new TextField(10); //
T3 = new TextField(20); //
Label L1 = new Label("+");
Button B1 = new Button("=");
B1.addActionListener(new MyActionListener_cal_ad()); //按下按钮,便触发了事件
//布局
setLayout(new FlowLayout());
add(T1); //T1
add(L1); //+
add(T2); //T2
add(B1); //=
add(T3); //T3
//最后
pack();
setVisible(true);
}
// 监听器类
private class MyActionListener_cal_ad implements ActionListener{
// 重写监听事件
@Override
public void actionPerformed(ActionEvent e) {
// 1.获得加数和被加数
// 2. 加法运算后 值放入第三个框
// 3. 清除前两个框
int i1 = Integer.parseInt(T1.getText());
int i2 = Integer.parseInt(T2.getText());
T3.setText(""+(i1+i2));
T1.setText("");
T2.setText("");
}
}
}
2.6 画笔paint
package com.GUI;
// import java.util.Date;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class paint1 {
public static void main(String[] args) {
MyPaint p1 = new MyPaint();
p1.loadFrame();
windowClose(p1);
}
private static void windowClose(Frame frame){
// 监听事件,监听窗口关闭事件
frame.addWindowListener(new WindowAdapter(){
// 窗口关闭时要做的事情
@Override
// 通过继承监听器的父抽象类,重新实现窗口关闭事件
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
class MyPaint extends Frame{
public void loadFrame() {
setBounds(200,200,600,400);
setVisible(true);
}
//画笔
@Override
public void paint(Graphics g) {
// 画笔 需要有颜色 可以画画
// g.setColor(Color.red);
g.fillOval(100,100,100,100);
// g.setColor(Color.green);
g.fillRect(150,200,200,200);
// 养成习惯 画笔用完 将其还原最初颜色
}
}
2.7 鼠标监听
package com.GUI;
// import java.util.Date;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
public class mouselistener {
public static void main(String[] args) {
MyMouse m1 = new MyMouse("画图");
// m1.loadFrame();
windowClose(m1);
}
private static void windowClose(Frame frame){
// 监听事件,监听窗口关闭事件
frame.addWindowListener(new WindowAdapter(){
// 窗口关闭时要做的事情
@Override
// 通过继承监听器的父抽象类,重新实现窗口关闭事件
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
class MyMouse extends Frame{
// 绘画需要画笔 需要监听鼠标当前位置 需要集合存储这些点
ArrayList points;
public MyMouse(String title){
super(title);
setBounds(200,200,400,300);
//存鼠标的点
points = new ArrayList<>();
setVisible(true);
// 鼠标监听器 针对这个窗口
this.addMouseListener(new MyMouseListener());
}
@Override
public void paint(Graphics g) {
// 画画 会自动监听鼠标
Iterator iterator = points.iterator();
while (iterator.hasNext()){ //不断迭代points里的元素
Point point = (Point) iterator.next();
g.setColor(Color.BLUE);
g.fillOval(point.x, point.y,10,10);
}
}
//添加一个点到界面上
// public void addPoint(Point point){
// points.add(point);
// }
private class MyMouseListener extends MouseAdapter{
//鼠标动作 按下 弹起 按住不放
@Override
public void mousePressed(MouseEvent e){
MyMouse myMouse = (MyMouse)e.getSource();
// 点击的时候 就会在界面上产生一个点
// 这个点就是鼠标的点
// myMouse.addPoint(new Point(e.getX(), e.getY()));
points.add(new Point(e.getX(), e.getY()));
// 每次点击鼠标 都要重画一遍
myMouse.repaint(); // 刷新
}
}
}
2.8 窗口监听
package com.GUI;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class windowlistener {
public static void main(String[] args) {
new MyWindow();
}
}
class MyWindow extends Frame{
public MyWindow(){
setBackground(Color.red);
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);
// super.windowClosing(e);
}
// 激活窗口
@Override
public void windowActivated(WindowEvent e) {
// super.windowClosing(e);
MyWindow source = (MyWindow) e.getSource(); //将事件监听的结果强制转化为一个对象 然后调用方法
source.setTitle("被激活了");
System.out.println("windowActivated");
}
});
}
}
2.9 键盘监听
package com.GUI;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class keyboardlistener {
public static void main(String[] args) {
new MyKeyListener();
}
}
class MyKeyListener extends Frame{
public MyKeyListener(){
setBounds(1,2,300,400);
setVisible(true);
this.addKeyListener(new KeyAdapter(){
//键盘
@Override
public void keyPressed(KeyEvent e){
// 获得键盘按下的键的码
int keyCode = e.getKeyCode(); //不需要记录这个值 直接使用它的静态属性即可 VK_XXX
System.out.println("你输入了"+keyCode);
if(keyCode==KeyEvent.VK_UP){
System.out.println("你按下了上键!");
}
// 根据不同的键 产生不同的效果
}
});
this.addWindowListener(new WindowAdapter(){
//窗口
@Override
public void windowClosing(WindowEvent w){
super.windowClosing(w);
System.exit(0);
}
});
}
}
3.Swing(稍微比awt高级)
**3.1 窗口、面板 **
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
public class JFrame02 {
public static void main(String[] args) {
new MyJFrame02().init();
}
}
class MyJFrame02 extends JFrame {
public void init(){
// this.setBackground(Color.GREEN);
this.setBounds(10,10,300,300);
this.setVisible(true);
// 设置文字 Label
JLabel lae = new JLabel("欢迎来到我的java", JLabel.CENTER);
this.add(lae);
// 让文本标签居中
// 获得一个容器
Container container = this.getContentPane();
container.setBackground(Color.BLUE);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
3.2 弹窗dialog
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
// 主窗口
public class DialogDemo extends JFrame {
public DialogDemo(){
this.setVisible(true);
this.setBounds(10,10,700,700);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// JFrame 放东西 容器
Container container = this.getContentPane();
// 绝对布局
container.setLayout(null);
// 按钮
JButton b1 = new JButton("点击弹出一个对话框"); // 创建
b1.setBounds(30,30,200,50);
// 点击按钮时 弹出一个弹窗
b1.addActionListener(new ActionListener() { // 监听器
@Override
public void actionPerformed(ActionEvent e) {
// 弹窗
new MyDialog();
}
});
container.add(b1);
}
public static void main(String[] args) {
new DialogDemo();
}
}
// 弹窗的窗口
class MyDialog extends JDialog{
public MyDialog(){
this.setVisible(true);
this.setBounds(100,100,500,500);
// this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JLabel lae = new JLabel("我带你学Java~");
lae.setBounds(20,20,100,100); // 必须设置bound 因为是绝对布局
Container container = this.getContentPane();
container.setLayout(null);
container.add(lae);
}
}
3.3 标签
label
new Label("")
升级为图标ICON
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
public class ImageIconDemo extends JFrame {
public ImageIconDemo(){
// 获取同级目录下对应文件的URL
JLabel label = new JLabel("ImageIconDemo");
URL img_url = ImageIconDemo.class.getResource("CoffeeMan.jpg");
// System.out.println("url: "+img_url);
ImageIcon Ic1 = new ImageIcon(img_url); // 命名切勿冲突
label.setIcon(Ic1);
label.setHorizontalAlignment(SwingConstants.CENTER);
Container container = getContentPane();
container.add(label);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setBounds(100, 100, 200, 200);
}
public static void main(String[] args) {
new ImageIconDemo();
}
}
3.4 面板Jpanel和滚动条JScroll
面板JPanel
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
public class JPanelDemo extends JFrame {
public JPanelDemo(){
Container container = this.getContentPane();
container.setLayout(new GridLayout(2,1,10,10)); // 后两个参数表示间距
JPanel J1 = new JPanel(new GridLayout(1,3));
JPanel J2 = new JPanel(new GridLayout(1,2));
JPanel J3 = new JPanel(new GridLayout(2,1));
JPanel J4 = new JPanel(new GridLayout(3,2));
J1.add(new JButton("1"));
J1.add(new JButton("2"));
J1.add(new JButton("3"));
J2.add(new JButton("1"));
J2.add(new JButton("2"));
J3.add(new JButton("1"));
J3.add(new JButton("2"));
J4.add(new JButton("1"));
J4.add(new JButton("2"));
J4.add(new JButton("3"));
J4.add(new JButton("4"));
J4.add(new JButton("5"));
J4.add(new JButton("6"));
container.add(J1);
container.add(J2);
container.add(J3);
container.add(J4);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(500,500);
this.setVisible(true);
}
public static void main(String[] args) {
new JPanelDemo();
}
}
滚动条面板JScrollPane
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
public class JScrollDemo extends JFrame {
public JScrollDemo(){
Container container = this.getContentPane();
// 文本域 可换行; 文本框 不能
JTextArea textArea = new JTextArea(20, 50);
textArea.setText("欢迎学习");
// Scroll面板
JScrollPane s1 = new JScrollPane(textArea); // 构造函数里写的是 形参:要用于展示的组件
container.add(s1);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setBounds(100,100,300,350);
}
public static void main(String[] args) {
new JScrollDemo();
}
}
3.5 按钮
图片按钮
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
public class JButton01 extends JFrame {
public JButton01() {
Container container = this.getContentPane();
// 将图片变为图标
URL url = JButton01.class.getResource("CoffeeMan.jpg");
ImageIcon icon = new ImageIcon(url);
//把图标放在按钮上
JButton B1 = new JButton();
B1.setIcon(icon);
B1.setToolTipText("图片按钮"); // 悬浮提示
// add
container.add(B1);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(300,300);
}
public static void main(String[] args) {
new JButton01();
}
}
单选按钮
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
public class JButton02 extends JFrame {
public JButton02() {
Container container = this.getContentPane();
// 将图片变为图标
URL url = JButton02.class.getResource("CoffeeMan.jpg");
ImageIcon icon = new ImageIcon(url);
// 单选框
JRadioButton radioButton01 = new JRadioButton("radioButton01");
JRadioButton radioButton02 = new JRadioButton("radioButton02");
JRadioButton radioButton03 = new JRadioButton("radioButton03");
// 由于单选框只能选择一个, 分组, 一个组中只能选一个
ButtonGroup group = new ButtonGroup();
group.add(radioButton01);
group.add(radioButton02);
group.add(radioButton03);
// add
container.add(radioButton01, BorderLayout.CENTER);
container.add(radioButton02, BorderLayout.NORTH);
container.add(radioButton03, BorderLayout.SOUTH);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(300,300);
}
public static void main(String[] args) {
new JButton02();
}
}
复选按钮
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
public class JButton03 extends JFrame {
public JButton03() {
Container container = this.getContentPane();
// 将图片变为图标
URL url = JButton03.class.getResource("CoffeeMan.jpg");
ImageIcon icon = new ImageIcon(url);
// 多选框
JCheckBox checkBox01 = new JCheckBox("checkBox01");
JCheckBox checkBox02 = new JCheckBox("checkBox02");
container.add(checkBox01, BorderLayout.NORTH);
container.add(checkBox02, BorderLayout.SOUTH);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(300,300);
}
public static void main(String[] args) {
new JButton03();
}
}
3.6 列表
下拉框
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Combobox01 extends JFrame {
public Combobox01(){
Container container = this.getContentPane();
JComboBox status = new JComboBox();
status.addItem(null);
status.addItem("正在上映");
status.addItem("即将上映");
status.addItem("正在热映");
status.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// System.out.println(e.getSource());
JComboBox JC = (JComboBox) e.getSource();
System.out.println(JC.getSelectedItem());
}
});
container.add(status);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(500,350);
}
public static void main(String[] args) {
new Combobox01();
}
}
列表框
package com.GUI_Swing;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
public class Combobox02 extends JFrame {
public Combobox02(){
Container container = this.getContentPane();
// 生成列表的内容 稀疏数组 静态
String[] contents = {"1", "2", "3"};
// 生成列表的内容 也可以动态
// Vector contents = new Vector();
// 列表需要放入内容
JList jList = new JList(contents);
// 动态添加
// contents.add("chenhao");
// contents.add("chenyanbin");
// contents.add("wuzhicheng");
container.add(jList);
jList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
JList j1 = (JList) e.getSource();
System.out.println(j1.getSelectedValue());
}
});
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(500,350);
}
public static void main(String[] args) {
new Combobox02();
}
}
应用场景
选择地区, 或者单个选项
列表展示信息,一般是动态扩容的
3.7 文本框
文本框(只有一行,与域相比)
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
public class Text01 extends JFrame {
public Text01(){
Container container = this.getContentPane();
// 文本框
JTextField jTextField01 = new JTextField("hello");
JTextField jTextField02 = new JTextField("world",20);
container.add(jTextField01,BorderLayout.NORTH);
container.add(jTextField02, BorderLayout.SOUTH);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(500,350);
}
public static void main(String[] args) {
new Text01();
}
}
密码框
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Text02 extends JFrame {
public Text02(){
Container container = this.getContentPane();
// 密码框
// 尽量写在面板上
JPasswordField jPF01 = new JPasswordField();
jPF01.setEchoChar('*');
jPF01.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JPasswordField jp = (JPasswordField) e.getSource();
System.out.println("实际密码是: "+jp.getPassword().toString());
}
});
container.add(jPF01, BorderLayout.CENTER);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(500,350);
}
public static void main(String[] args) {
new Text02();
}
}
文本域
package com.GUI_Swing;
import javax.swing.*;
import java.awt.*;
public class JScrollDemo extends JFrame {
public JScrollDemo(){
Container container = this.getContentPane();
// 文本域 可换行; 文本框 不能
JTextArea textArea = new JTextArea(20, 50);
textArea.setText("欢迎学习");
// Scroll面板
JScrollPane s1 = new JScrollPane(textArea); // 构造函数里写的是 形参:要用于展示的组件
container.add(s1);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setBounds(100,100,300,350);
}
public static void main(String[] args) {
new JScrollDemo();
}
}
注重
awt 和 swing 分别代表了基础和进阶的两种框架(我个人看法)
在GUI布局上,先多面板后嵌入能更好的布局
对代码的基本共识,比如设置参数一般方法是setXxx开头,
感悟
学着写了这些代码,理解了面向对象这一思想的强大之处
同时对创造这些架构的人抱有更加强大的敬意
知道了GUI的两个框架awt和Swing 的 基本使用技巧,同时对额外的内容 监听 有点上头,有点回到了本科写单片机代码的时候。
跟着kuang老师写代码的这些天,不仅仅是学了GUI这些,同时对代码的写法也有了自己的看法。比如一个GUI的创建可以有
1.构造函数写法
2.方法调用写法
3.直接main函数写法
等等。同时在计算器这节课彻底对面向对象的五体投地。
在IDE上,刚开始我是通过VScode上的java扩展模块来写的,实在不方便;
后面在idea里开了免费的学生账户,用起来发现真**好用,我立刻“抛弃”了简约但更不方便的VScode
(和我学python的时候很像hhh,学python的时候是先VS,然后VScode,最后Pycharm)
不得不说jetbrain这家公司开发的IDE确实不粗哦~
感悟有点多。先写到这。贪吃蛇项目还是单开一个吧。