[Java][图形程序设计Swing][学习笔记]

举报
John2021 发表于 2022/02/20 07:05:16 2022/02/20
【摘要】 很多人印象中Java编写的程序都是通过键盘接收输入,在控制台屏幕上显示结果。其实Java还可以编写使用图形用户界面(GUI) 的程序,今天就为大家介绍一下Java的图形界面-Swing。 1,Swing 概述在 Java 1.0 刚刚出现的时候,包含了一个用于基本 GUI 程序设计的类库,Sun将它称为抽象窗口工具箱( Abstract Window Toolkit, AWT)。基本AWT库...

很多人印象中Java编写的程序都是通过键盘接收输入,在控制台屏幕上显示结果。其实Java还可以编写使用图形用户界面(GUI) 的程序,今天就为大家介绍一下Java的图形界面-Swing。

1,Swing 概述

  • 在 Java 1.0 刚刚出现的时候,包含了一个用于基本 GUI 程序设计的类库,Sun将它称为抽象窗口工具箱( Abstract Window Toolkit, AWT)。基本AWT库采用将处理用户界面元素的任务委派给每个目标平台( Windows、Solaris、 Macintosh 等)的本地 GUI 工具箱的方式,由本地 GUI 工具箱负责用户界面元素的创建和动作。因此,Sun 公司的口号是“ 一次编写,随处使用”。
  • 但此方法在不同平台上,操作会存在差异。要想给予用户一致的、 可预见性的界面操作方式是相当困难的。在不同平台上的 AWT 用户界面库中存在着不同的 bug。研发人员必须在每一个平号上测试应用程序, 因此人们嘲弄地将 AWT 称为“ 一次编写, 随处调试”。
  • 在 1996 年,Netscape 创建了一种称为 IFC ( Internet Foundation Class) 的 GUI 库, 它采用了与 AWT 完全不同的工作方式。它将按钮、菜单这样的用户界面元素绘制在空白窗口上,而对等体只需要创建和绘制窗口。因此,Netscape 的 IFC 组件在程序运行的所有平台上的外观和动作都一样。Sun 与 Netscape 合作完善了这种方式, 创建了一个名为 Swing 的用户界面库。
  • 注意:Swing 没有完全替代 AWT, 而是基于 AWT 架构之上。Swing 仅仅提供了能力更加强大的用户界面组件。 尤其在采用 Swing 编写的程序中,还需要使用基本的 AWT 处理事件。可以理解为:Swing 是指 “ 被绘制的” 用户界面类;AWT 是指像事件处理这样的窗口工具箱的底层机制。
  • Swing的优势主要有:
    1. Swing 拥有一个丰富、 便捷的用户界面元素集合。
    2. Swing 对底层平台依赖的很少,因此与平台相关的 bug 很少。
    3. Swing 给予不同平台的用户一致的感觉。

2,创建框架

  • 在 Java 中,顶层窗口(就是没有包含在其他窗口中的窗口)被称为框架(frame)。在 AWT 库中有一个称为 Frame 的类, 用于描述顶层窗口。这个类的 Swing 版本名为 JFrame,它扩展于 Frame 类。JFrame是极少数几个不绘制在画布上的Swing组件之一。因此,它的修改部件(按钮、标题栏、图标等)由用户的窗口系统绘制,而不是由Swing绘制。
  • 本节中将介绍有关Swing的JFrame的常用方法。以下例子是给出了一个在屏幕中显示一个空框架的简单程序。

import javax.swing.*;
import java.awt.*;

public class SimpleFrameTest
{
    public static void main(String[] args)
    {
        EventQueue.invokeLater(() ->
        {
            SimpleFrame frame = new SimpleFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        });
    }
}

class SimpleFrame extends JFrame
{
    private static final int DEFAULT_WIDTH = 300;
    private static final int DEFAULT_HEIGHT = 200;

    public SimpleFrame()
    {
        setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
    }
}
  • Swing类位于javax.swing包中。包名javax表示这是一个Java扩展包,而不是核心包。
  • 默认情况下,框架的大小为0×0像素,这种框架没有什么实际意义。这里定义了一个子类SimpleFrame,它的构造器将框架大小设置为300×200像素。这是SimpleFrame和JFrame之间唯一的差别。
  • 在SimpleFrameTest类的main方法,我们构造了一个SimpleFrame对象使它可见。
  • 在每个Swing程序中,有两个技术问题需要强调
  • 1,所有的Swing组件必须由事件分派线程(event dispatch thread)进行配置,线程将鼠标点击和按钮控制转移到用户接口组件。下面的代码片段是事件分派线程中的执行代码:
EventQueue.invokeLater(()->
{
    statements
});
  • 2,定义一个用户关闭这个框架时的响应动作。对于这个程序而言,只让程序简单退出即可。选择这个响应动作的语句是:frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);,在包含多个框架的程序中,不能在用户关闭其中的一个框架时就让程序退出。在默认情况下,用户关闭窗口时只是将框架隐藏起来,而程序并没有终止。框架起初是不可见的,为了显示框架,main方法需要调用框架的setVisible()方法。
  • 在初始化语句结束后,main方法退出。需要注意,退出main并没有终止程序,终止的只是主线程。事件分派线程保持程序处于激活状态,知道关闭框架或调用System.exit方法终止程序。

