[Wyświetlenie] Applet Java wyświetlający kolejne zdjęcia

0

Na początek witam wszystkich użytkowników tego forum.

Napisałem applet którego zadaniem jest wyświetlanie kolejnych zdjęć w pętli. Gdy odpalam go w Eclipse wszystko fajnie działa. Podobnie przy wykorzystaniu appletviewer ale gdy umieszam go w html koniec radości. Dodam że jestem początkującym programistą i więcej napisałem aplikacji niż apletów.

Umieszczenie apletu w html:

<html>
<body>
<applet code="ImageApp.class" width=800 height=600>	<!-- codebase="x-applet"  -->
	<param name="file" value="ImageList.txt">	<!-- nazwa pliku -->
	<param name="colorR" value="21">         	<!-- wartość koloru czerwonego (0-255) -->
	<param name="colorG" value="222">         	<!-- wartość koloru zielonego (0-255) -->
	<param name="colorB" value="121">         	<!-- wartość koloru niebieskiego (0-255) -->
	<param name="miliSekundy" value="3000">     <!-- zmiana fotki co 3 sekundy -->
</applet>
</body>
</html>

Źródło apletu:

import java.applet.Applet;
import java.awt.*;
import java.io.*;
import java.util.*;

public class ImageApp extends Applet implements Runnable {
	
	//deklaracja zmiennych
	private static final long serialVersionUID = 1L;
	private ArrayList<String> imagesTable = new ArrayList<String>();
	private int cR, cG, cB, mSek;
	private String color, file, miliSekundy;
	private BufferedReader inputFile;
	private Image aktualneZdjecie;
	private int iloscZdjec;
	private int x = 10;
	private int y = 10;
	private int aktualnyNumerZdjecia = 0;
	private Thread my_thread = null;
	
	//inicjalizacja obiektów
	public void init() {
	
		//pobranie parametrów tła appletu
		if ((color=getParameter("colorR"))!=null) cR=Integer.parseInt(color);
		if ((color=getParameter("colorG"))!=null) cG=Integer.parseInt(color);
		if ((color=getParameter("colorB"))!=null) cB=Integer.parseInt(color);
		setBackground(new Color(cR,cG,cB));
		
		//pobranie parametru nazwy pliku z listą zdjęć, 
		//generowaną lokalnie przez użytkownika (programik zewnętrzny).
		//plik z listą jest umieszczony obok appletu i zdjęć
		if ((file=getParameter("file"))==null) {
			System.out.println("Nie pobrano nazwy pliku");
			file = "ImageList.txt";
		}
		
		//pobranie parametru milisekund
		if ((miliSekundy=getParameter("miliSekundy"))!=null) mSek=Integer.parseInt(miliSekundy);
		else mSek=3000;
		
		//metoda wypełnia tablicę typu ArrayList<String> i zwraca ją w postaci obietku
		myFileReader(file);
		
		//pobranie liczby wierszy z pliku
		iloscZdjec = imagesTable.size();
		
	}
	
	public void start() {
		my_thread = new Thread(this);
        my_thread.start();
	}
	
