Java笔记系列(基于马士兵的课堂)(9)-GUI编程

时间:2021-11-13 06:46:25

                              GUI编程

GUI图形用户接口

概述:AWT(包),组件和融合器,布局管理器,事件处理,java图形,windows事件。

AWT

与图形相关的类都封装在AWT这个包和他的子包中。AWT是抽象窗口开发包,放在任何系统都可以实行。但这个包并未完全的跨平台(每一平台相应调用的东西不同),在不同的平台显示并不完全相同。所以这是一个老的包。现在用的是java扩展包jvax.Swing。但是Swing(相对于更视觉化)离不开AWT(一些事件的处理)。

图形与界面:可以显示出来,可以与用户交互的图形元素(下拉条,输入框,菜单…)。

Java笔记系列(基于马士兵的课堂)(9)-GUI编程

Component(抽象类):可以显示出来的可以和用户进行交互的图形界面。(所有合一显示出来的图形界面都是component)<menucomponent>

子类container:用来容纳其他component元素的图形。(容器可以容纳容器)。

Java笔记系列(基于马士兵的课堂)(9)-GUI编程

Window:可以独立显示的容器(窗口)。(能够*添加的*窗口)

Panel:可以容纳其他元素,但是不能作为独立窗口显示出来,可以套在窗口里。(Applet)(必须添加到其他component里才能显示出来的非*窗口)

Frame:一般的窗口。

Dialog:对话框(不点不能进行下去)。

模态对话框(model):不能处理其他程序。

非模态对话框(modeless):可以不管他,处理其他的程序应用。

一般component不能独立出现,要添加到container中出现。

一般Swing里的新类会在老的类前加J(如JFrame)。

在javaAWT中还有一个专门的类color,其中有一些常用的颜色静态常量。

Test12 TestFrame.Java

注意setLocation)设定左上角点的位置。(x轴向右,y轴向下)

setSize),setVisible)(设定是否可见),setResizable)(设定是否可放大)

直接newFrame比较死板不能拥有自己的成员变量,但是继承Frame更加灵活,可以new出来自己的成员变量。

在计算机中三原色是红绿蓝,对于如果不想用Color类里所提供的静态成员变量,可以用newColor红颜色分量,绿颜色分量,蓝颜色分量)(每一个分量的最大值是255)

注意panel的setBounds是相对于窗口而不是相对于屏幕(电脑屏幕)。

Frame中有add()方法,将component加入窗口。

布局管理器:

Java笔记系列(基于马士兵的课堂)(9)-GUI编程

Java笔记系列(基于马士兵的课堂)(9)-GUI编程

Frame自带的布局管理器可以自定义其中的panel,或者button的位置,还可以决定其中图形是否随窗口改变而改变。所有布局管理器在java里封装都是layout。而自己定义的布局管理器(false,不会改变)。封装布局管理器的接口叫做layoutManager,所有实际的布局管理器都实现了这个接口,不同的布局管理器有自己布局管理的风格。如FlowLayout<Panel默认布局>(类)<默认居中,自定义button大小>(流水线式的布局)其中有静态常量CENTER,LEFT等。Frame有setLayout(从容器继承)。BoderLayout边框布局,是Frame的指定布局,将窗口化成5个区域,,一个区域只能放一个button,否则后来的会将前面的盖住,默认居中。想再加button可以再套panel再加button。对于add(button名,boderLayout.NORTH)<注意这些常量都是int类型的,比String类型的要简洁>(对于异常在编译时出现错误,要比运行时出现要好的多)

GridLayout(行数,列数)列成几列几行的小格行列。Frame里还有一个pack()<使窗口刚好包着button>

注意button和panel的嵌套可以实现各种奇形怪状的button布局。再用布局管理器管理

布局管理器:布局管理器自己设计自己的大小和位置。若实在想自己设计:勿忘setLayout(null);

事件监听机制:

事件模型:AWT遗留事件监听,Swing并没有重建事件监听。事件监听若自己主动编程序,去监听太过昂贵,费cpu,占用太多内存运行。所以需要等待事件发生后自动调用某个类的某个方法,这种方法叫做钩子函数<回调函数>。ActionEvent(类)(是一种事件)addActionLisenner(实现了ActionLisener接口的类的一个对象)<挂上这个类重写的actionPerformed方法>在执行时,直接调用这个方法,有多态可扩展性在其中体现(add是ActionLisenner使用的却是new出的类)。

Java笔记系列(基于马士兵的课堂)(9)-GUI编程

事件(本身是一个类):事件元对象(事件发生时出现的),事件和监听这件事的接口一一对应。当事件发生,事件元对象会向监听器(实现接口的类)发出信号让其处理(事件会被封装成一个对象作为参数传给监听器)。最后注册,让事件源对象知道被监听。

这个事件模型实现了absover模型和comand模式。

同样一个监听器可以同时监听多个按钮。

区分开的方法:setActionCommand(),getActionCommand()<可以区分两个打印的东西,若不设置就是button上显示的名字>

TestField类(输入框):

Java笔记系列(基于马士兵的课堂)(9)-GUI编程

TextField也可以发生ActionEvent,当在输入框敲回车时,发生ActionEvent。本来在其他的类方法中的局部变量是无法访问的,但是由于发生事件时,会传来事件信息,可以通过方法,getSource()<拿到事件元对象>(在ActionEvent父类的父类中)<传来Object再强制转换为想要的图形就行了>,这样间接拿到了局部变量的引用。注意getText(),setText();

还有一个setEchoChar(‘字符’)<设置回显字符>,这样可以有输入密码的感觉。

内部类机制:

