java必学必会之GUI编程

内容摘要
一、事件监听
  
测试代码一:




package cn.javastudy.summary;

import java.awt.*;
import java.awt.event.*;

public class TestTextField {
public static void m
文章正文

一、事件监听

  

测试代码一:

package cn.javastudy.summary;

import java.awt.*;
import java.awt.event.*;

public class TestTextField {
  public static void main(String args[]) {
    new MyFrameTextField();
  }
}

class MyFrameTextField extends Frame {
  MyFrameTextField() {
    TextField tf = new TextField();
    add(tf);
    tf.addActionListener(new Monitor3());
    tf.setEchoChar('*');
    /*
     * 这个setEchoChar()方法是设置文本框输入时显示的字符,这里设置为*, 
     * 这样输入任何内容就都以*显示出来,不过打印出来时依然可以看到输入的内容
     */
    setVisible(true);
    pack();
  }
}

class Monitor3 implements ActionListener {
  /*
   * 接口里面的所有方法都是public(公共的) 
   * 所以从API文档复制void actionPerformed(ActionEvent e)时 要在void前面加上public
   */
  public void actionPerformed(ActionEvent e) {
    /* 事件的相关信息都封装在了对象e里面,通过对象e的相关方法就可以获取事件的相关信息 */
    TextField tf = (TextField) e.getSource();
    /*
     * getSource()方法是拿到事件源,注意:拿到这个事件源的时候,
     * 是把它当作TextField的父类来对待 
     * getSource()方法的定义是:“public Object getSource()”返回值是一个Object对象,
     * 所以要强制转换成TextField类型的对象 
     * 在一个类里面想访问另外一个类的事件源对象可以通过getSource()方法
     */
    System.out.println(tf.getText());// tf.getText()是取得文本框里面的内容
    tf.setText("");// 把文本框里面的内容清空
  }
}

测试代码二:

package cn.javastudy.summary;

import java.awt.*;
import java.awt.event.*;
public class TestActionEvent2{
  public static void main(String args[]){
    Frame f = new Frame("TestActionEvent");
    Button btn1 = new Button("start");
    Button btn2 = new Button("stop");
    Monitor2 m2 = new Monitor2();//创建监听对象
    btn1.addActionListener(m2);
    /*一个监听对象同时监听两个按钮的动作*/
    btn2.addActionListener(m2);
    btn2.setActionCommand("GameOver");//设置btn2的执行单击命令后的返回信息
    f.add(btn1,BorderLayout.NORTH);
    f.add(btn2,BorderLayout.CENTER);
    
    f.pack();
    f.setVisible(true);
  }
}

class Monitor2 implements ActionListener{
  public void actionPerformed(ActionEvent e){
    System.out.println("a button has been pressed,"+"the relative info is:\n"+e.getActionCommand());
    /*使用返回的监听对象e调用getActionCommand()方法获取两个按钮执行单击命令后的返回信息
    根据返回信息的不同区分开当前操作的是哪一个按钮,btn1没有使用setActionCommand()方法设置
    则btn1返回的信息就是按钮上显示的文本*/
  }
}

二、TextField事件监听

  

测试代码:

package cn.javastudy.summary;

import java.awt.*;
import java.awt.event.*;

public class TestTextField {
  public static void main(String args[]) {
    new MyFrameTextField();
  }
}

class MyFrameTextField extends Frame {
  MyFrameTextField() {
    TextField tf = new TextField();
    add(tf);
    tf.addActionListener(new Monitor3());
    tf.setEchoChar('*');
    /*
     * 这个setEchoChar()方法是设置文本框输入时显示的字符,这里设置为*, 
     * 这样输入任何内容就都以*显示出来,不过打印出来时依然可以看到输入的内容
     */
    setVisible(true);
    pack();
  }
}

class Monitor3 implements ActionListener {
  /*
   * 接口里面的所有方法都是public(公共的) 
   * 所以从API文档复制void actionPerformed(ActionEvent e)时 要在void前面加上public
   */
  public void actionPerformed(ActionEvent e) {
    /* 事件的相关信息都封装在了对象e里面,通过对象e的相关方法就可以获取事件的相关信息 */
    TextField tf = (TextField) e.getSource();
    /*
     * getSource()方法是拿到事件源,注意:拿到这个事件源的时候,
     * 是把它当作TextField的父类来对待 
     * getSource()方法的定义是:“public Object getSource()”返回值是一个Object对象,
     * 所以要强制转换成TextField类型的对象 
     * 在一个类里面想访问另外一个类的事件源对象可以通过getSource()方法
     */
    System.out.println(tf.getText());// tf.getText()是取得文本框里面的内容
    tf.setText("");// 把文本框里面的内容清空
  }
}

使用TextField类实现简单的计算器

package cn.javastudy.summary;

import java.awt.*;
import java.awt.event.*;

public class TestMath {
  public static void main(String args[]) {
    new TFFrame();
  }
}

/* 这里主要是完成计算器元素的布局 */
class TFFrame extends Frame {
  TFFrame() {
    /*
     * 创建3个文本框,并指定其初始大小分别为10个字符和15个字符的大小 这里使用的是TextField类的另外一种构造方法 public TextField(int columns)
     */
    TextField num1 = new TextField(10);
    TextField num2 = new TextField(10);
    TextField num3 = new TextField(15);
    /* 创建等号按钮 */
    Button btnEqual = new Button("=");
    btnEqual.addActionListener(new MyMonitor(num1, num2, num3));
    /* 给等号按钮加上监听,让点击按钮后有响应事件发生 */
    Label lblPlus = new Label("+");
    /* “+”是一个静态文本,所以使用Label类创建一个静态文本对象 */
    setLayout(new FlowLayout());
    /* 把Frame默认的BorderLayout布局改成FlowLayout布局 */
    add(num1);
    add(lblPlus);
    add(num2);
    add(btnEqual);
    add(num3);
    pack();
    setVisible(true);

  }
}

class MyMonitor implements ActionListener {
  TextField num1, num2, num3;