3,框架定位

  • JFrame类本身只包含若干个改变框架外观的方法。当然,通过继承,从JFrame的各个超类中继承了许多用于处理框架大小和位置的方法。其中最重要的有下面几个:

    • setLocation和setBounds方法用于设置框架的位置。
    • setIconImage用于告诉窗口系统在标题栏、任务切换窗口等位置显示哪个图标。
    • setTitle用于改变标题栏的文字。
    • setResizable利用一个boolean值确定框架的大小是否允许用户改变。
  • AWT和Swing中框架和组件类的继承层次

3.1,框架属性

  • 组件类的很多方法是以获取/设置方法对形式出现的,这样的一个获取/设置方法对被称为一种属性。属性包含属性名和类型。将get或set之后的第一个字母改为小写字母就可以得到相应的属性名。
  • 针对get/set约定有一个例外:对于类型为boolean的属性,获取方法由is开头。

3.2,确定合适的框架大小

  • 要记住:如果没有明确地指定框架的大小,所有框架的默认值为0×0像素。

API:java.awt.Component 1.0

  • boolean isVisible()
  • void setVisible(boolean b)
    • 获取或设置visible属性。组件最初是可见的,但JFrame这样的顶层组件例外。
  • void setSize(int width,int height) 1.1
    • 使用给定的宽度和高度,重新设置组件的大小。
  • void setLocation(int x,int y) 1.1
    • 将组件移到一个新的位置上。如果这个组件不是顶层组件,x和y左边(或者p.x和p.y)是容器坐标;否则是屏幕坐标(例如:JFrame)
  • void setBounds(int x,int y,int width,int height) 1.1
    • 移动并重新设置组件的大小
  • Dimension getSize() 1.1
  • void setSize(Dimension d) 1.1
    • 获取或设置当前组件的size属性

API:java.awt.Window 1.0

  • void toFront()
    • 将这个窗口显示在其他窗口前面 — void toBack()
    • 将这个窗口移到桌面窗口栈的后面,并相应地重新排列所有的可见窗口。
  • boolean isLocationByPlatform() 5.0
  • void setLocationByPlatform(boolean b) 5.0
    • 获取或设置locationByPlatform属性。这个属性在窗口显示之前被设置,由平台选择一个合适的位置。

API:java.awt.Frame 1.0

  • boolean isResizable()
  • void setResizable(boolean b)
    • 获取或设置resizable属性。这个属性设置后,用户可以重新设置框架的大小。
  • String getTitle()
  • void setTitle(String s)
    • 获取或设置title属性,这个属性确定框架标题栏中的文字
  • Image getIconImage()
  • void setIconImage(Image image)
    • 获取或设置iconImage属性,这个属性确定框架的图标。窗口系统可能会将图标作为框架装饰或其他部位的一部分显示。
  • boolean isUndecorated() 1.4
  • void setUndecorated(boolean b) 1.4
    • 获取或设置undecorated属性。这个属性设置后,框架显示中将没有标题栏或关闭按钮这样的装饰。在框架显示之前,必须调用这个方法。
  • int getExtendedState() 1.4
  • void setExtendedState(int state) 1.4
    • 获取或设置窗口状态。状态是下列值之一。
    • Frame.NORMAL
    • Frame.ICONIFIED
    • Frame.MAXIMINZED_HORIZ
    • Frame.MAXIMIZED_VERT
    • Frame.MAXIMIZED_BOTH

API:java.awt.Toolkit 1.0

  • static Toolkit getDefaultToolkit()
    • 返回默认的工具箱
  • Dimension getScreenSize()
    • 返回用户屏幕的尺寸

API:javax.swing.ImageIcon 1.2

  • ImageIcon(String filename)
    • 构造一个图标,其图像存储在一个文件中
  • Image getImage()
    • 获得该图标的图像

6,使用颜色

  • Color类用于定义颜色。在java.awt.Color类中提供了13个预定义的常量,它们分别表示13种标准颜色

    • BLACK,BLUE,CYAN,DARK_GRAY,GRAY,GREEN,LIGHT_GRAY,MAGENTA,ORANGE,PINK,RED,WHITE,YELLOW
  • 可以通过提供红、绿、蓝三色成分创建一个Color对象,以达到定制颜色的目的。三种颜色都是用0-255(也就是一个字节)之间的整型数值表示,调用Color的构造器格式为:Color(int redness,int greenness,int blueness)

API:java.awt.Color 1.0

  • Color(int r,int g,int b)
    • 创建一个颜色对象
    • 参数:r 红色值(0-255)
    • 参数:g 绿色值(0-255)
    • 参数:b 蓝色值(0-255)

API:java.awt.Graphics 1.0

  • Color getColor()
  • void setColor(Color c)
    • 获取或改变当前的颜色。所有后续的绘图操作都使用这个新颜色
    • 参数:c 新颜色

