Java 使用Icon (版本2)

发展了一下,第2版 做了些自己想要的效果:




package com.han;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.LineBorder;
import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.basic.BasicBorders;
import javax.swing.plaf.metal.DefaultMetalTheme;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.MetalTheme;
import javax.swing.plaf.metal.OceanTheme;
import javax.swing.UnsupportedLookAndFeelException;

/**
 * If the graphic files are loaded from an initial thread, there may be a delay
 * before the GUI appears. If the graphic files are loaded from the event
 * dispatch thread, the GUI may be temporarily unresponsive. So we use
 * SwingWorker as a background processing for the loading of image files.
 * <p>
 * This application needs the customization of the image files' informations in
 * the private inner class "LoadImages".
 * <p>
 * This is the version 2.0 with the following improvements:
 * <ul>
 * <li>Optimization of certain codes.
 * <li>Adding the choice of several themes.
 * <li><font size="3" color="red"><b>Creating a Custom Icon
 * Implementation</b></font>
 * <p>
 * The {@code createImage} method returns null when it cannot find an image, but
 * what should the program do then? One possibility would be to ignore that
 * image and move on. Another option would be to provide some sort of default
 * icon to display when the real one cannot be loaded. Making another call to
 * {@code createImage} might result in another null so using that is not a good
 * idea. Instead let's create a custom {@code Icon} implementation.
 * </ul>
 * 
 * @author HAN
 * @version 2.0
 * @see IconDemoAPP version 1.0
 */
@SuppressWarnings("serial")
public class IconDemoAPP2 extends JPanel {
	private static JFrame frame;
	private JLabel photoLabel;
	private JToolBar toolBar;
	private int displayZone = 400;

	/**
	 * The constructor serves as the content pane construction.
	 */
	IconDemoAPP2() {
		// JPanel uses FlowLayout by default. We set it to BorderLayout for
		// use of tool bar. This JPanel will be used as content pane.
		setLayout(new BorderLayout());

		// Create and add the tool bar to the content pane
		toolBar = createToolBar();
		add(toolBar, BorderLayout.SOUTH);

		// Create the photoLabel.
		photoLabel = new JLabel();
		photoLabel.setHorizontalAlignment(SwingConstants.CENTER);
		photoLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

		// Create a scroll pane to contain the photoLabel and set it up to the
		// center of the content pane in order to display the photo we wanted.
		JScrollPane scrollPane = new JScrollPane(photoLabel);
		// I find the border of the scroll pane is ugly, so I simply delete it.
		scrollPane.setBorder(null);
		add(scrollPane, BorderLayout.CENTER);

		// Because at the moment the GUI appearing on screen, the is no content
		// in the center of the content pane, we have to initialize a size to
		// display.
		setPreferredSize(new Dimension(displayZone + 100, displayZone + 50));

		// start a SwingWorker to load images in a background thread.
		new LoadImages().execute();
	}

	private JToolBar createToolBar() {
		JToolBar toolBar = new JToolBar("Select an icon to be displayed");

		// Add two glue components in order to center the icon buttons.
		toolBar.add(Box.createGlue());
		toolBar.add(Box.createGlue());

		return toolBar;
	}

	/**
	 * @param path
	 *            - the path used to create the buffered image.
	 * @return an BufferedImage object, or <code>null</code> if the given path
	 *         is not valid or an error occurs during reading.
	 */
	private BufferedImage createImage(String path) {
		URL imageURL = getClass().getResource(path);
		if (imageURL != null) {
			try {
				return ImageIO.read(imageURL);
			} catch (IOException e) {
				System.err.println("an error occurs during reading.");
				e.printStackTrace();
				return null;
			}
		} else {
			System.err.println("Couldn't find file: " + path);
			return null;
		}
	}

	/**
	 * It is for the image icon without the description set by developer. If the
	 * image has a "comment" property that is a string, then the string is used
	 * as the description of this icon.
	 * <p>
	 * Create an icon from an original image, which has normally a bigger size.
	 * 
	 * @param image
	 *            - the original image to be converted to icon
	 * @param width
	 *            - the created icon width
	 * @param height
	 *            - the created icon height
	 * @return an Icon object
	 */
	private Icon createIcon(Image image, int width, int height) {
		return createIcon(image, width, height, null);
	}