在监听机制中,想要拿到构造窗口方法中的局部变量或者(launch方法中的局部变量),可以,在监听器类中构造方法,再在窗口类中调用该方法,将其所需内容传到监听器类中,但是过程繁琐,占用内存大,不合适。

更优雅的:可以直接传这个对象(窗口对象)在窗口类构造方法或者launch方法中,但是必须你所需要的东西一定是成员变量,不能是局部变量——这个叫做持有对方的引用。直接传对象,直接通过管家,要找什么直接找管家<个体对象不用直接找个体对象>,这样不会乱(门面模式对外,对内调停模式)。

除此之外,如果不想忘记传对象全部内容,还可以生成内部类。内部类可以毫无限制的使用包装类的成员变量或者是成员方法。编译内部类的class文件,名字是包装类名字+$+内部类名称+.class。

可以更清楚的组织逻辑,让防止不应该被其他类访问的类被其他类进行访问如本章的监听器,每个button都应该有不同的监听器,这样可以使这个类private化,这样也防止了重名类问题。

还有可能是两个接口的方法名称相同,返回值不同,无法构成重载,而某个类一定要实现两个接口,可以包装类实现一个,内部类实现一个。这时特别要注意的是,使用内部类时的成员变量位置,内部类声明位置(还有一种更内部的局部类,平时几乎不用)。

Graphics类:

揭示了所有图形系统都采用的机制,怎样在界面上画出图形。可以认为Graphics是一支画笔(可以画n多的东西),paint是container里的一个方法(用的时候要用),传一个画笔,必须要重写,而且不需要调用,自己就调用。当Frame窗口第一次显示时,paint会被调用,遮又显示需要调用,放大缩小时自动调用,改变窗口大小会被调用。

画笔可以调用getColor()<返回值为原来的颜色>;fillOval(a,b,c,d)<画一个实心的椭圆,ab长方体左上角位置,cd是长宽,然后做长方体内切椭圆>(区别于drawOval),勿忘最后用setColor()将画笔重置为原来的颜色<良好的编程习惯>。

drawLine();在Graphics里是一个抽象方法,却可以调用,是因为其实调用的是Graphics的子类重写方法。

鼠标事件适配器

鼠标监听器,MouseLisentener,对鼠标点击(mouseClicked),鼠标移进来(moseEntered),鼠标移出去,鼠标按下去,鼠标抬起来。

Mouseadpter实现了Mouselistener接口,可以直接继承Mouseadpter,间接实现,从而减少了重写方法的次数。提供了空的实现。

注意事件源的应用,拿到位置,拿到内容。Repaint()<Component中>是强制重画,如果不手动让其重画,必须盖住,第一次打开。。。才会画出来。

Repaint方法调用了update方法,再调用了paint()<双缓冲>,每个图形系统采用的机制,每个重画方法,一定是先update,再paint。

而且不能用paint,因为paint中的画笔和之前paint的画笔不一定能找的到,调用的起来。

WindowEvent

可以控制窗口的关闭。Window事件,windowLisenner处理事件:窗口被激活(点击两个窗口的那个窗口),窗口被返回为非激活状态,窗口关闭后的相应,窗口正在关闭时的相应(应该处理这个,WindowClosing),窗口图标化,窗口最大化。

关闭窗口:setVisible(false);<让窗口不可见>,System.exit(传0或-1在windows中);使系统退出。

但是这个类只出现在一个方法中,也只调用了一次,所以可以使用局部匿名类,将这个类定义在某个方法中,不需要写继承,只需要new这个类想要的父类,或者接口(本质上是将这个类当做这个类子类的一个对象)。不推荐这样写,但是要认识。

使用匿名类的范围:不能经常修改的类,匿名类代码并不过于长,逻辑比较简单。

匿名类有可能是两种创建方法(继承,实现),匿名类只能是内部类。

KeyEvent

KeyEvent中定义了特别多的静态常量,用来表示键盘上的每个键的值<int类型>(VK代表虚拟的键)。而对于KeyeEvent中可以将封装过来的键盘事件的信息,用方法getKeyCode(返回值为int比较VK_UP等值)

J2se结束。

附有关GUI编程的代码:

案例:实现点击处出现一个圆,并且可以关闭窗口,回复true后退出

package GraphicsTest;


import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
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 javax.swing.text.html.HTMLDocument.Iterator;
import java.util.Scanner;
public class G  extends Frame {


private static final long serialVersionUID = 1L;
ArrayList<Point> points=null;
G(String s){
super(s);
points=new ArrayList<Point>();//用来装点.
setLayout(null);
setBounds(300,300,400,400);
this.setBackground(new Color(100,200,200));
setVisible(true);
this.addMouseListener(new Moniter());
this.addWindowListener(new MyMoniter());
}
public static void main(String args[]){
G g=new G("Mouse Test");
}
public void paint(Graphics g){
java.util.Iterator i=points.iterator();
while(i.hasNext()){
Point p=(Point)i.next();
g.setColor(new Color(200,200,220));
g.fillOval(p.x,p.y,100,100);

}
}
class Moniter extends MouseAdapter{
public void mousePressed(MouseEvent e){
G f= (G)e.getSource();
f.addPoint(new Point(e.getX(),e.getY()));
f.repaint();
}
}
public void addPoint(Point p) {
points.add(p);//记点位置
}


class MyMoniter extends WindowAdapter {
public void windowClosing(WindowEvent e){
System.out.println("是否退出?");
boolean a; 
Scanner scan=new Scanner (System.in);
a=scan.nextBoolean();
if (a){
setVisible(false);

System.exit(0);}
}
}
}