如何使用图标

许多 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对象保存图像数据。

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

更复杂的图像图标示例

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

Try this:

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

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

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

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

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 文件中。下图说明了这些文件的几种配置方式:

包含图像文件的图像目录旁边的类文件,格式为 PNG。 类文件与 JAR 文件位于同一目录中。 JAR 文件是使用images目录中的所有图像创建的。
一个 JAR 文件中的类文件,另一个 JAR 文件中的图像。 类和图像文件在同一 JAR 文件中。

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

类文件位于名为omega的目录中。图片位于omega/images目录中。 omega目录中的类文件。 JAR 文件中的图像不在omega目录内,而是使用omega/images层次结构创建的。
一个大的 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 的三种方法:

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

<?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 文件。

大多数 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.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]);
}

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

图片图标 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讨论。

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

Method Purpose
void setDescription(String)

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

观看图像图标的图像加载

Method Purpose
void setImageObserver(ImageObserver)

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

使用图标的示例

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

Example Where Described Notes
LabelDemo 本节和

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

Note:

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

首页