前言
昨日诸事不顺,无奈跳过一天。虽然说得无辜,但也无法掩饰我没有一往无前的决心。若是真有,纵使山崩,也要学JAVA。继续学8。目录接前日。
一、AWT
4、事件监听
当发生某个事情的时候,做什么?
TestAction
public class TestAction {
public static void main(String[] args) {
//按下按钮,触发一些事件
Frame frame = new Frame();
Button button = new Button();
//因为进源码可以看见下面这个方法需要一个ActionListen,所以需要构造一个,此时写下方的Class
MyActionListener myActionListener = new MyActionListener();
button.addActionListener(myActionListener);
frame.add(button,BorderLayout.CENTER);
frame.pack();
windowClose(frame);//关闭窗口
frame.setVisible(true);
}
//关闭窗体事件
private static void windowClose(Frame frame){
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");
}
}
写好Frame和Button,使用Button的addActionListener方法,进源码观看发现此方法需要ActionListener参数,于是创建类MyActionListener重写接口,然后调用即可。
同时将关闭窗体事件抽象为方法,然后放进main方法中调用。
TestAction2(多个按钮共享一个监听事件)
public static void main(String[] args) {
//两个按钮,实现同一个监听
//开始停止
Frame frame = new Frame();
Button button1 = new Button("start");
Button button2 = new Button("stop");
//可以显示定义触发时会返回的命令,如果不定义显示,则会走默认的值
//可以多个按钮只写一个监听类
button2.setActionCommand("button2-stop");
MyMonitor myMonitor = new MyMonitor();
button1.addActionListener(myMonitor);
button2.addActionListener(myMonitor);
frame.add(button1,BorderLayout.NORTH);
frame.add(button2,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
class MyMonitor implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
//e.getActionCommand()获得按钮的信息
System.out.println("按钮被点击了:msg"+e.getActionCommand());
}
}
通过setActionCommand(String command)用字符串来显示地定义这个按钮的功能,然后在MyMonitor中使用getActionCommand方法来获得这个字符串,然后就可以通过if或别的选择和判断语句来实现一个Listener中定义多种动作,并根据按钮command的不同来实现不同的操作。
5、输入框监听
TextField
public class TestText01 {
public static void main(String[] args) {
//启动!
new MyFrame();
}
}
class MyFrame extends Frame {
public MyFrame(){
TextField textField = new TextField();
this.add(textField);
//监听这个文本框输入的文字
MyActionListener2 myActionListener2 = new MyActionListener2();
//按下enter,就会触发这个输入框的事件
textField.addActionListener(myActionListener2);
//设置替换编码
textField.setEchoChar('*');
setVisible(true);
pack();
}
}
class MyActionListener2 implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
TextField field = (TextField) e.getSource();//获得一些资源,返回一个对象
System.out.println(field.getText());
field.setText("");//按下回车后设置文本框为空
}
}
总结
- main方法中只写启动
- 创建新的Linster后,通过addActionListener添加到TextField中
- 按钮通过点击触发,TextField通过按下Enter触发
- 通过setEchoChar(char ch)将输入的明文替换为*
- 通过getSource()方法获得当前发生Event的对象并通过field存储,在MyFrame中可以看到获取的Sourse就是textField;
- 此处通过getSource获得当前对象(不能直接往ActionListener中用形参传入对象,但可以通过构造器传入对象,也可以使用内部类,见下一小节),再通过强制转型将Object类的e对象转换成需要的类型,此处为TextField。
- 通过getText获取文本框中的输入
- 通过Linstener中使用setText("")完成对文本框的清空
6、简易计算器,组合+内部类回顾复习
oop原则:组合,大于继承!
//继承:
class A extends B{
}
class A extends B{
public B b;
}
目前代码
public class TestCalc {
public static void main(String[] args) {
new Calculator();
}
}
class Calculator extends Frame {
public Calculator() {
//3个文本框
TextField num1 = new TextField(10);//字节数
TextField num2 = new TextField(10);//字节数
TextField num3 = new TextField(20);//字节数
//1个按钮
Button button = new Button("=");
button.addActionListener(new MyCalculatorListener(num1,num2,num3));
//1个标签
Label label = new Label("+");
//布局
setLayout(new FlowLayout());
add(num1);
add(label);
add(num2);
add(button);
add(num3);
pack();
setVisible(true);
}
}
//监听器类
class MyCalculatorListener implements ActionListener{
//获取三个对象
TextField num1,num2,num3;
public MyCalculatorListener(TextField num1,TextField num2,TextField num3) {
this.num1 = num1;
this.num2 = num2;
this.num3 = num3;
}
@Override
public void actionPerformed(ActionEvent e) {
//1.获得加数和被加数
int n1 = Integer.parseInt(num1.getText());
int n2 = Integer.parseInt(num2.getText());
//2.将这个值+法运算后,放到第三个框;
num3.setText(""+(n1+n2));
//3.清楚前两个框
num1.setText("");
num2.setText("");
}
}
优化代码(组合)
//简易计算器
public class TestCalc {
public static void main(String[] args) {
new Calculator();
}
}
class Calculator extends Frame {
//属性
TextField num1,num2,num3;
//不使用构造器,改为使用load方法
public void loadFrame(){
TextField num1 = new TextField(10);//字节数
TextField num2 = new TextField(10);//字节数
TextField num3 = new TextField(20);//字节数
Button button = new Button("=");
//往Listener中传入当前这个类,完成组合。
button.addActionListener(new MyCalculatorListener(this));
Label label = new Label("+");
setLayout(new FlowLayout());
add(num1);
add(label);
add(num2);
add(button);
add(num3);
pack();
setVisible(true);
}
}
//监听器类
class MyCalculatorListener implements ActionListener{
//获取计算器这个对象
Calculator calculator = null;
public MyCalculatorListener(Calculator calculator) {
this.calculator = calculator;
}
@Override
public void actionPerformed(ActionEvent e) {
//1.获得加数和被加数
int n1 = Integer.parseInt(calculator.num1.getText());
int n2 = Integer.parseInt(calculator.num2.getText());
//2.将这个值+法运算后,放到第三个框;
calculator.num3.setText(""+(n1+n2));
//3.清除前两个框
calculator.num1.setText("");
calculator.num2.setText("");
}
}
再优化(内部类)
优点
- 更好的包装
- 畅通无阻地访问外部类
所以直接把Listener写成内部类,删去构造器,直接使用变量。
//简易计算器
public class TestCalc {
public static void main(String[] args) {
new Calculator();
}
}
class Calculator extends Frame {
//属性
TextField num1,num2,num3;
//不使用构造器,改为使用load方法
public void loadFrame(){
//3个文本框
TextField num1 = new TextField(10);//字节数
TextField num2 = new TextField(10);//字节数
TextField num3 = new TextField(20);//字节数
//1个按钮
Button button = new Button("=");
button.addActionListener(new MyCalculatorListener());
//1个标签
Label label = new Label("+");
//布局
setLayout(new FlowLayout());
add(num1);
add(label);
add(num2);
add(button);
add(num3);
pack();
setVisible(true);
}
//内部类最大的好处就是能畅通无阻地访问外部类
private class MyCalculatorListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
//1.获得加数和被加数
int n1 = Integer.parseInt(num1.getText());
int n2 = Integer.parseInt(num2.getText());
//2.将这个值+法运算后,放到第三个框;
num3.setText(""+(n1+n2));
//3.清除前两个框
num1.setText("");
num2.setText("");
}
}
}
总结
三种不同思路实现了三次相同的计算器
1、使用类似面向过程的办法,一步步地实现计算器,在Listener中,直接传递3个num参数,进行计算和操作;
2、使用了面向对象的方法,不再直接传入三个参数,而是采用了组合方式,直接传入Calculator对象(通过this关键字)然后Linstener调用其中的变量完成计算和相关操作。
3、使用了内部类,在Calculator内部定义Linstener类并进行调用,这样的好处是能畅通无阻地访问外部类的所有变量,用private修饰*。
7、画笔
TestPaint
public class TestPaint {
public static void main(String[] args) {
new MyPaint().loadFrame();
}
}
class MyPaint extends Frame {
public void loadFrame(){
setBounds(200,200,600,500);
setVisible(true);
}
//画笔
@Override
public void paint(Graphics g) {
//画笔,需要有颜色,可以画画
g.setColor(Color.red);
//g.drawOval(100,100,100,100);
g.fillOval(50,50,50,50);
g.setColor(Color.green);
g.fillRect(150,150,200,200);
//养成习惯,画笔用完换成最初的颜色(black)。
}
}
8、鼠标监听
目的:想要实现鼠标画画
代码
此处未讲线程所以是每画一个点repaint一次
//鼠标监听事件
public class TestMouseListener {
public static void main(String[] args) {
new MyFrame("画图");
}
}
class MyFrame extends Frame {
//画画需要画笔,监听鼠标当前位置,需要集合储存点
ArrayList points;
public MyFrame(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()){
Point point = (Point) iterator.next();
g.fillOval(point.x,point.y,10,10);
}
}
//添加一个点到界面上
public void addPaint(Point point){
points.add(point);
}
//适配器模式
private class MyMouseListener extends MouseAdapter{
//鼠标 按下,弹起,按住不放
@Override
public void mousePressed(MouseEvent e) {
//这一句好像只是为了调用addPaint方法
MyFrame frame = (MyFrame) e.getSource();
//点击的时候就会再界面上产生一个点!
//这个点就是鼠标的点
frame.addPaint(new Point(e.getX(),e.getY()));
//每次点击鼠标都需要重新画一遍
frame.repaint();//刷新
}
}
}
一些想法
注意!
监听器中为了将鼠标坐标换成点加入ArrayList,采用了
public void mousePressed(MouseEvent e) {
//这一句好像只是为了调用addPaint方法
MyFrame frame = (MyFrame) e.getSource();
//点击的时候就会再界面上产生一个点!
//这个点就是鼠标的点
frame.addPaint(new Point(e.getX(),e.getY()));
//每次点击鼠标都需要重新画一遍
frame.repaint();//刷新
}
已经是内部类了,为什么还要专门为了用addPaint而getSource并强转成MyFrame呢?可以直接改写成:
public void mousePressed(MouseEvent e) {
addPoint(new Point(e.getX(),e.getY()));
repaint();
}
甚至addPoint()方法都是不必要的,可以直接写在监听器里
public void mousePressed(MouseEvent e) {
//addPoint(new Point(e.getX(),e.getY()));
points.add(new Point(e.getX(),e.getY()));
repaint();
}
如此,代码只有四个方法,分别是调用构造器的main方法,构造器方法、重写的监听方法和重写的paint方法。
程序总流程:
1、 创建Frame
2、 Frame构造器中初始化参数
3、 监听鼠标按压,如果有按压,用Point数据类型存储X和Y位置,并用ArrayList存储每一个点
4、 遍历ArrayList,在Frame上把所有点都画出来。
9、窗口监听
TestWindow
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 windowOpened(WindowEvent e) {
System.out.println("Window Opened");
}
@Override
public void windowClosing(WindowEvent e) {
System.out.println("Window Closing");
System.exit(0);
}
//激活窗口
@Override
public void windowClosed(WindowEvent e) {
System.out.println("Window Closed");
}
@Override
public void windowActivated(WindowEvent e) {
System.out.println("Window Activated");
}
@Override
public void windowDeactivated(WindowEvent e) {
System.out.println("Window Deactivated");
}
}
);
}
}
10、键盘监听
TestKeyListener
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();
System.out.println(keyCode);
//不需要记录上述数值,直接使用静态属性VK_XXX
if(keyCode == KeyEvent.VK_UP){
System.out.println("按下了↑键");
}
}
});
}
}
二、Frame
已经学过,只过一遍课,不写代码。