如何使用图标

原文: https://docs.oracle.com/javase/tutorial/uiswing/components/icon.html

许多 Swing 组件,例如标签,按钮和标签窗格,都可以使用图标进行装饰 - 一个固定大小的图片。图标是符合 Icon 接口的对象。 Swing 提供了Icon接口特别有用的实现: ImageIcon ,它从 GIF,JPEG 或 PNG 图像绘制图标。

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

An example of using image icons to decorate labels.

该程序使用一个图像图标来包含和绘制黄色 splats。一个语句创建图像图标,另外两个语句包括两个标签中每个标签上的图像图标:

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

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

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

在前面的代码片段中,ImageIcon构造器的第一个参数是相对于当前类的位置,并将被解析为绝对 URL。 description参数是一个字符串,允许辅助技术帮助视障用户了解图标传达的信息。

通常,应用程序提供自己的一组图像作为应用程序的一部分,就像我们的许多演示所使用的图像一样。您应该使用Class getResource方法获取图像的路径。这允许应用程序验证图像是否可用,如果不是,则提供合理的错误处理。当图像不是应用程序的一部分时,不应使用getResource并直接使用ImageIcon构造器。例如:

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

ImageIcon构造器指定文件名或 URL 时,处理将被阻止,直到图像数据完全加载或数据位置被证明无效为止。如果数据位置无效(但非空),则仍会成功创建ImageIcon;它没有任何尺寸,因此不会涂漆。如createImageIcon方法所示,建议首先验证 URL 是否指向现有文件,然后再将其传递给ImageIcon构造器。这样可以在文件不存在时进行正常的错误处理。如果在加载图像时需要更多信息,可以通过调用setImageObserver方法在图像图标上注册观察者。

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

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

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

The initial view of the IconDemo application.


Try this:

  1. 单击“启动”按钮以使用 Java™Web Start下载 JDK 7 或更高版本)运行 IconDemo。或者,要自己编译并运行示例,请参考示例索引

    Launches the IconDemo example

  2. 单击任何缩略图图像以查看完整尺寸的照片。

  3. 将鼠标悬停在照片上。出现一个工具提示,显示照片标题。


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

  • 作为附加到按钮的 GUI 元素(按钮上的缩略图图像)。
  • 显示图像(五张照片)。

照片由loadimages.execute单独加载。 loadimages代码将在本节稍后显示。

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

  1. /**
  2. * Action class that shows the image specified in it's constructor.
  3. */
  4. private class ThumbnailAction extends AbstractAction{
  5. /**
  6. *The icon if the full image we want to display.
  7. */
  8. private Icon displayPhoto;
  9. /**
  10. * @param Icon - The full size photo to show in the button.
  11. * @param Icon - The thumbnail to show in the button.
  12. * @param String - The descriptioon of the icon.
  13. */
  14. public ThumbnailAction(Icon photo, Icon thumb, String desc){
  15. displayPhoto = photo;
  16. // The short description becomes the tooltip of a button.
  17. putValue(SHORT_DESCRIPTION, desc);
  18. // The LARGE_ICON_KEY is actually the key for setting the
  19. // icon when an Action is applied to a button.
  20. putValue(LARGE_ICON_KEY, thumb);
  21. }
  22. /**
  23. * Shows the full image in the main area and sets the application title.
  24. */
  25. public void actionPerformed(ActionEvent e) {
  26. photographLabel.setIcon(displayPhoto);
  27. setTitle("Icon Demo: " + getValue(SHORT_DESCRIPTION).toString());
  28. }
  29. }

大多数情况下,图像图标的数据来自图像文件。您可以在文件服务器上配置应用程序的类和图像文件,这有许多有效的方法。您可能将类文件放在 JAR 文件中,或将图像文件放在 JAR 文件中;它们可能位于同一个 JAR 文件中,也可能位于不同的 JAR 文件中。下图说明了可以配置这些文件的一些方法:

| Diagram showing MyDemo.class and images/myImage.png under the parent directory | Diagram showing MyDemo.class and image.jar under the parent directory | | 包含图像文件的图像目录旁边的类文件,采用 PNG 格式。 | 与 JAR 文件位于同一目录中的类文件。使用images目录中的所有图像创建 JAR 文件。 | | Diagram showing MyDemo.jar and image.jar under the parent directory | Diagram showing MyDemo.class and images/myImage.png in the same JAR file | | 一个 JAR 文件中的类文件和另一个 JAR 文件中的图像。 | 同一 JAR 文件中的类和图像文件。 |

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

| Diagram showing omega package with MyDemo.class and image/myImage.png | Diagram showing omega package with MyDemo.class and image.jar | | 名为omega的目录中的类文件。 omega/images目录中的图像。 | omega目录中的类文件。 JAR 文件中的图像不在omega目录内,但是使用omega/images层次结构创建。 | | Diagram showing omega.jar which contains omega/MyDemo.class and omehttps://docs.oracle.com/javase/tutorial/images/myImage.png | | 一个大的 JAR 文件,其中包含omega目录下的类文件和omega/images目录下的图像文件。 |

显示的所有七个配置都是有效的,相同的代码读取图像:

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

getResource方法使类加载器查看程序类路径中的目录和 JAR 文件,并在找到所需文件后立即返回 URL。在示例中,MyDemo 程序尝试从omega类加载images/myImage.png文件。类加载器查看程序的/omehttps://docs.oracle.com/javase/tutorial/images/myImage.png类路径中的目录和 JAR 文件。如果类加载器找到该文件,它将返回包含该文件的 JAR 文件或目录的 URL。如果类路径中的另一个 JAR 文件或目录包含images/myImage.png文件,则类加载器将返回包含该文件的第一个实例。

以下是指定类路径的三种方法:

  • 使用-cp-classpath命令行参数。例如,如果图像位于名为images.jar的 JAR 文件中,并且类文件位于当前目录中:

    1. java -cp .;images.jar MyDemo [Microsoft Windows]
    2. java -cp ".;images.jar" MyDemo [UNIX-emulating shell on Microsoft
    3. Windows you must quote the path]
    4. java -cp .:images.jar MyDemo [UNIX]

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

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

    在所有文件都在一个 JAR 文件中的情况下,您可以使用以下任一命令:

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

    有关更多信息,请参阅 JAR 文件跟踪。

  • 在程序的 JNLP 文件中(由 Java Web Start 使用)。例如,这是DragPictureDemo使用的 JNLP 文件:

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <!-- JNLP File for DragPictureDemo -->
    3. <jnlp
    4. spec="1.0+"
    5. codebase="https://docs.oracle.com/javase/tutorialJWS/src/uiswing/misc/examples"
    6. href="DragPictureDemo.jnlp">
    7. <information>
    8. <title>DragPictureDemo</title>
    9. <vendor>The Java(tm) Tutorial: Sun Microsystems, Inc.</vendor>
    10. <homepage href="https://docs.oracle.com/javase/tutorial/uiswing/misc/examples/index.html#DragPictureDemo"/>
    11. <description>DragPictureDemo</description>
    12. <description kind="short">A demo showing how to install
    13. data transfer on a custom component.</description>
    14. <offline-allowed/>
    15. </information>
    16. <resources>
    17. <j2se version="1.6+"/>
    18. <jar href="allClasses.jar"/>
    19. <jar href="images.jar"/>
    20. </resources>
    21. <application-desc main-class="DragPictureDemo"/>
    22. </jnlp>

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

  • 设置CLASSPATH环境变量。最后一种方法是不推荐。如果未设置CLASSPATH,则默认使用当前目录(“。”)后跟 JRE 附带的系统类的位置。

大多数 Swing Tutorial 示例将图像放在包含示例的类文件的目录下的images目录中。当我们为示例创建 JAR 文件时,我们保持相同的相对位置,尽管我们经常将类文件放在与图像 JAR 文件不同的 JAR 文件中。无论文件系统中的类和图像文件位于何处 - 在一个 JAR 文件中,在多个 JAR 文件中,在命名包中,还是在默认包中 - 相同的代码都使用getResource查找图像文件。

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

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

