如何使用图标

许多 Swing 组件,例如标签,按钮和选项卡式窗格,都可以用* icon *(固定大小的图片)修饰。图标是遵循Iconinterface的对象。 Swing 提供了Iconinterface的一个特别有用的实现:ImageIcon,它从 GIF,JPEG 或 PNG 图像绘制图标。

这是带有三个标签的应用程序的快照,其中两个标签带有图标:

使用图像图标装饰标签的示例。

该程序使用一个图像图标来包含并绘制黄色图示。一个语句创建图像图标,另外两个语句在两个标签上分别包含图像图标:

ImageIcon icon = createImageIcon("images/middle.gif",
                                 "a pretty but meaningless splat");
label1 = new JLabel("Image and Text", icon, JLabel.CENTER);
...
label3 = new JLabel(icon);

createImageIcon方法(在前面的代码段中使用)是我们在许多代码示例中使用的方法。它找到指定的文件,并为该文件返回ImageIcon;如果找不到该文件,则返回null。这是一个典型的实现:

/** Returns an ImageIcon, or null if the path was invalid. */
protected ImageIcon createImageIcon(String path,
                                           String description) {
    java.net.URL imgURL = getClass().getResource(path);
    if (imgURL != null) {
        return new ImageIcon(imgURL, description);
    } else {
        System.err.println("Couldn't find file: " + path);
        return null;
    }
}

在前面的代码段中,ImageIcon构造函数的第一个参数是相对于当前类的位置的,并将解析为绝对 URL。 description参数是一个字符串,它允许assistive technologies帮助视觉障碍的用户理解图标传达的信息。

通常,应用程序提供它们自己的图像集作为应用程序的一部分,就像我们许多演示中使用的图像一样。您应该使用Class getResource方法来获取图像的路径。这使应用程序可以验证图像是否可用,如果没有,则可以提供合理的错误处理。如果映像不属于应用程序,则不应使用getResource,而应直接使用ImageIcon构造函数。例如:

ImageIcon icon = new ImageIcon("images/middle.gif",
                               "a pretty but meaningless splat");

当您为ImageIcon构造函数指定文件名或 URL 时,将阻止处理,直到完全加载图像数据或证明数据位置无效为止。如果数据位置无效(但非空),则仍成功创建ImageIcon;否则,它只是没有大小,因此不画任何东西。如createImageIcon方法所示,建议先将 URL 指向现有文件,然后再将其传递给ImageIcon构造函数。当文件不存在时,这可以进行优雅的错误处理。如果要在加载图像时获得更多信息,可以通过调用setImageObserver方法在图像图标上注册观察者。

在封面下,每个图像图标使用一个Image对象保存图像数据。

本节的其余部分包括以下主题:

更复杂的图像图标示例

这是一个使用六个图像图标的应用程序。其中五个显示缩略图,第六个则显示完整尺寸的照片。

IconDemo 应用程序的初始视图。

Try this:

  • 单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 IconDemo。或者,要自己编译并运行示例,请参考example index

  • 单击任意缩略图图像以查看完整尺寸的照片。

  • 将鼠标悬停在照片上。出现工具提示,显示照片标题。

IconDemoApp 演示通过以下方式使用的图标:

  • 作为附加在按钮上的 GUI 元素(按钮上的缩略图)。

  • 显示图像(五张照片)。

loadimages.execute将照片加载到单独的线程中。 loadimages代码在本节的稍后部分显示。

ThumbnailAction类是IconDemoApp.java的内部类,是AbstractAction的后代,它 管理 我们的全尺寸图像图标,缩略图版本及其说明。调用actionPerformed方法时,将全尺寸图像加载到主显示区域中。每个按钮都有其自己的ThumbnailAction实例,该实例指定要显示的不同图像。

/**
 * Action class that shows the image specified in it's constructor.
 */
private class ThumbnailAction extends AbstractAction{

    /**
     *The icon if the full image we want to display.
     */
    private Icon displayPhoto;

    /**
     * @param Icon - The full size photo to show in the button.
     * @param Icon - The thumbnail to show in the button.
     * @param String - The descriptioon of the icon.
     */
    public ThumbnailAction(Icon photo, Icon thumb, String desc){
        displayPhoto = photo;

        // The short description becomes the tooltip of a button.
        putValue(SHORT_DESCRIPTION, desc);

        // The LARGE_ICON_KEY is actually the key for setting the
        // icon when an Action is applied to a button.
        putValue(LARGE_ICON_KEY, thumb);
    }

    /**
     * Shows the full image in the main area and sets the application title.
     */
    public void actionPerformed(ActionEvent e) {
        photographLabel.setIcon(displayPhoto);
        setTitle("Icon Demo: " + getValue(SHORT_DESCRIPTION).toString());
    }
}

使用 getResource 加载图像

通常,图像图标的数据来自图像文件。可以在文件服务器上配置应用程序的类和图像文件的多种有效方法。您可能将类文件放在 JAR 文件中,或者将图像文件放在 JAR 文件中。它们可能在同一个 JAR 文件中,或者可能在不同的 JAR 文件中。下图说明了这些文件的几种配置方式:

该图显示了父目录下的 MyDemo.class 和 images/myImage.png该图显示了父目录下的 MyDemo.class 和 image.jar
包含图像文件的图像目录旁边的类文件,格式为 PNG。类文件与 JAR 文件位于同一目录中。 JAR 文件是使用images目录中的所有图像创建的。
该图显示了父目录下的 MyDemo.jar 和 image.jar该图在同一 JAR 文件中显示 MyDemo.class 和 images/myImage.png
一个 JAR 文件中的类文件,另一个 JAR 文件中的图像。类和图像文件在同一 JAR 文件中。

如果您正在编写实际应用程序,则可能(建议)将文件放入包中。有关软件包的更多信息,请参见学习 Java 语言跟踪中的创建和使用包。以下是使用名为“ omega”的软件包的一些可能的配置:

该图显示了带有 MyDemo.class 和 image/myImage.png 的 omega 包该图显示了带有 MyDemo.class 和 image.jar 的 omega 包
类文件位于名为omega的目录中。图片位于omega/images目录中。omega目录中的类文件。 JAR 文件中的图像不在omega目录内,而是使用omega/images层次结构创建的。
该图显示了包含 omega/MyDemo.class 和 omega/images/myImage.png 的 omega.jar
一个大的 JAR 文件,其类文件位于omega目录下,图像文件位于omega/images目录下。

显示的所有七个配置均有效,并且相同的代码读取该图像:

java.net.URL imageURL = myDemo.class.getResource("images/myImage.gif");
...
if (imageURL != null) {
    ImageIcon icon = new ImageIcon(imageURL);
}

getResource方法使类加载器在程序的 Classpath 中浏览目录和 JAR 文件,并在找到所需文件后立即返回 URL。在该示例中,MyDemo 程序try从omega类加载images/myImage.png文件。类加载器在程序的 Classpath 中通过/omega/images/myImage.png查找目录和 JAR 文件。如果类加载器找到该文件,它将返回 JAR 文件的 URL 或包含该文件的目录。如果 Classpath 中的另一个 JAR 文件或目录包含images/myImage.png文件,则类加载器将返回包含该文件的第一个实例。

以下是指定 Classpath 的三种方法:

  • 使用-cp-classpath命令行参数。例如,在图像位于名为images.jar的 JAR 文件中且类文件位于当前目录中的情况下:
java -cp  .;images.jar  MyDemo  [Microsoft Windows]
java -cp ".;images.jar" MyDemo  [UNIX-emulating shell on Microsoft
                                Windows — you must quote the path]
java -cp  .:images.jar  MyDemo  [UNIX]

