Java图形用户界面

为什么要是用图形界面?
命令行操作VS鼠标点击操作
文字VS图标
黑白VS彩色图形化
大量记忆VS直观感觉
专家VS普通用户
图形用户界面(Graphic User Interface)的最基本的元素就是窗口(Windows)
在这里插入图片描述
Java中图形界面的形式
Applet:嵌入到HTML网页中的Java程序
优势:
每次打开网页,Applet都可以重新下载,更新及时
客户端执行,比普通网页功能强大
缺点:
客户端必须已经安装JRE,并且配置正确
JRE可能存在漏洞,被攻击
不能读写客户机上的文件
不能连接出了服务器以外的机器
浏览器支持方面可能存在问题
Applet类是Applet程序的容器类
所有其他要显示的内容都放在Applet容器内
主要方法:
继承关系:
java.lang.Object
java.awt.Component
java.awt.Container
java.awt.Panel
java.applet.Applet
javax.swing.JApplet
✈️✈️Applet其实是一种AWT容器,可以容纳AWT所有的组件
JApplet其实是一种Swing容器,可以容纳Swing所有的组件
在这里插入图片描述
用法:
Applet程序没有main()函数作为入口,必须在浏览器里面调用
Applet程序通常继承Applet类开始

public class MyFirstApplet extends Applet {
	public void init() {
		//初始化…
	}

	public void paint(Graphics g) {
		//绘图……
	}
}

Web中的Applet
将写好的Applet编译成.class文件
使用HTML代码将.class文件包含到页面中

<applet code=“MyFirstApplet.class” width=“300” height=“400” />

