Java高级教程3_图形用户界面GUI

 

张老师的Java高级教程中图形用户界面GUI对应的笔记

网络编辑器还要重新排版,提供原始文件下载,先看个概貌

 

Java高级3_图形用户界面GUI

AWT的基础知识

GUIGraphical User Interface图形用户界面。JDK中提供了AWTSwing两个包用于GUI程序设计和开发。

AWTJava的早期版本,里边提供的组件有限,可提供基本的GUI程序设计与开发。

Swing是对AWT的改进,包括AWT中的所有组件,还提供了更多的组件和功能,可实现GUI程序设计的所有功能。

要使用AWT组件,就需要导入java.awt.*;

软件包 java.awt的描述

包含用于创建用户界面和绘制图形图像的所有类。在 AWT术语中,诸如按钮或滚动条之类的用户界面对象称为组件。Component类是所有 AWT组件的根。有关所有 AWT组件的公共属性的详细描述,请参见 Component

当用户与组件交互时,一些组件会激发事件。AWTEvent类及其子类用于表示 AWT组件能够激发的事件。有关 AWT事件模型的描述,请参见 AWTEvent

容器是一个可以包含组件和其他容器的组件。容器还可以具有布局管理器,用来控制容器中组件的可视化布局。AWT包带有几个布局管理器类和一个接口,此接口可用于构建自己的布局管理器。有关更多信息,请参见 Container LayoutManager

GUI组件可分为两大类:

1、基本组件:java.awt.Component及其子类

       里边不能再添加其他组件,如按钮、文本框

2、容器:java.awt.Container及其子类,容器也是组件的一种,属于component的子类

       可以再放置其他组件,如窗口中放置按钮、文本框等

 

Frame f = new Frame(“窗口显示的标题”);

刚创建的窗口并不会显示出来,还在内存中。要让它显示出来,需要:

f.setVisible(true);  设置为true就显示,false隐藏

       刚创建的窗口因为没有设置大小,所以显示出来只有一个标题栏和最大最小关闭按钮,但现在的按钮都不起作用,要关闭它可在命令行中用CTRL+C结束它。

       修改窗口的大小:

f.setSize(300, 500);

       在窗口中增加按钮

f.add(new Button(按钮上的文字));

       程序的GUI部分由AWT线程管理,主线程将窗口显示出来有就已经结束了,但窗口还显示在桌面上,在命令行状态下发现程序并没有结束。

       让窗口显示5秒后自动关闭

Thread.sleep(5000)

       将窗口对象释放,从内存中清除掉,GUI组件没有了AWT线程即自动结束了。

f.dispose();     JDK1.3GUI组件释放后线程依然存在

使用setVisible(false)只是将窗口隐藏起来,窗口还存在于内存中,AWT线程依然存活

 

AWT的事件处理

u  事件处理机制

       GUI只是提供给用户操作的图形界面,并不提供对用户操作事件的处理,比如用户点击鼠标、按下键盘等等事件,需要相应的程序代码支持。如上面的程序,点击关闭按钮窗口并不会关闭。

       为了让GUI程序能够与用户交互,Java设计了事件处理机制来处理程序和用户之间的交互。

事件:用户对组件的一个操作,称为一个事件

事件源:发生事件的组件就是事件源

事件处理器:某个Java类中负责处理事件的成员方法

事件源、事件、事件处理器之间的工作关系

 

u  事件分类

按产生事件的物理操作和GUI组件的表现形式分类:

MouseEvent:鼠标按下、鼠标点击……

WindowEvent:窗口关闭、打开、获得焦点、最大化……

ActionEvent:并不对应某个具体事件,按钮或菜单被操作了、文本框里输入数据了……

              …          用户的某个操作导致某个组件的基本作用发生了,就会发生ActionEvent

              …          比如用鼠标点击或使用快捷键激活某个菜单,都会发生这个事件。

通过事件本身都可以获取事件源,以及与事件相关的详细信息。

按事件的性质分类:

       低级事件

       语义事件,又叫高级事件          JDK的帮助文档中查找java.awt.event,里边所列出的event事件类对应的监听器对象listener中只有一个成员方法的就是语义事件。有多个成员方法的就是低级事件。

u  事件监听器

       一个事件监听器对象只负责处理一类事件,事件监听器中的每一个方法负责处理这类事件中的某一个具体事件。

       上面的限定规则在面向对象的程序设计语言中是通过接口类来实现的。在事件源和事件监听器对象之间进行约束的接口类就是事件监听器接口。事件监听器接口类的名称与事件类的名称是对应的,如MouseEvent事件类的监听器接口为MouseListener

实例:实现关闭窗口的事件处理

1、先编写一个监听器类,来处理关闭按钮被点击时的动作,监听器内部代码将窗口关闭

class MyWindowListener implements对窗口事件处理的类必须实现WindowListener接口

{WindowListener接口中有7个方法都需要覆盖,对不需要具体操作的事件可以空实现即可

       public void windowOpened(WindowEvent e)

       {

}

       public void windowClosing(WindowEvent e)窗口正在关闭,还没消失

