IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaFX Discussion :

Méthode invoke (interf. InvocationHandler du proxy dyn.) et opération sur composant GraphiQ JAVAFX


Sujet :

JavaFX

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut Méthode invoke (interf. InvocationHandler du proxy dyn.) et opération sur composant GraphiQ JAVAFX
    Bonjour,

    Excusez moi de vous déranger, je suis un peu perdu. Lorsque je passe par un proxy dynamique pour effectuer une opération (ici il s'agit de faire passer un calque de type StackPane contenant un spinner au dessus d'un AnchorPane), celle-ci n'est effectuée qu'à la fin de la méthode invoke. Il semblerait que cette dernière bloque toute opération graphique. Il y aurait il moyen de retirer ce blocage s'il vous plait ? Vous allez surement me dire que cela ne sert à rien mais c'est un exemple que j'ai créé car présenter l'autre version qui nécessite le passage par un proxy aurait été un peu trop long.

    Ci-dessous le code de la classe Calque :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     
    import javafx.geometry.Insets;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.Background;
    import javafx.scene.layout.BackgroundFill;
    import javafx.scene.layout.CornerRadii;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
     
    public class Calque extends StackPane {
     
    	private String urlImg;
    	private ImageView imgV;
        private Image image;
     
     
    	public Calque(){
    		this.urlImg = "application/spinner.gif";
    		this.initImg();
    		this.setStyle("-fx-min-Width:-infinity;"
    				+ "-fx-min-Height:-infinity;"
    				+ "-fx-max-Width:-infinity;"
    				+ "-fx-pref-Width:1024;"
    				+ "-fx-pref-Height:800;"
    				+ "-fx-opacity:0.8;");
     
    		AnchorPane.setLeftAnchor(this, 0.0); 
    		AnchorPane.setRightAnchor(this, 0.0); 
    		AnchorPane.setBottomAnchor(this, 0.0); 
    		AnchorPane.setTopAnchor(this, 0.0); 
     
     
    		this.backgroundProperty().set(new Background(new BackgroundFill(Color.valueOf("#4B4B4B"), CornerRadii.EMPTY, Insets.EMPTY)));
    		this.setVisible(false);
    		this.toBack();
    	}
     
    	private void initImg() {
            imgV = new ImageView();
            imgV.setFitHeight(320);
            imgV.setFitWidth(320);
            image = new Image(urlImg);
            imgV.setImage(image);
            this.getChildren().add(imgV);
            this.setCache(true);
        }
     
     
    	public void show(){
    		this.toFront();
    		this.setVisible(true);
    	}
     
    	public void hide(){
    		this.toBack();
    		this.setVisible(false);
    	}
     
     
    }
    Le bout de code permettant d'initialiser le proxy. Il est écrit au sein controller.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ProxyTest<ClassePrTest> testProxy = new ProxyTest<ClassePrTest>(obj,cl);
    objInter = (InterfPrTest) Proxy.newProxyInstance(ClassePrTest.class.getClassLoader(), obj.getClass().getInterfaces(), testProxy);
    //...
    objInter.method1() // méthode d'appel lancée lors du clique sur le bouton.
    Et la classe ProxyTest :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    
    public class ProxyTest<T> implements InvocationHandler {
    
        private T cible;
        private Calque calque;
    
        public ProxyTest(T cible, Calque calque) {
            this.cible = cible;
            this.calque = calque;
        }
    
        @Override
        public Object invoke(Object arg0, Method arg1, Object[] arg2) throws IllegalAccessException,
                IllegalArgumentException, InvocationTargetException, InterruptedException {
            calque.show();
            Thread.sleep(5000);
            Object val = null;
            val = arg1.invoke(cible, arg2);
            this.calque.hide();
            return val;
        }
    
    }
    En gros, il ne se passe rien que ce soit en mode debug ou le temps que le Thread.sleep(5000) soit fini sur l'écran. Je dois attendre que le return val soit fait pour que les opérations de la méthode .show() apparaissent sur l'écran. Sniff.

    Je vous remercie d'avance pour votre aide et vous souhaite une bonne journée.

    Cordialement,

    Vincent

    (des modifications à faire avec Quantumtoolkit ou Toolkit de javafx ou Platform, peut-être une histoire de runlater, suis perdu. Désolé du dérangement)

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 900
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 900
    Billets dans le blog
    54
    Par défaut
    Bon j'avoue ne pas avoir tout compris ni le besoin d'utiliser un proxy au lieu d'une interface mais pour ce que j'en pense tu dois sans doute bloquer le JavaFX Application Thread pendant 5 bonnes secondes (il suffit d'imprimer le thread courant juste avant le sleep()) donc vi ça bloque tout et c'est mal.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut
    En fait, j'ai mis le sleep un peu bêtement sur l'exemple de test et je l'ai remplacé par la suite par une méthode assez longue. En gros, il s'agit de mettre en place l'affichage d'un spinner (pas de progressbar, il a été choisi un fichier animé gif) lors de l'appel de méthodes qui seront assez longues sur des instances de plusieurs classes (elles contiennent pas mal de méthodes). J'ai testé aussi avec aop:around de spring, j'en reviens au même résultat. Tout ce qui a attrait à la partie GUI est bloqué lorsque je passe dans la méthode invoke du proxy (ou la simple méthode @around lorsque j'utilise le framework spring). Cela se débloque que quand tout est fini. Après, je me suis aperçu que si je passe par la création au sein de ces méthodes d'un nouveau stage ou d'un dialog (avec pour owner la window principale), là, leur affichage se fait dès le début de la méthode (donc avant le lancement des opérations sur lesquelles je veux mettre un spinner). Mais malheureusement, dans les deux cas, je perds quand même l'animation du gif pendant toute la durée de la méthode. J'ai fait plusieurs tentatives avec des tasks, des thread, des modalités différentes, je ne récupère pas l'animation. Mais bon, je ne suis pas super doué et donc je viens demander un peu d'aide car je m'y prends sûrement très mal. Merci pour votre première réponse.

  4. #4
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 900
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 900
    Billets dans le blog
    54
    Par défaut
    Est-ce que tu peux me fournir le code d'un test très très simple (ex: un unique spinner dans une scène toute vide, un gif anime tout bête) qui fasse exactement la même chose et l'attacher sous forme de projet ZIP dans ta reponse ? Sans pouvoir comprendre comment tu opères ni pourquoi un proxy est necessaire, je ne saisis pas trop ni ce que tu veux faire, ni comment potentiellement le corriger.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2014
    Messages : 101
    Par défaut
    Bonjour,

    Je t'ai joins comme convenu ce que tu m'as demandé. En fait, sur l'essai maintenant cela marche avec l'utilisation de classes du package javafx.concurrent. Néanmoins, quand je lance l'opération sur le gros projet, cela ne marche toujours pas. Enfin, là je viens de rajouter l'utilisation des services (cet après midi en faisant des essais je ne passais que par des tâches mais cela marchait quand même sur le projet de test ) en m'inspirant des informations trouvées sur ce que tu sembles avoir écrit http://fabrice-bouye.developpez.com/...d-javafx/#LV-C et du site d'Oracle. Sur le gros projet, il s'agit de l'interception d'appels de services (côté client) qui vont lancer des opérations plutôt longues du côté serveur (passage par rest et base de donnée PGSql).

    Bref, je te remercie pour ton aide.

    Je te souhaite une bonne soirée et j'espère que mon code sera compréhensible lors de sa lecture (je ne suis pas un expert). La classe la plus importante dans le cadre de la réalisation des opérations est com.vinou.divers.aspect.CalqueShowInvocation

    Cordialement,

    Vincent
    Fichiers attachés Fichiers attachés

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 900
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 900
    Billets dans le blog
    54
    Par défaut
    Aaaah !
    un projet Maven et sous Spring... C'est pas vraiment ce que j'appelle un test minimal reproduisant le soucis en question.

    Bon alors, sans essayer de préjuger aucunement de la bonne manière dont Spring est sensé être utilisé ou de la meilleure façon de faire dans ce domaine (chui un noob ! ) , il me semble qu'une partie du soucis vient du fait que tu sembles attendre une exécution linéaire des choses alors qu'au contraire, tout est sensé fonctionné en asynchrone : c'est a dire qu'on lance des methodes dans le vide, elles retournent tout de suite, mais lors de l’exécution réelle elles font un effet de bord qui a un retour dans l'UI (ce qui est la manière normale de faire avec Service+Task, Platform.runLater() ou même SwingWorker ou SwingUtilities.invokeLater qui fonctionnent ainsi d'ailleurs)

    Pour ce que j'en comprends, le workflow d’exécution devrait être similaire a :

    JFXAP = JavaFX Application Thread.
    WT = Worker thread.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    // Au chargement du FXML.
    FXMLoader.load()  
        ->  SampleController.new()
        ->  SampleController.initialize() 
            -> SpringApplicationContext.getBean();                 // JFXAP: crée un pointeur de AnchorPane.
            -> apInst.setAp();		                       // JFXAP: passe une référence sur le AnchorPane racine du FXML.
        <- // JFXAP: retour.
     
    // Lors du clic sur le bouton.
    FXML (Bouton) 
        -> SampleController.Essai()
            -> SpringApplicationContext.getBean();                 // JFXAP: crée un pointeur de test.
            -> clPrTest.method();                                    
               -> CalqueShowInvocation.show();                     // JFXAP: invoque implicitement lors de l'appel a method().
               -> // JFXAP: recupere le pointeur d'AnchorPane.
               -> // JFXAP: cree un calque.
               -> // JFXAP: ajoute le calque dans l'AnchorPane.
               -> // JFXAP: charge le GIF anime.
               -> // JFXAP: met le GIF anime en place dans le calque.
               -> // JFXAP: creation de services/thread.
               -> // JFXAP: lancement de service/thread.
           <- // JFXAP: retour.
       <- // JFXAP: retour.
     
    // Lors de l’exécution de la tache.
    Task.call()                                                   // WT: on est dans le thread du service.
        -> jp.proceed();                                          // WT: invoque explicitement dans le service/thread.
            -> cClassePrTest.method();              	      // WT: invoque implicitement par proceed().
            <-                                                    // WT: fin exécution distante longue sur serveur. 
        <- // WT: retour.
     
    // "Plus tard", à la fin de la tache.
    Fin du service/thread 
        -> Service.getOnSucceeded().handle()                      // JFXAP: invoqué lorsque le service réussit.
            -> AnchorPane.getChildren().remove()                  // JFXAP: retrait du calque.             
        <- // JFXAP: retour.
    // Ou:
        -> Service.getOnFailed().handle()                         // JFXAP: invoqué lorsque le service échoue.
            -> [...]
    Donc, pour ce faire, j'ai remplacé le corps de la méthode show() de la classe CalqueShowInvocation par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    ApInstance apInst = SpringApplicationContext.getBean(ApInstance.class);
     
    AnchorPane ap = apInst.getAp();
    Calque cl = new Calque();
    ap.getChildren().add(cl);
    String urlImg = "com/vinou/spinner.gif";
    ImageView imgV = new ImageView();
    imgV.setFitHeight(320);
    imgV.setFitWidth(320);
    Image image = new Image(urlImg);
    imgV.setImage(image);
    cl.getChildren().add(imgV);
    cl.setVisible(true);
    Service<Void> showService = new Service<Void>() {
     
        @Override
        protected Task<Void> createTask() {
            return new Task<Void>() {
     
                @Override
                protected Void call() throws Exception {
                    try {
                        jp.proceed();
                    } catch (Exception ex) { // Rethrow.                            
                        throw ex;
                    } catch (Throwable t) { // Unexpected, pack and rethrow.
                        Exception unexpected = new Exception(t);
                        throw unexpected;
                    }
                    return null;
                }
            };
        }
    };
    showService.setOnSucceeded(workerStateEvent -> ap.getChildren().remove(cl));
    showService.setOnFailed(workerStateEvent -> {
        Throwable t = workerStateEvent.getSource().getException();
        // Gerer les erreurs ici.
    });
    showService.start();
    Et il devrait être possible d'utiliser un thread a la place du service bien sur, quelque chose du genre (le workflow est un peu différent bien sur ca on a pas les callbacks de service qui s’exécutent dans JFXAP) :

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Thread th = new Thread() {
     
        @Override
        public void run() {
            try {
                jp.proceed();
                // Quand ca se passe bien.
                Platform.runLater(() -> ap.getChildren().remove(cl));
            } catch (Throwable t) {
                // Gerer les erreurs ici.
            }
        }
    };
    th.start();

    Ce qui fait que le calque disparait bien lorsque les 100K itérations sont terminées. Mais bon, j'ignore si c'est la bonne maniere de faire et surtout j'ignore si ca fonctionnera dans ton envirronement client-serveur (et pis il manque la gestion des erreurs bien sur).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

Discussions similaires

  1. Utilisation de la classe Méthod et de la méthode Invoke
    Par peche dans le forum Servlets/JSP
    Réponses: 4
    Dernier message: 12/04/2010, 15h49
  2. Réponses: 8
    Dernier message: 19/06/2006, 15h31
  3. [Reflexion] Pb méthode invoke
    Par Delhio dans le forum API standards et tierces
    Réponses: 5
    Dernier message: 13/05/2006, 22h13
  4. [VB.NET 1.1] [Thread] Méthode invoke
    Par toniolol dans le forum Windows Forms
    Réponses: 5
    Dernier message: 15/02/2006, 16h04
  5. Réponses: 4
    Dernier message: 05/06/2005, 14h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo