创建循环自身的动画文本

时间:2015-06-03 20:18:12

标签: java swing animation timer

我试图制作一个新闻自动收报机类型的东西,其中输入一个字符串,并在JPanel内部文本循环。

我知道它目前每秒大约移动90个像素,并且此字体中每个字符大约有16个像素。所以我要问的是我如何使用这些信息来制作它,以便在计时器运行一段时间后,产生一个新的动画文本,以及在第一个动画文本完全离开屏幕后,如何从中删除它记忆。

这是我到目前为止所做的,代码是从这里大量借用的:Java Animate JLabel,所以如果你看到任何不需要的代码,请告诉我。

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.EnumMap;
import javax.swing.*;

@SuppressWarnings("serial")
public class AnimateExample extends JPanel {
    private static final int TIMER_DELAY = 20;
    private static final String KEY_DOWN = "key down";
    public static final int TRANSLATE_SCALE =2;
    private static final Font BG_STRING_FONT = new Font(Font.SANS_SERIF,
            Font.BOLD, 32);
    private EnumMap<Direction, Boolean> dirMap = 
            new EnumMap<AnimateExample.Direction, Boolean>(Direction.class);
    private BufferedImage image = null;
    private int posX = 100;
    private int posY = 50;
    Timer t;

    public AnimateExample() {
        for (Direction dir : Direction.values()) {
            dirMap.put(dir, Boolean.TRUE);
        }
        t = new Timer(TIMER_DELAY, new TimerListener());
        t.start();


        ActionMap actionMap = getActionMap();
        for (final Direction dir : Direction.values()) {
            actionMap.put(dir.Left + KEY_DOWN, new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    dirMap.put(dir, true);
                }
            });
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g.setFont(BG_STRING_FONT);
        g.setColor(Color.LIGHT_GRAY);
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        String s = "Hi, I'm trying to make a news ticker type thing where a string is entered and inside of a JPanel the text is looped.I know it moves currently at about 90 pixels a second and that there is about 16 pixels per char in this font. So what I am asking is how I can use this information to make it so that after a timer runs for a certain time, a new animated text is spawned, and how after the 1st animated text leaves the screen completely, how to delete it from the memory.";

        g.drawString(s, posX, posY);

    }

    private class TimerListener implements ActionListener {
        public void actionPerformed(java.awt.event.ActionEvent e) {
            for (Direction dir : Direction.values()) {
                if (dirMap.get(dir)) {
                    posX += dir.getX() * TRANSLATE_SCALE;
                    posY += dir.getY() * TRANSLATE_SCALE;
                }
            }
            repaint();
            if(posX<-500)
            {
                t.stop();
            }
        };
    }

    enum Direction {
        Left( KeyEvent.VK_LEFT, -1, 0);

        private int keyCode;
        private int x;
        private int y;

        private Direction(int keyCode, int x, int y) {
            this.keyCode = keyCode;
            this.x = x;
            this.y = y;
        }
        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }
    }

    private static void createAndShowGui() {
        AnimateExample mainPanel = new AnimateExample();

        JFrame frame = new JFrame("Animate Example");
        frame.setUndecorated(true);
        frame.setSize(1600, 900);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(null);
        frame.add(mainPanel);
        mainPanel.setBounds(new Rectangle(1600,400));
        frame.setVisible(true);    
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

编辑: 我也在想,也许在一定的时间或距离之后重置X位置,但问题是它需要该区域对于一个屏幕长度是空白的。如果你有一个解决方法,它也会很棒。

2 个答案:

答案 0 :(得分:2)

您可以查看Marquee Panel。它使用与大多数滚动器不同的方法。您将实际组件添加到面板,并滚动组件。

这允许您滚动文本或图像。您可以使用带有HTML的标签,以便您可以使用彩色文本等。邮件将继续滚动,直到您手动停止滚动。

目前没有替换滚动消息的自动机制。虽然您可以轻松创建消息的列表或队列。然后,当邮件完成完全滚动时,您只需删除当前邮件并添加新邮件。

以下是您需要更改的MarqueePanel课程的部分代码:

public void actionPerformed(ActionEvent ae)
{
    scrollOffset = scrollOffset + scrollAmount;
    int width = super.getPreferredSize().width;

    if (scrollOffset > width)
    {
        scrollOffset = isWrap() ? wrapOffset + scrollAmount : - getSize().width;
        //  add code here to swap component from the List or Queue 
    }

    repaint();
}

当然,您还需要在类中添加一个方法,以便将组件添加到List或Queue中。

答案 1 :(得分:1)

不要担心字符宽度,因为不同的字体会产生可变的字符宽度。而是使用 private double convertToNumber(String number) { double d = Double.parseDouble(number); if (d % 1.0 == 0) { return Integer.parseInt(number); } else { return d; } } 来衡量FontMetrics宽度,并将其确定为String,这时文本将完全偏离屏幕的左侧。

您可以使用某种xPos <= -stringWidth来管理文本,根据需要弹出下一个文本。此示例只是将最后一条消息弹出到队列的末尾,因此它将不断重复

enter image description here

Queue