GUI编程

前言

某koukou老师的任务罢了,好在狂神老师居然有GUI的课,只能说是有救星了。

【狂神说Java】GUI编程入门到游戏实战

最好笑的是,老师要求掌握的居然是14年的知识,就连狂神在上这门课的时候都在吐槽:你们在网络上几乎看不到这样的教学资源,因为已经很少很少了(被淘汰了)

主要是这个学期的短学期实践十有八九是koukou老师,非得是用java设计图形化可视化,所以学还是得学,不该挂的课就是不能挂!

1、了解GUI

组建:

  • 窗口
  • 弹窗
  • 面板
  • 文本框
  • 列表框
  • 按钮
  • 图片
  • 监听事件
  • 鼠标
  • 键盘事件
  • (狂神老师提到逆向破解游戏基本使用java来写

2、简介

GUI的核心:

Swing AWT

为什么javaGUI不流行?

  • 界面丑
  • 需要jre环境

那么为什么要学?

  • 自制工具(确实,ctf许多工具都是用javaGUI写成打包的jar
  • 极小概率在工作中维护Swing界面(大概我这辈子见不到了吧
  • 重点是学习监听事件,可以由此了解MVC架构

3、AWT

3.1 AWT介绍

用于GUI编程,AWT就是抽象窗口工具

(Eclipse和IDEA就是用java Swing写出来的)

  1. 包含了很多类和接口
  2. 包含了很多元素:窗口、按钮、文本框
  3. 在java.awt包中

3.2 组件和容器

1、Frame

我们现来看看第一个frame

  1. package top.woodwhale.study;
  2. import java.awt.*;
  3. // GUI的第一个界面
  4. public class TestFrame {
  5. public static void main(String[] args) {
  6. // Frame
  7. Frame frame = new Frame("First Java Window");
  8. // 需要设置可见性,长度、宽度
  9. frame.setVisible(true);
  10. frame.setSize(400,400);
  11. // 设置背景颜色 Color
  12. frame.setBackground(new Color(22, 87, 220));
  13. // 弹出的初始位置
  14. frame.setLocation(200,200);
  15. // 设置大小固定
  16. frame.setResizable(false);
  17. }
  18. }

效果就是一个蓝色的、不可拉伸、不可关闭的窗口

思考:

  • 为什么无法关闭?
  • 如何让窗口关闭?只能靠关闭程序吗?

如果我们需要同时开启多个窗口,有没有什么好的方法呢?

  • 可以写一个自类,继承自Frame,然后实现我们需要的功能
  1. package top.woodwhale.study;
  2. import java.awt.*;
  3. public class TestFrame2 {
  4. public static void main(String[] args) {
  5. // 展示多个窗口
  6. MyFrame mf1 = new MyFrame(100,100,200,200,Color.black);
  7. MyFrame mf2 = new MyFrame(300,100,200,200,Color.orange);
  8. MyFrame mf3 = new MyFrame(100,300,200,200,Color.green);
  9. MyFrame mf4 = new MyFrame(300,300,200,200,Color.pink);
  10. }
  11. }
  12. class MyFrame extends Frame{
  13. static int id = 0; // 可能存在多个窗口,需要一个计数器
  14. public MyFrame(int x,int y,int w,int h,Color color) {
  15. super("Myframe"+ (++id));
  16. setBackground(color);
  17. setBounds(x,y,w,h);
  18. setVisible(true);
  19. }
  20. }

效果如下:(有点好看

2、Panel

面板Panel可以看成是一个空间,但是不能单独存在,可以存在与一个框架中。类似于前段的div(大概

以下的例子通过适配器模式来监听窗口关闭事件

  1. package top.woodwhale.study;
  2. import java.awt.*;
  3. import java.awt.event.WindowAdapter;
  4. import java.awt.event.WindowEvent;
  5. public class TestPanel {
  6. public static void main(String[] args) {
  7. // 先创建一个框架
  8. Frame frame = new Frame();
  9. // 设置一个面板
  10. Panel panel = new Panel();
  11. // 设置布局
  12. frame.setLayout(null);
  13. // 框架的坐标
  14. frame.setBounds(300,300,500,500);
  15. // 框架的背景
  16. frame.setBackground(new Color(40,161,35));
  17. // 面板设置坐标,相对于frame
  18. panel.setBounds(50,50,400,400);
  19. panel.setBackground(new Color(190,15,60));
  20. // frame.add()
  21. frame.add(panel);
  22. // 将面板设置为可见
  23. frame.setVisible(true);
  24. // 监听窗口关闭事件
  25. // 适配器模式:
  26. frame.addWindowListener(new WindowAdapter() {
  27. // 窗口点击关闭的时候需要做的事情
  28. @Override
  29. public void windowClosing(WindowEvent e) {
  30. System.exit(0);
  31. }
  32. });
  33. }
  34. }

效果如下:(我们点击关闭按钮可以结束进程,也就是退出

3、布局管理

  • 流式布局

    这个按钮的年代感直接出来了,有种wine打开exe的味道了

    1. package top.woodwhale.study;
    2. import java.awt.*;
    3. public class TestFlowLayout {
    4. public static void main(String[] args) {
    5. Frame frame = new Frame("114514");
    6. // 组件-按钮
    7. Button button1 = new Button("button1");
    8. Button button2 = new Button("button2");
    9. Button button3 = new Button("button3");
    10. // 设置为流式布局 默认是居中
    11. frame.setLayout(new FlowLayout());
    12. // frame.setLayout(new FlowLayout(FlowLayout.RIGHT));
    13. frame.setSize(200,200);
    14. // 把按钮添加上去
    15. frame.add(button1);
    16. frame.add(button2);
    17. frame.add(button3);
    18. frame.setVisible(true);
    19. }
    20. }
  • 东西南北中

    狂神老师说这是视频软件的布局,为什么我第一反应是,上下左右都是广告,中间是小视频(bushi

    1. package top.woodwhale.study;
    2. import java.awt.*;
    3. public class TestBorderLayout {
    4. public static void main(String[] args) {
    5. Frame frame = new Frame("114514");
    6. Button east = new Button("east");
    7. Button west = new Button("west");
    8. Button south = new Button("south");
    9. Button north = new Button("north");
    10. Button center = new Button("center");
    11. frame.add(east,BorderLayout.EAST);
    12. frame.add(west,BorderLayout.WEST);
    13. frame.add(south,BorderLayout.SOUTH);
    14. frame.add(north,BorderLayout.NORTH);
    15. frame.add(center,BorderLayout.CENTER);
    16. frame.setSize(300,300);
    17. frame.setVisible(true);
    18. }
    19. }
  • 表格布局

    就是类似表格的形式,这里使用了pack()方法来使大小、内容自动填充

    1. package top.woodwhale.study;
    2. import java.awt.*;
    3. public class TestGridLayout {
    4. public static void main(String[] args) {
    5. Frame frame = new Frame("114514");
    6. Button bt1 = new Button("bt1");
    7. Button bt2 = new Button("bt2");
    8. Button bt3 = new Button("bt3");
    9. Button bt4 = new Button("bt4");
    10. Button bt5 = new Button("bt5");
    11. Button bt6 = new Button("bt6");
    12. frame.setLayout(new GridLayout(3,2));
    13. frame.add(bt1);
    14. frame.add(bt2);
    15. frame.add(bt3);
    16. frame.add(bt4);
    17. frame.add(bt5);
    18. frame.add(bt6);
    19. frame.pack(); // java方法,用来自动填充
    20. frame.setVisible(true);
    21. }
    22. }

4、狂神老师的作业time

如何完成下图的格式布局?

直接动手

动手之前先进行构思,一个好的项目,构思占据80%,代码只有20%!!!

我们现构建一个两行一列的frame,然后在中间部分上下各设置一个面板,frame的上半部分和下半部分都使用东西南北中的布局管理,再在两个面板中设置东西南北中格式,其中上面的嵌套一个两行一列的面板,下面的嵌套一个两行两列的面板

最终效果:

代码:

  1. package top.woodwhale.study;
  2. import java.awt.*;
  3. import java.awt.image.ImageObserver;
  4. public class MyLayout {
  5. public static void main(String[] args) {
  6. Frame frame = new Frame("114514");
  7. frame.setSize(400,300);
  8. frame.setLocation(300,300);
  9. frame.setBackground(Color.orange);
  10. frame.setVisible(true);
  11. // 两行一列
  12. frame.setLayout(new GridLayout(2,1));
  13. // 4个面板
  14. Panel panel1 = new Panel(new BorderLayout());
  15. Panel panel2 = new Panel(new GridLayout(2,1));
  16. Panel panel3 = new Panel(new BorderLayout());
  17. Panel panel4 = new Panel(new GridLayout(2,2));
  18. panel1.add(new Button("East-1"),BorderLayout.EAST);
  19. panel1.add(new Button("West-1"),BorderLayout.WEST);
  20. panel2.add(new Button("p2-btn-1"));
  21. panel2.add(new Button("p2-btn-2"));
  22. panel1.add(panel2,BorderLayout.CENTER);
  23. panel3.add(new Button("East-2"),BorderLayout.EAST);
  24. panel3.add(new Button("West-2"),BorderLayout.WEST);
  25. for (int i = 0; i < 4; i++) {
  26. panel4.add(new Button("for-"+i));
  27. }
  28. panel3.add(panel4,BorderLayout.CENTER);
  29. frame.add(panel1);
  30. frame.add(panel3);
  31. }
  32. }

5、总结

  1. Frame是一个顶级窗口
  2. Panel无法单独显示,得放入Frame(容器)中
  3. 布局管理
    • 流式
    • 东西南北中
    • 表格
  4. 设置大小、定位、背景、监听
  5. 设计模式不要直接写,先去构想!

3.3 监听事件

1、监听测试

监听就是,当发生某事件后,我们监听到了这个动态,应该有某种反馈

先来点效果图:

可以观察到,我们第一次这个巨大按钮,就会在控制台输出一次114514,这是为啥呢?

  1. package top.woodwhale.study2;
  2. import java.awt.*;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. import java.awt.event.WindowAdapter;
  6. import java.awt.event.WindowEvent;
  7. public class TestActionEvent {
  8. public static void main(String[] args) {
  9. Frame frame = new Frame();
  10. // 按下按钮的时候,触发一些事件
  11. Button button = new Button("点我控制台输出114514");
  12. // 因为addActionListener需要一个ActionListener,所以我们字节写一个MyActionListener类
  13. MyActionListener myActionListener = new MyActionListener();
  14. button.addActionListener(myActionListener);
  15. frame.add(button);
  16. frame.setSize(300,300);
  17. frame.setVisible(true);
  18. windowClose(frame);
  19. }
  20. // 关闭窗口事件
  21. private static void windowClose(Frame frame) {
  22. frame.addWindowListener(new WindowAdapter() {
  23. @Override
  24. public void windowClosing(WindowEvent e) {
  25. System.exit(0);
  26. }
  27. });
  28. }
  29. }
  30. class MyActionListener implements ActionListener{
  31. @Override
  32. public void actionPerformed(ActionEvent actionEvent) {
  33. System.out.println("114514");
  34. }
  35. }

其实是因为,我们设置了一个按钮的监听器,我们自己写了一个MyActionListener类,是ActionListener的一个接口,我们重写的方法就是只要有这个事件产生,就输出114514。

而我们在button中使用了addActionListener方法,将我们重写的监听器赋予给了这个按钮,所以我们按下这个按钮的时候就能在控制台看到输出的114514。

并且,我们通过在主类中写了一个windowClose的static方法,这样,我们通过方法的封装直接实现了点击关闭按钮关闭窗口的监听事件。

2、单监听器监听多个事件

如果我们想实现多个按钮同时监听一个事件呢?我们可以只写一个监听类,通过更改setActionCommand达到不同的监听效果。

如下图所示,我们点击start按钮可以在控制台输出“开始”

如果我们点击Stop按钮,会输出“哼哼”

这种效果其实就是一个监听器监听了多个事件

  1. package top.woodwhale.study2;
  2. import java.awt.*;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. public class TestActionEvent2 {
  6. public static void main(String[] args) {
  7. // 两个按钮,实现同一个监听
  8. // 开始按钮和停止按钮
  9. Frame frame = new Frame("Start ~ Stop");
  10. Button button = new Button("Start");
  11. Button button1 = new Button("Stop");
  12. // 可以显示的定义触发会返回的命令,如果不显示定义,则会走默认的值
  13. // 这样我们可以多个按钮,但是只需要一个监听类,只需要更改setActionCommand
  14. button1.setActionCommand("Stop");
  15. MyMonitor myMonitor = new MyMonitor();
  16. button.addActionListener(myMonitor);
  17. button1.addActionListener(myMonitor);
  18. frame.add(button,BorderLayout.NORTH);
  19. frame.add(button1,BorderLayout.SOUTH);
  20. frame.setSize(300,300);
  21. frame.setVisible(true);
  22. }
  23. }
  24. class MyMonitor implements ActionListener {
  25. @Override
  26. public void actionPerformed(ActionEvent actionEvent) {
  27. // actionEvent.getActionCommand()获得按钮的信息'
  28. String command = actionEvent.getActionCommand();
  29. if (command.equals("Stop")) {
  30. System.out.println("想要Stop?哼哼哼哼哼哼哼哼哼哼哼哼哈哈哈哈哈哈哈哈哈~");
  31. } else if (command.equals("Start")) {
  32. System.out.println("开始");
  33. }
  34. }
  35. }

3、输入框TextField监听

我们用TextField类可以创造出输入框的对象,输入框在很多地方都很常见,比如密码输入

这里我们用密码输入来当引子

我们应该实现什么功能?

  • 首先考虑输入单行密码,密码只能显示*号
  • 其次就是输入按下回车我们可以得到密码
  • 最后就是按下回车我们此前输入的密码会清空

如何实现?

  • 第2和第3点可以通过设置监听事件完成
  • 第1点可以通过textField.setEchoChar('*'); 替换编码的方法来实现

效果如下:

  • 按下回车之前:

  • 按下回车之后:

代码实现:

  1. package top.woodwhale.study2;
  2. import java.awt.*;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. import java.awt.event.WindowAdapter;
  6. import java.awt.event.WindowEvent;
  7. public class TestText {
  8. public static void main(String[] args) {
  9. // 启动
  10. new MyFrame();
  11. }
  12. }
  13. class MyFrame extends Frame {
  14. public MyFrame() {
  15. // 写单行文本
  16. TextField textField = new TextField();
  17. // 因为MyFrame继承了Frame,可以直接使用add方法
  18. add(textField);
  19. // 监听这个文本框输入的文字,按下enter控制台就会输出我们输入的内容,并且清空文本
  20. MyAL myAL = new MyAL();
  21. textField.addActionListener(myAL);
  22. // 替换编码
  23. textField.setEchoChar('*');
  24. setVisible(true);
  25. setSize(300,100);
  26. // 设置点击关闭监听事件
  27. addWindowListener(new WindowAdapter() {
  28. @Override
  29. public void windowClosing(WindowEvent e) {
  30. System.exit(0);
  31. }
  32. });
  33. }
  34. }
  35. class MyAL implements ActionListener {
  36. @Override
  37. public void actionPerformed(ActionEvent actionEvent) {
  38. // 获取一些资源,返回了一个对象
  39. TextField field = (TextField) actionEvent.getSource();
  40. // 获得输入框的文字
  41. System.out.println(field.getText());
  42. field.setText("");
  43. }
  44. }

3.4 实现简易计算器

1、前言

在这章之前,狂神老师说了一点比较重要的——oop原则组合大于继承

其实这是装饰器模式的一个体现:

比如我们如果在A类中要实现B的部分功能,一般都是将A继承B的功能。

但是因为Java不能多继承,所以组合就出现了

  1. // 继承
  2. public class A extends B {
  3. }
  4. // 组合
  5. public class A {
  6. public B b;
  7. }

此外,阿里巴巴手册中提出,少用多态、少用继承!(虽然多态和继承是面向对象的三大特性之二)

2、构思

在开始写代码之前,我们需要先构思。

GUI界面如下:

界面其实就是三个输入框,一个“=”按钮,一个“+”标签,然后按照流式模型就可以构造出来了

重点来了:

如何完成监听前两个输入框的值,并且将第三个输入框写入计算后的结果?

3、setter方式

我们在面向对象的学习中,都了解到了构造器,那么我们是不是可以吧三个输入框通过构造器来获取呢?

我们在监听器类中创建三个私有的三个输入框类,通过new对象的时候将传入的三个输入框setter完成。

这样,我们在监听器类中就获取了三个输入框的对象!接下来的操作就不用多所了,代码注释中写有。

代码

  1. package top.woodwhale.study2;
  2. import java.awt.*;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. public class TestCalc {
  6. public static void main(String[] args) {
  7. new Calculator();
  8. }
  9. }
  10. // 计算器类
  11. class Calculator extends Frame {
  12. public Calculator() {
  13. // 3个文本框
  14. TextField num1 = new TextField(10);
  15. TextField num2 = new TextField(10);
  16. TextField num3 = new TextField(10);
  17. // 1个按钮
  18. Button button = new Button("=");
  19. button.addActionListener(new MyCalcListener(num1, num2, num3));
  20. // 1个标签
  21. Label label = new Label("+");
  22. setLayout(new FlowLayout());
  23. add(num1);
  24. add(label);
  25. add(num2);
  26. add(button);
  27. add(num3);
  28. pack();
  29. setVisible(true);
  30. }
  31. }
  32. // 监听器类
  33. class MyCalcListener implements ActionListener {
  34. private TextField num1, num2, num3;
  35. // 获取三个变量
  36. public MyCalcListener(TextField num1, TextField num2, TextField num3) {
  37. this.num1 = num1;
  38. this.num2 = num2;
  39. this.num3 = num3;
  40. }
  41. @Override
  42. public void actionPerformed(ActionEvent actionEvent) {
  43. // 1.获得加数和被加数
  44. int n1 = Integer.parseInt(num1.getText());
  45. int n2 = Integer.parseInt(num2.getText());
  46. // 2.将这个值进行加法运算后,防到第三个框
  47. num3.setText(n1+n2+"");
  48. // 3.清除前两个框
  49. num1.setText("");
  50. num2.setText("");
  51. }
  52. }

运行截图:

按下按钮前:

按下按钮后:

4、组合方式

我们在前言部分就提到了,组合是远远好于继承的,那么如何使用组合的方式来获取三个对话框中的输入输出呢?

我们之前使用的setter方式相当于传数据,而面向对象的组合方式,就是相当于传对象了。

  • 如何实现?
  • 在计算器类中写一个loadFrame方法,在这个方法中实现外部大Frame的构造
  • 再自己写一个监听类,其中的构造器是直接获取计算器这个对象,而这个计算器对象包含了num1,num2,num3的属性,我们通过更改这些属性的状态来完成计算器的实现!

完整代码:

  1. package top.woodwhale.study2;
  2. import java.awt.*;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. public class TestCalc2 {
  6. public static void main(String[] args) {
  7. new Calculator2().loadFrame();
  8. }
  9. }
  10. // 计算器类
  11. class Calculator2 extends Frame {
  12. // 属性
  13. TextField num1, num2, num3;
  14. // 方法
  15. public void loadFrame() {
  16. num1 = new TextField(10);
  17. num2 = new TextField(10);
  18. num3 = new TextField(10);
  19. Button button = new Button("=");
  20. button.addActionListener(new MyCalcListener2(this)); // 将自己这个Calculator对象给监听器类
  21. Label label = new Label("+");
  22. setLayout(new FlowLayout());
  23. add(num1);
  24. add(label);
  25. add(num2);
  26. add(button);
  27. add(num3);
  28. pack();
  29. setVisible(true);
  30. }
  31. }
  32. // 监听器类
  33. class MyCalcListener2 implements ActionListener {
  34. // 获取计算器这个对象,在一个类中组合另一个类
  35. private Calculator2 calculator = null;
  36. // 获取三个变量
  37. public MyCalcListener2(Calculator2 calculator) {
  38. this.calculator = calculator;
  39. }
  40. @Override
  41. public void actionPerformed(ActionEvent actionEvent) {
  42. int n1 = Integer.parseInt(calculator.num1.getText());
  43. int n2 = Integer.parseInt(calculator.num2.getText());
  44. calculator.num3.setText(n1+n2+"");
  45. calculator.num1.setText("");
  46. calculator.num2.setText("");
  47. }
  48. }

效果图:

按下按钮前:

按下按钮后:

5、内部类方式

面向对象的更高级形式——内部类方法实现

  • 更好的包装
  • 更简洁的代码
  • 更易懂的对象

如何实现?

  • 我们只需要将刚刚写的监听器类写入计算器类的内部类就可以了,这样这个监听器就算计算器专门的监听器,并且计算器这个类中有着完整的——属性、方法、内部类。完美的面向对象的体现!
  • 内部类的最大好处就是——随意访问外部类的属性和方法
  1. package top.woodwhale.study2;
  2. import java.awt.*;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. public class TestCalc2 {
  6. public static void main(String[] args) {
  7. new Calculator2().loadFrame();
  8. }
  9. }
  10. // 计算器类
  11. class Calculator2 extends Frame {
  12. // 属性
  13. TextField num1, num2, num3;
  14. // 方法
  15. public void loadFrame() {
  16. num1 = new TextField(10);
  17. num2 = new TextField(10);
  18. num3 = new TextField(10);
  19. Button button = new Button("=");
  20. button.addActionListener(new MyCalcListener2()); // 将自己这个Calculator对象给监听器类
  21. Label label = new Label("+");
  22. setLayout(new FlowLayout());
  23. add(num1);
  24. add(label);
  25. add(num2);
  26. add(button);
  27. add(num3);
  28. pack();
  29. setVisible(true);
  30. }
  31. // 监听器类
  32. class MyCalcListener2 implements ActionListener {
  33. @Override
  34. public void actionPerformed(ActionEvent actionEvent) {
  35. int n1 = Integer.parseInt(num1.getText());
  36. int n2 = Integer.parseInt(num2.getText());
  37. num3.setText(n1+n2+"");
  38. num1.setText("");
  39. num2.setText("");
  40. }
  41. }
  42. }

3.5 Paint画笔

现了解这个paint方法,是Frame中的一个方法,我们自己构造一个MyPaint类,继承Frame,然后重写paint方法,这样在我们的Frame中就可以画出我们想要的东西了!

效果图:

实现代码:

  1. package top.woodwhale.study3;
  2. import java.awt.*;
  3. public class TestPaint {
  4. public static void main(String[] args) {
  5. new MyPaint().loadFrame();
  6. }
  7. }
  8. class MyPaint extends Frame {
  9. public void loadFrame() {
  10. setBounds(200,200,600,500);
  11. setVisible(true);
  12. }
  13. // 画笔
  14. @Override
  15. public void paint(Graphics g) {
  16. // 画笔需要有颜色,可以画画
  17. g.setColor(Color.red);
  18. g.fillOval(100,100,100,100); // 实心的圆
  19. g.setColor(Color.green);
  20. g.fillRect(150,200,300,200);
  21. // 养成习惯,画笔用完,将他还原到最初的颜色
  22. }
  23. }

3.6 鼠标监听

  • 目的:想要实现鼠标画画!

  • 如何实现?

  • 有了方法之后,我们开始构建

代码如下:

  1. package top.woodwhale.study3;
  2. import java.awt.*;
  3. import java.awt.event.MouseAdapter;
  4. import java.awt.event.MouseEvent;
  5. import java.util.ArrayList;
  6. public class TestMouseListener {
  7. public static void main(String[] args) {
  8. new MyFrame("画画");
  9. }
  10. }
  11. class MyFrame extends Frame {
  12. // 画画需要画笔,需要监听鼠标当前的位置,需要集合来存储这个点
  13. ArrayList points;
  14. public MyFrame(String title) {
  15. super(title);
  16. setVisible(true);
  17. // 存储鼠标点击的坐标
  18. points = new ArrayList<>();
  19. setBounds(200,200,400,300);
  20. // 鼠标监听器,相对于这个窗口
  21. this.addMouseListener(new MyMouseListener());
  22. }
  23. @Override
  24. public void paint(Graphics g) {
  25. // 画画,监听鼠标的事件
  26. for (Object o : points) {
  27. Point point = (Point) o;
  28. g.setColor(Color.blue);
  29. g.fillOval(point.x, point.y, 10, 10);
  30. }
  31. }
  32. // 参加一个点到界面上
  33. public void addPaint(Point point) {
  34. points.add(point);
  35. }
  36. // 适配器模式
  37. private static class MyMouseListener extends MouseAdapter {
  38. // 鼠标有,按下,弹起,按住不放
  39. // 添加
  40. @Override
  41. public void mousePressed(MouseEvent e) {
  42. MyFrame myframe = (MyFrame) e.getSource();
  43. // 我们点击的时候,就会在界面上产生一个点(坐标形式)
  44. // 这个点就是鼠标点击的坐标
  45. myframe.addPaint(new Point(e.getX(),e.getY()));
  46. // 每次点击鼠标都需要重新画一遍
  47. myframe.repaint(); // 刷新
  48. }
  49. }
  50. }

效果如图:

3.7 窗口监听

窗口监听其实在之前点击关闭退出那里已经讲了很多了,这里再补充一点

  • 尽量将内部类实现为匿名内部类,这样看起来更美观
  • 常用的就是关闭和聚焦
  1. package top.woodwhale.study3;
  2. import java.awt.*;
  3. import java.awt.event.WindowAdapter;
  4. import java.awt.event.WindowEvent;
  5. public class TestWindow {
  6. public static void main(String[] args) {
  7. new WindowFrame();
  8. }
  9. }
  10. class WindowFrame extends Frame {
  11. public WindowFrame() {
  12. setBackground(Color.blue);
  13. setBounds(100,100,200,200);
  14. setVisible(true);
  15. // 使用内部类
  16. // addWindowListener(new MyWindowListener());
  17. // 使用匿名内部类
  18. this.addWindowListener(new WindowAdapter() {
  19. // 关闭窗口
  20. @Override
  21. public void windowClosing(WindowEvent e) {
  22. System.exit(0);
  23. }
  24. // 激活窗口
  25. @Override
  26. public void windowActivated(WindowEvent e) {
  27. WindowFrame source = (WindowFrame) e.getSource();
  28. source.setTitle("被激活啦!");
  29. }
  30. });
  31. }
  32. // class MyWindowListener extends WindowAdapter{
  33. // @Override
  34. // public void windowClosing(WindowEvent e) {
  35. // System.exit(0); // 正常退出
  36. // }
  37. // }
  38. }

3.8 键盘监听

键盘监听,顾名思义,就是监听键盘的状态,用的多的就是判断键盘按下了什么键

  • 思考:

    1. 如何判断按下了什么键?
    2. 如何对按下了键盘之后进行操作?
  • 下面这段代码就是判断键盘是否按下了 up这个键,如果按下了就在控制台输出一个“upupup!~"
  1. package top.woodwhale.study3;
  2. import java.awt.*;
  3. import java.awt.event.KeyAdapter;
  4. import java.awt.event.KeyEvent;
  5. import java.awt.event.WindowAdapter;
  6. import java.awt.event.WindowEvent;
  7. public class TestKeyListener {
  8. public static void main(String[] args) {
  9. new KeyFrame();
  10. }
  11. }
  12. class KeyFrame extends Frame {
  13. public KeyFrame() {
  14. setBounds(1,2,300,300);
  15. setVisible(true);
  16. // 匿名内部类实现监听器
  17. this.addKeyListener(new KeyAdapter() {
  18. // 键盘按下
  19. @Override
  20. public void keyPressed(KeyEvent e) {
  21. // 获得键盘下的键是哪一个
  22. int keyCode = e.getKeyCode();
  23. // System.out.println(keyCode);
  24. // 不需要记录KeyCode的值,直接判断
  25. if (keyCode == KeyEvent.VK_UP) {
  26. System.out.println("upupup!~");
  27. }
  28. }
  29. });
  30. // 匿名内部类实现关闭
  31. this.addWindowListener(new WindowAdapter() {
  32. @Override
  33. public void windowClosing(WindowEvent e) {
  34. System.out.println("See you next time!");
  35. System.exit(0);
  36. }
  37. });
  38. }
  39. }

4、Swing

AWT是Swing的基础,Swing从AWT进化而来

随便调用个一个JFrame类,进入源码看一下,直接看到extends Frame

4.1 窗口与面板

JFrame其实和Frame类似,只不过涉及到了容器这个概念,每一个窗口都有容器,而容器需要实例化

举例代码:

  1. package top.woodwhale.study4;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. public class JFrameDemo {
  5. // init() 初始化方法
  6. public void init() {
  7. // 顶级窗口
  8. JFrame jFrame = new JFrame("一个JFrame窗口");
  9. jFrame.setVisible(true);
  10. jFrame.setBounds(100,100,200,200);
  11. // 设置文字 JLabel
  12. JLabel jLabel = new JLabel("1145141919810");
  13. // 让文本居中
  14. jLabel.setHorizontalAlignment(SwingConstants.CENTER);
  15. jFrame.add(jLabel);
  16. // jf有容器,容器需要实例化
  17. Container container = jFrame.getContentPane();
  18. container.setBackground(Color.orange);
  19. // JFrame自带的设置关闭操作方法
  20. jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  21. }
  22. public static void main(String[] args) {
  23. // 建立一个窗口
  24. new JFrameDemo().init();
  25. }
  26. }

效果如下:

4.2 弹窗

JDialog是一个弹窗的窗口类,我们用一个继承JDialog的类来写一个弹窗事件

  1. package top.woodwhale.study4;
  2. import javax.swing.*;
  3. import javax.swing.text.LabelView;
  4. import java.awt.*;
  5. import java.awt.event.ActionEvent;
  6. import java.awt.event.ActionListener;
  7. // 主窗口
  8. public class DialogDemo extends JFrame {
  9. public DialogDemo() {
  10. this.setVisible(true);
  11. this.setSize(700,500);
  12. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  13. // JFrame 放东西,放入容器中
  14. Container container = this.getContentPane();
  15. // 绝对布局
  16. container.setLayout(null);
  17. // 按钮
  18. JButton jButton = new JButton("点击弹出114514"); // 创建
  19. jButton.setBounds(30,30,200,50);
  20. // 点击这个按钮,弹出一个弹窗,需要一个监听事件
  21. jButton.addActionListener(new ActionListener() { // 监听器
  22. @Override
  23. public void actionPerformed(ActionEvent actionEvent) {
  24. // 弹窗
  25. new MyDialogDemo();
  26. }
  27. });
  28. container.add(jButton);
  29. }
  30. public static void main(String[] args) {
  31. new DialogDemo();
  32. }
  33. }
  34. // 弹窗的窗口,默认就有点击关闭事件
  35. class MyDialogDemo extends JDialog{
  36. public MyDialogDemo() {
  37. this.setVisible(true);
  38. this.setBounds(100,100,500,500);
  39. Container contentPane = this.getContentPane();
  40. // contentPane.setLayout(null);
  41. contentPane.add(new JLabel("1145141919810"));
  42. }
  43. }

来点效果图:

  • 点击前:

  • 点击后:

4.3 标签

label就是标签

  1. new JLabel("114514");

图标、图片是icon

显示一个自己画的图标:

  1. package top.woodwhale.study4;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. // 图标是一个接口,需要实现类,JFrame继承
  5. public class IconDemo extends JFrame implements Icon {
  6. private int width;
  7. private int height;
  8. public IconDemo() throws HeadlessException {
  9. }
  10. public IconDemo(int width, int height) throws HeadlessException {
  11. this.width = width;
  12. this.height = height;
  13. }
  14. public static void main(String[] args) {
  15. new IconDemo().init();
  16. }
  17. public void init() {
  18. IconDemo iconDemo = new IconDemo(15,15);
  19. JLabel jLabel = new JLabel("iconTest", iconDemo, SwingConstants.CENTER);
  20. Container container = getContentPane();
  21. container.add(jLabel);
  22. this.setVisible(true);
  23. this.setSize(300,300);
  24. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  25. }
  26. @Override
  27. public void paintIcon(Component component, Graphics graphics, int i, int i1) {
  28. graphics.fillOval(i,i1,this.width,this.height);
  29. }
  30. @Override
  31. public int getIconWidth() {
  32. return this.width;
  33. }
  34. @Override
  35. public int getIconHeight() {
  36. return this.height;
  37. }
  38. }

效果如下:

那么如何来设置自定义图片icon呢?

效果如下的这种:

也很简单:

  1. package top.woodwhale.study4;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. import java.net.URL;
  5. public class ImageIconDemo extends JFrame {
  6. public static void main(String[] args) {
  7. new ImageIconDemo();
  8. }
  9. public ImageIconDemo() throws HeadlessException {
  10. // 获取图片的地质
  11. JLabel jLabel = new JLabel("ImageIcon");
  12. URL url = ImageIconDemo.class.getResource("woodwhale.jpg");
  13. assert url != null;
  14. ImageIcon imageIcon = new ImageIcon(url);
  15. jLabel.setIcon(imageIcon);
  16. jLabel.setHorizontalAlignment(SwingConstants.CENTER);
  17. Container container = getContentPane();
  18. container.add(jLabel);
  19. setVisible(true);
  20. setSize(300,300);
  21. setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  22. }
  23. }

4.4 面板

JPanel

和之前学的Panel一样,就是多了容器操作

  1. package top.woodwhale.study5;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. public class JPanelDemo extends JFrame {
  5. public JPanelDemo() {
  6. Container container = this.getContentPane();
  7. container.setLayout(new GridLayout(2,1,10,10)); // 后面的参数表示间距
  8. JPanel jPanel = new JPanel(new GridLayout(1,3));
  9. jPanel.add(new JButton("114"));
  10. jPanel.add(new JButton("514"));
  11. jPanel.add(new JButton("1919"));
  12. container.add(jPanel);
  13. this.setVisible(true);
  14. this.setSize(300,300);
  15. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  16. }
  17. public static void main(String[] args) {
  18. new JPanelDemo();
  19. }
  20. }

效果如下:

那么如何来点滚动条呢?

使用JScroll即可

代码:

  1. package top.woodwhale.study5;
  2. import javax.swing.*;
  3. import java.awt.*;
  4. public class JScrollDemo extends JFrame {
  5. public JScrollDemo() {
  6. // 容器
  7. Container container = this.getContentPane();
  8. // 文本
  9. JTextArea textArea = new JTextArea(20,50);
  10. textArea.setText("114514");
  11. // 滚动条
  12. JScrollPane scrollPane = new JScrollPane(textArea);
  13. container.add(scrollPane);
  14. this.setVisible(true);
  15. this.setBounds(300,300,300,300);
  16. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  17. }
  18. public static void main(String[] args) {
  19. new JScrollDemo();
  20. }
  21. }

4.5 按钮

其实Swing中的按钮和html中的选择框很像,也是需要设置选择域进行分组,许多单选框如果在一个组就只能选一个,多选就没这么限制了

Swing中的按钮分为下面三类:

  • 图片按钮 (JButton中的setIcon实现

    效果图:

    代码:

    1. package top.woodwhale.study5;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. import java.net.URL;
    5. public class JButtonDemo1 extends JFrame {
    6. public JButtonDemo1 (){
    7. Container container = this.getContentPane();
    8. URL rs = JButtonDemo1.class.getResource("woodwhale.jpg");
    9. assert rs != null;
    10. Icon icon = new ImageIcon(rs);
    11. // 把这个图标放在按钮上
    12. JButton jButton = new JButton();
    13. jButton.setIcon(icon);
    14. jButton.setToolTipText("114514");
    15. container.add(jButton);
    16. this.setVisible(true);
    17. this.setSize(300,300);
    18. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    19. }
    20. public static void main(String[] args) {
    21. new JButtonDemo1();
    22. }
    23. }
  • 单选按钮 (JRadioButton和ButtonGroup

    效果如下:

    代码:

    1. package top.woodwhale.study5;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. public class JButtonDemo2 extends JFrame {
    5. public JButtonDemo2() {
    6. Container container = this.getContentPane();
    7. // 单选框
    8. JRadioButton radioButton = new JRadioButton("JRadioButtonTest");
    9. JRadioButton radioButton1 = new JRadioButton("JRadioButtonTest114514");
    10. JRadioButton radioButton2 = new JRadioButton("JRadioButtonTest1919810");
    11. // 由于单选框只能选择一个,所以需要分组
    12. ButtonGroup buttonGroup = new ButtonGroup();
    13. buttonGroup.add(radioButton);
    14. buttonGroup.add(radioButton1);
    15. buttonGroup.add(radioButton2);
    16. container.add(radioButton1,BorderLayout.CENTER);
    17. container.add(radioButton,BorderLayout.NORTH);
    18. container.add(radioButton2,BorderLayout.SOUTH);
    19. this.setVisible(true);
    20. this.setSize(300,300);
    21. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    22. }
    23. public static void main(String[] args) {
    24. new JButtonDemo2();
    25. }
    26. }
  • 复选按钮 ( JCheckBox

    效果图:

    代码:

    1. package top.woodwhale.study5;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. public class JButtonDemo3 extends JFrame {
    5. public JButtonDemo3() {
    6. Container container = this.getContentPane();
    7. // 多选框
    8. JCheckBox ch1 = new JCheckBox("114514");
    9. JCheckBox ch2 = new JCheckBox("1919810");
    10. container.add(ch1,BorderLayout.NORTH);
    11. container.add(ch2,BorderLayout.SOUTH);
    12. this.setVisible(true);
    13. this.setSize(300,300);
    14. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    15. }
    16. public static void main(String[] args) {
    17. new JButtonDemo3();
    18. }
    19. }

4.6 列表

  • 下拉框

    效果如下:

    代码:

    1. package top.woodwhale.study6;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. import java.awt.event.ActionEvent;
    5. import java.awt.event.ActionListener;
    6. public class ComboDemo1 extends JFrame {
    7. public ComboDemo1() {
    8. Container contentPane = this.getContentPane();
    9. JComboBox comboBox = new JComboBox();
    10. comboBox.addItem(null);
    11. comboBox.addItem("114514");
    12. comboBox.addItem("1919810");
    13. // 监听选择
    14. comboBox.addActionListener(new ActionListener() {
    15. @Override
    16. public void actionPerformed(ActionEvent actionEvent) {
    17. System.out.println(comboBox.getSelectedIndex());
    18. System.out.println(comboBox.getSelectedItem());
    19. }
    20. });
    21. contentPane.add(comboBox);
    22. this.setVisible(true);
    23. this.setSize(300,100);
    24. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    25. }
    26. public static void main(String[] args) {
    27. new ComboDemo1();
    28. }
    29. }
  • 列表框

    效果如下:

    代码:

    1. package top.woodwhale.study6;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. import java.util.LinkedList;
    5. import java.util.Vector;
    6. public class ComboDemo2 extends JFrame {
    7. public ComboDemo2() {
    8. Container container = this.getContentPane();
    9. // 生成Vector内容
    10. Vector contents = new Vector();
    11. JList jList = new JList(contents);
    12. // 动态添加
    13. contents.add("114514");
    14. contents.add("1919810");
    15. container.add(jList);
    16. this.setVisible(true);
    17. this.setSize(300,300);
    18. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    19. }
    20. public static void main(String[] args) {
    21. new ComboDemo2();
    22. }
    23. }
  • 应用场景:

    1. 选择地区、班级、学院之类的多选择器
    2. 展示一些列表信息,一般使用动态扩容

4.7 文本框

  • 文本框

    效果如下:

    代码:

    1. package top.woodwhale.study6;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. public class TextDemo1 extends JFrame {
    5. public TextDemo1() {
    6. Container container = this.getContentPane();
    7. JTextField t1 = new JTextField("hello");
    8. JTextField t2 = new JTextField("word",20);
    9. container.add(t1,BorderLayout.NORTH);
    10. container.add(t2,BorderLayout.SOUTH);
    11. this.setVisible(true);
    12. this.setSize(300,300);
    13. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    14. }
    15. public static void main(String[] args) {
    16. new TextDemo1();
    17. }
    18. }
  • 密码框

    默认效果图:

    但是我们可以通过setEchoChar的方法来更改显示

    代码:

    1. package top.woodwhale.study6;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. public class TestDemo2 extends JFrame {
    5. public TestDemo2() {
    6. Container container = this.getContentPane();
    7. JPasswordField passwordField = new JPasswordField();
    8. passwordField.setEchoChar('*');
    9. container.add(passwordField);
    10. this.setVisible(true);
    11. this.setBounds(300,300,300,300);
    12. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    13. }
    14. public static void main(String[] args) {
    15. new TestDemo2();
    16. }
    17. }
  • 文本域

    JTextArea可以配合面板使用

    效果图(上面在面板中使用的例子):

    代码:

    1. package top.woodwhale.study5;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. public class JScrollDemo extends JFrame {
    5. public JScrollDemo() {
    6. // 容器
    7. Container container = this.getContentPane();
    8. // 文本(20行,50列)
    9. JTextArea textArea = new JTextArea(20,50);
    10. textArea.setText("114514");
    11. // 滚动条
    12. JScrollPane scrollPane = new JScrollPane(textArea);
    13. container.add(scrollPane);
    14. this.setVisible(true);
    15. this.setBounds(300,300,300,300);
    16. this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    17. }
    18. public static void main(String[] args) {
    19. new JScrollDemo();
    20. }
    21. }

【Java】GUI编程的更多相关文章

  1. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  2. Java GUI编程中AWT/swing/SWT的优缺点

    http://www.cnblogs.com/dugang/archive/2010/10/22/1858478.html AWT AWT是Abstract Window Toolkit(抽象窗口工具 ...

  3. Java GUI编程4---标签组件JLabel

    Java GUI编程4---标签组件JLabel 2018年06月11日 22:06:58 蓝蓝223 阅读数 12103更多 个人分类: Java书籍摘抄 所属专栏: Java Swing图形界面 ...

  4. java Gui编程 事件监听机制

    1.     GUI编程引言 以前的学习当中,我们都使用的是命令交互方式: 例如:在DOS命令行中通过javac java命令启动程序. 软件的交互的方式:   1. 命令交互方式    图书管理系统 ...

  5. java GUI编程二

    java基础学习总结--GUI编程(二) 一.事件监听 测试代码一: 1 package cn.javastudy.summary; 2 3 import java.awt.*; 4 import j ...

  6. Java GUI编程

    ----基础 // 创建一个窗体对象        JFrame frame = new JFrame();        // 设置窗口大小        frame.setSize(300, 20 ...

  7. Java GUI编程-(项目代码_扫雷_弹钢琴)

    --扫雷 package com;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionLis ...

  8. [Java] GUI编程基础 绘图

    库 swing awt 过程 创建窗口JFrame JFrame-->MenuBar-->Container 屏幕坐标系:左上角为原点 Graphics2D Main.java 1 imp ...

  9. Java GUI编程SwingUtilities.invokeLater作用

    1 http://blog.micxp.com/index.php/archives/109/ 2

  10. 实验十五 GUI编程练习与应用程序部署

    实验十五  GUI编程练习与应用程序部署 实验时间 2018-12-6 一:理论部分 1.Java 程序的打包:编译完成后,程序员将.class 文件压缩打包为 .jar 文件后,GUI 界面序就可以 ...

随机推荐

  1. Windows服务(.net Core 3.1-Topshelf-log4net-quartz)

    https://github.com/yezei/Topshelf-log4net-quartz.git

  2. 前端实现list排序

    需求 针对list中某个字段,实现list的升序和降序 效果图 代码 我是用在angular1.X中项目的,根据list中的sort字段进行排序. # sort.html <style> ...

  3. 【LeetCode】339. Nested List Weight Sum 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 dfs 日期 题目地址:https://leetcod ...

  4. 【九度OJ】题目1441:人见人爱 A ^ B 解题报告

    [九度OJ]题目1441:人见人爱 A ^ B 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1441 题目描述: 求A^B ...

  5. 【LeetCode】210. Course Schedule II 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 拓扑排序,BFS 拓扑排序,DFS 参考资料 日期 ...

  6. 【LeetCode】771. Jewels and Stones 解题报告

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述: 题目大意 解题方法 数组count 字典Counter 日期 题目地址 ...

  7. Problem 2221 RunningMan(fuzoj)

     Problem 2221 RunningMan Accept: 130    Submit: 404Time Limit: 1000 mSec    Memory Limit : 32768 KB ...

  8. codeforc 603-A. Alternative Thinking(规律)

    A. Alternative Thinking time limit per test 2 seconds memory limit per test 256 megabytes   Kevin ha ...

  9. [opencv]计算多边形逼近曲线的长度

    //利用曲线逼近,计算逼近曲线的长度 //首先创建一个逼近曲线 vector<Point2f> approx; approxPolyDP(contours[i], approx, 2, t ...

  10. <数据结构>XDOJ334.分组统计

    问题与解答 问题描述 先输入一组数,然后输入其分组,按照分组统计出现次数并输出,参见样例. 输入格式 输入第一行表示样例数m,对于每个样例,第一行为数的个数n,接下来两行分别有n个数,第一行有n个数, ...