	/**
	 * It is for the image icon that needs a description for the visually
	 * impaired user.
	 * <p>
	 * Create an icon from an original image, which has normally a bigger size.
	 * 
	 * @param image
	 *            - the original image to be converted to icon
	 * @param width
	 *            - the created icon width
	 * @param height
	 *            - the created icon height
	 * @param desc
	 *            - the description for created icon, which would allow
	 *            assistive technologies to help visually impaired user
	 *            understand what information the icon conveys.
	 * @return an Icon object
	 */
	private Icon createIcon(Image image, int width, int height, String desc) {
		BufferedImage iconImage = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_RGB);
		Graphics2D g2 = iconImage.createGraphics();
		g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
				RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		g2.drawImage(image, 0, 0, width, height, null);
		g2.dispose();// dispose() is together with create().
		if (desc == null) {
			// If the image has a "comment" property that is a string, then the
			// string is used as the description of this icon.
			return new ImageIcon(iconImage);
		} else {
			// Return the image icon with specified description set by us.
			return new ImageIcon(iconImage, desc);
		}
	}

	/**
	 * Based on the original big image, we create a scaled version (keep the
	 * initial width-height ratio) to display if this image is bigger than the
	 * display zone we customized; or else, display it directly.
	 * 
	 * @param photoPath
	 *            - the path of original big image.
	 */
	private void displayPhoto(String photoPath) {
		BufferedImage photo = createImage(photoPath);
		if (photo == null) {
			photoLabel.setIcon(new MissingIcon());
		} else {
			int width = photo.getWidth();
			int height = photo.getHeight();
			int maxLength = Math.max(width, height);
			int displayZone = getDisplayZone();
			if (maxLength < displayZone) {
				// display the photo directly
				photoLabel.setIcon(new ImageIcon(photo));
			} else {
				// display the scaled version (keep the initial width-height
				// ratio).
				if (maxLength == photo.getWidth()) {
					// The width is bigger than the height.
					photoLabel
							.setIcon(createIcon(
									photo,
									displayZone,
									(int) (displayZone * ((float) height / (float) width))));
				} else {
					// The height is bigger than the width.
					photoLabel
							.setIcon(createIcon(
									photo,
									(int) (displayZone * ((float) width / (float) height)),
									displayZone));
				}
			}
		}
	}

	@SuppressWarnings("unused")
	private void setDisplayZone(int displayZone) {
		this.displayZone = displayZone;
	}

	private int getDisplayZone() {
		return displayZone;
	}

	@SuppressWarnings("unused")
	private static void setTheme(String laf) {
		setTheme(laf, null);
	}

	private static void setTheme(String lafName, String theme) {
		LookAndFeelInfo[] lafInfos = UIManager.getInstalledLookAndFeels();
		HashMap<String, String> lafs = new HashMap<String, String>();
		for (int i = 0; i < lafInfos.length; i++) {
			lafs.put(lafInfos[i].getName(), lafInfos[i].getClassName());
		}

		if (lafs.containsKey(lafName)) {
			// the input L&F name is valid and contained in the installed L&Fs.
			if (lafName.equals("Metal")) {
				if (theme == null) {
					try {
						UIManager.setLookAndFeel(lafs.get(lafName));
					} catch (ClassNotFoundException | InstantiationException
							| IllegalAccessException
							| UnsupportedLookAndFeelException e) {
						e.printStackTrace();
					}
				} else {
					if (theme.equals("DefaultMetal")) {
						setMetalTheme(new DefaultMetalTheme());
					} else if (theme.equals("Ocean")) {
						setMetalTheme(new OceanTheme());
					} else if (theme.equals("Aqua")) {
						setMetalTheme(new AquaTheme());
					} else if (theme.equals("Charcoal")) {
						setMetalTheme(new CharcoalTheme());
					} else if (theme.equals("Contrast")) {
						setMetalTheme(new ContrastTheme());
					} else if (theme.equals("Emerald")) {
						setMetalTheme(new EmeraldTheme());
					} else if (theme.equals("Ruby")) {
						setMetalTheme(new RubyTheme());
					} else {
						System.err.println("Your input theme name for the "
								+ "Metal L&F is invalid.");
					}
				}
			} else {
				try {
					UIManager.setLookAndFeel(lafs.get(lafName));
				} catch (ClassNotFoundException | InstantiationException
						| IllegalAccessException
						| UnsupportedLookAndFeelException e) {
					e.printStackTrace();
				}
				if (theme != null) {
					System.err.println("The " + lafName
							+ " L&F does not contain acctually any theme. "
							+ "Acctually for this application the only L&F "
							+ "that has the created themes is Metal L&F.");
				}
			}
		} else {
			// the input L&F name is invalid.
			System.err.println("Your input L&F name is invalid. And the "
					+ "application will use the default system L&F.");
		}
	}

	/**
	 * Set the theme used by MetalLookAndFeel.
	 * <p>
	 * After the theme is set, MetalLookAndFeel needs to be re-installed.
	 * <p>
	 * If this is not done the results are undefined.
	 * 
	 * @param metalTheme
	 *            - the metal theme to be set.
	 */
	private static void setMetalTheme(MetalTheme metalTheme) {
		MetalLookAndFeel.setCurrentTheme(metalTheme);

		// re-install the Metal Look and Feel
		try {
			UIManager.setLookAndFeel(new MetalLookAndFeel());
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}
	}

	private class LoadImages extends SwingWorker<Void, Icon> {
		private String imageDir = "/images/IconDemo/";
		private String[] imageNames = { "Chrysanthemum.jpg", "Desert.jpg",
				"Hydrangeas.jpg", "Jellyfish.jpg", "Koala.jpg" };
		private String[] imageCaptions = { "Chrysanthemum", "Desert",
				"Hydrangeas", "Jellyfish", "Koala" };

		private Icon buttonIcon;
		private int iconIndex = 0;

		@Override
		protected Void doInBackground() throws Exception {
			System.out.println("We are now in the Swing's predefined thread: "
					+ "The background thread...");
			for (int i = 0; i < imageNames.length; i++) {

				BufferedImage image = createImage(imageDir + imageNames[i]);
				if (image == null) {
					buttonIcon = new MissingIcon();
				} else {
					buttonIcon = createIcon(image, 32, 32, imageCaptions[i]);
				}

				// Multiple invocations to the publish method might occur before
				// the process method is executed. For performance purposes all
				// these invocations are coalesced into one invocation with
				// concatenated arguments. And the process method might be
				// executed many times, which is invoked asynchronously from the
				// event-dispatching thread.
				publish(buttonIcon);
			}
			return null;
		}

		@Override
		protected void process(List<Icon> iconChunks) {
			for (Icon buttonIcon : iconChunks) {
				JButton toolBarButton = new JButton(new ToolBarButtonAction(
						buttonIcon, imageDir + imageNames[iconIndex],
						imageCaptions[iconIndex]));
				iconIndex++;

				// Add the new button just BEFORE the last glue, which centers
				// the buttons in the tool bar.
				toolBar.add(toolBarButton, toolBar.getComponentCount() - 1);
			}
		}

		@Override
		protected void done() {
			// After the change of bound properties, you might have to
			// revalidate the related component for the right layout, by using
			// JComponent.revalidate() method, or simply call frame.pack().
			// toolBar.revalidate();
			// frame.pack();
		}
	}

	private class ToolBarButtonAction extends AbstractAction {
		ToolBarButtonAction(Icon buttonIcon, String actionCommand,
				String toolTip) {
			putValue(LARGE_ICON_KEY, buttonIcon);
			putValue(ACTION_COMMAND_KEY, actionCommand);
			putValue(SHORT_DESCRIPTION, toolTip);
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			// The action command represents the path of the image we want to
			// display in the center of the content pane.
			String path = e.getActionCommand();

			// Show the photo in the main area.
			displayPhoto(path);

			// Set the application title.
			frame.setTitle("Icon demo: " + new File(path).getName());
		}

	}

	/**
	 * For thread safety, this method should be invoked from the
	 * event-dispatching thread.
	 */
	private static void createAndShowGUI() {
		// Create the window.
		frame = new JFrame("Icon demo: Please select an image");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// Create and set up the content pane.
		JPanel contentPane = new IconDemoAPP2();
		frame.setContentPane(contentPane);

		// realize the inside components.
		frame.pack();

		// this centers the frame on the screen
		frame.setLocationRelativeTo(null);

		// display the window.
		frame.setVisible(true);
	}

	public static void main(String[] args) {
		if (!SwingUtilities.isEventDispatchThread()) {
			System.out.println("This is in the initial thread...");
		}

		// You can shift between the L&Fs. In my computer environment, for
		// example, the installed L&Fs are: Metal, Nimbus, CDE/Motif, Windows
		// and Windows Classic. In the Metal L&F, there are some themes:
		// DefaultMetal, Ocean, Aqua, Charcoal, Contrast, Emerald and Ruby. So
		// you can use setTheme("Metal");, setTheme("Nimbus");, or
		// setTheme("Metal", "Aqua");.
		setTheme("Metal", "Charcoal");

		// Schedule a job for the event-dispatching thread:
		// creating and showing this application's GUI.
		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {
				if (SwingUtilities.isEventDispatchThread()) {
					System.out.println("This is in the event-dispatching "
							+ "thread...");
				}
				createAndShowGUI();
			}

		});
	}
}

/**
 * Create a placeholder icon, which consists in a white box with a black border
 * and a red x inside. It's used to display something when there are issues
 * loading an icon from an external location.
 * 
 * @author HAN
 * 
 */
class MissingIcon implements Icon {
	private int width = 32;
	private int height = 32;

	@Override
	public void paintIcon(Component c, Graphics g, int x, int y) {
		// TODO Auto-generated method stub
		Graphics2D g2 = (Graphics2D) g;
		Shape rect = new Rectangle2D.Double(x + 1, y + 1, width - 2, height - 2);
		g2.setColor(Color.WHITE);
		g2.fill(rect);
		g2.setColor(Color.BLACK);
		g2.draw(rect);// By default, the stroke is 1.0f solid line.

		g2.setColor(Color.RED);
		BasicStroke stroke = new BasicStroke(4.0f);
		g2.setStroke(stroke);
		g2.draw(new Line2D.Double(x + 10, y + 10, x + width - 10, y + height
				- 10));
		g2.draw(new Line2D.Double(x + 10, y + height - 10, x + width - 10,
				y + 10));
	}

	@Override
	public int getIconWidth() {
		// TODO Auto-generated method stub
		return width;
	}

	@Override
	public int getIconHeight() {
		// TODO Auto-generated method stub
		return height;
	}
}

/**
 * This class describes a theme using "blue-green" colors.
 */
class AquaTheme extends DefaultMetalTheme {

	public String getName() {
		return "Aqua";
	}

	private final ColorUIResource primary1 = new ColorUIResource(102, 153, 153);
	private final ColorUIResource primary2 = new ColorUIResource(128, 192, 192);
	private final ColorUIResource primary3 = new ColorUIResource(159, 235, 235);

	protected ColorUIResource getPrimary1() {
		return primary1;
	}

	protected ColorUIResource getPrimary2() {
		return primary2;
	}

	protected ColorUIResource getPrimary3() {
		return primary3;
	}

}

/**
 * This class describes a theme using gray colors.
 */
class CharcoalTheme extends DefaultMetalTheme {

	public String getName() {
		return "Charcoal";
	}

	private final ColorUIResource primary1 = new ColorUIResource(66, 33, 66);
	private final ColorUIResource primary2 = new ColorUIResource(90, 86, 99);
	private final ColorUIResource primary3 = new ColorUIResource(99, 99, 99);

	private final ColorUIResource secondary1 = new ColorUIResource(0, 0, 0);
	private final ColorUIResource secondary2 = new ColorUIResource(51, 51, 51);
	private final ColorUIResource secondary3 = new ColorUIResource(102, 102,
			102);

	private final ColorUIResource black = new ColorUIResource(222, 222, 222);
	private final ColorUIResource white = new ColorUIResource(0, 0, 0);

	protected ColorUIResource getPrimary1() {
		return primary1;
	}

	protected ColorUIResource getPrimary2() {
		return primary2;
	}

