GUI图形化界面

版权声明:仅供学习,谢谢 https://blog.csdn.net/weixin_43907332/article/details/86501613

GUI(Graphical User Interface),图形用户界面。

  1. AWT(Abstract Window Toolkit),抽象窗口工具集,第一代的 Java GUI 组件,是重量
    级的。
  2. Swing, 不依赖于底层细节,轻量级的组件

AWT

AWT 概念

GUI全程是Graphical User Interface,即图形用户界面。根据作用GUI组件可分为基本组件和容器。
组件又称构件,诸如按钮、文本框之类的图形界面元素。
容器其实是一种比较特殊的组件,可以容纳其他组件,如窗口、对话框等。
所有的容器类都是java.awt.Container的直接或间接子类。

  1. 提供了基本的GUI组件,用在所有的Java applets及应用程序中。
  2. 具有可以扩展的超类,他们的属性是继承的。
  3. 确保显示在屏幕上的每个GUI组件都是抽象类组件的子类。
  4. Container,它是Component的一个子类,而且包括两个主要子类-Panel -window
  5. AWT(Abstract Window Toolkit),抽象窗口工具包,SUN公司提供的用于图形界面编程(GUI)的类库。基本的AWT库处理用户界面元素的方法是把这些元素的创建和行为委托给每个目标平台上(Windows、Unix、Macintosh等)的本地GUI工具进行处理。例如:如果我们使用AWT在一个Java窗口中放置一个按钮,那么实际上使用的是一个具有本地外观和感觉的按钮。这样,从理论上来说,我们所编写的图形界面程序能运行在任何平台上,做到了图形界面程序的跨平台运行。

建立图形用户界面

  • Container的两个主要类型是Window和Panel
  • Window是Java.awt.Window的对象
    - Window是java.awt.Window的对象。Window是显示屏上独立的本机窗口,它独立于其他容器。
    - Window有两种形式:Frame(框架)和Dialog(对话框)。Frame和Dialog是Window的子类。Frame是一个带有标题和缩放角的窗口。对话框没有菜单条。尽管它能移动,但它不能缩放。
  • Panel是Java.awt.Panel的对象
    - Panel是Java.awt.Panel的对象。Panel包含在另一个容器中,或是在Web浏览器的窗口中。Panel确定四边形,其他组件可以放入其中。Panel必须放在Window之中(或Window的子类中)以便能显示出来
    - 注:容器不但能容纳组件,还能容纳其他容器,这一事实对于建立复杂的布局是关键的,也是基本的。

定位组件

  1. 容器里的组件的位置和大小是由布局管理器决定的。
  2. 可以通过停用布局管理器来控制组件的大小或位置。
  3. 然后必须用组件上的setLocation(),setSize(),或setBounds()来定位它们在容器里的位置
  4. 容器里的组件的位置和大小是由布局管理器决定的。容器对布局管理器的特定实例保持一个引用。当容器需要定位一个组件时,它将调用布局管理器来做。当决定一个组件的大小时,同样如此。布局管理器完全控制容器内的所有组件。它负责计算并定义上下文中对象在实际屏幕中所需的大小。

Frames

  1. 是Window的子类
  2. 具有标题和缩放角
  3. 从容器继承并以add方式添加组件
  4. 能以字符串规定的标题来创建不可见框架对象
  5. 能将BorderLayout当做缺省布局管理器
  6. 用setLayout方式来改变缺省布局管理器
  7. Frame是Window的一个子类。它是带有标题和缩放角的窗口。它继承于Java.awt.Container,因此,可以用add()方式来给框架添加组件。框架的缺省布局管理器就是Border Layout。它可以用setLayout()方式来改变。
  8. 框架类中的构造程序Frame(String)用由String规定的标题来创建一个新的不可见的框架对象。当它还处于不可见状态时,将所有组件添加到框架中。
  9. 在框架显示在屏幕上之前,必须做成可见的==(通过调用程序setVisible(true))==,而且其大小是确定的(通过调用程序setSize()或pack())
