黑马程序员—图形界面编程基础

来源:互联网 发布:背包问题 贪心算法 编辑:程序博客网 时间:2024/06/05 05:25
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

图形编程基础

1、工具集的介绍:

        在图形用户界面(GUI:Graphical User Interface)中存在着主要两代的工具集,分别是:

AWT: Abstract Windowing Tookit抽象窗口工具包,由于它在系统中大量的使用了Windows的系统函数,所以对平台的依赖性比较强,跨平台相对弱一些,属于重量级组件。假如我们在windows下用AWT开发的图形界面,

Swing包是基于AWT包所建立的,其中的有些类继承了AWT包中的类和并覆写的其中的方法,所有的功能都是由JAVA来实现,可移植性强,里面的组件更加丰富,并且在不断的升级和扩充,所以也成为了现在图形界面设计主要用的工具包。

        而Eclipse就是由JAVA编写,它用的是SWT组件:

SWT(Standard Widget Toolkit)即标准小窗口工具箱,是IBM公司推出的一种在Eclipse中使用的集成开发环境,Eclispse界面的编写就来源于此工具

        在图形界面的开发中,我们将几乎所有涉及的工具类中的实例对象成为组件

它们继承关系:


图1

        其中Container作为容器组件是具备里面可以添加其它组件的功能的(通过add方法)而其它组件例如Button之类的则不行,比如我这个窗口下有很多按钮,按钮之上则不能再有其它的东西了
2、布局管理器
        在图形编程中,布局在实际操作中占据的重要地位,它决定着我们的界面是否美观,是一种在编码之前最好打草稿的存在,而所有的布局的实例对象都有一个完整的名称:布局管理器
现在让我们去API找一下关于布局的线索……经过较为艰难的寻找,我们在Container类中找到了我们想要的方法:
public void setLayout(LayoutManager mgr)
设置此容器的布局管理器。 
参数: 
mgr - 指定的布局管理器
        之所以找起来比较艰难,因为它没经过组件父类的撰写,而又没经过其子类的覆写。此方法接收一个LayoutMangaer接口的实例对象,作为在一个方法中两度出现的关键词Layout我们有必要知道它就是布局的意思,它可以为我们接下来的寻找提供重要的线索。我们顺着LayoutMangaer的超链接点进去,就可以看到此接口的实现类中拥有者Layout后缀的词不少,想必它们都是各式各样的布局了,而咱们点进去一个FlowLayout,看看它的布局特点,它拥有者与它的英文单词组合相应的名字:流式布局,从中可以通过给的图示发现流式布局的特点,它的组件会像流水一样依次排列,而它默认的插入组件后的位置是水平居中对齐,竖直靠上对齐的,而再次插入的组件则会排在一个组件的右边,而后依次向右,如果一行放不下则会换行后保持着水平居中的排列,行满则依次向下。如图:


图2

        而这个布局特性咱们了解了,也知道怎么通过setLayout 方法与容器关联了,然后咱们看一下构造方法就知道怎么创建布局类的实例对象了。发现它其实是存在有参构造方法的,这个咱们可以回头再去研究,可以先用无参构造把一个东西做出来看看先,而无参构造实际上用的就是默认参数的设定,如上图2。
PS:如果一个画布上需要多种布局的话,则需要插入多个Panel(面板),再用面板的布局类型设置来解决同一窗口多个布局的情况
3、第一个窗口
现在了解了容器的大致概念和布局,那么咱们可以通过查阅API试着创建第一个窗口了,而其关于窗口的设置主要在咱们具体的窗口类或者其父类中查找
代码如下:

