(RISOLTO) Applet non funzionante (SOLO) nel browser

di il
5 risposte

(RISOLTO) Applet non funzionante (SOLO) nel browser

Salve ragazzi, sono qui perchè ho un grosso grattacapo.

Ho creato un' applet.

Il codice HTML per la mia applet è:
<applet code=gui.clientGUI.MyApplet.class 
        archive="QTminer.jar"
        width=400 height=200>
</applet>
e questo è il contenuto del file jar:
  • C:\Users\Francesco\Desktop>jar tf QTminer.jar
    META-INF/MANIFEST.MF
    .project
    gui/GUI$1.class
    gui/GUI$2.class
    gui/GUI$3.class
    gui/GUI.class
    gui/GUI.java
    gui/clientGUI/LoginFrame$1.class
    gui/clientGUI/LoginFrame$2$1.class
    gui/clientGUI/LoginFrame$2.class
    gui/clientGUI/LoginFrame$3$1.class
    gui/clientGUI/LoginFrame$3.class
    gui/clientGUI/LoginFrame$4$1.class
    gui/clientGUI/LoginFrame$4.class
    gui/clientGUI/LoginFrame.class
    gui/clientGUI/LoginFrame.java
    gui/clientGUI/ClientFrame$1.class
    gui/clientGUI/ClientFrame$2$1.class
    gui/clientGUI/ClientFrame$2.class
    gui/clientGUI/ClientFrame$3$1$1.class
    gui/clientGUI/ClientFrame$3$1.class
    gui/clientGUI/ClientFrame$3.class
    gui/clientGUI/ClientFrame$4$1.class
    gui/clientGUI/ClientFrame$4.class
    gui/clientGUI/ClientFrame$5$1.class
    gui/clientGUI/ClientFrame$5.class
    gui/clientGUI/ClientFrame$6$1.class
    gui/clientGUI/ClientFrame$6$2.class
    gui/clientGUI/ClientFrame$6.class
    gui/clientGUI/ClientFrame.class
    gui/clientGUI/ClientFrame.java
    gui/clientGUI/MyApplet$1$1$1.class
    gui/clientGUI/MyApplet$1$1$2.class
    gui/clientGUI/MyApplet$1$1.class
    gui/clientGUI/MyApplet$1.class
    gui/clientGUI/MyApplet.class
    gui/clientGUI/MyApplet.java
    gui/clientGUI/SplashScreen$1.class
    gui/clientGUI/SplashScreen.class
    gui/clientGUI/SplashScreen.java
    gui/resources/LoginFrame_background.jpg
    gui/resources/QTminer_background_original.jpg
    gui/resources/Qtminer_background.jpg

    .classpath
prima che vi dica quale sia il problema, vi mostro alcune delle classi principali che i frame, in questa applet, estenderanno e/o sfrutteranno:

1. GUI CLASS

Questa classe è estesa da tutti i frame dell'applet (tranne quello iniziale, in cui c'è il metodo init, per intenderci).
Contiene metodi per il caricamento dei componenti grafici e degli eventi e per inserire eventi nell'EDT.

Ecco il codice della Classe GUI:
import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;

import javax.swing.SwingUtilities;

public abstract class GUI{
	
	private volatile boolean showable=false;

	public GUI(){
	
		if (!EventQueue.isDispatchThread()){
			
			try {
				SwingUtilities.invokeAndWait(new Runnable(){
					
					public void run(){
						
						synchronized(GUI.this){
							
							initGraphics();
							setEventListeners();
							showable=true;
							GUI.this.notify();
						}
							
					}
				});
			}
			catch (InvocationTargetException e) {
			
				e.printStackTrace();
			}
			catch (InterruptedException e) {
			
				e.printStackTrace();
			}
		}
		else{

			synchronized(GUI.this){
				
				initGraphics();
				setEventListeners();
				showable=true;
				GUI.this.notify();
			}
		}
			
	}

	protected void scheduleGUIAction(Runnable toRun){
		
		if (toRun!=null ){
				
			try {
				
				SwingUtilities.invokeAndWait(toRun);
			}
			catch (InvocationTargetException | InterruptedException e) {
			
				e.printStackTrace();
			}
		}
	}

	protected void scheduleAction(long delayTimeMS,Runnable toRun){
		
		Thread T=new Thread(new Runnable(){
			
			public void run(){
					
				try {
					
					if (delayTimeMS>0)Thread.sleep(delayTimeMS);
					if (toRun!=null) toRun.run();
				}
				catch (InterruptedException e) {

					e.printStackTrace();
				}
			}
		});
		T.start();
	}
	
	protected abstract void initGraphics();
	protected abstract void setEventListeners();
	
	public abstract void inShow();
	
	public static void show(GUI object){
		
		Thread T=new Thread(new Runnable(){
			
			public void run(){
				
				if (object.showable==false){
					
					synchronized(object){
						
						try {
							
							object.wait();
						}
						catch (InterruptedException e) {
						
							e.printStackTrace();
						}
					}
				}
			
				object.inShow();
			}
		});
		
		T.start();
	}
}
Spiegherò brevemente cosa fanno alcuni di questi metodi:
protected abstract void initGraphics();
protected abstract void setEventListeners();
public abstract void inShow();
initGraphics() - inizializza i componenti grafici nel frame.
setEventListeners() -Qui verranno raggruppati tutti gli event listeners.
inShow() - Questo metodo serve a indicare cosa deve essere fatto quando la classe GUI chiama, tramite il metodo statico show, il metodo inShow() su un oggetto GUI passato in input.

2. APPLET CLASS

Qui è dove inizia la mia applet, nessun costruttore, solo il metodo init().
import gui.GUI;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIManager.LookAndFeelInfo;

import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.lang.reflect.InvocationTargetException;

@SuppressWarnings("serial")
public class MyApplet extends JApplet{
	
	static volatile boolean closed=true;
	
	public void init(){
		
		try {
			
		    for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
		       
		    	if ("Nimbus".equals(info.getName())) {
		        
		    		UIManager.setLookAndFeel(info.getClassName());
		            break;
		        }
		    }
		}
		catch (Exception e) {
			
			try {
				
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			}
			catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e1) {

				e1.printStackTrace();
			}
		}

		getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
		
		JButton btnStartApplication = new JButton("Start Application");
		
		btnStartApplication.addActionListener(new ActionListener() {
		
			public void actionPerformed(ActionEvent e) {
				
				
				closed=false;
				Thread T=new Thread(new Runnable(){

					public void run(){
						
						while (!closed){
							
							if (btnStartApplication.isEnabled()==true){
								
								
								try {
									SwingUtilities.invokeAndWait(new Runnable(){
										
										public void run(){
											
											btnStartApplication.setEnabled(false);
											SplashScreen ss=new SplashScreen();
											GUI.show(ss);
										}
									});
								}
								catch (InvocationTargetException | InterruptedException e) {

									e.printStackTrace();
								}
							}									
						}
							
						SwingUtilities.invokeLater(new Runnable(){
							
							public void run(){
								
								btnStartApplication.setEnabled(true);
							}
						});
					}
				});
				T.start();	
			}
		});
		getContentPane().add(btnStartApplication);
	}
}
Nulla di strano qui, notate solo come viene creato l'oggetto SplashScreen che vedremo a breve.

3. SPLASHSCREEN CLASS
import gui.GUI;

import javax.swing.JWindow;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import javax.swing.SwingConstants;

import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Color;

public class SplashScreen extends GUI{
	
	private JWindow window;
	private JLabel lblNewLabel;
	
