我正在开发一个基于 NetBeans 平台的纸牌游戏,我正在努力了解动态图像。为什么是动态的?好吧,我希望卡片在运行时根据页面的更改(即名称、文本、成本等)进行调整。
我的第一个技巧是创建一个组件(JPanel),其中预先放置了标签,我根据卡片值加载了文本/图像。这似乎工作正常,但是当我想到某些页面在以后的版本中具有不同的外观时(这意味着并非所有内容都在同一个地方),这变得很麻烦。
所以我试图根据某种模板来了解如何做到这一点。
任何想法?
有一个后续问题:JList of cards?
我正在开发一个基于 NetBeans 平台的纸牌游戏,我正在努力了解动态图像。为什么是动态的?好吧,我希望卡片在运行时根据页面的更改(即名称、文本、成本等)进行调整。
我的第一个技巧是创建一个组件(JPanel),其中预先放置了标签,我根据卡片值加载了文本/图像。这似乎工作正常,但是当我想到某些页面在以后的版本中具有不同的外观时(这意味着并非所有内容都在同一个地方),这变得很麻烦。
所以我试图根据某种模板来了解如何做到这一点。
任何想法?
有一个后续问题:JList of cards?
最后我有时间回到这个问题上,并且能够找到一种使用 Java 2D 教程的方法。
这些图片与我将在我的应用程序中使用的图片不同,但可以作为概念证明。
包javaapplication3;
导入 java.awt.*;导入 java.awt.font.FontRenderContext;导入 java.awt.font.LineBreakMeasurer;导入 java.awt.font.TextAttribute;导入 java.awt.font.TextLayout;导入 java.awt.image.BufferedImage;导入java.io.File;导入 java.io.IOException;导入 java.net.MalformedURLException;导入 java.net.URL;导入 java.text.AttributedCharacterIterator;导入 java.text.AttributedString;导入 java.util.ArrayList;导入 java.util.HashMap;导入 java.util.logging.Level;导入 java.util.logging.Logger;导入 javax.imageio.ImageIO;
/** * * @author Javier A. Ortiz Bultrón */ public class DefaultImageManager {
/** * @param args the command line arguments */ public static void main(String[] args) { try { // TODO code application logic here DefaultImageManager manager = new DefaultImageManager(); URL url = DefaultImageManager.class.getResource("weather-rain.png"); manager.getLayers().add(ImageIO.read(url)); url = DefaultImageManager.class.getResource("weather-sun.png"); manager.getLayers().add(ImageIO.read(url)); manager.addText(new Font("Arial", Font.PLAIN, 10), "Many people believe that Vincent van Gogh painted his best works " + "during the two-year period he spent in Provence. Here is where he " + "painted The Starry Night--which some consider to be his greatest " + "work of all. However, as his artistic brilliance reached new " + "heights in Provence, his physical and mental health plummeted. ", 200, 150, new Point(0, 0)); manager.generate(); } catch (MalformedURLException ex) { Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,
空,前);} catch (IOException ex) { Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE, null, ex); } } /** * 用于创建最终图像的层 */ private ArrayList layers = new ArrayList(); 私有 ArrayList textLayers = new ArrayList();
/** * @return the layers */ public ArrayList<BufferedImage> getLayers() { return layers; } private Dimension getMaxSize() { int width = 0, height = 0; for (BufferedImage img : getLayers()) { if (img.getWidth() > width) { width = img.getWidth(); } if (img.getHeight() > height) { height = img.getHeight(); } } return new Dimension(width, height); } public void addText(Font font, String text, int height, int width, Point location) { BufferedImage textImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); HashMap<TextAttribute, Object> map = new HashMap<TextAttribute, Object>(); map.put(TextAttribute.FAMILY, font.getFamily()); map.put(TextAttribute.SIZE, font.getSize()); map.put(TextAttribute.FOREGROUND, Color.BLACK); AttributedString aString = new AttributedString(text, map); AttributedCharacterIterator paragraph = aString.getIterator(); // index of the first character in the paragraph. int paragraphStart = paragraph.getBeginIndex(); // index of the first character after the end of the paragraph. int paragraphEnd = paragraph.getEndIndex(); Graphics2D graphics = textImage.createGraphics(); FontRenderContext frc = graphics.getFontRenderContext(); // The LineBreakMeasurer used to line-break the paragraph. LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc); // Set break width to width of Component. float breakWidth = width; float drawPosY = 0; // Set position to the index of the first character in the paragraph. lineMeasurer.setPosition(paragraphStart); // Get lines until the entire paragraph has been displayed. while (lineMeasurer.getPosition() < paragraphEnd) { // Retrieve next layout. A cleverer program would also cache // these layouts until the component is re-sized. TextLayout layout = lineMeasurer.nextLayout(breakWidth); // Compute pen x position. If the paragraph is right-to-left we // will align the TextLayouts to the right edge of the panel. // Note: this won't occur for the English text in this sample. // Note: drawPosX is always where the LEFT of the text is placed. float drawPosX = layout.isLeftToRight() ? 0 : breakWidth - layout.getAdvance(); // Move y-coordinate by the ascent of the layout. drawPosY += layout.getAscent(); // Draw the TextLayout at (drawPosX, drawPosY). layout.draw(graphics, drawPosX, drawPosY); // Move y-coordinate in preparation for next layout. drawPosY += layout.getDescent() + layout.getLeading(); } getTextLayers().add(textImage); } public void generate() throws IOException { Dimension size = getMaxSize(); BufferedImage finalImage = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB); for (BufferedImage img : getLayers()) { finalImage.createGraphics().drawImage(img, 0, 0, size.width, size.height, 0, 0, img.getWidth(null), img.getHeight(null), null); } for(BufferedImage text: getTextLayers()){ finalImage.createGraphics().drawImage(text, 0, 0, text.getWidth(), text.getHeight(), 0, 0, text.getWidth(null), text.getHeight(null), null); } File outputfile = new File("saved.png"); ImageIO.write(finalImage, "png", outputfile); } /** * @return the textLayers */ public ArrayList<BufferedImage> getTextLayers() { return textLayers; } /** * @param textLayers the textLayers to set */ public void setTextLayers(ArrayList<BufferedImage> textLayers) { this.textLayers = textLayers; } }
它仍然需要对文本的位置进行一些特别的改进,但它确实有效。我想我可以实现一个 xml 格式来存储所有这些信息,因此很容易配置。在下面的示例中,太阳被绘制在雨之上,而文本则位于所有之上。对于我的应用程序,每一层都将构建我想要的页面。
以下是我使用的图片:
最后的结果: