Java 使用Icon (版本2)

来源:互联网 发布:周杰被黑真相知乎 编辑:程序博客网 时间:2024/06/07 00:03

发展了一下,第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 panetoolBar = 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 directlyphotoLabel.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 Feeltry {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;@Overrideprotected 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;}@Overrideprotected 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);}}@Overrideprotected 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);}@Overridepublic 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 screenframe.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() {@Overridepublic 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;@Overridepublic void paintIcon(Component c, Graphics g, int x, int y) {// TODO Auto-generated method stubGraphics2D 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));}@Overridepublic int getIconWidth() {// TODO Auto-generated method stubreturn width;}@Overridepublic int getIconHeight() {// TODO Auto-generated method stubreturn 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;}}


原创粉丝点击