	@Override
	protected void initGraphics() {

		window=new JWindow();

		window.setBounds(new Rectangle(0, 0, 883, 590));
		window.setLocationRelativeTo(null);
		window.getContentPane().setLayout(null);
		
		lblNewLabel = new JLabel("Welcome",SwingConstants.CENTER);
		lblNewLabel.setForeground(Color.DARK_GRAY);
		lblNewLabel.setFont(new Font("Segoe UI", Font.BOLD | Font.ITALIC, 24));
		lblNewLabel.setBounds(0, 313, 883, 41);
		window.getContentPane().add(lblNewLabel);
		
		JLabel label = new JLabel("");

		label.setIcon(new ImageIcon(this.getClass().getResource("/gui/resources/Qtminer_background.jpg")));
		
		label.setBounds(0, 0, 883, 592);
		window.getContentPane().add(label);
	}

	@Override
	protected void setEventListeners() {

	}

	@Override
	public void inShow() {
		
		scheduleGUIAction(new Runnable(){
			
			public void run(){
				
				window.setVisible(true);
			}
		});		
		
		scheduleAction(1500,new Runnable(){
			
			public void run(){
			
				ClientFrame cf=new ClientFrame();
				GUI.show(cf);
				window.dispose();
			}
		});
	}
}
Un semplice SplashScreen, come vedete.

THE PROBLEM

Finalmente è ora di indicare il problema qual è:

Quando eseguo la mia applet dentro eclipse, tutto funziona, ma quando esporto in jar e la lancio tramite browser, solo la mia applet class viene "mostrata", cioè la finestra in cui c'è il bottone "Start Application". e anche se lo premo, non accade nulla.

Cosa sto sbagliando? potete aiutarmi? grazie.

5 Risposte

  • Re: (RISOLTO) Applet non funzionante (SOLO) nel browser

    Dopo qualche tentativo di debug all'interno del browser ho notato che:

    1: nella classe SplashScreen, l'istruzione:
    label.setIcon(new ImageIcon(this.getClass().getResource("/gui/resources/Qtminer_background.jpg")));
    blocca il programma

    2: se provo a creare un nuovo frame che estende GUI all'interno del metodo inShow() della classe SPlashScreen, per esempio:
    NewFrame frame=new Frame();
    GUI.show(frame);
    il programma si blocca alla chiamata del costruttore, senza NEMMENO entrare nel costruttore della classe GUI!

    Probabile deadlock? Richiedo aiuto
  • Re: (RISOLTO) Applet non funzionante (SOLO) nel browser

    Guarda, te lo dico sinceramente e onestamente. Hai fatto una architettura (parlo principalmente della classe GUI) che è parecchio complessa e aggiungo pure "contorta", fumosa.

    Le classi Swing dei componenti (e anche dei model) dovrebbero sempre essere istanziate nel contesto del EDT. Insomma, per dirlo in altro modo, nel costruttore non ha granché senso dire: sono nel EDT allora invoco xyz() direttamente altrimenti passo per un invokeAndWait.

    Oltretutto c'è un altro discorso generale (le GUI qui non c'entrano) legato alla costruzione degli oggetti. Esiste una regoletta che bisognerebbe sempre rispettare. Dal punto di vista linguistico la si può enunciare in diversi modi ma io te la dico così:

    "Un costruttore di una classe NON dovrebbe mai invocare un metodo della propria classe che è soggetto a override (in una sottoclasse, chiaramente)"

    Già questo lo hai ignorato, poiché il costruttore di GUI invoca metodi che sono soggetti a override.
    Nel tuo caso non ci sarebbero, a prima vista, grossi problemi reali. Ma la questione esiste ed è in generale.

    Poi comunque sono evidenti altre cose fumose tipo: nel init() di MyApplet hai usato una anonymous inner-class per un ActionListener. Nel suo actionPerformed() vai ad usare un'altra anonymous inner-class per un Runnable del thread nel cui run() vai ad usare un'altra anonymous inner-class ancora per il Runnable per il invokeAndWait. Il tutto mescolato a while, if ecc..
    Un livello così fumoso di annidamento io lo farei solamente sotto tortura .....

    E già che parliamo del init(), forse non lo sai ma il init() delle Applet NON è invocato nel contesto del EDT. Ma in un thread specifico del container delle applet. Quindi non è proprio appropriato quello che hai fatto.

    Guarda te lo ripeto ancora e meglio: con la struttura che hai fatto ti stai solo tirando addosso un (gran bel) po' di "rogne" ....

    Il mio consiglio, se lo accetti, è questo: riconsidera davvero BENE il tutto da capo/zero e magari cercando prima di colmare alcune lacune riguardo la costruzione degli oggetti e anche sul EDT e sul ciclo di vita delle applet.
  • Re: (RISOLTO) Applet non funzionante (SOLO) nel browser

    Caro andbin hai proprio ragione... riconsidererò questa parte del progetto.


    ma ora guarda qui:

    import javax.swing.ImageIcon;
    import javax.swing.JApplet;
    import javax.swing.JButton;
    import javax.swing.JLabel;
    import javax.swing.JWindow;
    import javax.swing.SwingConstants;
    import javax.swing.SwingUtilities;
    
    import java.awt.Color;
    import java.awt.FlowLayout;
    import java.awt.Font;
    import java.awt.Rectangle;
    import java.awt.event.ActionListener;
    import java.awt.event.ActionEvent;
    
    @SuppressWarnings("serial")
    public class MyApplet extends JApplet{
    	
    	public void init(){
    		
    		SwingUtilities.invokeLater(new Runnable(){
    			
    			public void run(){
    				
    				getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
    				
    				JButton btnStartApplication = new JButton("Start Application");
    				
    				btnStartApplication.addActionListener(new ActionListener() {
    				
    					public void actionPerformed(ActionEvent e) {
    						
    						new SS();
    					}
    				});
    				getContentPane().add(btnStartApplication);
    			}
    		});
    			
    	}
    }
    
    class ss{
    	
    	private JWindow window;
    	private JLabel lblNewLabel;
    	
    	public SS(){
    		
    		SwingUtilities.invokeLater(new Runnable(){
    			
    			public void run(){
    				
    				window=new JWindow();
    
    				window.setBounds(new Rectangle(0, 0, 883, 590));
    				window.setLocationRelativeTo(null);
    				window.getContentPane().setLayout(null);
    				
    				lblNewLabel = new JLabel("Welcome",SwingConstants.CENTER);
    				lblNewLabel.setForeground(Color.DARK_GRAY);
    				lblNewLabel.setFont(new Font("Segoe UI", Font.BOLD | Font.ITALIC, 24));
    				lblNewLabel.setBounds(0, 313, 883, 41);
    				window.getContentPane().add(lblNewLabel);
    				
    				JLabel label = new JLabel("");
    
    				label.setIcon(new ImageIcon(this.getClass().getResource("/gui/resources/Qtminer_background.jpg")));
    				
    				label.setBounds(0, 0, 883, 592);
    				window.getContentPane().add(label);
    				
    				window.setVisible(true);
    			}
    		});
    	}
    }
    un codice molto semplice, non è vero? beh, il problema è esattamente lo stesso... che diamine succede??

    Il bottone funziona benissimo quando eseguo l'applet in eclipse, ma quando la eseguo nel browser (Internet Explorer) non funziona!
  • Re: (RISOLTO) Applet non funzionante (SOLO) nel browser

    Usando la Java Console, ho notato che mi viene restituita una nullpointerexception proprio all'istruzione in cui carico l'imageicon dal percorso, che però è giusto!

    Cosa ne pensi?
  • Re: (RISOLTO) Applet non funzionante (SOLO) nel browser

    Risolto:

    Il problema era dato dal sistema operativo che bloccava l'accesso al file jar. Eseguendo l'applet da un web-server reale (quindi non da un file html locale), i problemi non vengono rilevati e l'applet viene eseguita correttamente.

    Grazie lo stesso per l'aiuto andbin!
Devi accedere o registrarti per scrivere nel forum
5 risposte