如果图像和类文件位于单独的 JAR 文件中,则命令行将类似于:

java -cp .;MyDemo.jar;images.jar MyDemo  [Microsoft Windows]

如果所有文件都在一个 JAR 文件中,则可以使用以下命令之一:

java -jar MyAppPlusImages.jar
java -cp .;MyAppPlusImages.jar MyApp  [Microsoft Windows]

有关更多信息,请参见JAR Files

  • 在程序的 JNLP 文件中(由 Java Web Start 使用)。例如,这是DragPictureDemo使用的 JNLP 文件:
<?xml version="1.0" encoding="utf-8"?>
<!-- JNLP File for DragPictureDemo -->
<jnlp
  spec="1.0+"
  codebase="https://docs.oracle.com/javase/tutorialJWS/src/uiswing/misc/examples"
  href="DragPictureDemo.jnlp">
  <information>
    <title>DragPictureDemo</title>
    <vendor>The Java(tm) Tutorial: Sun Microsystems, Inc.</vendor>
    <homepage href="https://docs.oracle.com/javase/tutorial/uiswing/misc/examples/index.html#DragPictureDemo"/>
    <description>DragPictureDemo</description>
    <description kind="short">A demo showing how to install
        data transfer on a custom component.</description>
    <offline-allowed/>
  </information>
  <resources>
    <j2se version="1.6+"/>
    <jar href="allClasses.jar"/>
    <jar href="images.jar"/>
  </resources>
  <application-desc main-class="DragPictureDemo"/>
</jnlp>

在此示例中,类文件和图像文件位于单独的 JAR 文件中。使用 XML jar标记指定 JAR 文件。

  • 设置CLASSPATH环境变量。 不建议使用后一种方法。如果未设置CLASSPATH,则默认使用当前目录(“.”)以及 JRE 随附的系统类的位置。

大多数 Swing 教程示例都将图像放在包含示例类文件的目录下的images目录中。在为示例创建 JAR 文件时,尽管通常将类文件放在与图像 JAR 文件不同的 JAR 文件中,但我们保持相同的相对位置。无论类和图像文件在文件系统中的哪个位置(一个 JAR 文件,多个 JAR 文件,一个命名程序包或默认程序包中),相同的代码都使用getResource查找图像文件。

有关更多信息,请参见以与位置无关的方式访问资源应用程序开发注意事项

将图像加载到 Servlets 中

Servlets 通常从提供 Servlets 的计算机中加载图像数据。您可以在APPLET标记中指定有关 applet 中使用的图像的信息。有关APPLET标签的更多信息,请参见使用 APPLET 标签

加载图像图标时提高感知性能

由于照片图像的访问速度可能很慢,因此IconDemoApp.java使用SwingWorker可以提高用户感知到的程序性能。

背景图片加载 -程序使用javax.swing.SwingWorker对象加载每个照片图像并在后台线程中计算其缩略图。使用SwingWorker可防止程序在加载和缩放图像时出现冻结。

这是处理每个图像的代码:

/**
 * SwingWorker class that loads the images a background thread and calls publish
 * when a new one is ready to be displayed.
 *
 * We use Void as the first SwingWorker param as we do not need to return
 * anything from doInBackground().
 */
private SwingWorker<Void, ThumbnailAction> loadimages = new SwingWorker<Void, ThumbnailAction>() {

    /**
     * Creates full size and thumbnail versions of the target image files.
     */
    @Override
    protected Void doInBackground() throws Exception {
        for (int i = 0; i < imageCaptions.length; i++) {
            ImageIcon icon;
            icon = createImageIcon(imagedir + imageFileNames[i], imageCaptions[i]);

            ThumbnailAction thumbAction;
            if(icon != null){

                ImageIcon thumbnailIcon = new
                     ImageIcon(getScaledImage(icon.getImage(), 32, 32));

                thumbAction = new ThumbnailAction(icon, thumbnailIcon, imageCaptions[i]);

            } else {
                // the image failed to load for some reason
                // so load a placeholder instead
                thumbAction = new ThumbnailAction(placeholderIcon, placeholderIcon, imageCaptions[i]);
            }
            publish(thumbAction);
        }
        // unfortunately we must return something, and only null is valid to
        // return when the return type is void.
        return null;
    }

    /**
     * Process all loaded images.
     */
    @Override
    protected void process(List<ThumbnailAction> chunks) {
        for (ThumbnailAction thumbAction : chunks) {
            JButton thumbButton = new JButton(thumbAction);
            // add the new button BEFORE the last glue
            // this centers the buttons in the toolbar
            buttonBar.add(thumbButton, buttonBar.getComponentCount() - 1);
        }
    }
};

SwingWorker 在后台线程中调用doInBackground方法。该方法将完整尺寸的图像,缩略图尺寸的图像和标题放入ThumbnailAction对象。然后,SwingWorker 将ThumbnailAction传递给process方法。 process方法在事件分发线程上执行,并通过向工具栏添加按钮来更新 GUI。 JButton有一个带操作对象的构造函数。动作对象确定按钮的许多属性。在我们的情况下,按钮图标,标题和按下按钮时要执行的操作均由ThumbnailAction决定。

开销 -该程序final将所有源图像加载到内存中。这并非在所有情况下都是理想的。加载许多非常大的文件可能导致程序分配非常大的数量或内存。应小心 管理 加载的图像的数量和大小。

与所有与性能相关的问题一样,此技术适用于某些情况,不适用于其他情况。同样,此处描述的技术旨在提高程序的感知性能,但不一定会影响其实际性能。

创建自定义图标实现

createImageIcon方法在找不到图像时返回 null,但是程序应该怎么办?一种可能性是忽略该图像并 continue 前进。另一种选择是提供某种默认图标,以在无法加载实际图标时显示。再次调用createImageIcon可能会导致另一个 null,因此使用它不是一个好主意。相反,让我们创建一个自定义Icon实现。

MissingIcon 的示例。

您可以在MissingIcon.java中找到自定义图标类的实现。以下是其代码中有趣的部分:

/**
 * The "missing icon" is a white box with a black border and a red x.
 * It's used to display something when there are issues loading an
 * icon from an external location.
 *
 * @author Collin Fagan
 */
public class MissingIcon implements Icon{

    private int width = 32;
    private int height = 32;

    private BasicStroke stroke = new BasicStroke(4);

    public void paintIcon(Component c, Graphics g, int x, int y) {
        Graphics2D g2d = (Graphics2D) g.create();

        g2d.setColor(Color.WHITE);
        g2d.fillRect(x +1 ,y + 1,width -2 ,height -2);

        g2d.setColor(Color.BLACK);
        g2d.drawRect(x +1 ,y + 1,width -2 ,height -2);

        g2d.setColor(Color.RED);

        g2d.setStroke(stroke);
        g2d.drawLine(x +10, y + 10, x + width -10, y + height -10);
        g2d.drawLine(x +10, y + height -10, x + width -10, y + 10);

        g2d.dispose();
    }

    public int getIconWidth() {
        return width;
    }

    public int getIconHeight() {
        return height;
    }
}

paintIcon方法传递了Graphics对象。 Graphics对象使paintIcon方法可以访问整个 Java2D API。有关绘画和 Java2D 的更多信息,请参见进行定制绘画

下面的代码演示了SwingWorker doInBackground方法中如何使用MissingIcon类。

private MissingIcon placeholderIcon = new MissingIcon();

...
if(icon != null) {
    ...

} else {
    // the image failed to load for some reason
    // so load a placeholder instead
    thumbAction = new ThumbnailAction(placeholderIcon, placeholderIcon, imageCaptions[i]);
}

使用自定义图标有一些含义:

  • 因为图标的外观是动态确定的,所以图标绘制代码可以使用任何信息(例如,组件和应用程序状态)来确定要绘制的内容。

  • 根据平台和图像类型的不同,使用自定义图标可能会提高性能,因为绘制简单形状有时会比复制图像更快。

  • 由于MissingIcon不执行任何文件 I/O,因此不需要单独的线程来加载映像。

图片图标 API

下表列出了常用的ImageIcon构造函数和方法。请注意,ImageIcon不是JComponent甚至不是Component的后代。

使用图像图标的 API 分为以下几类:

设置,获取和绘制图像图标的图像

方法或构造函数Purpose
ImageIcon()

ImageIcon(byte[])
ImageIcon(byte[], String)
ImageIcon(Image)
ImageIcon(Image, String)
ImageIcon(String)
ImageIcon(String, String)
ImageIcon(URL)
ImageIcon(URL, String)
创建ImageIcon实例,对其进行初始化以包含指定的图像。第一个参数指示源(图像,字节数组,文件名或 URL),应从中加载图像图标的图像。源必须采用java.awt.Image类支持的格式:GIF,JPEG 或 PNG。当出现第二个参数时,将为图像提供描述。描述也可以通过setDescription设置,并为assistive technologies提供有用的文本信息。
void setImage(Image)
Image getImage()
设置或获取通过图像图标显示的图像。
void paintIcon(Component,Graphics,int,int)在指定的图形上下文中绘制图像图标的图像。仅当实现要执行自己绘制的自定义图标时,才可以覆盖此设置。 Component对象用作图像观察器。您可以依赖Component类提供的默认行为,并传入任何组件。两个int自变量指定图标绘制的左上角。
URL getResource(String)
在(* java.lang.ClassLoader *)
中查找具有给定名称的资源。有关更多信息,请参见使用 getResource 加载图像
InputStream getResourceAsStream(String)
in(* java.lang.ClassLoader *)
使用给定名称查找资源,并返回用于读取资源的 Importing 流。有关更多信息,请参见将图像加载到 Servlets讨论。

设置或获取有关图像图标的信息

MethodPurpose
void setDescription(String)

String getDescription()
设置或获取图像描述。此描述旨在供assistive technologies使用。
int getIconWidth()
int getIconHeight()
获取图像图标的宽度或高度(以像素为单位)。

观看图像图标的图像加载

MethodPurpose
void setImageObserver(ImageObserver)

ImageObserver getImageObserver()
设置或获取图像图标的图像观察器。
int getImageLoadStatus()获取图像图标图像的加载状态。此方法返回的值由MediaTracker定义。

使用图标的示例

下表仅列出了许多使用ImageIcon的示例。

ExampleWhere DescribedNotes
LabelDemo本节和

如何使用标签
演示使用应用程序标签中的图标(带有或不带有文本)。
IconDemo此部分使用标签显示大图像;使用同时具有图像和文本的按钮。
CustomIconDemo此部分使用由ArrowIcon.java实现的自定义图标类。
TumbleItem如何制作 ServletsServlets。在动画中使用图像图标。显示如何调用ImageIconpaintIcon方法。
ButtonDemo如何使用按钮,复选框和单选按钮显示如何在应用程序的按钮中使用图标。
CheckBoxDemo如何使用复选框使用多个 GIF 图像。
TabbedPaneDemo如何使用选项卡式窗格演示将图标添加到选项卡式窗格中的选项卡。
DialogDemo如何制作对话框显示如何在对话框中使用标准图标。
TreeIconDemo如何使用树木显示如何更改树节点显示的图标。
ActionDemo如何使用动作显示如何使用Action在工具栏按钮或菜单项中指定图标。
FileChooserDemo2如何使用文件 selectors使用PNG图像。显示如何在文件 selectors 中实现图像预览器和图像过滤器。

Note:

IconDemo中使用的照片的版权©2006 spriggs.net,并以知识共享许可许可。