  /*
   * 为了使对按钮的监听能够对文本框也起作用, 
   * 所以在自定义类MyMonitor里面定义三个TextField类型的对象 num1,num2,num3,
   * 并且定义了MyMonitor类的一个构造方法 这个构造方法带有三个TextField类型的参数,
   * 用于接收 从TFFrame类里面传递过来的三个TextField类型的参数 
   * 然后把接收到的三个TextField类型的参数赋值给在本类中声明的 三个TextField类型的参数num1,num2,num3 然后再在actionPerformed()方法里面处理num1,num2,num3
   */
  public MyMonitor(TextField num1, TextField num2, TextField num3) {
    this.num1 = num1;
    this.num2 = num2;
    this.num3 = num3;
  }

  public void actionPerformed(ActionEvent e) {
    /* 事件的相关信息都封装在了对象e里面,通过对象e的相关方法就可以获取事件的相关信息 */
    int n1 = Integer.parseInt(num1.getText());/* num1对象调用getText()方法取得自己显示的文本字符串 */
    int n2 = Integer.parseInt(num2.getText());/* num2对象调用getText()方法取得自己显示的文本字符串 */
    num3.setText("" + (n1 + n2));/* num3对象调用setText()方法设置自己的显示文本 */
    num1.setText("");
    /* 计算结束后清空num1,num2文本框里面的内容 */
    num2.setText("");
    // num3.setText(String.valueOf((n1+n2)));
    /* 字符串与任意类型的数据使用“+”连接时得到的一定是字符串,
     * 这里使用一个空字符串与int类型的数连接,这样就可以直接把(n1+n2)得到的int类型的数隐式地转换成字符串了,
     * 这是一种把别的基础数据类型转换成字符串的一个小技巧。
     * 也可以使用“String.valueOf((n1+n2))”把(n1+n2)的和转换成字符串 
     */
  }
}

JAVA里面的经典用法:在一个类里面持有另外一个类的引用

package cn.javastudy.summary;

import java.awt.*;
import java.awt.event.*;

public class TestMath1 {
  public static void main(String args[]) {
    new TTMyFrame().launchFrame();
    /* 创建出TTMyFrame对象后调用lauchFrame()方法把计算器窗体显示出来 */
  }
}

/* 做好计算器的窗体界面 */
class TTMyFrame extends Frame {
  /* 把设计计算器窗体的代码封装成一个方法 */
  TextField num1, num2, num3;

  public void launchFrame() {
    num1 = new TextField(10);
    num2 = new TextField(15);
    num3 = new TextField(15);
    Label lblPlus = new Label("+");
    Button btnEqual = new Button("=");
    btnEqual.addActionListener(new MyMonitorbtnEqual(this));
    setLayout(new FlowLayout());
    add(num1);
    add(lblPlus);
    add(num2);
    add(btnEqual);
    add(num3);
    pack();
    setVisible(true);
  }
}

/*
 * 这里通过取得TTMyFrame类的引用,然后使用这个引用去访问TTMyFrame类里面的成员变量 
 * 这种做法比上一种直接去访问TTMyFrame类里面的成员变量要好得多,
 * 因为现在不需要知道 TTMyFrame类里面有哪些成员变量了,
 * 现在要访问TTMyFrame类里面的成员变量,直接使用 TTMyFrame类对象的引用去访问即可,
 * 这个TTMyFrame类的对象好比是一个大管家, 而我告诉大管家,我要访问TTMyFrame类里面的那些成员变量,
 * 大管家的引用就会去帮我找,不再需要我自己去找了。 
 * 这种在一个类里面持有另一个类的引用的用法是一种非常典型的用法 
 * 使用获取到的引用就可以在一个类里面访问另一个类的所有成员了
 */
class MyMonitorbtnEqual implements ActionListener {
  TTMyFrame ttmf = null;

  public MyMonitorbtnEqual(TTMyFrame ttmf) {
    this.ttmf = ttmf;
  }

  public void actionPerformed(ActionEvent e) {
    int n1 = Integer.parseInt(ttmf.num1.getText());
    int n2 = Integer.parseInt(ttmf.num2.getText());
    ttmf.num3.setText("" + (n1 + n2));
    ttmf.num1.setText("");
    ttmf.num2.setText("");
  }
}

运行结果如下:

三、内部类

  

内部类的使用范例:

package cn.javastudy.summary;

import java.awt.*;
import java.awt.event.*;

public class TestMath3 {

  public static void main(String args[]) {
    new MyMathFrame().launchFrame();
  }
}

class MyMathFrame extends Frame {
  TextField num1, num2, num3;

  public void launchFrame() {
    num1 = new TextField(10);
    num2 = new TextField(15);
    num3 = new TextField(15);
    Label lblPlus = new Label("+");
    Button btnEqual = new Button("=");
    btnEqual.addActionListener(new MyMonitor());
    setLayout(new FlowLayout());
    add(num1);
    add(lblPlus);
    add(num2);
    add(btnEqual);
    add(num3);
    pack();
    setVisible(true);
  }

  /*
   * 这个MyMonitor类是内部类,它在MyFrame类里面定义 MyFrame类称为MyMonitor类的包装类
   */
  /*
   * 使用内部类的好处: 
   * 第一个巨大的好处就是可以畅通无阻地访问外部类(即内部类的包装类)的所有成员变量和方法 
   * 如这里的在MyFrame类(外部类)定义的三个成员变量num1,num2,num3, 
   * 在MyMonitor(内部类)里面就可以直接访问 
   * 这相当于在创建外部类对象时内部类对象默认就拥有了一个外部类对象的引用
   */
  private class MyMonitor implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int n1 = Integer.parseInt(num1.getText());
      int n2 = Integer.parseInt(num2.getText());
      num3.setText("" + (n1 + n2));
      num1.setText("");
      num2.setText("");
    }
  }
}

内部类带来的巨大好处是:

  • 可以很方便地访问外部类定义的成员变量和方法
  • 当某一个类不需要其他类访问的时候就把这个类声明为内部类。

四、Graphics 类

  

测试代码:

package cn.javastudy.summary;

import java.awt.*;
public class TestPaint{
  public static void main(String args[]){
    new MyPaint().launchFrame();
    /*在main()方法里面并没有显示调用paint(Graphics g)方法
    可是当创建出Frame窗体后却可以看到Frame窗体上画出了
    圆和矩形,这是因为paint()方法是一个比较特殊的方法
    在创建Frame窗体时会自动隐式调用
    当我们把Frame窗体最小化又再次打开时,又会再次调用
    paint()方法重新把圆和矩形在Frame窗体上画出来
    即每次需要重画Frame窗体的时候就会自动调用paint()方法*/
  }
}

class MyPaint extends Frame{
  public void launchFrame(){
    setBounds(200,200,640,480);
    setVisible(true);
  }
  
  public void paint(Graphics g){
    /*paint(Graphics g)方法有一个Graphics类型的参数g
    我们可以把这个g当作是一个画家,这个画家手里拿着一只画笔
    我们通过设置画笔的颜色与形状来画出我们想要的各种各样的图像*/
    /*设置画笔的颜色*/
    g.setColor(Color.red);
    g.fillOval(100,100,100,100);/*画一个实心椭圆*/
    g.setColor(Color.green);
    g.fillRect(150,200,200,200);/*画一个实心矩形*/
    /*这下面的两行代码是为了写程序的良好编程习惯而写的
    前面设置了画笔的颜色,现在就应该把画笔的初始颜色恢复过来
    就相当于是画家用完画笔之后把画笔上的颜色清理掉一样*/
    Color c = g.getColor();
    g.setColor(c);
  }
}

运行结果:

五、鼠标事件适配器

测试代码:

package cn.galc.test;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class MyMouseAdapter{
 public static void main(String args[]) {
  new MyFrame("drawing...");
 }
}

class MyFrame extends Frame {
 ArrayList points = null;
 MyFrame(String s) {
  super(s);
  points = new ArrayList(); 
  setLayout(null);
  setBounds(300,300,400,300); 
  this.setBackground(new Color(204,204,255));
  setVisible(true);
  this.addMouseListener(new Monitor());
  }
  
  public void paint(Graphics g) {
  Iterator i = points.iterator();
  while(i.hasNext()){
   Point p = (Point)i.next();
   g.setColor(Color.BLUE);
   g.fillOval(p.x,p.y,10,10);
   
  }
 }
 
 public void addPoint(Point p){
  points.add(p);
 }
}

class Monitor extends MouseAdapter {
 public void mousePressed(MouseEvent e) {
  MyFrame f = (MyFrame)e.getSource();
  f.addPoint(new Point(e.getX(),e.getY()));
  f.repaint();
 }
}

六、window事件

 测试代码:

package cn.galc.test;

import java.awt.*;
import java.awt.event.*;
public class TestWindowClose{
 public static void main(String args[]){
  new WindowFrame("关闭WindowFrame");
 }
}

class WindowFrame extends Frame{
 public WindowFrame(String s){
  super(s);
  setBounds(200,200,400,300);
  setLayout(null);
  setBackground(new Color(204,204,255));
  setVisible(true);
  this.addWindowListener(new WindowMonitor());
/*监听本窗体的动作,把所有的动作信息封装成一个对象传递到监听类里面*/
  
  this.addWindowListener(
  /*在一个方法里面定义一个类,这个类称为局部类,也叫匿名的内部类,
  这里的{……代码……}里面的代码很像一个类的类体,只不过这个类没有名字,所以叫匿名类
  在这里是把这个匿名类当成WindowAdapter类来使用,语法上这样写的本质意义是相当于这个匿名类
  从WindowAdapter类继承,现在new了一个匿名类的对象出来然后把这个对象当成WindowAdapter来使用
  这个匿名类出了()就没有人认识了*/
   new WindowAdapter(){
    public void windowClosing(WindowEvent e){
     setVisible(false);
     System.exit(-1);
    }
   }
  );
 }
 
 /*这里也是将监听类定义为内部类*/
 class WindowMonitor extends WindowAdapter{
  /*WindowAdapter(Window适配器)类实现了WindowListener监听接口
  重写了WindowListener接口里面的所有方法
  如果直接使用自定义WindowMonitor类直接去
  实现WindowListener接口,那么就得要重写WindowListener接口
  里面的所有方法,但现在只需要用到这些方法里面的其中一个方法
  所以采用继承实现WindowListener监听接口的一个子类
  并重写这个子类里面需要用到的那个方法即可
  这种做法比直接实现WindowListener监听接口要重写很多个用不到的方法要简洁方便得多*/
/*重写需要用到的windowClosing(WindowEvent e)方法*/
  public void windowClosing(WindowEvent e){
    setVisible(false);/*将窗体设置为不显示,即可实现窗体关闭*/
    System.exit(0);/*正常退出*/
   }
 }
}

七、键盘响应事件——KeyEvent

测试代码:

package cn.galc.test;

import java.awt.*;
import java.awt.event.*;
public class TestKeyEvent{
 public static void main(String args[]){
  new KeyFrame("键盘响应事件");
 }
}

class KeyFrame extends Frame{
 public KeyFrame(String s){
   super(s);
   setBounds(200,200,400,300);
   setLayout(null);
   setVisible(true);
   addKeyListener(new KeyMonitor());
  }
 /*把自定义的键盘的监听类定义为内部类
 这个监听类从键盘适配器KeyAdapter类继承
 从KeyAdapter类继承也是为了可以简洁方便
 只需要重写需要用到的方法即可,这种做法比
 直接实现KeyListener接口要简单方便,如果
 直接实现KeyListener接口就要把KeyListener
 接口里面的所有方法重写一遍,但真正用到的
 只有一个方法,这样重写其他的方法但又用不到
 难免会做无用功*/ 
 class KeyMonitor extends KeyAdapter{
  public void keyPressed(KeyEvent e){
    int keycode = e.getKeyCode();
   /*使用getKeyCode()方法获取按键的虚拟码*/
   /*如果获取到的键的虚拟码等于up键的虚拟码
   则表示当前按下的键是up键
   KeyEvent.VK_UP表示取得up键的虚拟码
   键盘中的每一个键都对应有一个虚拟码
   这些虚拟码在KeyEvent类里面都被定义为静态常量
   所以可以使用“类名.静态常量名”的形式访问得到这些静态常量*/
    if(keycode == KeyEvent.VK_UP){
      System.out.println("你按的是up键");
     }
   }
  }
}
/*键盘的处理事件是这样的:每一个键都对应着一个虚拟的码,
当按下某一个键时,系统就会去找这个键对应的虚拟的码,以此来确定当前按下的是那个键
*/

通过这篇文章和大家一起学习了GUI编程,希望大家对GUI编程有了更全面的认识,关于GUI编程远不止这些,还需要大家继续学习。


代码注释

作者:喵哥笔记

IDC笔记

学的不仅是技术,更是梦想!