Java - EDT, callback, codice ignorato

di il
3 risposte

Java - EDT, callback, codice ignorato

Ciao ragazzi, ho un problema molto strano con le swing di java.

Ho un codice semplicissimo, lo trovate alla fine del post (potete compilarlo ed eseguirlo senza problemi).

Voglio creare una classe che gestisca un JFrame e il suo ciclo di vita.
Questa classe avrà i metodi:

onCreate() - Le componenti grafiche vengono inizializzate;
onShow() - Le componenti grafiche vengono tutte rese visibili e correttamente renderizzate.

Ora, il metodo onCreate viene chiamato dal costruttore della mia classe, tramite una invokeAndWait per garantire l'esecuzione del codice nell'EDT. Nel metodo onCreate, viene impostato un componentListener sul JFrame da gestire, il quale ha il metodo componentShown, che serve per indicare che tutto è stato mostrato ed è visibile. In questo metodo, quindi, viene effettuata la chiamata al metodo onShow().

Sappiamo che un JFrame non è visibile finché non viene richiesto esplicitamente (frame.setVisible(true). E quindi ho aggiunto il metodo "show" che fa appunto questo, sempre eseguendo il codice nell'EDT.

ora il PROBLEMA: Il messaggio "SHOWN AND VALID" non viene mai eseguito.

Sapete dirmi perché? So che comunque nel disegnare gli elementi, il sistema operativo si prende del tempo, ed ecco perché ho voluto usare la callback componentShown per garantire che il metodo onShow sia chiamato quando tutto è stato effettivamente disegnato.
Attualmente, usare le JavaFX non è un'opzione, per tanto ho bisogno di continuare usando questa strategia.

Vi ringrazio in anticipo!
Ecco il codice:

import java.awt.EventQueue;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class TEST {

	private JFrame frame;
	private JScrollPane contentPane;
	private JPanel contentViewport;
	private JScrollPane fragmentContentPane;
	private JPanel fragmentContentViewport;
	
	public TEST() throws InvocationTargetException, InterruptedException{
	
		SwingUtilities.invokeAndWait(new Runnable(){
			
			public void run(){
				
				onCreate();
			}
		});
	}
	
	public void onCreate(){
		
		System.out.println("On create! EDT: "+EventQueue.isDispatchThread());
		frame=new JFrame();
		contentPane=new JScrollPane();
		contentViewport=new JPanel();
		contentPane.setViewportView(contentViewport);
		frame.setContentPane(contentPane);
		frame.addComponentListener(new ComponentAdapter(){
			
			public void componentShown(ComponentEvent e){
						
				onShow();
			}
		});
	}

	public void onShow(){
		
		System.out.println("On show! EDT: "+EventQueue.isDispatchThread());
		
		fragmentContentViewport=new JPanel();
		fragmentContentPane=new JScrollPane(fragmentContentViewport);
		fragmentContentPane.addComponentListener(new ComponentAdapter(){
			
			public void componentShown(ComponentEvent e){
				
				if (e.getComponent().isValid()) System.out.println("SHOWN AND VALID!");
			}
			
		});
		contentViewport.add(fragmentContentPane);
	}
	
	public void show() throws InvocationTargetException, InterruptedException{
		
		SwingUtilities.invokeAndWait(new Runnable(){
			
			public void run(){
				System.out.println("Showing..");
				frame.setVisible(true);
			}
		});
	}
	
	public static final void main(String[] args) throws InvocationTargetException, InterruptedException{
		
		TEST t=new TEST();
		t.show();
	}
}

3 Risposte

  • Re: Java - EDT, callback, codice ignorato

    Mi spiace, il tuo design è parecchio contorto, fumoso e potenzialmente critico. Non fare accrocchi di questo tipo.
  • Re: Java - EDT, callback, codice ignorato

    Ciao Andbin, ti ringrazio per la risposta. Ho risolto il problema, ma vorrei capire quali siano, secondo te, i punti carenti di tale approccio.

    Lo scopo dietro tale semplice codice è ottenere una classe che mi fornisca tutto ciò che mi serve per gestire il ciclo di vita della finestra e dei componenti stessi.
    Ti ringrazio per la disponibilità!
  • Re: Java - EDT, callback, codice ignorato

    Francesco93 ha scritto:


    Ciao Andbin, ti ringrazio per la risposta. Ho risolto il problema, ma vorrei capire quali siano, secondo te, i punti carenti di tale approccio.
    Innanzitutto invokeAndWait si usa più raramente rispetto ad invokeLater. Tu l'hai già usato 2 volte in punti dove, in teoria, non servirebbero nemmeno se si facesse diversamente.

    Il tuo problema di prima, ad occhio (non l'ho provato) è che nel main fai new TEST() e questo fa invocare il costruttore, fa invocare onCreate (nel EDT), fa arrivare fino al frame.addComponentListener(....) (ma occhio, il suo componentShown NON viene invocato subito). E fin qui ok.
    Poi nel main fai t.show() e questo fa invocare il run() del Runnable in show che fa solo il frame.setVisible(true). Questo scatena il componentShown del ComponentListener registrato prima.
    A quel punto viene invocato onShow() che va a creare un altro JPanel, ecc... Ma già poco prima del onShow, presumibilmente, la finestra è GIA' visibile e tu invece vai a fare altro DOPO questo. Come ad esempio registrare un altro ComponentListener. Ma la finestra è appunto già visibile, quindi presumibilmente, quel componentShown NON viene invocato.

    Francesco93 ha scritto:


    Lo scopo dietro tale semplice codice è ottenere una classe che mi fornisca tutto ciò che mi serve per gestire il ciclo di vita della finestra e dei componenti stessi.
    Il tuo codice poi comunque ha anche un altro problema. Se a fronte di un click su un pulsante, voce di menù o altro vuoi dare la possibilità all'utente di aprire un'altra finestra come quella che hai fatto, non puoi fare la stessa cosa che hai fatto nel main (new TEST() e poi lo show()). Questo perché sei GIA' nel Event Dispatch Thread e la documentazione a riguardo è chiarissima: invokeAndWait NON VA invocato dal EDT.

    Se vuoi creare una classe base astratta che faccia appunto da "base" per altre tue finestre e che fornisca servizi utili o comunque una "infrastruttura" relativa al ciclo di vita di una finestra .... si PUO' fare .... ma NON così come hai fatto tu.
    Ripeto: non fare accrocchi di quel tipo.
Devi accedere o registrarti per scrivere nel forum
3 risposte