       { 事件发生需要处理,会将事件对象传递过来,

可以用事件对象获取产生事件的窗口到底是那个

e.getWindow().setVisible(false);只是将窗口隐藏,并没消失

       还可以使用e.getSourcee.getComponent得到事件对应的来源或源组件,都可以得到当前发生事件的事件源,但这三个方法返回值不同,getSource返回Object,个头Component返回Component,所以使用这两个方法时须将返回值强制转换为Window类型

e.getWindow().dispose();

System.exit(0);程序退出

}

       public void windowClosed(WindowEvent e)窗口已经关闭,消失了

       {

}

}

2、将时间监听器对象注册到窗口上

f.addWindowListener(new MyWindowListener());

 

事件处理流程:

       要处理发生在某个GUI组件上的某类事件XXXEvent的某种具体情况,事件处理通用编写流程:

1、编写一个实现对应事件监听器接口XXXListener的监听器类。

2、在监听器类中处理相应事件的方法中编写具体处理代码,其他情况不处理可以空实现

3、调用组件的addXXXListener方法,将这个监听器类对象注册到GUI组件上。

 

u  事件适配器 与事件相关的包都在java.awt.event

自己编写事件监听器需要实现对应事件监听器接口中的所有方法,为了简化编写过程,

JDK中提供了大多数事件监听器接口的最简单的实现类,称为事件适配器(Adapter)。

       这样编写监听器时只需继承相应的事件适配器,覆盖自己想要处理情况的事件处理方法即可,其他情况由事件适配器默认方式处理。

示例:使用事件适配器关闭窗口

1、建一个时间监听器类,继承窗口事件适配器WindowAdapter

class YourWindowListener extends WindowAdapter

{ 只考虑关闭窗口操作,其他情况由适配器默认方式处理,即什么也不做

       public void windowClosing(WindowEvent e)

       {

              e.getWindow().dispose();

       System.exit(0);

}

}

2、将监听器注册到事件窗口上,替换原来的MyWindowListener

f.addWindowListener(new YourWindowListener);

使用事件适配器时发生的常见问题:

1、方法中的代码有问题,还是方法没被调用?

2、方法名写错了(调用的是适配器的空方法),还是没有注册事件监听器?

事件适配器的不足:

       Java中不允许多继承,如果要做监听器的类已经继承其他类了,就不能在继承适配器类,这时就需要实现监听器接口才可以。

       ActionListener中只有一个方法actionPerformed方法,JDK就没有提供适配器类,使用时需要实现其中的方法。

 

u  灵活设计事件监听器类

怎样才能在事件监听器中访问非事件源的其他GUI组件?在上面的窗口程序中,怎样

使用按钮(事件源)来关闭窗口(非事件源)?

编写一个监听器类,实现ActionListener接口

class MyActionListener implements ActionListener

{

       public void actionPerformed(ActionEvent e)

       [

       f.dispos();      这句代码需要访问外边的Frame,怎么访问呢?

]

}

为了方便实现,用Frame所在的类直接实现ActionListener接口,实现其中的方法,那么这个窗口类自己本身就是一个监听器对象了。把这个监听器this注册到按钮上即可。但是用这种方式引用Frame的的时候很麻烦。可以将所有对Frame的操作定义到一个函数中,完成窗体初始化,在main方法中调用初始化方法即可。

也可以用内部类来实现ActionListener接口,作为监听器对象,注册到按钮上即可

用匿名内置类实现事件监听器

       还可以用匿名内部类的形式实现addListener(new ActionListener(){ 实现的方法})

 

u  事件处理的多重运用

同一个操作触发了多个事件(低级和语义事件),如用鼠标点击一个按钮,既触发了鼠

标事件,又触发了按钮本身的事件。到底要执行哪个事件处理方法呢?或者鼠标点击后,鼠标事件执行后,按钮本身的动作事件(如改变标题)也执行。

       在按钮上注册两个监听器对象,一个处理鼠标事件,一个处理按钮动作事件。

一般不需要处理引发事件的低级事件,只需处理动作事件即可,比如鼠标点击菜单,不需处理鼠标点击事件,只需处理菜单的语义事件即可。

举例:打人   司法处理就是低级事件;   公司内部处理就是语义事件,比如违反公司纪律、迟到、早退都是违反公司纪律,有多种引发方式。

一个组件上的一个动作产生多种不同类型的事件,打人违反法律、违反公司纪律

一个事件监听器对象注册到多个事件源上,多个按钮使用一种处理方式

一个事件源上注册处理同一类事件的多个监听器对象,总统的多个保镖

 

u  修改组件的默认事件处理方式

只有在组件上注册了某种事件监听器对象后,组件才会产生相应的事件对象。

默认的事件处理过程:processEvent方法调用相应的processXXXEvent方法,将事件对

象传递给相应的XXXListener监听器,由监听器进行相应的事件处理。

       如果要修改默认的事件处理方式,需要覆盖组件的processEvent或者processXXXEvent方法,processEvent方法是处理所有事件的总入口,processXXXEvent是专门用于处理XXX事件的岔路口。

       没有注册事件监听器时,对应的时间处理方法不会响应并执行,调用enableEvents(long eventsToEnable)方法,可以在没有注册事件监听器的情况下,对某些类型的事件进行响应。

编程示例:窗口上显示一个按钮,一旦鼠标移动到这个按钮上,按钮就移动到其他位置,这样,鼠标就永远无法点击到这个按钮。

       需要覆盖按钮的鼠标移动事件的默认处理方式,创建button的子类,覆盖其中的processMouseMotionEvent方法,隐藏自己,显示另一个。

1、框架代码

class MyFrame extends Fream继承Fream,本身也是一个窗体

       public MyFrame()构造函数中添加窗体监听器

       {

       addWindowListener(new WindowAdapter()

{

       public void windowClosing(WindowEvent e)

       {

       dispose();

       System.exit(0);

}

});

}

public static void main(String [] args)

{

       MyFrame frame = new MyFrame();

       frame.setSize(400, 400);

frame.setTitle(“My Frame”);

frame.setVisible(true);

}

2、编写自定义的button类,修改默认处理方式

class MyButton extends Button

{

       按钮本身就有一个伙伴

       MyButton friend = null;

       public MyButton(String title)子类不会继承父类的构造函数,自定义一个一样的

       { 直接使用父类的构造方法

       super(title);

       没有注册监听器也要对某些事件进行处理,执行下边的语句后,不管以后产生的MyButton对象有没有注册鼠标移动的监听器,都会处理这个事件。

       enableEvent(AWTEvent.MOUSE_MOTION_EVENT_MASK);

}

覆盖默认的鼠标移动处理方式

protected void processMouseMotionEvent(MouseEvent e)

{

       this.setVisible(false);

       friend.setVisible(true);

}

}

3、将按钮加入1中的窗口框架中

MyButton btn1 = new MyButton(“来点我呀”)

MyButton btn2 = new MyButton(“来点我呀”)

btn1.friend = btn2;

btn2.friend = btn1;

frame.add(btn1);

frame.add(btn2);默认布局方式but2会覆盖掉btn1,使用下面的方式就可以解决

frame.add(btn1North);

frame.add(btn2South);

but1.setVisible(fasle);注意此行代码不能放在frame.setVisible(true)上面,因为主窗口还没显示出来,它里边的所哟组件都处于不可显示状态,设置更别说了。

 

GUI组件上的图形操作

u  Graphics类与图形绘制

有时需要在GUI组件上绘制图形、打印文字、显示图像……组件对象并不提供对这些

方法的操作。只提供一个getGraphics方法Component.getGraphics会返回一个包含组件的屏幕、外观等窗口信息的Graphics对象,Graphics对象提供了在组件表面绘制图形、打印文字、显示图像等操作的方法。

Graphics.drawLine(int x1, int y1, int x2, int y2)画直线

Graphics.drawString(String str, int x, int y)显示字符串,xy表示str输出区域的左下角坐标

示例:以鼠标在窗口中按下的位置作为起始点,释放时的位置为终点,在释放时将直线画出,并在每条直线的起始点和终止点位置打印出它们的坐标值。

1、产生框架窗口frame

2、在框架窗口中添加鼠标事件监听器,覆盖其中的mousePressedmouseReleased方法

frame.addMouseListener(new MouseAdapter(){

int x, y; 记录起始点坐标

public void mousePressed(MouseEvent e)

{

       x = e.getX();   y=e.getY();

}

public void mouseReleased(MouseEvent e)

{ 获取当前窗口的Graphics对象,画图,设置颜色……setColor

       getGraphics().drawString(起始点,x,y);注意,两次调用返回的Graphics对象不是同一个

       getGraphics().drawLine(x,y,e.getX(),e.getY());

       可以用Graphics对象设置字体

       g.setFont(new Font());Font(String name, int style, int size)
                                         
根据指定名称、样式(常量值)和磅值大小,创建一个新Font

              张老师演示就有效,我设置字体怎么没效果呢?颜色线上有效,字都是黑的

getGraphics()多次返回多个对象,设置在不同的对象上当然无效了。

}

});

 

u  组件重绘的处理

窗体重绘后不包括窗体组件上通过Graphics画出来的图形。系统只记录了窗体上的信

息,并没有记录组件表面的内容。

paint(Graphics g) 窗体移动,改变大小等等需要重绘、曝光

       窗体组件被重新绘制时,AWT线程会调用窗体组件的paint(Graphics g)方法将显卡中保存的窗体信息绘制出来。,

       默认重绘不包括组件表面的内容,如上个程序中画出来的直线和坐标值,如果要让它们也重绘,可以修改窗体中的paint方法,将原来的内容重新画出来。

AWT线程对组件重绘的调用过程

       paint方法是由AWT线程管理调度的,应用程序不应直接调用paint方法,需要曝光刷新重绘时,就要使用paint方法,但不要直接调用paint,先调用repaint方法,repaint会调用update方法,update方法内部会现将组件表面的内容清空,再调用paint进行重绘。

示例:将上例程序改写,窗口重绘后保留窗口中原来的数据。

1、需要记录直线的起始和终止点坐标,将上例的鼠标监听器中记录终点坐标的两个变量放在方法体外。因为paint方法要访问这4个变量

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值