GUI编程
AWT
AWT简单介绍
抽象窗口工具集(CAbstract Window Toolkit)
awt编程中有两个基类:Component和MenuComponent
- Component :代表一个能以图形化方式显示出来,并可以于用户交互的对象,例如Button代表一个按钮,TextField代表一个文本框等;
- MenuComponent:则代表图形界面的菜单组件,包括MenuBar(菜单条),MenuItem(菜单项)等子类。
Container 是一种特殊的Component,它代表一种容器,可以承装普通的Component.
AWT还有一个非常重要的接口叫做LayoutManager(布局管理器),如果一个容器中有多个组件,那么容器就需要使用LayoutManager来管理这些组件的布局方式。(网状布局,流式布局等)
Container容器
Window 窗口容器:可以独立存在的顶级窗口,默认使用BorderaLayout管理其内部的组件布局
Panel 可以容纳其他组件,但不能独立存在,他必须内嵌其他容器中使用,默认使用FlowLayout管理其内部的组件布局
ScrollPane 是一个带滚动条的容器,他也不能独立存在,默认使用BorderLayout管理器内部的组件布局
Component基类方法签名 | 方法功能 |
---|---|
setLocation(int x,int y) | 设置组件位置 |
setSize(int width,int height) | 设置组件大小 |
setBounds(int x,int y,int width,int height) | 同时设置组件位置和大小 |
setVisible(Boolean b) | 设置该组件的可见性 |
Container容器根类方法签名 | 方法功能 |
---|---|
Component add(Component comp) | 向容器中添加其他组件,(该组件既可以是普通组件也可以是容器),并返回被添加的组件。 |
Component getComponentAt(int x,int y); | 返回指定点的组件 |
int getComponentCount() | 返回该容器组件的数量 |
Component[] getCompuonents(); | 返回该容器内的所有组件。 |
Window 容器效果:
Panel 容器效果:
ScrollPane 容器效果:
LayoutManager 布局管理器
LayoutManager 布局管理器 可以根据运行的平台来自动调整组件的大小,程序员不用再手动设置组件(种类繁多)的大小和位置,只需要为容器选择合适的布局管理器即可;
LayoutManager 的实现类:GridLayout(网格布局),FlowLayout(流式布局)
LayoutManager的子接口:LayoutManager2 实现类:CardLayout(卡片布局),BorderLayout(边框布局),GridManager(网格包布局);
FlowLayout(流式布局)
构造方法 | 方法功能 |
---|---|
FlowLayout() | 使用默认的对齐方式和默认的垂直间距,水平间距创建FlowLayout 布局管理器 |
FlowLayout(int align) | 使用指定的对齐方式及默认的垂直间距,水平间距来创建FlowLayout布局管理器 |
FlowLayout(int align,int hgap,int vgap) | 使用指定的对其方法及指定的垂直间距和水平间距来创建FlowLayout布局管理器。 |
package com.awt.xm.layout_manager;
import org.junit.Test;
import java.awt.*;
/**
* LayoutManager
*/
public class D1 {
/**
* FlowLayout(流式布局)
*/
@Test //测试类不用手动推出
public void test2()
// public static void main(String ...args)
{
Frame frame = new Frame("这里测试FlowLayout");
frame.setLayout(new FlowLayout(FlowLayout.CENTER,20,20));
for (int i = 0; i < 100; i++) {
frame.add(new Button("按钮"+i));
}
//pack 方法设置标签(窗口)最佳大小
frame.pack();
frame.setVisible(true);
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
BorderLayout(边框布局)
将容器分为EAST WEST CENTER NORTH SOUTH
- 当使用BorderLayout布局管理器的容器中添加组件时,需要指定要添加的区域,如果没有指定添加区域,默认添加到中间区域
- 如果向一个区域中添加多个组件,后放入的组件会覆盖先前的组件
- 如果不往某个区域放入组件,那么该区域不会空白出来,而是被其他区域占用
package com.awt.xm.layout_manager;
import java.awt.*;
/**
* BorderLayout(边框布局)
*/
public class D2 {
public static void main(String[] args) {
Frame frame = new Frame("测试BorderLayout");
frame.setLayout(new BorderLayout(30,30));
frame.add(new Button("东侧按钮"),BorderLayout.EAST);
frame.add(new Button("北侧按钮"),BorderLayout.NORTH);
frame.add(new Button("中侧按钮"),BorderLayout.CENTER);
frame.add(new Button("南侧按钮"),BorderLayout.SOUTH);
frame.add(new Button("西侧按钮"),BorderLayout.WEST);
frame.add(new TextField("测试文件框"));
frame.pack();
frame.setBackground(Color.BLUE);
frame.setVisible(true);
}
}
GridLayout(网格布局)
构造方法 | 方法功能 |
---|---|
GridLayout(int rows,int cols) | 采用指定的行数和列数,以及默认的横向间距和纵向间距分割成多个网格 |
GridLayout(int rows,int cols,int hgap,int vgap) | 采用指定的行数和列数,以及指定的横向间距和纵向间距将容器分割成多个网格 |
计算器效果实现
package com.awt.xm.layout_manager;
import java.awt.*;
/**
* GridLayout(网格布局)
*/
public class D3 {
public static void main(String[] args) {
Frame frame = new Frame("测试GridLayout计算器");
Panel panel = new Panel();
panel.add(new TextField(70));
frame.add(panel, BorderLayout.NORTH);
Panel panel1 = new Panel();
for (int i = 0; i < 10; i++) {
panel1.add(new Button(Integer.toString(i)));
}
panel1.add(new Button("+"));
panel1.add(new Button("-"));
panel1.add(new Button("*"));
panel1.add(new Button("/"));
panel1.add(new Button("="));
panel1.setLayout(new GridLayout(3, 5,4,4));
frame.add(panel1,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
GrigBagLayout(网格包布)
不推荐,因为Swing 中有更加强大的布局管理器
CardLayout(卡片布局)
CardLayout布局 以时间而非空间来管理它里面的组件,他将加入容器的所有组件看成一叠卡片(每个卡片其实就是一个组件),每次只有最上面的那个Component 才可见。
方法名称 | 方法功能 |
---|---|
CardLayout() | 创建默认的CardLayout布局管理器 |
CardLayout(int hgap,int vagp) | 通过指定卡片和容器左右边界的间距,上下边界的间距来创建CardLayout布局管理器 |
first(Container target) | 显示target容器中的第一张卡片 |
last(Container target) | 显示target容器中的最后一张卡片 |
previous(Container target) | 显示target容器中的前一张卡片 |
next(Container target) | 显示target容器中的后一张卡片 |
show(Container target,String name ) | 显示target容器中指定名字的卡片 |
package com.awt.xm.layout_manager;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* CardLayout(卡片布局)
*/
public class D5 {
public static void main(String[] args) {
Frame frame = new Frame("CardLayout布局");
Panel panel = new Panel();
String[] names = {"第一张", "第二张", "第三张", "第四张", "第五张"};
for (int i = 0; i < names.length; i++) {
panel.add(names[i], new Button(names[i]));
}
CardLayout cardLayout = new CardLayout();
panel.setLayout(cardLayout);
frame.add(panel, BorderLayout.CENTER);
Panel panel1 = new Panel();
Button b1 = new Button("上一张");
panel1.add(b1);
Button b2 = new Button("下一张");
panel1.add(b2);
Button b3 = new Button("第一张");
panel1.add(b3);
Button b4 = new Button("最后一张");
panel1.add(b4);
Button b5 = new Button("第三张");
panel1.add(b5);
//事件监听器
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
switch (actionCommand) {
case "上一张":
cardLayout.previous(panel);
break;
case "下一张":
cardLayout.next(panel);
break;
case "第一张":
cardLayout.first(panel);
break;
case "最后一张":
cardLayout.last(panel);
break;
case "第三张":
cardLayout.show(panel,"第三张");
break;
}
}
};
b1.addActionListener(actionListener);
b2.addActionListener(actionListener);
b3.addActionListener(actionListener);
b4.addActionListener(actionListener);
b5.addActionListener(actionListener);
frame.add(panel1, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
BoxLayout(盒子布局)
该布局属于java.swing 包
方法名称 | 方法功能 |
---|---|
BoxLayout(Container target int axis) | 指定创建基于target容器的BoxLayout布局管理器,该布局管理器的组件按axis方向排列。其中axis有BoxLayout.X_ASIX(横向)和BoxLayout.Y_ASIS(纵向) |
package com.awt.xm.layout_manager;
import javax.swing.*;
import java.awt.*;
/**
* BoxLayout(盒子布局)
*/
public class D6 {
public static void main(String[] args) {
Frame frame = new Frame("BoxLayout测试");
frame.setLayout(new BoxLayout(frame,BoxLayout.Y_AXIS));
frame.add(new Button("第一"));
frame.add(new Button("第二"));
frame.pack();
frame.setVisible(true);
}
}
在java.swing包中,提供了一个新的容器Box 该容器的默认布局管理器就是BoxLayout,大多数情况下,使用Box容器去容纳多个GUI组件,然后把Box容器作为一个组件,添加到其他容器中,从而形成整体的窗口布局。
Box容器方法
方法名称 | 方法功能 |
---|---|
static Box createHorizontalBox() | 创建一个水平排列组件的Box容器 |
static Box createVerticalBox() | 创建一个垂直排列组件的Box容器 |
package com.awt.xm.layout_manager;
import javax.swing.*;
import java.awt.*;
/**
* Box容器默认实现BoxLayout布局
*/
public class D7 {
public static void main(String[] args) {
Frame frame = new Frame("Box容器默认实现BoxLayout布局");
Box box = Box.createHorizontalBox();
box.add(new Button("水平一"));
box.add(new Button("水平二"));
Box box1 = Box.createVerticalBox();
box1.add(new Button("垂直一"));
box1.add(new Button("垂直二"));
frame.add(box);
frame.add(box1,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
Box容器方法扩充
方法名称 | 方法功能 |
---|---|
static Component createHorizontalGlue() | 创建一条水平Glue组件(可在两个方向上同时拉伸) |
static Component createVerticalGlue() | 创建一条垂直Glue组件(可在两个方向上同时拉伸) |
static Component createHorizontalStrut(int width) | 创建一条指定宽度(水平方向不可拉伸,垂直方向可以)的Strut组件 |
static Component createVerticalStrut(int height) | 创建一条指定高度(垂直方向不可拉伸,水平方向可以)的Strut组件 |
package com.awt.xm.layout_manager;
import javax.swing.*;
import java.awt.*;
/**
* Box容器和BoxLayout布局分割实现
*/
public class D8 {
public static void main(String[] args) {
Frame frame = new Frame("Box容器和BoxLayout布局分割实现");
Box box = Box.createHorizontalBox();
box.add(new Button("水平一"));
box.add(Box.createHorizontalGlue());//返回组件,可以在两个方向拉伸
box.add(new Button("水平二"));
box.add(Box.createHorizontalStrut(30));//水平不可以拉伸
box.add(new Button("水平三"));
Box box1 = Box.createVerticalBox();
box1.add(new Button("垂直一"));
box1.add(Box.createVerticalGlue());//返回组件,可以在两个方向拉伸
box1.add(new Button("垂直二"));
box1.add(Box.createVerticalStrut(30));//垂直方向不能拉伸
box1.add(new Button("垂直三"));
frame.add(box,BorderLayout.NORTH);
frame.add(box1,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
AWT常用组件
组件名 | 功能 |
---|---|
Button | 按钮 |
Canvas | 用于绘图的画布 |
CheckBox | 复选框(可以作为单选框使用) |
CheckboxGroup | 用于将多个Checkbox组件合成一组,一组Checkbox组件将只用一个可以被选中,即全部变成 单选框组件 |
Choice | 下拉选择框 |
Frame | 窗口(Window容器的实现类对象)在GUI程序中通过该类创建窗口 |
Label | 标签类,用于放置提示性文本 |
List | 列表框组件,可以添加多条项目 |
Panel | 不能单独存在的基本容器类,必须放到其他容器中 |
Scrollbar | 滑动条组件,如果需要用户输入位于某个范围的值,就可以使用滑动条组件,比如调色板中设置%RGB的三个值所用的滑动条。当创建一个滑动条时,必须指定它的方向,初始值,滑块的大小,最大值和最小值 |
ScrollPane | 带水平及垂直滚动条的容器组件 |
TextArea | 多行文本域 |
TextField | 单行文本框 |
用法演示:
package com.awt.xm.component;
import javax.swing.*;
import java.awt.*;
/**
* awt组件测试类
*/
class BasicComponent {
Frame frame = new Frame("awt组件测试");
TextArea textArea = new TextArea(5, 20);
Choice choice = new Choice();
CheckboxGroup checkboxGroup = new CheckboxGroup();
Checkbox checkbox = new Checkbox("女", checkboxGroup, true);
Checkbox checkbox1 = new Checkbox("男", checkboxGroup, false);
Checkbox checkbox4 = new Checkbox("是美女吗");
TextField textField = new TextField(60);
Button button = new Button("确认");
List list = new List(6, true);
public void init() {
Box box1 = Box.createHorizontalBox();
choice.add("红色");
choice.add("蓝色");
choice.add("绿色");
box1.add(choice);
box1.add(checkbox);
box1.add(checkbox1);
box1.add(checkbox4);
Box box2 = Box.createVerticalBox();
box2.add(textArea);
box2.add(box1);
Box box3 = Box.createHorizontalBox();
box3.add(box2);
list.add("红色");
list.add("白色");
list.add("蓝色");
box3.add(list);
Box box4 = Box.createHorizontalBox();
box4.add(textField);
box4.add(button);
frame.add(box3);
frame.add(box4, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
public class Demo1 {
public static void main(String[] args) {
new BasicComponent().init();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.exit(0);
}
}
//方法签名(全类名,形参列表,返回值数据类型)只是一种说法
菜单组件
Dialog对话框
Dialog对话框时Window类的子类,是一个容器类(BorderLayout布局),属于特殊组件,对话框时可以独立存在的顶级窗口,因此用法和普通的窗口用法几乎一样,但是使用对话框需要注意以下两点:
- 对话框通常依赖于其他窗口,就是通常需要有一个父窗口
- 对话框有非模式(non-modal)和模式(modal)两种,当某个模式对话框被打开后,该模式对话框总是位于他的父窗口之上,在模式对话框被关闭之前,父窗口无法获得焦点。
方法签名 | 方法功能 |
---|---|
Dialog (Frame owner,String title , boolean modal ) | 创建一个对话框对象,owner:当前对话框的父窗口 title:当前对话框的标题 modal:当前对话框是否是模式对话框 |
package com.awt.xm.component;
import java.awt.*;
/**
*Dialog对话框
*/
public class De2 {
public static void main(String[] args) {
Frame frame = new Frame("测试Dialog对话框");
Dialog dialog1 = new Dialog(frame,"模式对话框",true);
dialog1.setBounds(300,300,500,300);
dialog1.add(new TextArea(5,30));
dialog1.add(new Button("确认"),BorderLayout.SOUTH);
Dialog dialog2 = new Dialog(frame,"非模式对话框",false);
dialog2.setBounds(300,300,500,300);
Button button1 = new Button("打开模式对话框");
Button button2 = new Button("打开非模式对话框");
button1.addActionListener(e -> dialog1.setVisible(true));
button2.addActionListener(e -> dialog2.setVisible(true));
frame.add(button1,BorderLayout.NORTH);
frame.add(button2,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
FileDialog (文件对话框)
Dialog类有一个子类: fileDialog ,他代表一个文件对话框,用于打开或保存文件,需要注意的是FileDialog无法指定模态或非模态,这是因为FileDialog依赖运行平台的实现,如果运行平台的文件对话框是模态的,那么FileDialog 也是模态的,否则是非模态的。
方法签名(全类名,形参列表) | 方法功能 |
---|---|
FileDialog (Frame parent,String title,int mode) | 创建一个文件按对话框:parent: 指定父窗口,title:对话框标题 mode: 文件对话框类型,如果指定为FileDialog.LOAD,用于打开文件;指定为FileDialog.SAVE,用于保存文件 |
Stirng get Directory() | 获取被打开或保存文件的绝对路径 |
String getFile() | 获取被打开或保存的文件名 |
package com.awt.xm.component;
import java.awt.*;
/**
* FileDialog对话框
*/
public class De3 {
public static void main(String[] args) {
Frame frame = new Frame("测试FileDialog对话框");
FileDialog fileDialog1 = new FileDialog(frame, "选择要打开的文件::", FileDialog.LOAD);
FileDialog fileDialog2 = new FileDialog(frame, "选择要保存的路径::", FileDialog.SAVE);
Button button1 = new Button("打开文件");
Button button2 = new Button("保存文件");
button1.addActionListener(e -> {
fileDialog1.setVisible(true);
String directory = fileDialog1.getDirectory();
String file = fileDialog1.getFile();
System.out.println("打开的路径为:" + directory);
System.out.println("打开的文件名为:" + file);
});
button2.addActionListener(e -> {
fileDialog2.setVisible(true);
String directory = fileDialog2.getDirectory();
String file = fileDialog2.getFile();
System.out.println("保存的路径为:" + directory);
System.out.println("保存的文件名为:" + file);
});
frame.add(button1, BorderLayout.NORTH);
frame.add(button2, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
GUI事件处理机制
定义及核心概念
定义:当在某一个组件上发生某些操作的时候,会自动的触发一段代码的执行。
4个核心的概念:
- 事件源(Event Source):操作发生的场所,通常某个组件,例如按钮,窗口等;
- 事件(Event):在事件源上发生的操作叫做事件,GUI会把事件都封装到一个Event对象中,如果需要知道该事件的详细信息,就可以通过Event对象来获取;
- 事件监听器(Event Listener):当在某个事件源上发生了某个事件,事件监听器就可以对这个事件进行处理。(代码处理)
- 注册监听(Register Listener): 吧某个事件监听器(A)通过某个事件(B)绑定到某个事件源(C)上,当在事件源(C)上发生了事件(B)之后,那么事件监听器(A)的代码就会自动执行;
package com.awt.xm.event_listener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Dem1 {
public Frame frame;
public Button button;
public TextField textField;
public void init()
{
frame=new Frame("事件监听测试");
//事件源
button=new Button("显示");
textField=new TextField();
//注册监听,可以通过,外部类对象,成员内部类的对象,匿名内部类,Lambda表达式都可以
//多个事件源得使用同一个事件监听器的话,用成员内部类或外部类比较好
button.addActionListener(new MyListener());
frame.add(textField,BorderLayout.NORTH);
frame.add(button);
frame.pack();
frame.setVisible(true);
}
private class MyListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
textField.setText("你好世界!");
System.out.println("OK按钮被点击了"+e);
}
}
public static void main(String[] args) {
new Dem1().init();
}
}
常见的事件和事件监听器
常见事件:
AWT中的事件分为低级事件和高级事件
1.低级事件:
低级事件:这类事件是基于某一个特定的动作的事件。比如进入,点击,拖放等动作的鼠标事件,再比如得到焦点和失去焦点等焦点事件。
事件 | 触发时机 |
---|---|
ComponentEvent | 组件事件,当组织尺寸发生变化、位置发生移动、显示/隐藏状态发生改变时触发该事件。 |
ContainerEvent | 容器事件,当容器里发生添加组件、删除组件时触发该事件。 |
WindowEvent | 窗口事件,当窗 口状态发生改变(如打开、关闭、最大化、最 小化)时触发该事件。 |
FoucusEvent | 焦点事件,当组件得到焦点或失去焦点 时触发该事件。 |
KeyEvent | 键盘事件 ,当按键被按下、松开、单击时触发该事件。 |
MouseEvent | 鼠标事件, 当进行单击,按下,松开,移动鼠标等动作时触发该事件。 |
PaintEvent | 组件绘制事件,该事件是一个特殊的事件类型,当GUI组件调用update/paint方法来呈现自身时触发该事件,该事件并非专用于事件处理模型 |
2.高级事件:
这类事件并不会基于某个特定的动作,而是根据功能含义定义的事件。
事件 | 触发时机 |
---|---|
ActionEvent | 动作事件:当按钮,菜单项被单击时,在TextFiled中按下Enter键时触发 |
AdjustmentEvent | 调节事件:在滑动条上滑动滑块以调节数值时,触发该事件 |
ItemEvent | 选项事件:当用户选中某项,或取消选中某项时,触发该事件 |
TextEvent | 文本事件:当文本框,文本域中的文本发生改变时,触发该事件 |
事件监听器
不同的事件使用不同的监听器监听,不同的监听器需要不同的监听器接口,当指定事件发生后,事件监听器就会调用所包含的事件处理器(重写的接口代码)来处理事件。
事件类别 | 描述信息 | 监听器接口 |
---|---|---|
ActionEvent | 激活组件 | ActionListener |
ItemEvent | 选择某些项目 | ItemListener |
MouseEvent | 鼠标移动 | MouseMotionListener |
MouseEvent | 鼠标点击 | MouseListener |
KeyEvent | 键盘输入 | KeyListener |
FocusEvent | 组件收到或失去焦点 | KeyListener |
AdjustmentEvent | 移动了滚动条等组件 | AdjustmentListener |
ComponentEvent | 对象移动缩放显示隐藏 | ComponentListener |
WindowEvent | 窗口收到窗口级事件 | WindowListener |
ContainerEvent | 容器中增加或删除了组件 | ContainerListener |
TextEvent | 文本字段或文本区发生改变 | TextListener |
演示代码:
- 通过ContainerListener监听Frame容器添加组件,通过TextListener 监听Text Filed内容变化,通过ItemListener 监听Choice条目选中状态变化
- 适配器模式,避免多余实现
package com.awt.xm.event_listener;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Dem2 {
Frame frame = new Frame("测试不同的监听器");
TextField tf = new TextField(30);
Choice choice = new Choice();
public void init() {
choice.add("宫本");
choice.add("公孙离");
choice.add("鲁班大师");
//TextListener
tf.addTextListener(new TextListener() {
@Override
public void textValueChanged(TextEvent e) {
//System.out.println(e.getSource());
System.out.println("当前文本框中的内容:" + tf.getText());
}
});
//ComponentListener
frame.addContainerListener(new ContainerListener() {
@Override
public void componentAdded(ContainerEvent e) {
Component child = e.getChild();
System.out.println("frame中添加了:" + child);
}
@Override
public void componentRemoved(ContainerEvent e) {
}
});
//ItemListener
choice.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
Object item = e.getItem();
System.out.println("当前选择的条目为:" + item);
}
});
//适配器模式
//监听用户点击X的动作
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Box box = Box.createHorizontalBox();
box.add(choice);
box.add(tf);
frame.add(box);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Dem2().init();
}
}