由于照片图像访问速度较慢, IconDemoApp.java 使用SwingWorker来改善用户所感知的节目性能。

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

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

  1. /**
  2. * SwingWorker class that loads the images a background thread and calls publish
  3. * when a new one is ready to be displayed.
  4. *
  5. * We use Void as the first SwingWorker param as we do not need to return
  6. * anything from doInBackground().
  7. */
  8. private SwingWorker<Void, ThumbnailAction> loadimages = new SwingWorker<Void, ThumbnailAction>() {
  9. /**
  10. * Creates full size and thumbnail versions of the target image files.
  11. */
  12. @Override
  13. protected Void doInBackground() throws Exception {
  14. for (int i = 0; i < imageCaptions.length; i++) {
  15. ImageIcon icon;
  16. icon = createImageIcon(imagedir + imageFileNames[i], imageCaptions[i]);
  17. ThumbnailAction thumbAction;
  18. if(icon != null){
  19. ImageIcon thumbnailIcon = new
  20. ImageIcon(getScaledImage(icon.getImage(), 32, 32));
  21. thumbAction = new ThumbnailAction(icon, thumbnailIcon, imageCaptions[i]);
  22. } else {
  23. // the image failed to load for some reason
  24. // so load a placeholder instead
  25. thumbAction = new ThumbnailAction(placeholderIcon, placeholderIcon, imageCaptions[i]);
  26. }
  27. publish(thumbAction);
  28. }
  29. // unfortunately we must return something, and only null is valid to
  30. // return when the return type is void.
  31. return null;
  32. }
  33. /**
  34. * Process all loaded images.
  35. */
  36. @Override
  37. protected void process(List<ThumbnailAction> chunks) {
  38. for (ThumbnailAction thumbAction : chunks) {
  39. JButton thumbButton = new JButton(thumbAction);
  40. // add the new button BEFORE the last glue
  41. // this centers the buttons in the toolbar
  42. buttonBar.add(thumbButton, buttonBar.getComponentCount() - 1);
  43. }
  44. }
  45. };

SwingWorker 在后台线程中调用doInBackground方法。该方法将全尺寸图像,缩略图大小图像和标题放入ThumbnailAction对象。然后,SwingWorker 将ThumbnailAction传递给process方法。 process方法在事件分派线程上执行,并通过向工具栏添加按钮来更新 GUI。 JButton有一个构造器,它接受一个动作对象。操作对象确定按钮属性的数量。在我们的例子中,按下按钮图标,标题和按下按钮时要执行的操作都由ThumbnailAction确定。

Overhead - 该程序最终将所有源图像加载到内存中。在所有情况下这可能都不可取。加载一些非常大的文件可能会导致程序分配非常大的数量或内存。应注意管理加载的图像的数量和大小。

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

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

An example of MissingIcon.

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

  1. /**
  2. * The "missing icon" is a white box with a black border and a red x.
  3. * It's used to display something when there are issues loading an
  4. * icon from an external location.
  5. *
  6. * @author Collin Fagan
  7. */
  8. public class MissingIcon implements Icon{
  9. private int width = 32;
  10. private int height = 32;
  11. private BasicStroke stroke = new BasicStroke(4);
  12. public void paintIcon(Component c, Graphics g, int x, int y) {
  13. Graphics2D g2d = (Graphics2D) g.create();
  14. g2d.setColor(Color.WHITE);
  15. g2d.fillRect(x +1 ,y + 1,width -2 ,height -2);
  16. g2d.setColor(Color.BLACK);
  17. g2d.drawRect(x +1 ,y + 1,width -2 ,height -2);
  18. g2d.setColor(Color.RED);
  19. g2d.setStroke(stroke);
  20. g2d.drawLine(x +10, y + 10, x + width -10, y + height -10);
  21. g2d.drawLine(x +10, y + height -10, x + width -10, y + 10);
  22. g2d.dispose();
  23. }
  24. public int getIconWidth() {
  25. return width;
  26. }
  27. public int getIconHeight() {
  28. return height;
  29. }
  30. }

paintIcon方法传递Graphics对象。 Graphics对象为paintIcon方法提供对整个 Java2D API 的访问。有关绘画和 Java2D 的更多信息,请参阅执行自定义绘画

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

  1. private MissingIcon placeholderIcon = new MissingIcon();
  2. ...
  3. if(icon != null) {
  4. ...
  5. } else {
  6. // the image failed to load for some reason
  7. // so load a placeholder instead
  8. thumbAction = new ThumbnailAction(placeholderIcon, placeholderIcon, imageCaptions[i]);
  9. }

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

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

  • 根据平台和图像类型,您可以通过自定义图标获得性能提升,因为绘制简单形状有时比复制图像更快。

  • 因为MissingIcon不执行任何文件 I / O,所以不需要单独的线程来加载图像。

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

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

方法或构造器 目的
ImageIcon()

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

方法 目的
void setDescription(String)

String getDescription() | 设置或获取图像的描述。该描述旨在供辅助技术使用。 | | int getIconWidth() int getIconHeight() | 获取图像图标的宽度或高度(以像素为单位)。 |

方法 目的
void setImageObserver(ImageObserver)

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

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

在哪里描述 笔记
LabelDemo 本节和

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


Note: The photographs used in the IconDemo are copyright ©2006 spriggs.net and licenced under a Creative Commons Licence.