Swing and threads: scroll text
import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; public class ScrollText extends JComponent { private BufferedImage image; private Dimension imageSize; private volatile int currOffset; private Thread internalThread; private volatile boolean noStopRequested; public ScrollText(String text) { currOffset = 0; buildImage(text); setMinimumSize(imageSize); setPreferredSize(imageSize); setMaximumSize(imageSize); setSize(imageSize); noStopRequested = true; Runnable r = new Runnable() { public void run() { try { runWork(); } catch (Exception x) { x.printStackTrace(); } } }; internalThread = new Thread(r, "ScrollText"); internalThread.start(); } private void buildImage(String text) { RenderingHints renderHints = new RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); renderHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); BufferedImage scratchImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); Graphics2D scratchG2 = scratchImage.createGraphics(); scratchG2.setRenderingHints(renderHints); Font font = new Font("Serif", Font.BOLD | Font.ITALIC, 24); FontRenderContext frc = scratchG2.getFontRenderContext(); TextLayout tl = new TextLayout(text, font, frc); Rectangle2D textBounds = tl.getBounds(); int textWidth = (int) Math.ceil(textBounds.getWidth()); int textHeight = (int) Math.ceil(textBounds.getHeight()); int horizontalPad = 10; int verticalPad = 6; imageSize = new Dimension(textWidth + horizontalPad, textHeight + verticalPad); image = new BufferedImage(imageSize.width, imageSize.height, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = image.createGraphics(); g2.setRenderingHints(renderHints); int baselineOffset = (verticalPad / 2) - ((int) textBounds.getY()); g2.setColor(Color.white); g2.fillRect(0, 0, imageSize.width, imageSize.height); g2.setColor(Color.blue); tl.draw(g2, 0, baselineOffset); // Free-up resources right away, but keep "image" for // animation. scratchG2.dispose(); scratchImage.flush(); g2.dispose(); } public void paint(Graphics g) { // Make sure to clip the edges, regardless of curr size g.setClip(0, 0, imageSize.width, imageSize.height); int localOffset = currOffset; // in case it changes g.drawImage(image, -localOffset, 0, this); g.drawImage(image, imageSize.width - localOffset, 0, this); // draw outline g.setColor(Color.black); g.drawRect(0, 0, imageSize.width - 1, imageSize.height - 1); } private void runWork() { while (noStopRequested) { try { Thread.sleep(100); // 10 frames per second // adjust the scroll position currOffset = (currOffset + 1) % imageSize.width; // signal the event thread to call paint() repaint(); } catch (InterruptedException x) { Thread.currentThread().interrupt(); } } } public void stopRequest() { noStopRequested = false; internalThread.interrupt(); } public boolean isAlive() { return internalThread.isAlive(); } public static void main(String[] args) { ScrollText st = new ScrollText("Java can do animation!"); JPanel p = new JPanel(new FlowLayout()); p.add(st); JFrame f = new JFrame("ScrollText Demo"); f.setContentPane(p); f.setSize(400, 100); f.setVisible(true); } }