视频学习资料:GUI编程入门到游戏实战
视频UP说,优秀的程序员要看源码学习类的使用,就不要看帮助文档API了。英语不太差,都能知道这些方法是怎么用的。
阅读文章:java中事件监听器
GUI编程详解
文章目录
1 GUI编程
图形用户户界面,又称为图形用户接口(Graphical User Interfaces,GUI)。GUI指的就是采用图形方式显示的计算机操作用户界面。
【我们点击QQ图标,就会弹出一个QQ登陆界面的对话框。这个QQ图标就可以被称作图形化的用户界面。】
实现GUI编程的必不可少的三个条件:
- 组件:组件就是一些基本的图形元素,包含有两类组件,一类是像我们经常用到的按钮、文本框、文本域、多选按钮、单选按钮等;另一类是我们经常说到的容器,比如说窗体、Panel等,它的作用主要是用来组织界面上的组件或者单元。
- 事件:事件是指组件触发的动作事件,java中不同的事件由不同的监听器处理,组件是事件源对象,而监听器主要用来接收来自事件源对象产生的动作事件,然后对其处理。
- 事件监听。
JavaGUI开发的核心技术:
java.awt
包:主要提供字体/布局管理器javax.swing
包[商业开发常用] :主要提供各种组件(窗口/按钮/文本框)
JavaGUI缺点:
(1)因为界面不美观
(2)需要jre环境
为什么要学习JavaGUI开发:
(1)可以写出自己心中想要的一些小工具
(2)工作时候,也可能需要维护到swing界面
(3)了解MVC架构,了解监听
2 AWT包
- 抽象窗口工具包(Abstract Window Toolkit,AWT)包括了很多类和接口,用于Java Application的GUI编程。
- 支持图形用户界面编程的功能包括: 用户界面组件;事件处理模型;图形和图像工具(包括形状、颜色和字体类);布局管理器(窗口布局、特定窗口的尺寸);数据传送类等。
2.1 界面基本属性
- 万物皆对象,new一个Frame对象。Frame是一个顶级窗口
- 一定要
setVisible()
和setSize()
不然看不见窗口。 - 适配器模式监听事件。
package guistudy;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TextFrame {
public static void main(String[] args) {
//对象对象新建对象(万物皆对象)
Frame frame = new Frame("Java图形用户界面");
//设置一些属性
//两个必要属性:可见,窗口大小。不设置都看不见窗口
frame.setVisible(true);
frame.setSize(600,400);
frame.setBackground(new Color(128, 227, 188));
frame.setLocation(800,300);//初始弹出位置
// frame.setBounds(300,200,600,600);//包含setSize和setLocation
frame.setResizable(false);//窗口大小是否可变
//监听事件,监听窗口关闭事件(不然点x关闭不了窗口)
//适配器模式
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
//设置结束程序
System.exit(0);
}
});
}
}
关于Color对象设置技巧(RGB)
监听事件,直接选用适配器模式,可以先只重写这一个“点击关闭”事件。
2.2 同时展示多个窗口
package guistudy;
import java.awt.*;
public class MulFrame {
public static void main(String[] args) {
//展示多个窗口
MyFrame myFrame1 = new MyFrame(100,100,300,300,Color.BLUE);
MyFrame myFrame2 = new MyFrame(400,100,300,300,Color.GREEN);
MyFrame myFrame3 = new MyFrame(100,400,300,300,Color.ORANGE);
MyFrame myFrame4 = new MyFrame(400,400,300,300,Color.CYAN);
}
}
class MyFrame extends Frame {
static int id=0;//可能存在多个窗口,就需要一个计数器解决
public MyFrame(int x,int y,int w,int h,Color color){
super("NO."+(++id));
setBackground(color);
setBounds(x,y,w,h);
setVisible(true);
}
}
问题:没有设置监听,运行的窗口无法关闭,只能通过关闭java运行机制停止程序运行。
2.3 Panel面板
Panel对象不能单独显示,必须添加到某个容器中。可以借助Frame对象。
package guistudy;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class PanelText {
public static void main(String[] args) {
Frame frame = new Frame();
Panel panel = new Panel();//不能单独显示
frame.setLayout(null);//布局
frame.setBounds(300, 300, 500, 500);
frame.setBackground(Color.lightGray);
frame.setVisible(true);
panel.setBounds(50, 50, 400, 400);
panel.setBackground(Color.PINK);
//把面板添加给框架
frame.add(panel);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
2.4 布局管理
- 流式布局:从左到右。
排成一行,位置可以时左边,中间(默认),右边。
语法:frame.setLayout(new FlowLayout());
//默认中间,可以设置参数FlowLayout.LEFT
(左对齐),FlowLayout.RIGHT
右对齐。
- 东西南北中式布局:
语法:frame.add(btn1,BorderLayout.WEST);
参数对应方位。
- 表格布局
语法:frame.setLayout(new GridLayout(2,3));
//参数代表行列数
f.pack()
方法:f的大小会被设置为最佳大小,也就是prefrredSize(也就是正好把frame的内容包起来)。相当于语句f.setSize(f.getPreferredSize());
布局测试类:
package guistudy;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class FlowLayoutText {
public static void main(String[] args) {
Frame frame = new Frame("流式布局");
frame.setBounds(300, 300, 500, 500);
frame.setBackground(Color.lightGray);
frame.setVisible(true);
Button btn1 = new Button("btn1");
Button btn2 = new Button("btn2");
Button btn3 = new Button("btn3");
Button btn4 = new Button("btn4");
Button btn5 = new Button("btn5");
//(1)流式布局
// frame.setLayout(new FlowLayout());//默认中间
// frame.setLayout(new FlowLayout(FlowLayout.LEFT));//左
// frame.setLayout(new FlowLayout(FlowLayout.RIGHT));//右
//
// frame.add(btn1);
// frame.add(btn2);
// frame.add(btn3);
// frame.add(btn4);
// frame.add(btn5);
// //(2)东南西北中式布局
// frame.add(btn1,BorderLayout.WEST);
// frame.add(btn2,BorderLayout.NORTH);
// frame.add(btn3,BorderLayout.EAST);
// frame.add(btn4,BorderLayout.SOUTH);
// frame.add(btn5,BorderLayout.CENTER);
//(3)表格布局
frame.setLayout(new GridLayout(2,3));
frame.add(btn1);
frame.add(btn2);
frame.add(btn3);
frame.add(btn4);
frame.add(btn5);
frame.pack();//Java函数,可以自定义布局
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
2.5 事件监听
- 将一个监听器(listener)与特定的控件(如按钮等)绑定起来,当发生用户点击等事件(Event)时,调用监听器的处理方法,从而响应用户的动作。是为事件/监听器模式。
- 方法:
btn1.addActionListener(MyActionListener);
为控件添加监听,需要一个相应类ActionListener作为参数,可自定义并实现方法。
e.getActionCommand()
可以获取控件点击后返回的信息。
btn2.setActionCommand("over");
可以显示的定义触发会返回的命令,如果不显示定义,则会走默认的值(label)。
一个简单的按钮点击测试:
package guistudy.listener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
//简单的事件监听
public class Demo01 {
public static void main(String[] args) {
Frame frame = new Frame();
Button btn1 = new Button("start");
Button btn2 = new Button("stop");
//事件监听:将响应控件点击方法和按钮控件绑定。多个空间可以用相同的监听类
//因为,addActionListener()需要一个ActionListener
//所以我们构造一个命名为MyActionListener,包含相应方法。
ActionListener MyActionListener = new MyActionListener();
btn1.addActionListener(MyActionListener);
btn2.addActionListener(MyActionListener);
//可以显示的定义触发会返回的命令,如果不显示定义,则会走默认的值(label)
btn2.setActionCommand("over");
//相当于给框架右上角的×设置事件监听
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);//退出程序
}
});
//布局
frame.setLayout(new FlowLayout());//流式布局
frame.add(btn1);
frame.add(btn2);
frame.setVisible(true);
frame.setLocation(600,800);
frame.pack();
}
}
class MyActionListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
//e表示空间本身,e.getActionCommand()可以获取控件点击后返回的信息
System.out.println("控件被点击了→"+e.getActionCommand());
if(e.getActionCommand().equals("start")){
System.out.println("程序开始!");
}
else{
System.out.println("程序结束!");
}
}
}
运行结果:
2.6 TextField输入框监听
- 方法
TextField n1 = new TextField(10);
输入框构造方法参数表示字符数,控制文本框长度。
TextField.getText()
获取文本框字符串
TextField.setText("");
设置文本框字符串
简易文本框加法计算器
简易计算器设计:
(1)三个文本框:两个用于输入,一个用于输出
(2)一个标识(label):“+”【标识没有任何作用,就是显示文字】
(3)一个控件:“=”。实现监听事件:完成加法运算,向第三个框输出结果并且清空前两个框。
关于写代码:组合(类中调用类)大于继承(extends、implements)!
package guistudy.listener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
//文本框事件监听,并制作简易计算器
public class Demo02 {
public static void main(String[] args) {
new Calculator().loadFrame();//组合:类中调用类
}
}
//计算器类
class Calculator {
//属性
TextField n1, n2, n3;
//方法
public void loadFrame(){
Frame frame = new Frame("加法计算器");
n1 = new TextField(10);//字符数
n2 = new TextField(10);
n3 = new TextField(20);
Label label = new Label("+");
Button button = new Button("=");
button.addActionListener(new MyCalListener(this));
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.setLayout(new FlowLayout());
frame.add(n1);
frame.add(label);
frame.add(n2);
frame.add(button);
frame.add(n3);
frame.setVisible(true);
frame.pack();
frame.setLocation(800,600);
}
}
//监听器类
class MyCalListener implements ActionListener {
Calculator cal = null;
public MyCalListener(Calculator calculator) {//构造函数
cal = calculator;
}
@Override
public void actionPerformed(ActionEvent e) {
//String类转换为int类
int s1 = Integer.parseInt(cal.n1.getText());
int s2 = Integer.parseInt(cal.n2.getText());
cal.n3.setText(""+(s1+s2));
cal.n1.setText("");
cal.n2.setText("");
}
}
2.7 画笔
画笔不是一个控件不需要new出来,只是Frame框架的一个方法,我们实现画笔功能,只需要对Frame类重写paint()方法。
不添加鼠标监听的自动画笔小测试:
package guistudy.listener;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
//画笔
public class Demo03 {
public static void main(String[] args) {
MyFrame myFrame = new MyFrame();
myFrame.loadFrame();
windowClose(myFrame);
}
//监听事件 关闭
private static void windowClose(Frame frame){
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
class MyFrame extends Frame{
void loadFrame(){
setTitle("画笔");
setBounds(200,300,500,500);
setVisible(true);
}
@Override//重写画笔方法
public void paint(Graphics g) {
//设置画笔:颜色 形状
g.setColor(Color.PINK);
g.drawLine(100,100,200,200);
g.setColor(Color.ORANGE);
g.drawOval(250,100,100,100);//空心圆
g.fillRect(250,250,100,100);//实心矩形
}
}
2.8 鼠标监听
- 鼠标事件: 鼠标作用在一个组件上。鼠标键按下,鼠标键抬起,单击鼠标键,鼠标移动,鼠标拖动等。
- 注册鼠标事件方法:
Frame对象.addMouseListener(MouseListener)
- 鼠标事件监听接口:MouseListener//接受鼠标事件
该接口方法包括三种:
1)mouseClicked(MouseEvent e)
2)mouseEntered(MouseEvent e)
3)mouseExited(MouseEvent e) - 鼠标事件监听适配器(抽象类):MouseAdapter。
适配器帮助我们实现鼠标事件监听,可以只重写一个方法,不需要都重写一遍,减轻代码工作量。
鼠标画点思维图:
package guistudy.listener;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;
//鼠标监听
public class Demo04 {
public static void main(String[] args) {
new MyMouseFrame("鼠标画点");
}
}
//自定义配置鼠标画点的类
class MyMouseFrame extends Frame{
ArrayList points;//一个列表存放点
public MyMouseFrame(String title) throws HeadlessException {
super(title);
setBounds(200, 200, 500, 500);
setVisible(true);
points = new ArrayList();//存放鼠标点的集合
this.addMouseListener(new MyMouseListener());
this.addWindowListener(new MyWindowAdapter());
}
@Override//重写画笔
public void paint(Graphics g) {
super.paint(g);
//画画:遍历画所有的点
Iterator iterator = points.iterator();
while (iterator.hasNext()){
Point point = (Point) iterator.next();
g.setColor(Color.pink);
g.fillOval(point.x,point.y,10,10);//实心圆
}
}
//添加鼠标点到集合
public void addPoint(Point point){
points.add(point);
}
//监听窗口关闭
class MyWindowAdapter extends WindowAdapter{
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
//鼠标监听
class MyMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
MyMouseFrame frame= (MyMouseFrame) e.getSource();//获取鼠标点的信息
frame.addPoint(new Point(e.getX(),e.getY())); //获取鼠标点的当前位置添加到集合
frame.repaint();//刷新 每一次点击鼠标就会刷新
}
}
}
2.9 窗口监听
最小化
常用的两个窗口监听——窗口关闭,窗口激活:
package study.gui.listener;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
//窗口监听
public class TextWindow {
public static void main(String[] args) {
new WindowFrame();
}
}
class WindowFrame extends Frame{
public WindowFrame() throws HeadlessException {
setBounds(100,200,400,300);
setBackground(Color.PINK);
setVisible(true);
this.addWindowListener(new WindowAdapter() {匿名内部类
@Override
public void windowClosing(WindowEvent e) {//窗口关闭
System.out.println("窗口关闭....");
System.exit(0);//0正常关闭,1异常关闭
}
@Override
public void windowActivated(WindowEvent e) {//窗口激活
WindowFrame source = (WindowFrame) e.getSource();
source.setTitle("激活成功");
System.out.println("窗口激活....");
}
});
}
}
把这个窗口最小化再打开就是“窗口激活”:
2.10 键盘监听
package study.gui.listener;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
//键盘监听
public class TextKey {
public static void main(String[] args) {
new MyKeyFrame();
}
}
class MyKeyFrame extends Frame{
public MyKeyFrame() throws HeadlessException {
setBounds(10,10,200,200);
setVisible(true);
this.addKeyListener(new KeyAdapter() {
@Override//键盘按下
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();//首先要获取当前键盘要按下的键的值(ASCII码)
System.out.println(keyCode);
if (keyCode==KeyEvent.VK_DOWN){//不用记值,直接使用静态属性"VK_xx"
System.out.println("你按下了【↓】");
}
else if(keyCode==KeyEvent.VK_UP){
System.out.println("你按下了【↑】");
}
else{
System.out.println(keyCode+"未识别按钮");
}
}
});
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}