# Live Ticker "Endlosschleife"



## sMau90 (9. Sep 2011)

Hi,
Ich versuche grade einen Live Ticker in Java zu schreiben. Ich habe aber einfach keine gute Idee, wie ich es schaffe, dass der Text wenn er links "aus dem Bild rausläuft" auf der rechten Seite direkt wieder "einläuft". Also am besten so, dass keine Lücken entstehen. Mein Code bist jetzt (der Text läuft einfach einmal von rechts nach links durch):


```
public class PanelTicker extends JPanel {
	
	public PanelTicker() {
		setFont(new Font("Arial", Font.BOLD, 32));
		setBorder(null);
		setDoubleBuffered(true);
		
	}
	
	String tickerString = "";
	int x = 10;
	
	private Timer timer = new Timer(100, new ActionListener() {
		public void actionPerformed(ActionEvent arg0) {
			move();
		}
	});
	
	
	public void paintComponent(Graphics g) {
		
		/*
		 * Antialising einschalten
		 */
		((Graphics2D)g).setRenderingHint
		  (RenderingHints.KEY_ANTIALIASING,
		   RenderingHints.VALUE_ANTIALIAS_ON);

		Image image = new ImageIcon("/home/samu/Desktop/1.jpg").getImage();
		g.drawImage(image, 0, 0, Color.BLACK, this);
		g.setColor(Color.WHITE);
		g.drawString(tickerString, x, 32);
		
	}
	
	public void move() {
		
			x--;
			repaint();
			Display.getDisplayFrame().repaint();
	}
	
	public void setTimerDelay(int delay) {
		timer.setDelay(delay);
	}
	
	public void setTickerString() {
		
		tickerString = PanelDisplayControls.getTextFieldTickerString().getText();
		
	}
	

	public void setTimer(Timer timer) {
		this.timer = timer;
	}

	public Timer getTimer() {
		return timer;
	}
		
}
```

Wenn ich ja irgendwie die Position des gezeichneten Strings bestimmen könnte, würde ich schon klar kommen, aber hab einfach keine Idee und hab auch noch nicht viel mit Graphics gemacht.

Danke schonmal für die Hilfe

Grüße,
sMau


----------



## Michael... (9. Sep 2011)

Grundsätzlich ist es eine schlechte Idee das Bild in der paintComponent zu laden.
Wenn das Bild aus der Komponente "herausgelaufen" ist, musst Du die x Koordinate natürlich auf einen vernünftigen Wert zurück setzen.
Wenn Du keine Lücken haben willst, musst Du das Bild zwei bis x-mal zeichnen.


----------



## sMau90 (9. Sep 2011)

Ok, das Bild dient ja nur als Hintergrund. Und ja stimmt ist nicht sonderlich effektiv das immer mit neu zuzeichnen. Aber das was sich bewegt ist der String, nicht das Bild.
Also grundsätzlich hab ich aber die gleiche Idee die du grade geschildert hast, dass wenn ich die Position vom Ende des Strings, also so zu sagen den äußersten rechten Pixel, bestimme, kann ich das Programm dann entsprechend reagieren lassen. Aber ich weiß nicht wie ich die Position bestimme, oder welche andere Bedingung sonst in Frage käme.
Bin für jeden Vorschlag offen (=

Grüße,
sMau


EDIT

Ich glaube ich habe gefunden was ich gesucht habe, damit kann ich die breite des Strings in Pixeln berechnen und so auch den äußeren rechten Punkt.

```
g.getFontMetrics().stringWidth(string);
```

Falls dennoch jemand nen Ansatz für ne elegantere Lösung hat, immer her damit.


----------



## Michael... (9. Sep 2011)

sMau90 hat gesagt.:


> Ich glaube ich habe gefunden was ich gesucht habe, damit kann ich die breite des Strings in Pixeln berechnen und so auch den äußeren rechten Punkt.
> 
> ```
> g.getFontMetrics().stringWidth(string);
> ...


Sorry, hatte das mit dem String gar nicht gesehen. Wenn man davon ausgehen kann, dass der Font gleichbleibt oder sogar explizit für die Komponente gesetzt wird, sollte man die FontMetrics nicht vom Graphics Objekt sondern auch hier wieder ausserhalb der paintComponent von der Komponente direkt bezogen werden.
Ein anderere - vielleicht auch nicht ganz so schöner - Ansatz wäre, den String zu manipulieren, also vorne immer Buchstaben abschneiden. Damit könnte man einfach nur ein Label plus Thread/Timer nehmen ohne die paintComponent zu überschreiben.


----------



## sMau90 (9. Sep 2011)

Der Font ist gleichbleibend und wird einmal explizit gesetzt.
Allerdings kann ich dir nicht ganz folgen, hab noch nich so viel mit Graphics gemacht.
Wenn du mir ein kleines Beispiel gibst, was du damit meinst reicht das aber bestimmt schon.

Jedenfalls nochmal vielen Dank für die ganzen Antworten.

Grüße,
sMau


----------



## Michael... (9. Sep 2011)

Ganz am Anfang setzt Du ja den Font 
	
	
	
	





```
new Font("Arial", Font.BOLD, 32));
```
, wenn Du nun eine Referenz auf das Font Objekt in einer Instanzvariablen halten würdest, könntest Du unmittelbar in der setTickerString() (die eigentlich keine echte set-Methode ist ;-)) über dessen FontMetrics die Breite des Strings bestimmen.

```
int width = font.getFontMetrics().stringWidth(tickerString);
```
In der von Dir geposten Zeile sieht es so aus, als würdest Du die Breite immer wieder in der paintComponent(...) neu berechnen, was - wenn der Font immer der gleiche bleibt - unnötig ist.


----------



## jgh (9. Sep 2011)

ich hatte sowas mal vor langer Zeit auch implementiert...hier mal ein kleines KSKB:
Er beginnt jetzt von neuem, wenn der alte String "rausgelaufen" ist...aber das ist ja auch ruckzuck änderbar, wenn man einfach die Länge des Tickerstrings mitberechnet.


```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class LiveTickerPanel extends JPanel implements Runnable {
	private static final long serialVersionUID = 1L;
	private JLabel tickerLabel;
	private String tickerString;
	private int x = 0;
	private int step = 2;
	private int delay = 80;

	public LiveTickerPanel() {
		initComponents();
	}

	private void initComponents() {
		setLayout(new FlowLayout());
		this.setBackground(Color.RED);
		setOpaque(true);
		tickerString = "Das ist nur der Teststring";
		tickerLabel = new JLabel(tickerString);
		add(tickerLabel);
		tickerLabel.setLocation(x, 0);
		start();
	}

	private void start() {
		Thread t = new Thread(this);
		t.setDaemon(true);
		t.start();
	}

	public static void main(String[] args) {
		JFrame f = new JFrame();
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setSize(new Dimension(300, 300));
		f.setLocationRelativeTo(null);
		LiveTickerPanel ltp = new LiveTickerPanel();
		f.add(BorderLayout.SOUTH, ltp);
		f.setVisible(true);
	}

	@Override
	public void run() {
		while (!Thread.interrupted()) {
			if (isVisible()) {
				int widthX = getWidth();
				int laenge = tickerLabel.getWidth();
				if (x > -laenge) {
					x = x - step;
					SwingUtilities.invokeLater(new Runnable() {
						@Override
						public void run() {
							tickerLabel.setLocation(x, 0);
						}
					});
				} else {
					x = widthX;
				}
			}
			try {
				Thread.sleep(delay);
			} catch (InterruptedException e) {
				return;
			}
		}
	}
}
```


----------



## sMau90 (9. Sep 2011)

Ja cool danke, werd ich so machen (=

@JGH
Auch nochmal Danke für dieses Beispiel


----------



## sMau90 (12. Sep 2011)

Bin jetzt endlich mal dazu gekommen das auszuprobieren und es klappt auch alles wunderbar, allerdings wenn ich versuche das hier zu machen:


```
int width = font.getFontMetrics().stringWidth(tickerString);
```

Bekomme ich die Meldung "getFontMetrics is undefined for Type font".

Jemand ne Idee wie ich da trotzdem dran komme? Oder gibt es ne Möglichkeit wie ich einfach außerhalb der paint Methode an das "Grphics Objekt" ran komme? Damit ich nicht bei jedem repaint die String Länge neu berechne.

Grüße,
sMau


----------



## Michael... (12. Sep 2011)

Sorry, mein Fehler so kurz vorm Wochenende lässt die Konzentration bei mir nach ;-)
Die Methode getFontMetrics(...) musst Du an Deiner Komponente aufrufen.
Innerhalb Deines Panels sollte sowas funktionieren:

```
int width = getFontMetrics(font).stringWidth(tickerString);
```


----------



## sMau90 (12. Sep 2011)

Danke (=
funktioniert perfekt


----------