用浏览器打开包含改代码的网页,即可初始化刚刚写的Applet.
✈️✈️目前大部分的浏览器都默认不支持Applet,可以使用AppletViewer查看HTML页面里面的Applet.
Application或者桌面程序
AWT:初级Java图形界面
Swing:高级Java图形界面
AWT编程基础
AWT
AWT随JDK1.0一起发布,提供了一套最基本的GUI类库,具有最基本的窗口,按钮,文本框等.所有AWT组件都在jav.awt包中.
问题:
界面太丑
功能有限
只有有限的组件
最多只支持4中字体
非面向对象的编程模式
使用Swing替代AWT组件,但使用AWT作为基础
Swing中的事件处理机制还是基于AWT
Swing中大部分布局器都和AWT中相同
AWT的体系结构
在这里插入图片描述
AWT Component
Component也称为"组件",用来表示图用户界面上各种组成元素:按钮,文本框等.
Component类的主要方法:
setLocation(int x,int y)
setSize(int with,int height)
setBounds(int x,int y,int width,int height)
setVisible(boolean b)
具体方法请查看API文档.
AWT Container
Container也称为"容器",容器可以装在其他的Component.
Container的主要方法:
Component add(Component comp)
int getComponentCount()
Component[] getComponents()
在这里插入图片描述
AWT Frame
Frame是图形界面中的窗口主类,用于在用户桌面上显示一个应用程序窗口.
Frame具有标题栏,可以通过拖动标题栏来改变窗口的位置。
Frame的构造函数Frame(String title)可以指定标题栏显示的文字。
Frame初始化时不可见,必须调用其setVisible(true)方法才能显示出来。(其show()方法已经被废弃,不推荐使用。)
Frame默认就有窗口对应的按钮,但是其关闭按钮默认是无效的
AWT Panel
Panel是AWT中最常用的容器,用于组织其他Component的放置和便于定位。
Panel不能独立存在,必须放在Window或者Frame中
Panel组件放入其他容器中基本看不出来。
Panel和布局器组合使用之后可以实现强大的界面布局。
Panel也可以作为绘图的画布使用
AWT ScrollPane
ScrollPane是一种特殊的Panel,它跟Panel的区别在于其带有滚动条
ScrollPane也不能独立存在,必须放在顶层容器内部
可以用来装载其他的容器,当它所装载的容器大于ScrollPane本身的话,ScrollPane会自动产生滚动条。
一般不允许改变ScrollPane自己的布局器。
ScrollPane的构造函数ScrollPane(int scrollbarDisplayPolicy)允许在构造是选择ScrollPane显示滚动条的策略。
SCROLLBARS_ALWAYS:不管内容是不是大于其本身,都显示滚动条。
SCROLLBARS_AS_NEEDED :当内容大于其本身才显示滚动条(默认是这个选项)。
SCROLLBARS_NEVER :不管内容是不是大于其本身,都不显示滚动条。
AWT常用组件

  • AWT常用的Component
    AWT提供的Component的种类比较全面,基本涵盖了界面设计的各方各面,可以完成常用的界面设计任务。
    除了前面介绍过的容器组件之外,其他主要的组件有:
    Button:按钮
    Checkbox:复选框
    CheckboxGroup复选框组,之后一个复选框能被选中
    Choice:下拉选择框
    Label:标签,用于显示一个字符串
    List:列表
    TextField:单行文本框
    TextArea:多行文本区域
    具体用法简单,更多细节请查看API文档。
  • Dialog
    Dialog也称为对话框,是一种顶级容器,可以独立存在,不需要放置在其他容器内部。
    Dialog一般从另外一个Window或者Frame内部打开,其具有一个owner属性,需要设置为打开它的那个窗口。
    Dialog的构造函数有很多重载,这些重载中主要出现的参数如下:
    owner:是哪个窗口打开了这个对话框?
    title:对话框标题栏显示的名称。
    modal:是否打开模式对话框。一旦模式对话框打开后,不能再操作其他窗口中的内容,直到模式对话框被关闭。
  • FileDialog
    FileDialog是Dialog的子类。主要用于打开或者保存文件时选择文件的位置和名称。
    构造函数中出现的参数:
    parent:是哪个窗口打开了这个对话框?
    title:对话框的标题栏所显示的名字。
    mode:以什么模式打开文件对话框?
    LOAD:打开文件对话框
    SAVE:保存文件对话框
    方法:
    getDirectory():获得选择的文件的路径
    getFile():获得选择的文件的名称
    ☎️☎️FileDialog默认就是模式对话框
    用户取消选择后getDirectory()和getFile()值都为null
    布局管理器
    ScrollPane里面的Component为什么没有显示全?
    因为ScrollPane本身默认使用了布局管理器BorderLayout。
    布局管理器可以实现将容器中的组件自动地以不同的放置方式呈现出来。
    布局管理器的特点
    跨平台,在不同的平台上都有不同的呈现。
    不需要用户指定组件的大小和位置,自动决定最佳的位置和大小。
    可以根据容器本身的大小自动适应。(在窗口大小改变的时候可以实现自动适应)。
    每个容器都具有自己的默认布局管理器。
    容器具有setLayout()方法来改变其默认的布局管理器。
    此外,若指定不使用任何布局管理器(setLayout(null)),则可以实现让程序员自己指定空间的位置和大小。

布局管理器的种类
AWT为容器提供了5种常用的布局管理器:
FlowLayout
BorderLayout
GridLayout
GridBagLayout
CardLayout
Swing中提供了另外一种布局管理器:BoxLayout。

布局管理器的类结构
在这里插入图片描述
LayoutManager
LayoutManager接口声明了5个基本方法:
void addLayoutComponent(String name, Component comp)
void layoutContainer(Container parent)
Dimension minimumLayoutSize(Container parent)
Dimension preferredLayoutSize(Container parent)
void removeLayoutComponent(Component comp)

LayoutManager2
LayoutManager2接口在LayoutManager接口之上添加了4个方法:
void addLayoutComponent(Component comp, Object constraints)
float getLayoutAlignmentX(Container target)
float getLayoutAlignmentY(Container target)
void invalidateLayout(Container target)
Dimension maximumLayoutSize(Container target)

布局管理器的工作原理
如果这个容器设置了布局管理器(layoutMgr != null),那么检查layoutMgr是否实现的是LayoutManager2接口,如果是就调用布局管理器的“void addLayoutComponent(Component comp, Object constraints)”方法。
否则(实现的是LayoutManager接口)再判断constraints是否是String类型,如果是就调用布局管理器的“void addLayoutComponent(String name, Component comp)”方法。
如果布局管理器实现的是LayoutManager2接口,那么它的“void addLayoutComponent(String name, Component comp)”永远不会被awt框架调用到。
null布局管理器
null布局管理器也称为“绝对定位布局管理器”。
程序员可以任意指定容器中Component的大小和位置。
此时Component将以绝对定位的方式放置。
当窗口大小改变时,Component的绝对位置并不会改变。
Component的位置是从它所处的容器的左上角开始计算的。

FlowLayout
以从左到右(从上到下)的顺序依次排列加入的Component,在遇到边界时,从下一行(列)的开头开始继续排列。
三个构造函数:
FlowLayout(): 默认构造函数
FlowLayout(int align): 指定对其方式
LEFT, RIGHT, CENTER, LEADING, TRAILING
FlowLayout(int align, int hgap, int vgap):还可以指定水平和垂直间距,默认构造函数使用CENTER对其,hgap和vgap均为5
Panel容器默认使用FlowLayout。

BorderLayout
BorderLayout把容器的的布局分为五个位置:
CENTER、EAST、WEST、NORTH、SOUTH。
往BorderLayout布局的容器中添加Component时,需要指定添加的位置,否则将添加到中心位置。
BorderLayout的构造函数:
BorderLayout()
BorderLayout(int hgap, int vgap)
Frame、Window和ScrollPane默认使用该布局。
在这里插入图片描述
使用BorderLayout
如何向BorderLayout布局的容器中放入多个Component?
直接向BorderLayout的任何一个方向中添加多个Component,仅显示最后添加的那个。
可以多个将多个Panel配合使用来实现复杂的布局。
Box
Box实际上是一个容器
虽然它不是布局管理器,但是通常却作为布局管理器工作
它可以实现让组件水平或者垂直放置
Box通常使用其Box.createHorizontalBox()或者Box.createVerticalBox()静态方法创建
它通常和Panel组合使用
通过Box.createVerticalStrut()或者Box.createHorizontalStrut()静态方法可以创建一个水平或者垂直的空白对象用于分割
GridLayout
GridLayout按照构造函数提供的参数,将整个容器分为大小相等的网格状。
当往容器中添加Component时,以从上到下,从左到右的方式往网格中添加。
和FlowLayout的区别
GridLayout中的Component自动占用某个网格,而FlowLayout中的Component可以按自己的大小占用不同的空间。
GridLayout中每行的Component数量相同,而FlowLayout中每行中Component的数量可能不同。
构造函数:
GridLayout(int rows, int cols)
GridLayout(int rows, int cols, int hgap, int vgap)
GridBagLayout
GridBagLayout是最功(nan)能(yi)强(shi)大(yong)的布局管理器。
类似GridLayout, GridBagLayout将容器分为很多网格。
与GridLayout不同:
GridBagLayout的网格数量不是由构造函数决定的。
可以让Component跨多个Grid。
可以让每个Grid大小不一致。
窗口大小改变时,GridBagLayout可以精确地控制每个Grid的拉伸变化。
GridBagLayout具有特殊方法:setConstraints(Component c, GridBagConstraints constraints)
将一个GridBagConstraints对象和Component绑定在一起
GridBagConstraints
使用好GridBagLayout的关键在于使用GridBagConstraints。
GridBagConstraints可以控制容器中某个Component的布局特性。
使用GridBagConstraints的关键在于精确地设置其属性值:
gridx和gridy: 设置Component在网格中的横向和纵向位置。
gridwidth和gridheight:设置Component能在横向和纵向横跨多少个网格。
fill:控制Component如何填充网格的区域:
NONE、HORIZONTAL 、VERTICAL 、BOTH 。
ipadx和ipady:设置Component的内部填充大小,即在Component的最小大小上还需要加多少
insets:外部填充大小,类似于Border
GridBagConstraints的anchor属性
作用:控制Component在网格中显示的位置
anchor有三种类别的值:absolute、orientation-relative和baseline-relative。
三种类别可取的值为:
在这里插入图片描述
GridBagConstraints的属性
weightx和weighty:设置在横向和纵向的占用比重。
当窗口大小改变的时候,可以使用这两个属性来控制Component随着窗口变化时,Component大小的变化比率。
两个属性的默认值为0,取值范围[0.0, 1.0]。
窗口大小变化时,比较同一行或者同一列中不同Component所对应的值的比值。
在这里插入图片描述
CardLayout
一种三维的布局管理器,除了容器的高和宽之外,还加入了第三个维度。
每次只显示一张卡片(Component),可以通过方法切换当前显示的卡片。(默认显示第一张。)
构造函数:
CardLayout()
CardLayout(int hgap, int vgap):
主要方法:
first(Container target)
last(Container target)
previous(Container target)
next(Container target)
show(Container target, String name)
事件处理
图形界面
图形界面组件仅仅可以搭建出一个可视化的界面,而界面的功能并没有实现
例如:点击关闭按钮后,窗口并不能关闭。
再例如:CardLayout的例子中,点击按钮并没有切换不同的卡片。
原因在于,我们并没有给用户点击相应按钮后的效果做相应的编程。
事件处理
在界面搭建完成后,一般需要对相应的按钮等组件的功能提供相应的代码。
例如:用户点击关闭按钮后,窗口应该关闭。
再例如:CardLayout的例子中,用户点击“上一页”和“下一页”按钮后,应该显示相应的页面。
在这里插入图片描述
什么是事件(event)?
广义上说,事件即是某种状态的改变。
通过马克思主义哲学我们知道,事物的运动是永恒的,静止是相对的。永恒的运动意味着事物本身无时无刻不在发生着改变。
我们生活的这个世界和宇宙都有无穷的改变在发生,但是,这当中的绝大多数对你来说并不是事件,或者说并不是你关心的事件。
例如,菜市场上一个小商贩卖注水猪肉被工商查处了。这显然是一个事件。对于在菜市场买菜的人来说,这是一个他们所关心的事件。对于在课堂上的你来说,你并不关心。
在所有的变化中,你能捕获到的,感兴趣的变化,对你来说,才能真正认为是一个事件。
程序中的事件
对于我们的计算机来说,只要机器开着,里面的硬件和软件就会发生状态的改变。
可是对你要编写的程序来讲,并不是所有的这些改变都是事件。你所需要的事件,只是你对这些变化中感兴趣的极小一部分。
例如,窗口打开了、窗口关闭了、某个按钮被单击了、某个单选框被选中了、某个菜单被展开了等等。
你只需要找到你感兴趣的这样一种状态的改变,并且能够捕获它,就可以利用事件处理模型来完成你想做的事情了。
什么是事件处理
当某个事件发生的时候(界面中某个Component的某种状态改变的时候),我们希望在这个时机执行一些代码,就需要写事件处理。
例如:用户在关闭窗口的时候,我们希望判断用户更改过的内容是否已经保存。
再例如:当用户单击某个按钮的时候,我们希望弹出一个对话框。
当这些事件发生的时候,我们希望做的事情,就称为事件处理。
Java是一种面向对象的语言,在Java中使用监听器类来探知一个事件(改变),使用监听器类中的方法来在事件发生的时机下处理事件。
Java事件处理的三要素
在Java事件处理的模型中,有三种类非常重要,要理解事件处理,必须理解这三种类:
事件源(event source):是这个对象的状态改变引发的事件,通常是Component。
事件(event):事件源到底什么状态发生了改变?例如:按钮到底是被左键单击了?还是被右键单击了?
事件监听器(event listener):监听器被安装在某个Component上,负责监听这个Component到底有什么状态被改变了。一般仅在感兴趣的Component上安装感兴趣的监听器来监听感兴趣的事件。例如:一般不会监听TextField对象的事件,而会监听Button的单击事件。
AWT事件处理流程
在这里插入图片描述
处理用户单击按钮事件
在这里插入图片描述
AWT处理事件的模板
在这里插入图片描述
☁️☁️不同的Component有不同的事件会发生,可以查看API文档
添加事件监听器的方法一般都是addXXXListener(…)
有些监听器内部有多个方法,可以监听多种事件,但一般都相关
AWT中的事件
要能正确处理事件首先要确定哪些Component会发生什么事件。
AWT中事件主要分为两大类:低级事件和高级事件。
低级事件:
ComponentEvent:组件事件,当组件尺寸发生改变、位置发生变化、显示/隐藏状态发生改变时,就会触发该事件
ContainerEvent:容器事件,当容器里增加、删除组件时,就会触发该事件
WindowEvent:窗口事件,当窗口状态发生改变(打开、关闭、最大化、最小化)时,就会触发该事件
FocusEvent:焦点事件,当组件得到焦点或者失去焦点时,就会触发该事件
KeyEvent:键盘事件,当键盘按键被按下、松开时就会触发该事件
MouseEvent:鼠标事件,当一个组件被鼠标按下、放开、在其上面移动鼠标时,就会触发该事件
PaintEvent:绘制事件,当GUI组件调用update()/paint()方法时触发该事件,该事件并非专用于事件处理模型中,一般也很少直接监听该事件。
高级事件
高级事件基于语义,并不和特定的动作相关,而依赖于触发该事件的组件类别。
ActionEvent:动作事件,当按钮、菜单等能产生Action的项目被单击,或者在TextField中按下Enter按钮时,就会触发该事件。
AdjustmentEvent:调节事件,在滑动条上移动滑块调节数值时触发该事件。
ItemEvent:选项事件,当在有很多项目的组件中,选中或者取消选中了某一个项目,就会触发该事件。
TextEvent:文本事件,当文本框或者文本域这类具有文本的组件中,文本发生变化时,就会触发该事件。
不同的Event对象,有不同的属性和方法,可以获得和该事件相关的一些信息。
AWT中的事件层次关系
在这里插入图片描述
eg:窗口事件处理
如何正确关闭窗口?
前面的例子中,窗口无法关闭。
AWT中Frame之所以没有默认实现关闭方法,是因为窗口中可能有编辑的内容没有保存,如果默认就关闭窗口则内容可能丢失。
必须提供一个让用户在窗口关闭时保存内容的方法。
WindowListener可以处理这样的问题。
WindowListener接口有很多方法:
其中windowClosing()方法会在用户点击窗口的关闭按钮后被调用。
可以使用System.exit(0)方法退出程序(不推荐)
也可以使用Frame.dispose()方法关闭窗口,如果该窗口是最后一个被dispose的GUI窗口,则JVM会退出。
⛈️⛈️如果还有窗口没有被dispose,那么程序本身不会退出。例如,如果有的窗口被setVisible(false),此时窗口仅仅是不显示,但是并没有被销毁。此时不会显示任何窗口,但是程序并没有退出。
监听器的实现形式
监听器是一类特殊的Java类/对象。在AWT中,监听器主要有一下集中实现形式:
监听器作为外部类:
优点:规范易于理解、类本身可以重用
缺点:一般情况下不利于实现事件处理中的功能,因为不易于访问界面中的属性和方法
监听器作为内部类
优点:可以方便的访问主类中的任何属性和方法,包括私有方法
缺点:使得主类过于复杂、不可以在不同界面中重用
监听器作为主类本身
优点:跟内部类相似
缺点:使得主类方法过多
监听器作为匿名内部类
优点:可以访问主类的方法
缺点:每个事件都需要写匿名内部类,不能重用、不利于理解
EventAdapter
EventAdapter也称为事件适配器,它和EventListener功能是一致的。
EventListener是接口,而有的监听器可能存在多个监听方法,因此必须实现这些方法。
例如:每次使用WindowListener都需要实现所有的7个方法,显得代码凌乱。而一般情况下,我们只对windowClosing()这个事件感兴趣。
EventAdapter是一个类,它的作用就是一个EventListener的空实现,即所有的方法都实现了,然而没有写任何代码。
使用EventAdapter,我们仅仅需要实现我们感兴趣的方法,其他方法自动留空。
如果主类已经继承了某个类,那么使用EventAdapter就变成多继承,因此这种情况下无法使用。

发布了69 篇原创文章 · 获赞 12 · 访问量 7350

猜你喜欢

转载自blog.csdn.net/weixin_43291459/article/details/103221448