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

2D Java Discussion :

Optimisation du rafraichissement d'un viewer de courbe


Sujet :

2D Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 84
    Par défaut Optimisation du rafraichissement d'un viewer de courbe
    Bonjour à tous,

    J'ai développé un viewer de courbes XY.

    Pour afficher une courbe, un algo permet de réduire le nombre de point à afficher pour ne pas faire planter la carte graphique.
    (les courbes peuvent avoir plusieurs dizaines de million de points...).

    Cet algo peut prendre un peu de temps pour calculer la courbe à afficher.

    Deux soucis se posent :
    1) Comment éviter de figer l'affichage du fait que l'algo est lancé dans la méthode "paintComponent(Graphics g)" du JComponent par définition?

    2) Est il possible de gérer des demandes de rafraichissement multiples?
    Genre si un rafraichissement est en cours mais qu'une nouvelle demande arrive on "tue" le précèdent rafraichissement pour ne réaliser que le dernier demandé.

    J'ai tenté ceci mais les courbes ne s'affiche plus (réalisé dans la méthode: view.draw(...)):

    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
     
    /*
     * (non-Javadoc)
     * @see math.xyploter.data.view.CurvesView#draw(java.awt.Graphics2D, java.awt.geom.Rectangle2D, math.xyploter.axis.Axis, math.xyploter.axis.Axis, math.number.ValueReader)
     */
    @Override
    public void draw(final Graphics2D g2, final Rectangle2D parentBounds, final Axis xAxis, final Axis yAxis, final ValueReader reader) {
    	try {
    		if (drawThread != null && drawThread.isAlive()) {
    			drawThread.interrupt();
    			drawThread.join();	// wait before continue
    		}
     
    		Runnable r = new Runnable() {
    			public void run() {
    				for (V view:MainCurveViews.this) {
    					if (Thread.currentThread().isInterrupted()) {
    						break;
    					}
    					view.draw(g2, parentBounds, xAxis, yAxis, reader);
    				}
    			};
    		};
     
    		drawThread = new Thread(r);
    		drawThread.setDaemon(true); 	// allows not stopping the JVM close method
    		//drawThread.setPriority(Thread.MIN_PRIORITY);
    		drawThread.start();
    	}
    	catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
    	catch(java.util.ConcurrentModificationException e) {
    		System.out.println("MainCurveViews.draw() error:ConcurrentModificationException");
    	}
    }
    D'avance merci pour votre aide.

  2. #2
    Membre chevronné
    Homme Profil pro
    Architecte technique
    Inscrit en
    Mai 2020
    Messages
    348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mai 2020
    Messages : 348
    Par défaut
    Bonjour,

    Swing gère déjà des threads pour séparer la présentation du reste de l'application. Ça me paraît assez étrange de lancer un thread dans les méthodes dessin.

    Peut-être pourriez vous utiliser un SwingWorker pour calculer les points en arrière-plan et mettre à jour quand le calcul est terminé. Vous pourriez même faire des mises à jour au fur et à mesure du calcul.

    https://docs.oracle.com/javase/7/doc...ingWorker.html

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 84
    Par défaut
    Bonjour et merci pour ta réponse,

    J'ai tenté d'utiliser un SwingWorker. Mais les courbes ne s'affichent toujours pas.

    Un peu de précision sur ma structure de classe :
    - une classe MainView possède une liste de ViewCurve de courbe.
    La méthode draw ci dessus appartient à cette classe MainView.
    Elle est lancée par la méthode "paintComponent(Graphics g)" du JComponent qui contient le ploter (contenant le MainView).
    C'est pour cela que je lance les viewCurve.draw(...) dans un thread pour les détacher de l'EDT.

    - la classe ViewCurve dispose d'un renderer pour afficher la courbe sur l'écran. La methode ViewCurve.draw(...) est définit ci-dessous.
    Elle lance simplement la méthode draw() du renderer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    	/* (non-Javadoc)
    	 * @see com.math.xyploter.data.view.ICurveView#draw(java.awt.Graphics2D, java.awt.geom.Rectangle2D, com.math.xyploter.axis.Axis, com.math.xyploter.axis.Axis, com.math.number.ValueReader)
    	 */
    	@Override
    	public void draw(Graphics2D g2, Rectangle2D parentBounds, Axis xAxis, Axis yAxis, ValueReader reader) {
    		this.getRenderer().draw(g2, parentBounds, xAxis, yAxis, reader);
    	}
    Voici ce qui j'ai fait avec le SwingWorker:

    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
     
    public class XYLineRendererWorker extends SwingWorker<Boolean, XYLine> {
     
    	public XYLineRenderer renderer;
    	public Graphics2D g2;
    	public Rectangle2D parentBounds;
    	public Axis xAxis;
    	public Axis yAxis;
    	public ValueReader reader;
     
    	public XYLineRendererWorked(XYLineRenderer renderer, Graphics2D g2, Rectangle2D parentBounds, Axis xAxis, Axis yAxis, ValueReader reader) {
    		this.renderer = renderer;
    		this.g2 = g2;
    		this.parentBounds = parentBounds;
    		this.xAxis = xAxis;
    		this.yAxis = yAxis;
    		this.reader = reader;
    	}
     
     
    	/* (non-Javadoc)
    	 * @see javax.swing.SwingWorker#doInBackground()
    	 */
    	@Override
    	protected Boolean doInBackground() throws Exception {
    		//construction des points de la courbe "affichable"...
     
    		return true;
    	}
     
    	@Override
    	protected void process(List<XYLine> lines) {
    		for (XYLine l: lines)
    			g2.drawLine(l.x1, l.y1, l.x2, l.y2);
    	}
    }
    Pour faire simple la méthode "doInBackground()" est un copié collé de la methode viewCurve.draw(...) dans lequel les
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g2.drawLine(x1, y1, x2, y2);
    ont été remplacés par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    publish(new XYLine(x1, y1, x2, y2));
    La méthode CurveRenderer.draw(...) est définie ci-dessous.
    Elle construit et lance le worker.
    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
     
    	/*
    	 * (non-Javadoc)
    	 * @see math.xyploter.data.renderer.CurveRenderer#draw(java.awt.Graphics2D, java.awt.geom.Rectangle2D, math.xyploter.axis.Axis, math.xyploter.axis.Axis, math.number.ValueReader)
    	 */
    	@Override
    	public void draw(Graphics2D g2, Rectangle2D parentBounds, Axis xAxis, Axis yAxis, ValueReader reader) {
    		if ((parentBounds.getHeight()<20) || parentBounds.getHeight()<20)
    			return;
     
    		initPaint(g2);
     
    		XYLineRendererWorker worker = new XYLineRendererWorker(this, g2, parentBounds, xAxis, yAxis, reader);
    		worker.execute();
    	}
    Il me semble que le détachement de EDT est réalisé par le thread dans le draw(...) de la MainView.
    Et que la synchro avec l'EDT est réalisée avec le worker.
    Avec vous une idée sur ce qui cloche?

  4. #4
    Membre chevronné
    Homme Profil pro
    Architecte technique
    Inscrit en
    Mai 2020
    Messages
    348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mai 2020
    Messages : 348
    Par défaut
    ...La méthode draw .. est lancée par la méthode "paintComponent(Graphics g)"... C'est pour cela que je lance les viewCurve.draw(...) dans un thread pour les détacher de l'EDT.
    J'ai l'impression que c'est la tout votre problème. Swing et le SwingWorker vont se charger de processer les résultats dans le bon thread d'affichage. Il faudrait lancer le worker en dehors du draw qui est déjà dans le cycle de "dessin".

    Par exemple, lorsque un point est rajouté, vous lancez le worker qui va faire son calcul en arrière-plan et délivrer des valeurs au fur et à mesure. Ça n'est qu'à la réception de ces valeurs que vous redessinez le composant sans utiliser de thread, car le worker s'en charge déjà pour vous.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 84
    Par défaut
    Je suis d'accord avec le fait que le traitement est lancé initialement par l'EDT à travers la méthode "paintComponent(Graphics g)".

    L'objet Curve n'est pas lié à la partie graphique (c'est une volonté). Il peut être créé et modifié indifféremment du graphique.
    C'est pour cela que j'ai une classe ViewCurve. Cette classe rend une curve "dessinable". Elle gère les modifications de curve et son dessin (en fonction des propriétés du view) dans le ploter.
    Il est donc normal que ce soit le graphique qui demande à se rafraichir (à travers la méthod "paintComponent(Graphics g)").

    J'ai lancé un thread pour le détacher de l'EDT.
    Il me semble que c'est l'objectif du thread. Je me trompe?

    J'ai fait un "SwingUtilities.isEventDispatchThread()" dans le thread créé dans le MainView.draw() (dans le runnable.run() du premier message). Il me retourne bien false.

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 84
    Par défaut
    Je pense avoir trouvé pourquoi les courbes ne s'affiche pas.

    Ci-dessous la méthode paintComponent().

    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
    /*
     * (non-Javadoc)
     * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
     */
    @Override
    public void paintComponent(Graphics g) {
    	super.paintComponent(g);
    	Graphics2D g2 = (Graphics2D) g.create(0, 0, getWidth(), getHeight());
    	//...
     
    	desk.draw(g2, bounds);
     
    	//g2.dispose();
    	System.out.println("Stop DrawablePanel.paintComponent()");	
    }
    desk est un object de type Drawable (qui possède une liste d'objet de type Drawable...)
    En partant de cette méthode paintComponent, voici la succession d'appel des méthodes paint() et draw() des différents objects.
    Désolé pour la forme synthétique. J'espère que cela se comprend.

    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
    DrawablePanel.paintComponent(){
    	for (Drawable drawable:drawables)
    		drawable.paint();
    }
     
    XYPlot extends Drawable;
     
    XYPlot.paint(){
    	(XYPlotRenderer) getXYPlotRenderer().paint() {
    		// dessine la grille et les axes
     
    		(MainCurvesView) getMainCurvesView().draw(){
    			for (CurveView view:getCurveViews())
    				view.getRenderer().draw(){		// La méthode CurveRenderer.draw(...) est définie dans mon précedent message (création du SwingWorker()
    					//...
    					XYLineRendererWorker worker = new XYLineRendererWorker(this, g2, parentBounds, xAxis, yAxis, reader);
    					System.out.println("Start SwingWorker");
    					worker.execute();
    			}
    		}
    		// ...
    	}
    }
    Donc si vous avez tout suivi, le soucis vient du fait que lors de la création du swingworker, on "libère" la méthode view.getRenderer().draw().
    Elle peut se terminer pour revenir à la fin de l'exécution de la méthode paintComponent() (après la fin de l'appel de la ligne desk.draw(g2, bounds).
    On exécute donc "g2.dispose();" !!!

    Alors que l'EDT n'a peut être pas encore débuté l'affichage des courbes.
    Je dis peut "être pas" mais c'est sur, du fait du long temps de calcul d'affichage de ces courbes.

    J'ai le problème mais pas la solution propre pour bien structurer mon code. avez vous des suggestions?

Discussions similaires

  1. [XL-2010] Optimiser le rafraichissement d'une user form
    Par andy.spit dans le forum Macros et VBA Excel
    Réponses: 15
    Dernier message: 11/12/2012, 10h53
  2. Réponses: 1
    Dernier message: 06/06/2010, 10h33
  3. Fittage d'un courbe (optimisation)
    Par Bouchaa dans le forum MATLAB
    Réponses: 1
    Dernier message: 18/05/2010, 22h57
  4. optimiser le tracé d'une courbe
    Par Zorgz dans le forum 2D
    Réponses: 3
    Dernier message: 04/09/2006, 16h17
  5. [TP]Optimiser le rafraîchissement de l'écran en mode texte?
    Par Ponytear dans le forum Turbo Pascal
    Réponses: 8
    Dernier message: 15/02/2004, 11h12

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