	protected ColorUIResource getPrimary3() {
		return primary3;
	}

	protected ColorUIResource getSecondary1() {
		return secondary1;
	}

	protected ColorUIResource getSecondary2() {
		return secondary2;
	}

	protected ColorUIResource getSecondary3() {
		return secondary3;
	}

	protected ColorUIResource getBlack() {
		return black;
	}

	protected ColorUIResource getWhite() {
		return white;
	}

}

/**
 * This class describes a higher-contrast Metal Theme.
 */
class ContrastTheme extends DefaultMetalTheme {

	public String getName() {
		return "Contrast";
	}

	private final ColorUIResource primary1 = new ColorUIResource(0, 0, 0);
	private final ColorUIResource primary2 = new ColorUIResource(204, 204, 204);
	private final ColorUIResource primary3 = new ColorUIResource(255, 255, 255);
	private final ColorUIResource primaryHighlight = new ColorUIResource(102,
			102, 102);

	private final ColorUIResource secondary2 = new ColorUIResource(204, 204,
			204);
	private final ColorUIResource secondary3 = new ColorUIResource(255, 255,
			255);

	protected ColorUIResource getPrimary1() {
		return primary1;
	}

	protected ColorUIResource getPrimary2() {
		return primary2;
	}

	protected ColorUIResource getPrimary3() {
		return primary3;
	}

	public ColorUIResource getPrimaryControlHighlight() {
		return primaryHighlight;
	}

	protected ColorUIResource getSecondary2() {
		return secondary2;
	}

	protected ColorUIResource getSecondary3() {
		return secondary3;
	}

	public ColorUIResource getControlHighlight() {
		return super.getSecondary3();
	}

	public ColorUIResource getFocusColor() {
		return getBlack();
	}

	public ColorUIResource getTextHighlightColor() {
		return getBlack();
	}

	public ColorUIResource getHighlightedTextColor() {
		return getWhite();
	}

	public ColorUIResource getMenuSelectedBackground() {
		return getBlack();
	}

	public ColorUIResource getMenuSelectedForeground() {
		return getWhite();
	}

	public ColorUIResource getAcceleratorForeground() {
		return getBlack();
	}

	public ColorUIResource getAcceleratorSelectedForeground() {
		return getWhite();
	}

	public void addCustomEntriesToTable(UIDefaults table) {

		Border blackLineBorder = new BorderUIResource(
				new LineBorder(getBlack()));

		Object textBorder = new BorderUIResource(new CompoundBorder(
				blackLineBorder, new BasicBorders.MarginBorder()));

		table.put("ToolTip.border", blackLineBorder);
		table.put("TitledBorder.border", blackLineBorder);

		table.put("TextField.border", textBorder);
		table.put("PasswordField.border", textBorder);
		table.put("TextArea.border", textBorder);
		table.put("TextPane.border", textBorder);
		table.put("EditorPane.border", textBorder);
	}

}

/**
 * This class describes a theme using glowing green colors.
 */
class EmeraldTheme extends DefaultMetalTheme {

	public String getName() {
		return "Emerald";
	}

	private final ColorUIResource primary1 = new ColorUIResource(51, 142, 71);
	private final ColorUIResource primary2 = new ColorUIResource(102, 193, 122);
	private final ColorUIResource primary3 = new ColorUIResource(153, 244, 173);

	protected ColorUIResource getPrimary1() {
		return primary1;
	}

	protected ColorUIResource getPrimary2() {
		return primary2;
	}

	protected ColorUIResource getPrimary3() {
		return primary3;
	}

}

/**
 * This class describes a theme using red colors.
 */
class RubyTheme extends DefaultMetalTheme {

	public String getName() {
		return "Ruby";
	}

	private final ColorUIResource primary1 = new ColorUIResource(80, 10, 22);
	private final ColorUIResource primary2 = new ColorUIResource(193, 10, 44);
	private final ColorUIResource primary3 = new ColorUIResource(244, 10, 66);

	protected ColorUIResource getPrimary1() {
		return primary1;
	}

	protected ColorUIResource getPrimary2() {
		return primary2;
	}

	protected ColorUIResource getPrimary3() {
		return primary3;
	}

}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值