所谓图形用户界面就是我们现在最常用的windows操作系统的界面。
一、概述
GUI(Graphical User Interface),即图形用户界面,也就是我们现在最常用的windows系统的用户操作界面,我们可以用鼠标来点击按钮来进行操作,如:文件的创建、查看、重命名、删除等,这样的界面很直观,图形用户界面相对于比较友好、人性化,这样友好的界面在用户群中很受欢迎(在中国式这样的)。
而DOS就不具备GUI,这种界面叫CLI (Command line User Interface ) ,命令行模式的人机接口。所以他只能输入命令。玩DOS窗口要记住很多的操作命令,这对于我们来说,无疑是一个考验。
GUI 是一种结合计算机科学、美学、心理学、行为学,及各商业领域需求分析的人机系统工程,强调人--机--环境三者作为一个系统进行总体设计。这种面向客户的系统工程设计其目的是优化产品的性能,使操作更人性化,减轻使用者的认知负担,使其更适合用户的操作需求,直接提升产品的市场竞争力。
1、
GUI里面提供一些用来操作的窗口、菜单、按钮、工具栏和其他屏幕元素。
Java 里有两个包为GUI设计提供功能:AWT和Swing,AWT是早期版本,不能实现全部GUI设计功能,Swing对其进行改进,不但包含原来所有的部件,还具有更加丰富的部件和功能,AWT为Swing的基础。
容器(Container):是一种特殊的组件,能够容纳其他组件,如窗口、对话框等,这些是java.awt.Container类或者其子类。
基本组件:图形化显示与用户交互是按钮、文本框、复选框等,这些都是java.awt.Component类或者其子类,将组件放到容器内。
GUI层次图
2、布局
布局,简单地说,就是控制界面的排列方式,包括组件的位置和大小的设定。
创建指定布局方式类的对象,然后调用容器类的setLayout()方法来指定所需的布局方式。例:setLayout(new FlowLayout());
使用 setLocation() setSize() setBounds()设置组件的大小及位置。
布局管理器:指系统事先定义好的若干容器布局效果,使用它们可以方便地实现组件在容器的布局管理,并能够满足各种常规需要。例如,FlowLayout等
每一个容器都有默认的布局管理器,在创建一个容器对象时,同时也会创建一个相应的默认布局管理器对象,用户也可以随时为容器创建和设置新的布局管理器。
常用布局管理器
FlowLayout:流式布局,是Panel(及其子类)类型容器的默认布局管理器类型。
组件在容器中按照加入次序逐行定位,行内从左到右,一行排满后换行。自左向右、自上而下的安排组件,并且尽量将组件居中。
流式布局不会改变组件的尺寸,当当前行无法显示新增组件时,布局管理器会新增一行以安放新增组件且组件顺序和尺寸不随窗口变化而变化。
组件按原始大小进行显示。
构造方法 public FlowLayout()
public FlowLayout(int align)
public FlowLayout(int align,int hgap,int vgap)
(2)BorderLayout:边界布局,是Window及其子类类型容器的默认布局管理器。
将容器内的空间划分为东、南、西、北、中五个方位,并指明组件所在的方位,它是Window、Dialog、Frame的缺省布局方式。在使用边界布局的容器中,组件的尺寸也被布局管理器强行控制,即与其所在区域的尺寸相同。
构造方法 public BorderLayout() public BorderLayout(int hgap,int vgap)
BorderLayout的使用。
f.setLayout(new BorderLayout());
f.add(btnNorth,"North");
f.add(btnSouth,"South");
f.add(btnWest,"West");
f.add(btnEast,"East");
f.add(btnCenter,"Center");
(3)GridLayout:网格布局
需要事先指定布局的行列,形成网格。
组件由左向右、由上至下,并在本布局中会填充网格。缺点在此,因为有可能造成组件显示失真。
当组件超过列数的时候,不是直接添加到下一行,而是增加列数,行数保持不变。
和流布局管理器类不同的地方在于,组件不会因为窗体大小的变化而移位,相反,组件通过自动缩放以保持屏幕组件的网格关系。
构造方法 public GridLayout() public GridLayout(int rows,int cols) public GridLayout(int rows,int cols,int hgap,int vgap)
当GridLayout布局的容器尺寸发生变化时,每个单元格的大小都将随之作调整,组件的大小也会发生变化。
正常情况下使用GridLayout布局时,向容器中加入的组件数目应与容器划分出来的单元格总数相等,但假如出现两者数目不等的情况,程序也不会出错,而是保证行数为设置值,列数则通过指定的行数和布局中的组件总数来进行调整。
(4)卡片布局(CardLayout)
卡片布局可以同时容纳多个组件,但只能一次显示一个组件
卡片布局的创建过程:
(5) GridBagLayout
是所有AWT布局管理器当中最复杂的,同时他的功能也是最强大的.这种现象源于它所提供的众多的可配置选项,你几乎可以完全地控制容器的布局方式.尽管复杂性很明显,只要理解了基本思想,就很容易使用GridBagLayout了.
GridBagLayout从它的名字中你也可以猜到,它同GridLayout一样,在容器中以网格形式来管理组件.但GridBagLayout功能要来得强大得多.
GridBagLayout管理的所有行和列都可以是大小不同的.通常由一个专用类来对他布局行为进行约束,该类叫GridBagConstraints.其中的所有成员都是public的, 因此要学好如何使用GridBagLayout首先要了解有那些约束变量,以及如何设置这些约束变量.
常用构造: public GridBagLayout()
3、创建图形化的步骤:
创建一个容器,并设置其属性,将需要的组件添加到容器中,并编写相应的触发事件。
public static void main(String[] args)
{
//创建frame对象并初始化(带有标题和边框的窗口)
Frame f = new Frame("我的第一个Frame窗口");
//一般是横坐标 纵坐标
f.setSize(500,400);
//与左边界的距离,与上边界的距离
f.setLocation(500,100);
Button b = new Button("按钮");
f.add(b);
//匿名内部类
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.out.println("关闭窗口");
System.exit(0);
}
public void windowActivated(WindowEvent e)
{
System.out.println("窗口前置");
}
public void windowDeactivated(WindowEvent e)
{
System.out.println("窗口后置");
}
});
f.setLayout(new FlowLayout());
f.setVisible(true);
//System.out.println("Hello World!");
}
4、事件监听机制
创建一个Frame窗口,选择合适的布局管理器,并向容器中添加按钮组件。这时,我们实现的只是将窗口最小化、最大化,当点击关闭、按钮时,窗体并没有反应。也就是说,界面中的组件并没有实现和用户交互的功能。
public static void main(String[] args) {
//创建frame对象并初始化(带有标题和边框的窗口)
Frame f = new Frame("我的第一个Frame窗口");
//一般是横坐标 纵坐标
f.setSize(500,400);
//与左边界的距离,与上边界的距离
f.setLocation(500,100);
Button b = new Button("退出");
f.add(b);
f.setLayout(new FlowLayout());
f.setVisible(true);
}
事件监听机制原理图
(1)事件源:AWT/Swing包中的图形界面组件。
(2)事件:事件源所具备的对应事件和共性事件,是发生在界面上的用户交互行为。是系统对其可能处于的某种状态或某种操作的预先定义。比如,Frame中的关闭窗口。
事件一般分为三种类型:键盘事件、鼠标事件、以及组件的动作事件。
Java定义了许多事件类,来描述不同的用户行为。事件发生时,生成一个事件对象。 事件对象描述的是用户所执行的操作。
(3)监听器:用于接收的事件。
(4)事件处理方式:事件发生所采取的处理方式。事件的处理由事件处理程序完 成。每个AW组件都有自己的事件处理程序。当事件对象生成时,AWT事件处理系统就会将这个事件对象传递给所涉及的组件,由它们的事件处理程序进行相应处理。
在JDK中,将事件源和对事件的处理分开,这样就可以将界面和事件分离,将这些功能封装成类、接口或方法等,有利于提高代码的复用性。
对于事件源上发生的事件的处理代码就在这里。如:
f.addWindowListener(new WindowAdapter(){});
but.addActionListener(new ActionListener(){});
这里,调用组件的addWindowListener()、addActionListener()方法,将事件的监听器注册到GUI组件上。WindowAdapter、ActionListener是接口,接口中定义了窗体和Action事件的抽象方法,让其子类具体实现这些方法,并在方法体中自定义处理的代码。
窗体和Action事件
在上面的例子中,事件就是Frame窗体及其中的组件应该具有哪些与用户交互的操作动作(比如要关闭窗口或点击按钮希望出现什么回应等),事件源就是Frame窗体,监听器就是Frame类下的window类的addWindowListener()方法,其中接收的就是WindowAdapter接口的子类对象,WindowAdapter接口中有对应的方法用于对窗口所发生的事件作出处理。按钮的监听器是addActionListener()。
import java.awt.*;
import java.awt.event.*;
class FrameDemo {
//定义该图形中所需的组件的引用
private Frame f;
private Button but;
FrameDemo(){
//调用niit初始化方法,
init();
}
//定义初始化方法,用于设置窗体的属性等操作
public void init(){
//图形化界面初始化 创建组件对象
f = new Frame("Frame窗口");
//对frame进行基本设置 intx,inty 宽,高
f.setBounds(300,100,500,400);
//不设置默认填充整个frame
f.setLayout(new FlowLayout());
//初始化按钮组件
but = new Button("按钮");
//将组件添加到frame中
f.add(but);
//调用事件方法
myEvent();
//设置窗体为可见
f.setVisible(true);
}
//自定义事件方法
public void myEvent() {
//添加frame窗体监听事件
//当接口中的方法超过3个,则需使用适配器
f.addWindowListener(new WindowAdapter() {
//复写WindowAdapter接口中的windowClosing方法,并接收事件对象
public void windowClosing(WindowEvent e) {
//自定义处理代码
System.out.println("关闭窗口");
//用于退出窗体
System.exit(0);
}
}
);
//添加Button监听事件(点击按钮,窗体会退出)
but.addActionListener(new ActionListener(){
//复写ActionListener接口中的actionPerformed方法,
public void actionPerformed(ActionEvent e) {
//自定义处理方式
System.out.println("点我,奇迹就会出现");
System.exit(0);
}
}
);
}
public static void main(String[] args) {
//创建对象
//FrameDemo fd =
new FrameDemo();
}
}
鼠标事件
在图形用户界面中,我们可以单击或双击文件来完成一些操作。如,单击文件出现菜单,双击文件打开文件等。在一些网站上,当鼠标经过一些文字或图片时,也会做出一些回应,要么出现阴影,要么出现说明文字等。
这里则在窗体中的按钮(Button)组件上添加一些事件,用于实现单击、双击、鼠标经过时的交互情况。当双击鼠标时,经过按钮的单击这两个动作会先于双击执行,当双击完后,单击动作也会触发。
import java.awt.*;
import java.awt.event.*;
//定义一个类,用于封装实现鼠标事件的功能
class MouseEventDemo {
private Frame f;
private Button but;
MouseEventDemo() {
init();
}
public void init() {
f = new Frame("My Frame");
f.setBounds(300,100,500,400);
f.setLayout(new FlowLayout());
but = new Button("我的按钮");
f.add(but);
myEvent();
f.setVisible(true);
}
public void myEvent(){
//添加窗体事件
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.out.println("关闭窗口动作");
System.exit(0);
}
});
//添加按钮事件,按钮是当前事件源
but.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("点击动作");
}
});
//添加鼠标事件
//接收MouseAdapter接口的子类对象
but.addMouseListener(new MouseAdapter() {
//定义一个当鼠标经过和点击时的计数变量,
private int count = 1;
private int clickCount = 1;
//复写接口中的mouseClicked方法
public void mouseClicked(MouseEvent e){
//当鼠标被点击2下时,clickCount自增,并打印,测试
if (e.getClickCount()==2) {
System.out.println("双击我"+clickCount++);
}
}
//复写mouseEntered方法
public void mouseEntered(MouseEvent e){
System.out.println("飘过"+count++);
}
});
}
public static void main(String[] args) {
new MouseEventDemo();
}
}
键盘事件
添加键盘事件:
//当前事件源为button,只要点击按钮,则触发一些事件,就可以进行键盘操作。
but.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e) {
//当用键盘录入时,就会在控制台打印输入的键盘符和键盘符对应的整数
//System.out.println(e.getKeyChar()+"-----"+e.getKeyCode());
//根据键盘码获得诸如"shift"、"capslk"这样字符串所对应的键盘码
//System.out.println(KeyEvent.getKeyText(e.getKeyCode())+"----"+e.getKeyCode()
//如果触发事件,并按下的键盘符为Esc,则程序退出
if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
System.exit(0);
//组合键的录入。当按下ctrl 和 enter键时,触发该事件
if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER)
{
System.out.println("Control+Enter----");
}
}
});
添加一个文本框组件,并对其添加事件。
private TextField tf;
//文本框可以指定列数
tf = new TextField(30);
f.add(tf);
tf.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
int code = e.getKeyCode();
if (!(code>=KeyEvent.VK_0 && code<=KeyEvent.VK_9)) {
System.out.println(code+"非法输入");
//当向文本框中输入非法数据时,该非法数据不会显示在文本框中
e.consume();
}
}
});
Item Event 指定项被选中或取消的事件
(1)
ItemListener:接收项事件的监听器接口。特别适于处理项事件的类实现此接口。然后,使用组件的 addItemListener 方法向该组件注册由此类创建的对象。选定项事件发生时,调用侦听器对象的 itemStateChanged 方法。
ItemEvent
指示项被选定或取消选定的语义事件。该事件被传递到每个 ItemListener 对象,这些对象都已使用组件的 addItemListener 方法注册接收此类事件。
实现 ItemListener 接口的对象将在事件发生时获取此 ItemEvent。
运用到Item Event事件的组件有:
JRadioButton(单选按钮)通常是成组使用的,可以通过ButtonGroup类进行管理。
JComboBox(组合框)是一种“多选一”的组件,可编辑每项的内容,而且每项的内容可以是任意类,当用户选取组合框中的某一选择项时,可激发ItemEvent事件。
JCheckBox(复选框)有选中和未选中两种状态,允许用户从一组选项中进行多个选择。
(2)JCheckBox(复选框)举例说明
JCheckBox(复选框)事件响应:用户点击复选框使其选中状态发生变化时会ItemEvent事件。这时就会实现ItemListener接口的itemStateChanged()方法。
创建如下窗口,包含三个复选框和一个面板,选中某一复选框后,面板的背就变成相应的颜色。
package wangtingting;
import java.awt.Color;
import java.awt.event.ItemEvent;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CheckBoxTest {
private JFrame f;
private JPanel p1, p2;
private JCheckBox ck1,ck2,ck3;
CheckBoxTest(){
init();
}
public void init(){
//JFrame是Swing中的容器,该容器中可以放置其他组件
f = new JFrame ("CheckBoxTest");
ck1=new JCheckBox("红色");
ck2=new JCheckBox("黄色");
ck3=new JCheckBox("蓝色");
//JPanel面板是容器组件,依赖于顶级容器,不能独立存在。
p1=new JPanel();
p2=new JPanel();
//将JPanel面板添加到JFrame容器中。p1中放置复选框,p2中放置显示的颜色
f.add(p1,"North");
f.add(p2);
//将复选框添加到p1面板上
p1.add(ck1);
p1.add(ck2);
p1.add(ck3);
myEvent();
//调用框架的setSize方法,设定合适的框架大小。
f.setSize(400, 200);
//调用框架的相应方法,显示框架(默认情况下,框架在建立时是不可见的)。
f.setVisible (true);
}
public void myEvent(){
// 复写ItemListener接口中的itemStateChanged方法,添加处理方式的代码
ck1.addItemListener(new ItemListener() {
// 调用ItemEvent的父类(AWTEvent)中的setSource(Object newSource)方法
//用于将事件的目标更改为新的源。
public void itemStateChanged(ItemEvent e) {
if(e.getSource()==ck1)
p2.setBackground(Color.red);
else if(e.getSource()==ck2)
p2.setBackground(Color.yellow);
else
p2.setBackground(Color.blue);
}
});
ck2.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e) {
if(e.getSource()==ck1)
p2.setBackground(Color.red);
else if(e.getSource()==ck2)
p2.setBackground(Color.yellow);
else
p2.setBackground(Color.blue);
}
});
ck3.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e) {
if(e.getSource()==ck1)
p2.setBackground(Color.red);
else if(e.getSource()==ck2)
p2.setBackground(Color.yellow);
else
p2.setBackground(Color.blue);
}
});
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new CheckBoxTest();
}
}
总结:
在添加交互行为的时候,就是不断确定事件源(将事件注册到哪)、确定事件(以便调用事件对应的方法)、确定监听器(具有监听和处理事件的功能)、确定处理方式(处理代码,想要出现怎样的交互效果)的过程。基本的步骤就是:
如果接口中的方法大于等于3个,那么就要用适配器。
组件.addXxxListner(new XxxAdapter(){
//复写接口中的方法,接收事件对象,
public void xxxYyy(XxxEvent e){
//自定义事件的处理代码
}
});
其实,Swing组件的使用和AWT中的组件使用方法是相似的。因为Swing是以AWT为基础,用java语言编写的,只是对AWT 的功能进行了扩充。AWT 是基于本地方法的C/C++程序,其运行速度比较快;Swing是基于AWT 的Java程序,其运行速度比较慢事件的响应等工作还是要用awt来完成。