package Seventieth.Sixth;

import java.awt.*;

public class MyFrame extends Frame {
    public MyFrame(String title) {
        super(title);
    }

    public static void main(String[] args) {
        MyFrame frame = new MyFrame("First GUI app");

        frame.setSize(500, 500);
        frame.setBackground(Color.GREEN);//Color是类

        frame.setVisible(true);

    }
}

结果是:(此时点×无法关闭程序,因为我们还没有设定,我们可以手动终止java虚拟机运行)
在这里插入图片描述

Panels

  1. 为组件提供空间
  2. 允许子面板拥有自己的布局管理器
  3. 以add方法添加组件
    • 像Frames一样,Panels提供空间来连接任何GUI组件,包括其他面板。每个面板都可以有它自己的布局管理程序。
    • 一旦一个面板对象被创建,为了能看得见,它必须添加到窗口或框架对象上。用Container类中的add()方式可以做到这一点。
  4. 程序创建了一个小的黄色面板,并将她加到一个框架对象上
package Seventieth.Sixth;

import java.awt.*;

public class FrameWithPanel extends Frame {
    public FrameWithPanel(String title) {
        super(title);
    }

    public static void main(String[] args) {
        FrameWithPanel frame = new FrameWithPanel("frame with panel");

        Panel panel = new Panel();

        frame.setSize(200, 200);
        frame.setBackground(Color.BLACK);
        frame.setLayout(null);//禁止默认的布局管理器

        panel.setSize(100, 100);
        panel.setBackground(Color.YELLOW);

        frame.add(panel);

        frame.setVisible(true);
    }

}

结果是:
在这里插入图片描述

布局管理器

  1. 容器里组件的位置和大小是由布局管理器来决定的。容器对布局管理器的特定实例保持一个引用。当容器需要定位一个组件时,它将调用布局管理器来完成。当决定一个组件的大小时,也是如此。
  2. 在AWT中,给我们提供了五种布局管理器:
  3. BorderLayout,FlowLayout,GridLayout,CardLayout,GirdBagLayout
  4. 容器中组件的布局通常由布局管理器控制。每个Container(比如一个Panel或一个Frame)都有一个与它相关的缺省布局管理器,它可以通过调用setLayout()来改变
  5. 布局管理器负责决定布局方针以及其容器的每一个子组件的大小。
  6. 我们可以通过设置空布局管理器,来控制组件的大小和位置。调用setLayout(null)。
  7. 在设置空布局管理器后,必须对所有的组件调用setLocation(),setSize()或setBounds(),将它们定位在唉容器中。
    在这里插入图片描述
package Seventieth.Sixth;

import java.awt.*;

public class ExGui {
    private Frame frame;

    private Button button1;

    private Button button2;

    public void go(){
        frame = new Frame("gui example");

        frame.setLayout(new FlowLayout());//默认是BorderLayout

        button1 = new Button("Press me");
        button2 = new Button("Don't press me");

        frame.add(button1);
        frame.add(button2);

        frame.pack();//能容纳下所有组件的最小界面
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        ExGui window = new ExGui();

        window.go();
    }
}

结果是:
在这里插入图片描述

Border布局管理器

  1. Border布局管理器为在一个Panel或Window中放置组件提供一个更复杂的方案。Border布局管理器包括五个明显的区域:东、南、西、北、中。
  2. 北占据面板的上方,东占据面板的右侧,等等。中间区域是在东、南、西、北都填满后所剩下的区域。当窗口垂直延伸时,东、西、中区域也延伸;而当窗口水平延伸时,东、西、中区域也延伸。
  3. 当窗口缩放时,按钮相应的位置不变化,但其大小改变。
  4. BorderLayout是Frame类的默认布局管理器。
  5. BorderLayout将整个容器,布局划分成东、西、南、北、中五个区域,组件只能被添加到指定的区域。
  6. 如不指定组件的加入部分,则默认加入到Center区域。
  7. == 每个区域只能加入一个组件,如加入多个,则先前加入的组件会被遗弃。==
  8. BorderLayout型布局容器尺寸缩放原则
    - 北、南两个区域只能在水平方向缩放(宽度可调整)
    - 东、西两个区域只能在垂直方向缩放(高度可调整)
    - 中部可在两个方向上缩放
    - 在这里插入图片描述
  9. 布局管理器给予南、北组件最佳高度,并强迫它们与容器一样宽。但对于东、西组件,给予最佳宽度,而高度受到限制。
package Seventieth.Eighth;

import java.awt.*;

public class ExGui2 {
    private Frame frame;
    private Button bn, bs, bw, be, bc;

    public void go(){
        frame = new Frame("Border Layout");

        bn = new Button("B1");
        bs = new Button("B2");
        bw = new Button("B3");
        be = new Button("B4");
        bc = new Button("B5");

         frame.add(bn, BorderLayout.NORTH);
        frame.add(bs, BorderLayout.SOUTH);
        frame.add(bw, BorderLayout.WEST);
        frame.add(be, BorderLayout.EAST);
        frame.add(bc, BorderLayout.CENTER);


        frame.setSize(200, 200);
        frame.setVisible(true);

    }

    public static void main(String[] args) {
        ExGui2 gui = new ExGui2();

        gui.go();
    }
}

结果是:
在这里插入图片描述
如果把frame.add(bn, BorderLayout.NORTH);注释掉
结果是:
在这里插入图片描述

Flow布局管理器

  1. 与其他布局管理器不一样,Flow布局管理器不限制它所管理的组建的额大小,而是允许他们有自己的最佳大小。
  2. 默认是居中放置组件
  3. 如果想在组件之间创建一个更大的最小间隔,可以规定一个界限。
  4. 当用户对由Flow布局管理的区域进行缩放时,布局就发生变化
  5. 下面的例子就是如何用类容器的setLayout()方法来创建Flow布局对象并安装他们
setLayout(new FlowLayout(int align,int hgap,int vgap));
对齐的值必须是FlowLayout.LEFT,FlowLayout.RIGHT,或FlowLayout.CENTER
例如:
setLayout(new FlowLayout(FlowLayout.RIGHT, 20, 40));

new FlowLayout(FlowLayout.RIGHT, 20, 40)右对齐,组件之间水平间距20个像素,竖直间距40个像素;
new FlowLayout(FlowLayout.LEFT);左对齐,水平和竖直间距为缺省值:5;
new FlowLayout();使用缺省的居中对齐方式,水平和竖直间距为缺省值:5;

package Seventieth.Eighth;

import java.awt.*;

public class MyFlow {
    private Frame frame;
    private Button button1, button2, button3;

    public void go(){
        frame = new Frame("Flow Layout");
        //使用FlowLayout替换掉默认的BorderLayout布局管理器
        frame.setLayout(new FlowLayout());

        button1 = new Button("hello");
        button2 = new Button("world");
        button3 = new Button("welcome");

        frame.add(button1);
        frame.add(button2);
        frame.add(button3);

        frame.setSize(100, 100);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        MyFlow flow = new MyFlow();

        flow.go();
    }
}

结果是:
在这里插入图片描述
在这里插入图片描述

Grid布局管理器

  1. Grid布局管理器为放置组件提供了灵活性。用许多行和栏来创建管理程序。然后组件就填充到由管理程序规定的单元中。
  2. 比如,由语句new GridLayout(3,2)创建的有三行两栏的Grid布局能产生六个单元。
  3. Grid布局管理器总是忽略组建的最佳大小。所有单元的宽度是相同的,是根据单元数对可用宽度进行平分而定的。同样地,所有单元的高度是相同的,是根据行数对可用高度进行平分而定的。
  4. 将组件添加到网格中的命令决定它们占有的单元。单元的行数是从左到右填充,就像文本一样,而列是从上到下由行填充。
package Seventieth.Eighth;

import java.awt.*;

public class GridEx {
    private Frame frame;
    private Button b1, b2, b3, b4, b5, b6;

    public void go(){
        frame = new Frame("Grid Layout");

        frame.setLayout(new GridLayout(3, 2));

        b1 = new Button("1");
        b2 = new Button("2");
        b3 = new Button("3");
        b4 = new Button("4");
        b5 = new Button("5");
        b6 = new Button("6");

        frame.add(b1);
        frame.add(b2);
        frame.add(b3);
        frame.add(b4);
        frame.add(b5);
        frame.add(b6);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        GridEx grid = new GridEx();
        grid.go();
    }
}

结果是:
在这里插入图片描述
如果将最后一个按钮注释掉。
结果是:
在这里插入图片描述

Card布局管理器

  1. Card布局管理器能将界面看作一系列的卡,其中的一个在任何时候都可见。用add()方法来将卡添加到Card布局中。Card布局管理器的show()方法应请求转换到一个新卡中。

GridBag布局管理器

  1. 除了Flow、Border、Grid和Card布局管理器外,核心Java.awt也提供GridBag布局管理器
  2. GridBag布局管理器在网格的基础上提供复杂的布局,但它允许单个组件在一个单元中而不是填满整个单元那样地占用它们的最佳大小。网格包布局管理器也允许单个组件扩展成不止一个单元。

创建面板及复杂布局

是两个布局管理器的综合使用

public class ExGui3 {
    private Frame frame;
    private Panel panel;
    private Button b1, b2, b3, b4;

    public void go(){
        frame = new Frame("complex layout");

        b1 = new Button("West");
        b2 = new Button("hello");

        frame.add(b1, BorderLayout.WEST);
        frame.add(b2, BorderLayout.CENTER);

        panel = new Panel();

        b3 = new Button("world");
        b4 = new Button("welcome");

        panel.add(b3);
        panel.add(b4);

        frame.add(panel, BorderLayout.NORTH);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        ExGui3 exGui3 = new ExGui3();
        exGui3.go();
    }

}

结果是:
在这里插入图片描述

布局管理器总结

Frame

  1. Frame是一个顶级窗口。
  2. Frame的缺省布局管理器为BorderLayout。

Panel

  1. Panel无法单独显示,必须添加到某个容器中。
  2. Panel的缺省布局管理器为FlowLayout。
  3. 当把Panel作为一个组件添加到某个容器中后,该Panel仍然可以有自己的布局管理器。因此,可以利用Panel使得BorderLayout中某个区域显示多个组件。

注意

在程序中安排组件的位置和大小时,应注意:

  • 容器中的布局管理器负责各个组建的额大小和位置,因此用户无法在这种情况下设置组件的这些属性。如果试图使用Java语言提供的setLocation(),setSize(),stBounds()等方法,则都会被布局管理器覆盖。
  • 如果用户确实需要亲自设置组件大小或位置,则应取消该容器的布局管理器,方法为:setLayout(null);

AWT事件模型

什么是事件

  1. 事件——描述发生了什么的对象
  2. 事件源——事件的产生器
  3. 时间处理器——接受事件、解释事件并处理用户交互的方法
  4. 如果用户在用户界面层执行了一个动作(鼠标点击和按键),这将导致一个事件的发生。==事件是描述发生了什么的对象。==存在各种不同类型的事件类用来描述各种类型的用户交互。

事件源

事件源是一个事件的产生者。例如,在Button组件上点击鼠标会产生以这个Button为源的一个ActionEvent。这个ActionEvent实例是一个对象,它包含关于刚才所发生的那个事件的信息的对象,这些信息包括:

  • getActiongCommand——返回与动作相关联的 命令名称
  • getWhen——返回事件发生的时间

事件处理器

  • 时间处理器就是一个接受事件、解释事件并处理用户交互的方法

JDK1.0的事件模型:层次模型

在这里插入图片描述
当一个事件发生了,先交给Button看看是否能够处理,如果不能交给Panel,如果还不能交给Frame,如果都不处理,最后这个事件就不处理,这种模型早已被废弃,因为关系乱,一个事件谁都可以处理,没有一个准确的事件处理器