API:java.awt.Graphics2D 1.2

  • Paint getPaint()
  • void setPaint(Paint p)
    • 获取或设置这个图形环境的绘制属性。Color类实现了Paint接口。因此,可以使用这个方法将绘制属性设置为纯色。
  • void fill(Shape s)
    • 用当前的颜料填充该图形

API:java.awt.Component 1.0

  • Color getBackground()
  • void setBackground(Color c)
    • 获取或设置背景颜色
    • 参数:c 新背景颜色
  • Color getForeground()
  • void setForeground(Color c)
    • 获取或设置前景颜色
    • 参数:c 新背景颜色

7,文本使用特殊字体

  • 如果经常选用不同的字体显示文本。人们可以通过字体名(font face name)指定一种字体。字体名由"Helvetica"这样的字体家族名(font family name)和一个可选的"Bold"后缀组成。例如:"Helvetica"和"Helvetica Bold"属于"Helvetica"家族的字体。
  • 想知道某台计算机上允许使用的字体,需要调用GraphicsEnvironment类中的getAvailableFontFamilyNames方法。这个方法将返回一个字符型数组,其中包含了所有可用的字体名。
import java.awt.*;

public class ListFonts
{
    public static void main(String[] args)
    {
        String[] fontNames = GraphicsEnvironment
                .getLocalGraphicsEnvironment()
                .getAvailableFontFamilyNames();
        for (String fontName : fontNames)
        {
            System.out.println(fontName);
        }
    }
}

API:java.awt.Font 1.0

  • Font(String name,int style,int size)
    • 创建一个新字体对象
    • 参数:name 字体名。不是字体名(例如,“Helvetica Bold”),就是逻辑字体名(例如,“Serif”,“SansSerif”)
    • 参数:style 字体风格(Font.PLAIN,Font.BOLD,Font.ITALIC或Font.BOLD+Font.ITALIC)
    • 参数:size 字体大小
  • String getFontName()
    • 返回字体名,例如,“Helvetica Bold”
  • String getFamily()
    • 返回字体家族名,例如,“Helvetica”
  • String getName()
    • 如果采用逻辑字体名创建字体,将返回逻辑字体,例如,“SansSerif”;否则,返回字体名。
  • Font deriveFont(int style) 1.2
  • Font deriveFont(float size) 1.2
  • Font deriveFont(int style,float size) 1.2
    • 返回一个新字体,除给定大小和字体风格外,其余与原字体一样

API:java.awt.font.LineMetrics 1.2

  • float getLeading()
    • 返回字体的行间距-从一行文本底端到下一行文本顶端之间的空隙
  • float getHeight()
    • 返回字体的总高度-两条文本基线之间的距离(下坡度+行间距+上坡度)

API:java.awt.Graphics 1.0

  • Font getFont()
  • void setFont(Font font)
    • 获取或设置当前的字体。这种字体将被应用与后续的文本绘制操作中。
    • 参数:font 一种字体
  • void drawString(String str,int x,int y)
    • 采用当前字体和颜色绘制一个字符串
    • 参数:str 将要绘制的字符串
    • 参数:x 字符串开始的x坐标
    • 参数:y 字符串开始的y坐标

8,显示图像

  • 对于照片这样的复杂图像来说,通常都是由扫描仪或特殊的图像处理软件生成的。
  • 一旦图像保存在本地或网络上,就可以将它们读到Java应用程序中,并在Graphic对象上进行显示。
  • 以下例子:在一个窗口中平铺显示了一幅图像。这里采用paintComponent方法来实现平铺显示。它的基本过程为:先在左上角显示图像的一个拷贝,然后使用copyArea将其拷贝到整个窗口。
import javax.swing.*;
import java.awt.*;

public class ImageTest
{
    public static void main(String[] args)
    {
        JFrame frame = new ImageFrame();
        frame.setTitle("ImageTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

/*
 * A frame with an image component
 * */
class ImageFrame extends JFrame
{
    public ImageFrame()
    {
        add(new ImageComponent());
        pack();
    }
}

/*
 * A component that displays a tiled image
 * */
class ImageComponent extends JComponent
{
    private static final int DEFAULT_WIDTH = 300;
    private static final int DEFAULT_HEIGHT = 200;
    private Image image;

    public ImageComponent()
    {
        image = new ImageIcon("blue-ball.gif").getImage();
    }

    public void paintComponent(Graphics g)
    {
        if (image == null)
        {
            return;
        }

        int imageWidth = image.getWidth(this);
        int imageHeight = image.getHeight(this);

        //draw the image in the upper-left corner

        g.drawImage(image, 0, 0, null);

        //tile the image across the component

        for (int i = 0; i * imageWidth <= getWidth(); i++)
        {
            for (int j = 0; j * imageHeight <= getHeight(); j++)
            {
                if (i + j > 0)
                {
                    g.copyArea(0, 0, imageWidth, imageHeight, i * imageWidth, j * imageHeight);
                }
            }
        }
    }

    public Dimension getPreferredSize()
    {
        return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
    }
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。