import java.awt.*;public classGraph1 {    public static void main(String[] args) {        Framef=newFrame("第一个窗口");//用带有题目参数构造方法建立一个Frame类的窗口框架        f.setBounds(100,100, 500, 450);//建立此窗口左上角的坐标,和窗口长宽        f.add(new Label("为了窗口的内容"));//添加标签        f.add(new Label("为了窗口的功能"));        f.add(new Label("贯彻着我们对窗口最真实的爱"));        f.add(new Label("可爱而迷人的窗口组件"));        f.add(new Button("按钮"));//添加按钮        f.add(new Label("标签"));        f.add(new Label("我们在窗口中纵横的驰骋"));        f.add(new Label("白色的明天在等待着我们"));        f.add(new Label("就是这样"));        //在布局上为组件的对齐方式做居中设定,并设定组件之间的水平间距和竖直间距        f.setLayout(new FlowLayout(FlowLayout.CENTER ,490, 20));        f.setVisible(true);    }}

运行结果:


图3

         这里提一下,显示出窗口的设定的数值在相当于我们屏幕中的像素点阵,具体效果与我们屏幕的分辨率是分不开的。
         像标签按钮这种组件使其出现在窗口中的方法的很简单的,这里就不多讲了,我们也可以按照布局中的设置找到自己钟爱的布局去根据它对应的类中的具体方法来为咱们这个布局进行更细致的设定,也可以找到更多自己喜欢的插件来放进框中,在这里就不再赘述了。另外有兴趣的朋友可以试试如果在f.setLayout(new FlowLayout());之下再重新设置一种布局如:f.setLayout(new BorderLayout ());然后就会发现另一种布局就会将之前的流式布局覆盖掉。而现在回过头来看,大家可以发现除非我们用Ctil+C或者用编码工具中其它功能停止此JAVA程序的运行不然我们光点“X”图标是关不掉窗口的 (操作系统的任务管理器这种暴力的方式不提倡哈)。 为了让咱们的窗口摆脱只能看不能用的尴尬境地,为了它白色的明天……接下来就要介绍如何对它进行操作了(比如关闭窗口),这其中涉及到的知识点就是事件的监听处理机制。
4、事件的监听及处理
         首先我们要认识到,事件的监听处理是一系列动作所组成的流程,他们主要是由事件源 事件,监听,处理,这几个板块组成,但是在我们对这套流程一无所知之前,我们如果立刻去学习其中的组成部分的细节是有些费劲的,就像我们在日常生活或者工作中听别人讲述一件事情的时候,肯定是希望先知道一个梗概,对这件事情的来龙去脉有了一个轮廓,然后我们才能有更多的耐心对里面的具体内容进行详细的了解。
        整套系统的组成大致是这样的,事件类的实例对象可以将一个事件源的特定状态所发生变化的信息封装成一个对象传递给监听器并依据监听器里写好的处理方式进行处理,而监听器是绑定在此实例对象上的。
如果上面那段话讲得过于抽象的话,那么咱们再来看个例子,假如我将一个水银温度计放在腋下去测量温度,来得出我是否发烧了的结论。我就是事件源,而我的体温变化是一种特殊的事件,而温度计就是对于此特殊事件的监听器了,与JAVA中不同的是我体温过高的处理方式没有写在体温计上,假如它会报警,那就完全符合了。
事件:
        事件如异常一样是一个非常广义的概念。从它们事件类的根类的名字就可见一斑:EventObject,从名字可以看出来一切实例对象的事件的意思,而它的其下有数十子类,那些子类是怎么区分的呢?首先第一层级的子类不是指的事件类型,而是事件作用的对象类型,与根类EventObject命名方式不同是它们几乎都是用对象类型+Event方式来命名,而非将对象类型写在后面,当然重要的是它们都是将这两者拼在一起命名的,就像加法交换律所述的一样,无论关键字排列的顺序如何,它们的名字所反映的意义规律是一致的。
        由于我们在这章所需要的是处理的图形类的事件,所以我们很顺利的根据之前的看到的命名规律找到了我们想要的类名:AWTEvent,然后我们发现其下又有很多子类,而且我们发现依然是按产生事件的实例对象所属的类来划分的。看来咱们不得先确定一个具体的产生特殊事件的实例对象(我们也可以称其为事件源)后再回来找咱们需要的事件类了。
        这里可以告诉大家,在java的图形包中,事件本身是不需要咱们去编辑的,因为JAVA将这个包中所有的组件可以产生的各种情况都包含进去了,而且他们是会随着我们对这个组件各种状态的改变(比如按下按钮)而产生出来,就像异常类一样。
事件的监听器:
        事件的监听是依赖一个叫做监听器的接口的,我们需要去将它实例化并实现里面的方法,而EventListener接口是所有事件侦听器接口必须扩展的标记接口,换句话说就是所有监听类接口的超级接口,从名字可知,事件监听器,而面对着它一页都写不下的子类接口,而且它里面又不包含任何方法,可见咱们必须的通过有方法的子类去实现我们的目的,而子类的划分又是多种多样的,所以咱们暂时先放下它。
也许我们看到现在依然会觉得事件的产生到事件的接收是一件很奇怪的事情,虽然前文交代了这部分由系统来完成,但是我们依然会存在着对其的好奇心甚至如果搞不明白我们就难以进行下面的学习。在这里笔者也劝告大家往往信息的诞生和接收部分的原理是有着远超信息处理的复杂度的。我们可以给大家举一个温度传感器例子:
        有一种接触式(就是指其的检测方式是需要接触其被检测对象的,比如水银温度计就是接触式的,而那种红外不用接触皮肤的温度计就不是接触式的了)的温度传感器的主要材料由一种叫NTC的热敏电阻所组成,它的电阻是按温度增加非线性地减少,这非线性特性的最好的拟合是Steinhart-Hart方程式:
T = [K0 + K1(ln 1000R) + K2(ln 1000R)3]-1 – 273.15
        其中 T 是温度(C),R 是测量的电阻 (kΩ),K0 = 1.02119 × 10-3, K1 = 2.22468 × 10-4, and K2 = 1.33342 × 10-7。
由于它的电阻会随着它的温度的改变而改变,接下来我们就可以将它两端的电压输出然后经过A/D转换再根据公式进行计算就可以从仪表上读到温度了。而我们对待它所反映的温度信息是如何处理的呢?这想必比这个温度信息的产生要简单很多。当然我们只要对它保持着好奇心和追求,我们总是可以知道的,只不过不是现在而已。至于我为什么宁可绕一个大弯去将温度传感器也不告诉你们关于时间产生和监听的原理,答案就如同一首古老歌唱的一样:生活已经如此艰难,有些事情就不要拆穿。。
事件的处理:
         关于事件的处理我再举个例子,当我们通过振动源(可以是我们的声带)扰动周围的空气产生声波时,声波可以被认为是反应空气这个对象的状态改变的(它在以一个振动频率扰动着周围的空气),而我们的耳朵同样接收到了这份代表着空气(当然了也可以是别的介质,除了真空)振动的声音,而这个声音我们接收到了我们显然我不会对这份声音做什么,而是对于声源所反映的状态去做处理,这里就涉及到另一个层事件的反应了,毕竟我们是通过介质的改变才听见声源的声音的。如果声源来自一个人声:“救命啊!!!”我们作为听见的声音的人自然有义务去处理它,如果我们接收的是我们分不清来源的天籁,那么我只能认为有声音了,但是不知道是哪儿发出来的,如果我们没什么好奇心的话就可以不去管它了。(当然停下来聆听大自然的美好也是一种事件处理方式)。
        从此可见,事件处理往往不是指对接收的事件类对象进行处理,尽管我们管它们叫事件处理。可以说我们将这份被封装的事件类实例对象所反映的关于对象状态的改变信息当作一个事件的。
        上文中提到具体的事件处理是我们在开发中需要编辑的重点,那么我们首先得确定一个类的实例对象然后再对它的状态进行改变,然后让它产生特定的事件对象来去找监听器接收处理,就像catch所接收的那些异常一样,而接收以后我们就可以通过监听器中的方法去处理事件:它将事件的实例对象作为一个参数接收,然后返回处理结果。那么下面我们回到之前纠结的关窗口问题上来试着用一个按钮Button类组件来关掉窗口。
        我们从上文中已经知道事件是通过组件状态变化诞生的,而又是由监听器来接收和处理的,那么监听器具体是如何接收由组件诞生的事件的呢?让我们耐心的在Button类中找找线索,其实几乎不需要什么耐心。。API列表中第一个方法就是:
public void addActionListener(ActionListener l) 将一个动作类监听器加入到Button中
从这个方法所接收的参数类型中我们好像一下就知道我们要做什么了,之前没找到的监听器类型也找到了线索,顺着带有超链接ActionListener关键字点进去而暂时先把Button放到一边反正这个函数得等我们做好了监听器再运行了。
ActionListener中有一堆子类,咱们先找找是否有符合咱们目的的方法:
void  actionPerformed(ActionEvent e)我们很快就能看到里面唯一的方法,从方法说明中我们可以发现它具备处理动作类事件的作用,我们可以在它的方法体中{}撰写我们对于对它接收ActionEvent对象后的有关处理。我们可以撰写一个ButtonListener类来实现ActionListener接口,这个名字专业得就好像它本来就存在在API中一样。下面看看代码的实现:

import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;class ButtonListener implements ActionListener{//建立ActionListener类的监听器public void actionPerformed(ActionEvent e){if(e.getSource() instanceof Button) {判断此事件是否是由Button类产生System.out.println("按我呀按我呀");//事件的处理}}}public class Graph2 {public static void main(String[] args) {Frame f=new Frame();Button b=new Button("我是一个按钮");b.addActionListener(new ButtonListener());//加入按钮监听器f.setBounds(100, 100, 500, 400);f.add(b);f.setLayout(new FlowLayout());f.setVisible(true);}}

        运行结果在这里就不贴出来了,毕竟它更多的是动作的实施,至于显示效果与图3没什么区别,这里提一个函数方法getSource(),它来自EventObject类,意思是返回最初发生 Event 的对象。
这里没写出关闭窗口的处理方式,只是复制不去修改的话。。可关不掉窗口,可以给大家个提示,关闭窗口可以等同于退出当前程序。
        我们是一个发现Button类对象貌似它的组件状态改变只有一种信息,按钮按下去又弹起来以后才出现的事件捕捉。在这里我们可以为算是ActionEvent一种局限性的体现吧。而实际上我们按按钮的动作是一种鼠标动作,那么我们是否可以将捕捉鼠标事件的监听器加入到按钮中呢?答案时可以的。而之所以我们没发现Button中存在关于鼠标事件的监听信息是因为鼠标事件的监听适用范围很大,所以它不会单独存在在子类中,而我们需要去从它的父类中不断的向上寻找有关的信息。相关的方法是存在Component中的addMouseListener(MouseListener l)加入指定的鼠标监听器,我们顺着超链接去看MouseListener的时候发现它的方法都是抽象的,如果我们实现了这个接口就要将方法全部覆写,虽然这部失为一种办法,但是做起来可能会有不甘心的感觉,让我们看看周到的JAVA为我们准备了哪些礼物:MouseAdapter类,看看它在API中的说明吧:接收鼠标事件的抽象适配器类。此类中的方法为空。此类存在的目的是方便创建侦听器对象。可见它覆写了所有的MouseListener方法,但是却没有写内容,这样我们只需要继承它然后去实现其中我们想实现的方法即可。代码如下:

import java.awt.*;import java.awt.event.*;class  ButtonAdapter extends MouseAdapter{public void mousePressed(MouseEvent e){//鼠标按下时所产生的事件的方法System.out.println("鼠标按下去啦");}public void mouseReleased(MouseEvent e){//鼠标抬起来时所产生的事件的方法System.out.println("鼠标抬起来啦");}public void mouseClicked(MouseEvent e){//鼠标按下又抬起来一套动作所产生的事件的方法System.out.println("鼠标按下去又抬起来啦");}}public class Graph3 {public static void main(String[] args) {Frame f=new Frame();Button but=new Button("按我");but.addMouseListener(new ButtonAdapter());//将鼠标监听器放入按钮f.add(but);f.setBounds(100, 100, 500, 400);f.setLayout(new FlowLayout());f.setVisible(true);}}
        代码没怎么改,跟上一个大同小异,时间原因图像编程主要就介绍这些,剩下的主要就是查阅方法去逐渐的实现它们了,最后祝大家天天向上。

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com
0 0
原创粉丝点击