Java笔记-Topic 18 GUI
GUI是什么
GUI
GUI:通过文本、图像和“小部件”与计算机进行交互的方法
- GUI展示视觉元素,比如按钮、图标、窗口等等。
- 支持GUI的OS:MAC OS, Microsoft Windows
- 引入GUI是为了解决一些基于文本的用户界面(又称:cli,命令行界面)的问题,通常cli都需要输入很长的命令字
- Widgets: 指那些可以放进窗口里的东西,比如按钮
当进行GUI编程的时候,有三个主要的概念:
- Component组件: 用户可以在界面上看到并与之交互的对象
- Container容器:可以容纳其他组件的组件
- Event事件: 用户触发的动作,例如按下一个键或者点击一个鼠标按钮
设计GUI涉及到创造组件、将它们放入容器中,并安排程序响应事件
(比如通过鼠标点击响应事件)
创建GUI(javax.swing里面的JFrame和JButton)
java.awt 和 javax.swing
历史上的 java.awt问题:需要运行时对等资源
- 在有些平台上运行较慢(比如,Windows)
- 可移植性问题(外观和行为上的稍微的不同)
为什么javax.swing更好:
- 更有效的利用资源,轻量级的组件确实要比重量级的组件“更加轻便”
- 跨平台的一致性更高,因为Swing完全是Java编写的
- 更清晰的外观和感觉集成,因为可以使用swing实现一组组件提供匹配的外观和感觉
一些背景知识:java.awt包
java.awt包包含了在java里创建GUI应用和Applets要用到的大部分的类
AWT包中有超过40个类,可按如下基本分类:
- 容器类:能够包含其他图形组件的图形组件,比如面板、窗口、对话框和框架
- 组件类:原子图形组件,比如按钮、菜单和列表
- 布局管理器类:控制容器对象里或者容器对象上的组件对象的布局
此外AWT包中还有一些更通用的类:
- 基本图形类:控制和访问基本图形,比如点、矩形、多边形
- 事件处理类:处理从GUI和其他系统项目接受到的事件
- 事件监听类:从图形组件中接收事件并且对其进行操作
第一个GUI
创建一个GUI的步骤:
- 创建框架:创建一个JFrame的对象
JFrame myFrame = new JButton("Click me");
- 创建组件(比如创建一个按钮或者一个文本域)
JButton myButton = new JButton("Click me !");
- 将组件添加到框架里
myFrame.getContentPane().add(myButton);
此处补充:getContentPane()到底是什么
在 awt 中
Frame f = new Frame();
Button b = new Button();
f.add( b );
在 swing 中
JFrame jf = new JFrame();
JButton jb = new JButton();
jf.getContentPane().add( jb );
转载于: https://www.cnblogs.com/kanego/archive/2011/04/25/2027204.html
- 展示框架:必须给定框架大小和可见性
myFrame.setSize(100,100);
myFrame.setVisible(true);
【Example: 简单的GUI】
import javax.swing.*;
public class SimpleGui {
public static void main(String[] args) {
//1. 创建框架
JFrame myFrame = new JFrame();
// 2. 创建组件
JButton myButton = new JButton("Click me");
// 设置框架的关闭操作
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 3. 将组件添加到框架里
myFrame.getContentPane().add(myButton);
// 4. 设置框架的大小和可视性
myFrame.setSize(500,200);
myFrame.setVisible(true);
}
}
容器和组件
组件Components: 没有包容能力的单个实体
容器Containers: 能够包含其他组件对象的对象
组件和容器都是抽象类!!!
填充的方框是组件,他们可以是屏幕上的按钮,组件没有嵌套。
容器的事例
顶级容器(top-level container):每个swing里的应用程序必须至少有一个这样的容器
比如,JFrame,JDialog
通用容器(general-purpose container): 能够在大多数Swing的应用里找到
比如,JPanel,JScrollPane
框架:最常用的容器之一
框架:是一个有边框(border)、标题栏(title bar)或者可能有菜单栏(menu bar)的简单的可调整大小的窗口
- 你可以在你的程序里extend Frame(常用),或者通过在你自己的类里初始化Frame类(不常用)来建立一个基本的GUI
- 框架默认:初始的size为0;初始的可视性为false(不可视)
- 构造器里有:
setSize(int,int);
setVisible(boolean);
- 要改变框架的标题栏里的文本,可以使用方法setTitle(String);
【Example:使用java.awt包】
import java.awt.Frame;
public class FrameDemo extends Frame {
public FrameDemo() {
this.setTitle("EBU4201 Demo Frame");
this.setSize(250,100);
this.setVisible(true);
}
public static void main(String[] args) {
FrameDemo myFrame = new FrameDemo();
}
}
使用了java.awt包里的Frame,创建了一个简单的框架
【Example:使用javax.swing包】
import javax.swing.JFrame;
public class FrameDemo extends JFrame {
public FrameDemo() {
this.setTitle("EBU4201 Demo Frame");
this.setSize(250,100);
this.setVisible(true);
}
public static void main(String[] args) {
FrameDemo myFrame = new FrameDemo();
}
}
值得注意的是,在java.awt包里面 是Frame类;在javax.swing包里面是JFrame类
组件的事例
基本的Swing组件:通常由于得到用户的输入
有JButton、JRadioButton、JList、JCheckBox、JTextField
在Java API中的容器和组件的位置
【Practice Exercise 1】
// 引入了JPanel和Graphics
import javax.swing.JPanel;
import java.awt.Graphics;
public class DrawMessage extends JPanel {
// 此处 覆盖了JPanel里的方法paintComponet()
protected void paintComponet(Graphics g) {
super.paintComponent(g);
g.drawString("Welcome to Java", 20, 20);
}
}
import javax.swing.JFrame;
public class TestDrawMessage extends JFrame{
public TestDrawMessage() {
getContentPane().add(new DrawMessage());
}
public static void main(String[] args) {
JFrame frame = new TestDrawMessage();
frame.setSize(100, 200);
frame.setVisible(true);
}
}
事件和用户交互的处理
Java和事件驱动编程
当程序接受到某些特定的信号的时候就会触发事件(event)
事件是由外部用户行为产生的,比如敲击一个字符或者点击鼠标或者移动鼠标;或者是操作系统产生的,比如计时器的运行
事件处理:得到并处理用户事件的过程
其他的事件的举例
(笔记图)
在GUI里做一些操作
比如:When I click on the button, change the button text.
其中加粗的对应的就是:动作action——源source——事件event(传递信号)
需要知道的:
- 哪个用户的动作引起了改变
- 对应的组件是什么
- 什么事件作为这个动作的结果 需要出现
事件 & 源 & 监听器
每个事件都要有监听器和源
监听器接口(Listener Interface) :监听器(用户代码)和事件源(比如按钮)之间的桥梁
- 实现一个监听器接口就是给一个按钮调回用户代码的方法
事件源(event source):可以把用户的行为转化为事件的对象
每种不同的事件都要有相匹配对应的监听器接口,比如,对于鼠标事件(MouseEvents),你需要实现鼠标监听器接口(MouseListener interface); 再者,必须提供相关方法的补充.
编写事件处理程序
每个事件处理器(event handler)(比如,处理得到按钮的行为事件)需要三种代码(三个步骤):
- 实现/继承 行为监听器接口 (ActionListener)
在事件处理器这个类的声明里,要么实现一个监听器接口,要么继承一个实现了监听器接口的类
public class MyClass implements ActionListener {...}
- 注册组件 : 是一段表示你的程序希望监听事件的代码,通过将事件处理类的实例注册为一个或者多个组件上的监听器来实现。
someComponent.addActionListener(instanceOfMyclass);
- 定义事件处理方法:在监听器界面实现方法的代码
public void actionPerformed(ActionEvent e) {
// code that reacts to the action
}
(一张图说明这个过程)(可视解释)
【Example :Event Handler 事件处理器】
import javax.swing.*;
import java.awt.event.*;
// 第一步:继承ActionListener接口
public class AnotherSimpleGui implements ActionListener{
JButton myButton;
public static void main(String[] args) {
AnotherSimpleGui myGui = new AnotherSimpleGui();
myGui.go();
}
public void go() {
JFrame myFrame = new JFrame();
this.myButton = new JButton("Click me");
// 第二步:告诉按钮希望他监听这个事件
this.myButton.addActionListener(this);
myFrame.add(myButton);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setSize(500,200);
myFrame.setVisible(true);
}
// 第三步:实现监听器里面(ActionListener接口里面)的方法让它来处理事件
public void actionPerformed(ActionEvent enent) {
System.out.println("I've been clicked!");
}
}
注意:一定要在开头除了swing以外引入awt包里的event
其他的事件:鼠标事件
两个图
Practice Exercise 2
JLable 和JButton 类
JLable类:你可以将文本放入的组件
- 当创建一个label的时候你可以指定初始值和你希望放入标签里的内容
JLabel myLabel = new JLabel("text", JLabel.RIGHT);
- 可以使用getText()和setText()来得到或者改变label里面的值。
JButton类:继承自Component, 展示一个字符串,并为每次鼠标点击发送一个ActionEvent
- 按钮通常有边框显示
- 除了文本,JButton还可以显示图标
JButton myButton = new JButton("text");
组件 容器 和布局管理器
布局管理器(Layout Manager): 一个接口,他定义了在容器内定义和调整对象大小的方法。
- Java定义了几种默认的布局管理器的执行
- 一个容器里的几何放置是由LayoutManager对象来管理的
容器里可能含有别的组件,所以容器能够包含容器。
- 所有的容器都配备了一个布局管理器来定位和塑形(布局)容器里的组件
- AWT里面的许多动作发生在容器、组件和他们的布局管理器之间
管理GUI布局
布局管理器
布局允许你以独立的方式在屏幕上格式化组件
布局管理器定义在java.awt包里
标准JDK提供了五个继承LayoutManager接口的类:
- 流式布局 FlowLayout
- GridLayout
- BorderLayout
- CardLayout
- GridBagLayout
(后两项先暂不讨论)
改变布局
改变容器里布局的方法:
- 创建布局
- 在容器内调用setLayout()方法来使用新的布局
JPanel p = new JPanel();
p.setLayout(new FlowLayout());
- 或者同时执行前两个方法
JPanel p = new JPanel(new FlowLayout());
布局管理器需要在任何组件被添加到容器之前创建
流式布局 FlowLayout
FlowLayout是JPanel类的默认布局
- 当你在屏幕上添加组件的时候,根据添加的顺序和屏幕的宽度,组件从左到右(居中)流动
- 与文字处理器的自动换行和完全对齐相似
- 如果屏幕调整大小,组件的流动将会根据新的宽度和高度变化
构造器:
- FlowLayout()
- FlowLayout(int aliagn)
- FlowLayout(int align, int hgap, int vgap)
【Example:使用FlowLayout】
import javax.swing.*;
import java.awt.FlowLayout;
public class FlowLayoutDemo extends JFrame {
public FlowLayoutDemo(String title, int num) {
// 加标题
this.setTitle(title);
// 设置布局方式是流式布局
this.getContentPane().setLayout(new FlowLayout());
for(int i = 0; i<num; i++) {
JButton button = new JButton(""+i);
this.getContentPane().add(button);
// 创建按钮并且把按钮加到面板上
}
}
public static void main(String[] args) {
FlowLayoutDemo frame = new FlowLayoutDemo("My Demo", 10);
frame.setVisible(true);
frame.setSize(500,200);
// frame.pack();
}
}
呈现效果就是居中,哪怕调整了宽度和高度,也会时刻保持居中状态
GridLayout
GridLayout按照行或者列的顺序排列组件
- 如果每行个数是确定的,列的个数会是组件总数除以行的个数
- 如果每列个数是确定的,行的个数会是组件总数除以行的个数
- 添加组件的顺序是相关的
构造器:
- GridLayout(): 默认每个组件在单行里有一列
- GridLayout(int rows, int cols):
- GridLayout(int rows, int cols, int hgap, int vgap)
【Example:使用GridLayout】
BorderLayout
BorderLayout提供了五个存放组件的区域
- 他们以屏幕的四种不同的边界来命名,东西南北中(North, South, West, East, Center)
- 要添加一个组件,必须先指明要在哪个区域放置他
- 组件创建的顺序并不重要
- 北方和南方部分可以垂直拉伸
- center组件可以水平和垂直拉伸以填补任何剩余的空间
构造器:
- BorderLayout(): 默认,每个组件之间没有空隙
- BorderLayout(int hgap, int vgap)
怎样向框架里面添加一个按钮?
myFrame.getContentPane().add(myButton);
或者
myFrame.getContentPane().add(BorderLayout.CENTER, myButton);
【Example:使用BorderLayout】
import javax.swing.*;
import java.awt.*;
public class BorderLayoutDemo extends JFrame {
public BorderLayoutDemo() {
// 起标题 获取容器 给容器设置为BorderLayout布局模式
setTitle("BorderLayoutDemo");
Container content = getContentPane();
content.setLayout(new BorderLayout());
// 在不同的位置上添加按钮
content.add(BorderLayout.NORTH, new JButton("North"));
content.add(BorderLayout.SOUTH, new JButton("South"));
content.add(BorderLayout.EAST, new JButton("East"));
content.add(BorderLayout.WEST, new JButton("West"));
content.add(BorderLayout.SOUTH, new JButton("South 2"));
content.add(BorderLayout.CENTER, new JButton("Center"));
}
public static void main(String[] args) {
BorderLayoutDemo frame = new BorderLayoutDemo();
frame.pack();
frame.setVisible(true);
}
}
注意:South 2 会覆盖掉 South