	public void run() {
		while (true) {
			if (aktualnyNumerZdjecia!=(iloscZdjec-1)) 
				aktualneZdjecie = getImage(getCodeBase(), imagesTable.get(aktualnyNumerZdjecia++));
			else {
				aktualneZdjecie = getImage(getCodeBase(), imagesTable.get(aktualnyNumerZdjecia));
				aktualnyNumerZdjecia = 0;
			}
			repaint();
			
			try {
				Thread.sleep(mSek);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
		}
	}
	
	private ArrayList<String> myFileReader(String nazwaPliku) {
		try {
			inputFile = new BufferedReader(new FileReader(file));
			String line = "";
			while (true) {
				line = inputFile.readLine();
				if (line == null)
					break;
				imagesTable.add(line);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return imagesTable;
	}
	
	public void paint(Graphics g) {
		
		int imgWidth = aktualneZdjecie.getWidth(this);
		int imgHeight = aktualneZdjecie.getHeight(this);
		
		int x = (getWidth()-imgWidth)/2;
		int y = ((getHeight()-imgHeight)/2)-20;
		
		g.setColor(Color.WHITE);
		g.fillRect(x-10, y-10, imgWidth+20, imgHeight+50);
		
		g.drawImage(aktualneZdjecie, x, y, this);
		
	}
}

Aplet korzysta z pliku ImageList.txt z listą generowaną przez użytkownika (do tego napisałem oddzielną aplikację). Obok listy są umieszczone zdjęcia, klasa i index.html. Przykładowa lista:
100_4393.jpg
100_4394.jpg
100_4395.jpg

Pomożecie?

0
  1. Ty chcesz żeby aplet czytał dane z pliku lokalnego? Dopóki apletu nie podpiszesz nie będzie mogł tego robić.
  2. U mnie aplet działa, zgłasza wyjątek (java.io.FilePermission ImageList.txt read).
  3. Kolor tła możesz opisać krócej, przy pomocy jednego parametru w "formacie HTML"
        String parametr=getParameter("background");
        Color tlo;
        if (parametr!=null)
        {
            try
            {
                tlo=Color.decode(parametr);
            }
            catch(NumberFormatException e)
            {
                tlo=Color.black;
            }
        }
        setBackground(tlo);
0

Dzięki 'bo'. Jak widać jeszcze bardzo mało wiem o Java i Apletach. Metoda decode(#...) bardzo mi się podoba i tym samym zagościła u mnie już na co dzień :)

Szukałem jakiegoś kompletnego opisu podpisania appletu ale nie znalazłem.
Robię tak:

  1. Obok apletu wrzucam plik java.policy.applet o treści
    grant { permission java.security.AllPermission; };
  2. Zakładam że gdzieś w init() muszę poinformować aplet o istnieniu tego pliku ale nie wiem jak a metoda 'Brute Force' mi nie przypada do gustu

Ktoś coś podpowie?


Stronka nad którą pracuje (uczę się) i wrzucam m.in aplety Java: http://arka2010.republika.pl/

0

Podpisujesz nie aplet ale plik jar (jar, to zip z innym rozszerzeniem). Ten jar powinien zawierać wszystkie niestandardowe klasy używane przez aplet, być może tylko jedną.
Aplet umieszczasz na stronie tak:

<applet code="GlownaKlasa.class" archive="NazwaJara.jar">
...
</applet>

A podpisujesz tak:

keytool -genkey -keystore nazwa_magazynu -alias nazwa_aliasu, ten krok wykonujesz raz
jarsigner -keystore nazwa_magazynu plik_jar nazwa_aliasu

0

Wiele przeglądarek nadaje apletom maksymalne ograniczenie pamięci do 64 MB. Przy czym JVM zwraca tę wartość jako maxMemory. Jak łatwo sobie policzysz 20 zdjęć 800x600 na planie płaskim 32 bit zajmuje ok. 40 MB - pod warunkiem, że w pamięci będzie wyłącznie jedna fizyczna kopia obrazka. Często jednak zależnie od użycia różnych metod jest pobierana dwukrotnie większa pamięć, czyli w tym wypadku może to być 80 MB. A wtedy aplet wypada z pamięci lub sieje wyjątkami OutOfMemoryError. Powinieneś sprawdzić tę kwestię na jakimś aplecie testowym, który przydziela sobie tyle pamięci ile jest w stanie i wypisze tę wartość.

Co do kodu, to postaraj się unikać takich warunków jak if (aktualnyNumerZdjecia!=(iloscZdjec-1)) ponieważ jeżeli z powodu jakiegoś drobnego błędu aktualnyNumerZdjęcia stanie się wartością ujemną, to pętla opartej na nim przejdzie prawie wszystkie możliwe iteracje zanim z powrotem "przekręci" się do wartości spełniającej warunek. W międzyczasie może narobić mnóstwo szkód i może często zmylić co do przyczyny błędu. Lepiej jest zmienić taki warunek na
if (aktualnyNumerZdjecia < iloscZdjec), który jest czytelniejszy, nie wprowadza niepotrzebnego odejmowania i spełni swoją rolę nawet kiedy aktualnyNumerZdjęcia >= iloscZdjęc.
Być może nawet lepiej byłoby przepisać całą pętlę na coś takiego:

        public void run() {
                while(true) {
                        aktualnyNumerZdjecia = ++aktualnyNumerZdjecia % iloscZdjec;
                        //lub if (++aktualnyNumerZdjecia >= iloscZdjec) aktualnyNumerZdjecia = 0;
                        aktualneZdjecie = getImage(getCodeBase(), imagesTable.get(aktualnyNumerZdjecia));
                        repaint();
                        try {
                                Thread.sleep(mSek);
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }                       
                }
        }
0

Dziękuje wszystkim za pomoc. Stronka http://arka2010.republika.pl/ zostanie oficjalnie w niedziele otwarta. Dzięki wam wiem na czym polega podpisywanie paczek jar i nieco więcej o appletach. Podpisywanie appletów nie jest dobrym rozwiązaniem w tym konkretnie przypadku. Będę poszukiwał innego, może poprzez wyświetlenie zdjęć pobranych z html, bo przy większej ilości zdjęć zapakowanych do jar się zupełnie nie sprawdzi.


Dobrze że są takie fora istnieją :)</image>

0

Tak swoją drogą... Aplety Javy raczej nie służą do wykorzystywania jako logo/banner/zegarek

0

Logo to rzeczywiście przegięcie... takie drobne ekseprymenty.

Stopka - pierwotny plan był taki że cytat jest pobierany z pliku tekstowego, więc zmiana cytatu wiąże się jedynie z podmianą tekstu w pliku.

Clock - nie jestem z niego dumny, jeśli miał odświeżanie co sekunde mrygał mimo zastosowanego bufora.

Jednym z zastosowań appletów jest dynamika strony. Clock to dynamika. Nie znam innych zastosowań appletów, chętnie poznam :)

0

Symulacje, mapy, przedstawianie działania algorytmów, gry, czaty, programy.

sekunde mrygał mimo zastosowanego bufora
musisz overridnąć metody paint(Graphics) i update(Graphics), a na podabym obiekcie Graphics jedynie odrysowywać bufor (nie robić clear)

0

Rzeczywiście mnie to zastanawiało jak zrobić aby nie odrysowywać całego apletu a jedynie wskazówki zegara a nie cały zegar. To znacznie mniej obliczeń przy zastosowaniu AntyAliasingu. Początkowo była rysowana cała tarcza zegara, później na koszt liczby obliczeń zrezygnowałem z tego, ale nie pomogło. Jest odrysowanie całości co minutę.

Źródło clocka jest takie:

import java.applet.*;
import java.awt.*;
import java.util.*;

public class Clock extends Applet implements Runnable {
	
	private Color 	 tlo, 
					 wskazowkiColor;
	private String 	 bgcolor, 
					 wskazowki, 
					 clockTarget = "clock.png",
					 kropka = "kropka.png";
	private Graphics bufor;
	private Image 	 img,
					 kropkaImg,
					 offscreen;
	private Thread 	 t = null;
	private boolean  threadSuspended;
	private int 	 width, 
					 height,
					 hours = 0, 
					 minutes = 0, 
					 seconds = 0;
					 
	public void init() {
		
		//tło
		bgcolor = getParameter("background");
		if (bgcolor != null) {
			try {
				tlo = Color.decode(bgcolor);
			} catch (NumberFormatException e) {
				tlo = Color.black;
			}
		} else tlo = Color.black;
		setBackground(tlo);
		
		//wskazowki
		wskazowki = getParameter("wskazowki");
		if (wskazowki != null) {
			try {
				wskazowkiColor = Color.decode(wskazowki);
			} catch (NumberFormatException e) {
				wskazowkiColor = Color.green;
			}
		} else wskazowkiColor = Color.green;
		
		width = getSize().width;
		height = getSize().height;
		
		img = getImage(getCodeBase(), clockTarget);
		kropkaImg = getImage(getCodeBase(), kropka);
		offscreen = createImage(width, height);
		bufor = offscreen.getGraphics();
		
	}
	
	public void start() {
		if (t == null) {
			t = new Thread(this);
			t.setPriority(Thread.MIN_PRIORITY);
			threadSuspended = false;
			t.start();
		} else {
			if (threadSuspended) {
				threadSuspended = false;
				synchronized (this) {
					notify();
				}
			}
		}
	}
	
	public void stop() {
		threadSuspended = true;
	}
	
	public void run() {
		try {
			while (true) {
				Calendar cal = Calendar.getInstance();
				hours = cal.get(Calendar.HOUR_OF_DAY);
				if (hours > 12) hours -= 12;
				minutes = cal.get(Calendar.MINUTE);
				seconds = cal.get(Calendar.SECOND);
				if (threadSuspended) {
					synchronized (this) {
						while (threadSuspended) {
							wait();
						}
					}
				}
				repaint();
				t.sleep(60000);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	private void drawWedge(double angle, int radius, Graphics g) {
		
		angle -= 0.5 * Math.PI;
		int x = (int) (radius*Math.cos(angle));
		int y = (int) (radius*Math.sin(angle));
		angle += 2 * Math.PI / 3;
		int x2 = (int) (5 * Math.cos(angle));
		int y2 = (int) (5 * Math.sin(angle));
		angle += 2 * Math.PI / 3;
		int x3 = (int) (5 * Math.cos(angle));
		int y3 = (int) (5 * Math.sin(angle));
		
		g.drawLine(width / 2 + x2, height / 2 + y2, width / 2 + x, height / 2 + y);
		g.drawLine(width / 2 + x3, height / 2 + y3, width / 2 + x, height / 2 + y);
		/*
		angle -= 0.5 * Math.PI;
		int x = (int) (radius*Math.cos(angle));
		int y = (int) (radius*Math.sin(angle));
		angle += 2 * Math.PI / 3;
		int x2 = (int) (5 * Math.cos(angle));
		int y2 = (int) (5 * Math.sin(angle));
		angle += 2 * Math.PI / 3;
		int x3 = (int) (5 * Math.cos(angle));
		int y3 = (int) (5 * Math.sin(angle));
		
		g.fillPolygon(new int[] {(width / 2 + x2), (width / 2 + x), (width / 2 + x3)}, 
					  new int[] {(height / 2 + y2), (height / 2 + y), (height / 2 + y3)} , 3);
					  */
	}
	
	public void paint (Graphics g) {
		Graphics2D g2 = (Graphics2D) bufor;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		bufor.drawImage(img, 0, 0, this);
		bufor.setColor(wskazowkiColor);
		drawWedge(2*Math.PI*hours/12, width/6, bufor);
		drawWedge(2*Math.PI*minutes/60, width/4, bufor);
		bufor.drawImage(kropkaImg, ((width-35)/2), ((height-50)/2-2), this);
		
		g.drawImage(offscreen, 0, 0, this);
	}
}

Takie rozwiązanie znalazłem gdzieś w sieci, troszkę je przekształciłem ale ma ono wielką wadę. Wskazówka godziny przekręca się nie co 12 minut tylko co 60. Dobre jest to że zastosowano wątek, bo nie obciąża procesora. Pomyślę nad tym update(Graphics). Może coś mądrego wymyślę, z podpowiedzi też chętnie skorzystam.

Pozdrawiam

0

To update() to nawet fajne jest. Wystarczyło podmienić metodę paint(Graphics){} na update(Graphics){} i doimplementować wskazówkę sekund. Wszystko działa i już nie mryga :)

Przekręcanie wskazówki godziny rozwiązałem instrukcją else if{} i metodą rotate(radiany, srodekX, srodekY)

1 użytkowników online, w tym zalogowanych: 0, gości: 1