JDK1.1的事件模型:委托模型

**事件监听器:**实现了监听器接口的类。一个监听对象是一个实现了专门的监听器接口的类的实例。
在这里插入图片描述
点击Button后触发事件,自动调用他的方法,并不会往上提交给Panel或Frame,如果没有关联的方法就什么都不做。
优点:- 事件不会被意外地处理。
- 有可能创建并使用适配器(adapter)类对事件动作进行分类。
- 委托模型有利于把工作分布到各个类中

  1. 在Button对象上用鼠标进行点击时,将发送一个ActionEvent事件。这个ActionEvent事件会被使用addActionListener()方法进行注册的所有ActionListener的actionPerformed()方法接受
  2. ActionEvent类的getActionCommand()方法返回与动作相关联的命令名称。
  3. 以按钮的点击动作为例,将返回Button的标签。
package Seventieth.Nineth;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TestButton {
    public static void main(String[] args) {
        Frame frame = new Frame("Test Button");

        Button button = new Button("Press Me!");

        //增加事件处理器
        button.addActionListener(new ButtonHandler());

        /**
         * public void addActionListener(ActionListener l)
         * ActionListener是一个接口所有我们要写个类继承这个接口
         * void actionPerformed(ActionEvent e)
         * Invoked when an action occurs.
         * 重写这个接口中的方法
         */

        frame.add(button, BorderLayout.CENTER);

        frame.pack();//将窗口缩到最小
        frame.setVisible(true);
    }
}

class ButtonHandler implements ActionListener{
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button is pressed!");
    }
}

结果是:
在这里插入图片描述
当我点击按钮会输出Button is pressed!

  1. 当单机一个按钮时 就会产生一个事件(ActionEvent),然后检查是否有与该按钮关联的事件处理器(实际上就是一个方法),如果没有,那么什么都不执行;如果有,就会将该事件传递给与该按钮关联的事件处理器方法,作为该方法的参数,之后***该事件处理器方法就会自动得到调用***,并且该方法可以使用传递过来的ActionEvent对象,进而获得事件发生时与该事件及事件源相关联的那些信息。
  2. Java中的组件若想添加事件处理器,都会使用形如addXxxListenr的方法来添加。

AWT事件处理

在这里插入图片描述

图形用户界面的行为

  1. 事件类型
    1. 许多事件类在java.awt.event包中,也有一些事件类在API的其他地方
    2. 对于每类事件,都有一个接口,这个接口必须由想接受这个事件的类的对象实现。这个接口还要求定义一个或多个方法。当发生特定的事件时,就会调用这些方法
package Seventieth.Tenth;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.Date;

public class MyFrame2 {
    public static void main(String[] args) {
        Frame frame = new Frame("My Frame2");
        Button button = new Button("click me");

        button.addActionListener(new MyListener());
        frame.addWindowListener(new MyWindowListener());

        frame.add(button);
        frame.setSize(500, 500);
        frame.setVisible(true);
    }
}

class MyListener implements ActionListener {
    @Override
    @SuppressWarnings("deprecation")
    public void actionPerformed(ActionEvent e){
        long milliSeconds = e.getWhen();

        Date date = new Date(milliSeconds);

        System.out.println(date.toLocaleString());
    }
}

class MyWindowListener implements WindowListener{
    @Override
    public void windowOpened(WindowEvent e) {

    }

    @Override
    public void windowClosing(WindowEvent e) {

        System.out.println("关闭窗口");
        System.exit(0);
    }

    @Override
    public void windowClosed(WindowEvent e) {

    }

    @Override
    public void windowIconified(WindowEvent e) {

    }

    @Override
    public void windowDeiconified(WindowEvent e) {

    }

    @Override
    public void windowActivated(WindowEvent e) {

    }

    @Override
    public void windowDeactivated(WindowEvent e) {

    }
}

结果是:
在这里插入图片描述
2019-1-17 9:52:49
2019-1-17 9:52:52
关闭窗口

多监听者

多个监听者可以使一个程序的不相关部分执行同样的动作
事件发生时,所有被注册的监听者的处理器都会被调用

package Seventieth.Tenth;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class TwoListen implements MouseMotionListener, MouseListener {
    private Frame frame;
    private TextField textField;

    public void go(){
        frame = new Frame("Two Listeners Example");

        frame.add(new Label("click"), BorderLayout.NORTH);
        frame.addMouseMotionListener(this);
        frame.addMouseListener(this);

        frame.addMouseListener(new MyMouseListener());//对一个事件源可以注册多个监听器并且都会执行

        textField = new TextField(30);

        frame.add(textField, BorderLayout.SOUTH);

        frame.setSize(300, 200);

        frame.setVisible(true);
    }

    @Override
    public void mouseClicked(MouseEvent e) {

    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {//鼠标离开Frame

        String string = "The mouse has left the Frame";
        this.textField.setText(string);
    }

    @Override
    public void mouseDragged(MouseEvent e) {//鼠标拖拽

        String string = "x:" + e.getX() + ",y" + e.getY();
        this.textField.setText(string);

    }

    @Override
    public void mouseMoved(MouseEvent e) {

    }

    public static void main(String[] args) {
        TwoListen twoListen = new TwoListen();
        twoListen.go();
    }
}

class MyMouseListener implements MouseListener{
    @Override
    public void mouseClicked(MouseEvent e) {

    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {//鼠标进入Frame
        String string = "The Mouse has entered the Frame";
        System.out.println(string);

    }

    @Override
    public void mouseExited(MouseEvent e) {
        String str = "The mouse has exited the Frame";

        System.out.println(str);
    }
}

结果是:
在这里插入图片描述
The Mouse has entered the Frame
The mouse has exited the Frame
The Mouse has entered the Frame
The mouse has exited the Frame

事件Adapters(适配器)

  1. 你定义的Listener可以继承Adapter类,而且只需重写你所需要的方法
  2. 为了方便起见,Java语言提供了Adapters类,用来实现含有多个方法的类。这些Adapters类中的方法是空的。
  3. 你可以继承Adapters类,而且只需重写你所需要的方法
package GUI;

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class TwoListenAdapter {
    private Frame frame;
    private TextField textField;

    public void go() {

        frame = new Frame("Two Listeners Example");

        frame.add(new Label("click"), BorderLayout.NORTH);

        textField = new TextField(30);
        

        frame.add(textField, BorderLayout.SOUTH);
        frame.addMouseListener(new MyAdapter());

        frame.setSize(300, 200);

        frame.setVisible(true);

    }
    public static void main(String[] args) {
        TwoListenAdapter twoListen = new TwoListenAdapter();
        twoListen.go();
    }
}

class MyAdapter extends MouseAdapter{//把MouseListener中的方法全部空实现
    //这样我们可以抽取自己需要的重写的方法
    @Override
    public void mouseEntered(MouseEvent e) {//鼠标进入Frame
        String string = "The Mouse has entered the Frame";
        System.out.println(string);

    }

    @Override
    public void mouseExited(MouseEvent e) {
        String str = "The mouse has exited the Frame";

        System.out.println(str);
    }
}

结果是:
在这里插入图片描述
The Mouse has entered the Frame
The mouse has exited the Frame
The Mouse has entered the Frame
The mouse has exited the Frame
The Mouse has entered the Frame
The mouse has exited the Frame
4. 为了简化编程,JDK针对大多数事件监听器接口定义了相应的实现类,我们称之为事件适配器(Adapter)类
在适配器类中,实现了相应监听器接口所有方法,但不做任何事情,只要继承适配器类,就等于实现了响应的监听器接口
如果要对某类事件的某种情况进行处理,只要覆盖相应的方法就可以,其他的方法再也不用“简单实现”了
如果想作事件监听器的类已经继承了别的类,就不能再继承适配器类了,只能去实现事件监听器接口了。

猜你喜欢

转载自blog.csdn.net/weixin_43907332/article/details/86501613