View Full Version : [ Applet Java ] Scorrimento Immagini - Genymus
Salve, avrei bisogno di una applet java che faccia scorrere orrizzontalmente verso destra una serie di immagini in continuazione ripartendo dalla prima quando le ha visualizzate tutte.
Grazie
Genymus
Si tratta semplicemente di usare un offset per spostare l'origine degli assi tra un'invocazione e l'altra di:
for(int i = 0; i < maxFramesPerPage; i++) {
g.drawImage(frames[i], offsetX, 0, null);
}
Qui maxFramesPerPage è calcolato come il numero massimo di immagini visualizzabili in un un'unica schermata più uno.
L'offset varia da 0 a -frames[0].getWidth() (supponendo che frames sia un array di BufferedImage).
Quando l'offset raggiunge -frames[0].getWidth() fai scorrere il vettore a sinistra e aggiungi tante immagini quante sono necessarie a riempire nuovamente lo schermo.
Nulla di particolarmente esotico.
penso di aver capito...
può postarmi il codice completo?
Come no, eccolo qua.
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import javax.imageio.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.*;
public class SlideApplet extends JApplet {
private final Screen SCREEN = new ScreenImpl();
private void initializeUI() {
add(SCREEN.getComponent());
String speedValue = getParameter("speed");
if(speedValue != null) {
try {
SCREEN.setSpeed(Float.parseFloat(speedValue));
} catch(NumberFormatException ex) {
System.err.println("speed property " + speedValue + " not a float. Using default.");
}
}
try {
URL list = new URL(getCodeBase() + "/" + getParameter("imagelist"));
SCREEN.setImages(list);
SCREEN.start();
System.out.println("screen on line");
} catch(MalformedURLException ex) {
System.err.println("whops, wrong url!");
ex.printStackTrace();
}
}
public void init() {
EventQueue.invokeLater(new Runnable() {
public void run() {
initializeUI();
}
});
}
public void stop() {
SCREEN.stop();
}
}
interface Screen {
void setSpeed(float value);
void setImages(URL pathListUrl);
void start();
void stop();
JComponent getComponent();
}
class Ticker {
private long then;
private long tick;
public void start() {
then = System.nanoTime();
}
public void update() {
long now = System.nanoTime();
tick = (now - then) / 1000000;
then = now;
}
public long getTick() {
return tick;
}
}
class ScreenImpl extends JPanel implements Screen {
private final ActionListener LOOP = new ActionListener() {
public void actionPerformed(ActionEvent e) { slide(); }
};
private final javax.swing.Timer ANIMATOR = new javax.swing.Timer(5, LOOP);
private final CopyOnWriteArrayList<String> IMAGES = new CopyOnWriteArrayList<String>();
private final ImageLoader IMAGE_LOADER = new ImageLoaderImpl();
private final AtomicInteger OFFSET_X = new AtomicInteger();
private final AtomicInteger NEXT_IMAGE = new AtomicInteger();
private final AtomicBoolean WAITING_LOAD = new AtomicBoolean();
private volatile float speed = 0.05f;
/** edt fields */
private final Ticker TICKER = new Ticker();
private final LinkedList<BufferedImage> FRAMES = new LinkedList<BufferedImage>();
public void setSpeed(float value) {
if(value < 0.01f) {
System.err.println(value + " too low");
} else {
speed = value;
}
}
public void setImages(final URL pathListUrl) {
if(pathListUrl == null) {
System.err.println("ScreenImpl, method setImages, url is null");
return;
}
Thread runner = new Thread() {
public void run() {
try {
LinkedList<String> list = new LinkedList<String>();
Scanner in = new Scanner(pathListUrl.openStream());
while(in.hasNextLine()) {
list.add(in.nextLine());
}
setImages(list);
} catch(IOException ex) {
return;
}
}
};
runner.setDaemon(true);
runner.start();
}
public void setImages(Collection<String> paths) {
stop();
IMAGES.clear();
IMAGES.addAll(paths);
OFFSET_X.set(0);
NEXT_IMAGE.set(0);
start();
}
public JComponent getComponent() {
return this;
}
private void slide() {
TICKER.update();
int paintSize = OFFSET_X.get() - getWidth();
for(int i = 0; i < FRAMES.size(); i++) {
paintSize += FRAMES.get(i).getWidth();
}
if(paintSize <= getWidth()) {
loadNextFrame();
} else {
int delta = -(int)Math.round(speed * TICKER.getTick());
if(OFFSET_X.addAndGet(delta) + FRAMES.get(0).getWidth() <= 0) {
OFFSET_X.set(0);
FRAMES.remove(0);
}
repaint();
}
}
private void loadNextFrame() {
if(IMAGES.size() == 0) {
return;
}
if(WAITING_LOAD.get()) {
return;
}
WAITING_LOAD.set(true);
URL address = getClass().getResource(IMAGES.get(NEXT_IMAGE.get()));
IMAGE_LOADER.submit(new LoadImage(address, getGraphicsConfiguration()) {
public void run() {
FRAMES.add(getImage());
WAITING_LOAD.set(false);
}
});
if(address != null) {
if(NEXT_IMAGE.incrementAndGet() == IMAGES.size()) {
NEXT_IMAGE.set(0);
}
}
}
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D g = (Graphics2D)graphics;
graphics.translate(OFFSET_X.get(), 0);
int x = 0;
for(BufferedImage image : FRAMES) {
int y = getHeight() / 2 - image.getHeight() / 2;
graphics.drawImage(image, x, y, null);
x += image.getWidth();
}
}
public void start() {
TICKER.start();
ANIMATOR.start();
}
public void stop() {
IMAGE_LOADER.stop();
ANIMATOR.stop();
}
}
abstract class LoadImage implements Runnable {
private final URL ADDRESS;
private final GraphicsConfiguration GC;
private BufferedImage image;
LoadImage(URL address, GraphicsConfiguration gc) {
ADDRESS = address;
GC = gc;
}
URL getAddress() {
return ADDRESS;
}
GraphicsConfiguration getGC() {
return GC;
}
synchronized void setImage(BufferedImage image) {
this.image = image;
}
synchronized BufferedImage getImage() {
return image;
}
}
interface ImageLoader {
void submit(LoadImage task);
void stop();
}
class ImageLoaderImpl implements ImageLoader{
private LinkedBlockingQueue<LoadImage> TASK_QUEUE = new LinkedBlockingQueue<LoadImage>();
private final AtomicBoolean RUN = new AtomicBoolean(false);
private Thread runner;
private synchronized void setRunner(Thread t) {
runner = t;
}
private synchronized Thread getRunner() {
return runner;
}
public void stop() {
Thread t = getRunner();
if(t != null) {
t.interrupt();
}
RUN.set(false);
}
public void submit(LoadImage task) {
if(RUN.get() == false) {
RUN.set(true);
setRunner(new Thread() { public void run() { loop(); } });
getRunner().start();
}
for(LoadImage i : TASK_QUEUE) {
if(i.getAddress().equals(task.getAddress())) return;
}
TASK_QUEUE.offer(task);
}
private void loop() {
while(RUN.get()) {
try {
execute(TASK_QUEUE.take());
} catch(InterruptedException ex) {
return;
}
}
}
private void execute(LoadImage task) {
try {
System.out.println("loading " + task.getAddress());
BufferedImage image = ImageIO.read(task.getAddress());
task.setImage(optImage(image, task.getGC()));
EventQueue.invokeLater(task);
} catch(IOException ex) {
ex.printStackTrace();
}
}
private BufferedImage optImage(BufferedImage source, GraphicsConfiguration gc) {
if(gc == null) {
return source;
} else {
BufferedImage opt = gc.createCompatibleImage(source.getWidth(), source.getHeight(),
source.getTransparency());
Graphics2D g = opt.createGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
source.flush();
return opt;
}
}
}
Salve, la compilazione funziona alla perfezione...
mi può dire anche il codice html per i parametri?
Grazie
l'applet richiede due parametri, uno è speed l'altro è imagelist.
Il valore di speed è numerico ed esprime la velocità dello scorrimento delle immagini in pixel al millisecondo.
Il valore di imagelist è il percorso relativo di un file di testo. Questo file di testo contiene un elenco di percorsi relativi di file immagini (png, jpg, gif, bmp per la piattaforma standard Java SE 5+). Ogni linea di testo nel file contiene un percorso di immagine. Ad esempio il file potrebbe essere:
/immagini/thumb001.png
/immagini/thumb002.png
/immagini/thum003.png
/immagini/thum004.png
e così via fino a dove si vuole. Durante l'esecuzione il programma usa questi percorsi per caricare le immagini da visualizzare. Supponendo che il file si chiami list.txt si trovi nella stessa cartella dell'applet il codice dell'applet potrebbe essere:
<applet code="SlideApplet.class" width="400" height="400">
<param name="speed" value="0.05">
<param name="magelist" value="/list.txt">
</applet>
Non ho testato l'applet in linea. Adesso come adesso mi viene in mente che potrebbe esserci un problema nel caricamento delle immagini per via del getClass().getResource(). Forse sarebbe meglio usare dei percorsi assoluti.
Ho testato l'applet in linea, il caricamento delle immagini è ok ma c'è una valutazione ottimistica della banda in dowload del client :D (quantomeno della mia).
Il codice del metodo slide() al momento attende il caricamento dell'immagine necessaria ad assicurare il riempimento dello schermo prima di procedere con l'animazione il che causa interruzione dello scorrimento.
Sostituendo il metodo slide con questa versione:
private void slide() {
TICKER.update();
int paintSize = OFFSET_X.get() - getWidth();
for(int i = 0; i < FRAMES.size(); i++) {
paintSize += FRAMES.get(i).getWidth();
}
if(paintSize <= getWidth()) {
loadNextFrame();
}
if(FRAMES.size() == 0) return;
int delta = -(int)Math.round(speed * TICKER.getTick());
if(OFFSET_X.addAndGet(delta) + FRAMES.get(0).getWidth() <= 0) {
OFFSET_X.set(0);
FRAMES.remove(0);
}
repaint();
}
l'animazione prosegue se esiste almeno un'immagine nel buffer FRAMES. L'effetto cambia perchè adesso l'applet non è più in grado di garantire che l'utente veda effettivamente almeno un'immagine. E' possibile cioè che una banda particolarmente orrenda o immagini di dimensioni rilevanti causino lo svuotamento dell'applet.
Qui è roba da alchimisti. Non si può proiettare un'immagine che non c'è e non si può caricare l'immagine più rapidamente di quanto permetta la connessione del client.
Una soluzione potrebbe essere la ripetizione di un'immagine scelta a caso tra quelle tolte dal buffer ma ancora memorizzate.
La trama si complica :D.
Ps. Se vuoi provare qui (http://www.tukano.it/SlideApplet.html) trovi l'applet in funzione (le immagini le ho praticamente recuperate dal cestino, non farci caso).
Grazie
Funziona tutto alla perfezione.
Ps:Mi ha salvato la vita.
Genymus
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.