Maison  >  Article  >  Java  >  Comment dessiner efficacement des graphiques en constante évolution en Java ?

Comment dessiner efficacement des graphiques en constante évolution en Java ?

Patricia Arquette
Patricia Arquetteoriginal
2024-11-25 09:29:11373parcourir

How to Efficiently Draw Constantly Changing Graphics in Java?

Comment dessiner des graphiques en constante évolution en Java

Introduction

Création de graphiques dynamiques qui se mettent à jour cela peut constamment être une tâche difficile en Java. Dans cet article, nous montrerons comment résoudre ce problème en utilisant des techniques efficaces et la synchronisation des threads.

Énoncé du problème

Le code initial fourni dans la question présentait plusieurs problèmes de performances, ce qui entraîne des mises à jour graphiques lentes. L'objectif est d'optimiser le code pour obtenir des mises à jour constantes avec une vitesse améliorée.

Code optimisé

Voici une version optimisée du code :

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;

public class ZoomPanel extends JPanel {

    private static final int STEP = 40;
    private int iter = 0;
    private long cumulativeTimeTaken = 0;

    // Model to hold pixel colors
    private final Color[][] model = new Color[8][8];

    // Flag to prevent concurrent painting
    private boolean isDrawing = false;

    public static void main(String[] args) {
        final JFrame frame = new JFrame("Image zoom");

        final ZoomPanel zoomPanel = new ZoomPanel();
        frame.getContentPane().add(zoomPanel);
        final Ticker t = new Ticker(zoomPanel);

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                t.done();
                frame.dispose();
            }
        });
        t.start();

        frame.setLocation(new Point(640, 0));
        frame.pack();
        frame.setVisible(true);
    }

    // Sets the pixel color at the given position
    private void setColorAt(int x, int y, Color pixelColor) {
        model[x][y] = pixelColor;
        repaint(40 + x * STEP, 45 + y * STEP, 40 + (x * STEP) - 3, 45 + (y * STEP) - 3);
    }

    // Gets the pixel color at the given position
    private Color getColorAt(int x, int y) {
        return model[x][y];
    }

    // Draws the graphics
    public void paintComponent(Graphics g) {
        long start = System.currentTimeMillis();

        if (!SwingUtilities.isEventDispatchThread()) {
            throw new RuntimeException("Repaint attempt is not on event dispatch thread");
        }

        // Prevent concurrent painting
        isDrawing = true;

        final Graphics2D g2 = (Graphics2D) g;
        g2.setColor(getBackground());

        try {

            for (int x = 0; x < 8; x++) {
                for (int y = 0; y < 8; y++) {
                    g2.setColor(model[x][y]);
                    Ellipse2D e = new Ellipse2D.Double(40 + x * STEP, 45 + y * STEP, STEP - 3, STEP - 3);
                    g2.fill(e);
                    g2.setColor(Color.GRAY);
                    g2.draw(e);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        iter++;

        // Display FPS count
        g2.setColor(Color.black);
        long stop = System.currentTimeMillis();
        cumulativeTimeTaken += stop - start;
        StringBuilder sb = new StringBuilder();
        sb.append(iter)
                .append(" frames in ")
                .append((double) (cumulativeTimeTaken) / 1000)
                .append("s.");

        System.out.println(sb);

        // Allow painting again
        isDrawing = false;
    }

    private static class Ticker extends Thread {

        private final Robot robot;

        public boolean update = true;
        private final ZoomPanel view;

        public Ticker(ZoomPanel zoomPanel) {
            view = zoomPanel;
            try {
                robot = new Robot();
            } catch (AWTException e) {
                throw new RuntimeException(e);
            }
        }

        public void done() {
            update = false;
        }

        public void run() {
            int runCount = 0;
            while (update) {
                runCount++;
                if (runCount % 100 == 0) {
                    System.out.println("Ran ticker " + runCount + " times");
                }
                final Point p = MouseInfo.getPointerInfo().getLocation();

                Rectangle rect = new Rectangle(p.x - 4, p.y - 4, 8, 8);
                final BufferedImage capture = robot.createScreenCapture(rect);

                // Synchronized block to prevent concurrent access to the model
                synchronized (view) {
                    // If the panel is not drawing, update the model and repaint
                    if (!view.isDrawing) {
                        for (int x = 0; x < 8; x++) {
                            for (int y = 0; y < 8; y++) {
                                final Color pixelColor = new Color(capture.getRGB(x, y));

                                if (!pixelColor.equals(view.getColorAt(x, y))) {
                                    final int finalX = x;
                                    final int finalY = y;
                                    SwingUtilities.invokeLater(new Runnable() {
                                        public void run() {
                                            view.setColorAt(finalX, finalY, pixelColor);
                                        }
                                    });
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Améliorations

  • Robot Optimisation : La méthode getPixelColor dans le code d'origine était inefficace. En utilisant createScreenCapture pour récupérer les 64 pixels à la fois, nous améliorons considérablement les performances.
  • Smart Clipping : seule la région modifiée est repeinte, réduisant ainsi les mises à jour inutiles.
  • Threading amélioré : le modèle et la vue sont mis à jour sur le thread de répartition d'événements, garantissant une synchronisation appropriée des threads et évitant une concurrence potentielle. problèmes.
  • Surveillance FPS : Un compteur FPS imprime le nombre d'images mises à jour en une seconde.
  • Synchronisation : Un verrou empêche la peinture simultanée, améliorant encore la stabilité.

Ces optimisations se traduisent par une amélioration considérable des performances, les mises à jour d'écran apparaissant virtuellement instantané. Le compteur FPS fournit une mesure de la vitesse améliorée.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn