Façade Bibliothèque Graphique AWT (2)

Dans cet article, je vous propose de poursuivre la conception d’une façade pour un jeux 2D en tuiles (article précédent). Nous allons ajouter deux types de services: l’un pour gérer le cycle de création et de destruction de la fenêtre, et l’autre pour dessiner. Chaque service est géré par un lot de méthodes dans l’interface GUIFacade:

Les quatre premières méthodes gèrent la vie de la fenêtre:

  • La méthode createWindow() fabrique la fenêtre avec un titre donné;
  • La méthode setClosingRequested() permet de définir si le jeu doit être terminé;
  • La méthode isClosingRequested() permet de savoir si le jeu doit être terminé;
  • La méthode dispose() détruit la fenêtre et tout les éléments associés.

Les trois dernières méthodes permettent de dessiner dans la fenêtre:

  • La méthode beginPaint() permet de démarrer le dessin, et renvoie true si cela est possible;
  • La méthode drawLine() dessine une ligne. C’est un exemple parmi d’autres de méthode de dessin, toute une collection peut être imaginée pour dessiner des rectangles, des cercles, etc.;
  • La méthode endPaint() permet de terminer le dessin.

La plupart des bibliothèques graphiques suivent ce type de schéma où il faut commencer par “préparer” le dessin avec une méthode comme beginPaint(), puis le “libérer” avec une méthode comme endPaint(). En outre, il y a généralement une forme de blocage entre ces deux appels, ce qui signifie qu’il faut dessiner “au plus vite” si on souhaite proposer une expérience utilisateur agréable.

Ces méthodes peuvent être exploitées de la manière suivante: la fenêtre est créée (l. 2) et on répète tant que le jeu n’est pas terminé (l. 3). S’il est possible de commencer à dessiner (l. 4), on dessine une ligne (l. 5) puis on termine le dessin (l. 6). Enfin, la fenêtre est détruite (l. 9):

public static void run(GUIFacade gui) {
    gui.createWindow("Facade librairie graphique AWT");
    while(!gui.isClosingRequested()) {
        if (gui.beginPaint()) {
            gui.drawLine(100, 150, 600, 350);
            gui.endPaint();
        }
    }      
    gui.dispose();
}

L’utilisation de la façade ne dépend pas de son implantation: il est possible d’exploiter différentes implantations, par exemple la bibliothèque AWT incluse dans la bibliothèque standard de Java:

public class AWTGUIFacade implements GUIFacade {

    private AWTWindow window;
    
    private boolean closingRequested = false;
        
    private BufferStrategy bufferStrategy;
    
    private Graphics graphics;

    @Override
    public void createWindow(String title) {
        window = new AWTWindow(this);
        window.init(title);
        window.setLocationRelativeTo(null);
        window.setVisible(true);
        window.createBufferStrategy(2);
    }
    
    @Override
    public void setClosingRequested(boolean b) {
        closingRequested = b;
    }
    
    @Override
    public boolean isClosingRequested() {
        return closingRequested;
    }
    
    @Override
    public void dispose() {
        window.dispose();
    }
    
    @Override
    public boolean beginPaint() {
        bufferStrategy = window.getBufferStrategy();
        if (bufferStrategy == null)
            return false;
        graphics = bufferStrategy.getDrawGraphics();
        if (graphics == null)
            return false;
        graphics.setColor(Color.black);
        graphics.fillRect(0, 0, window.getWidth(), window.getHeight());
        return true;
    }

    @Override
    public void drawLine(int x1, int y1, int x2, int y2) {
        graphics.setColor(Color.white);
        graphics.drawLine(x1, y1, x2, y2);
    }
    
    @Override
    public void endPaint() {
        graphics.dispose();
        bufferStrategy.show();
    }
    
}

L’attribut window est une référence vers une classe AWTWindow qui hérite de java.awt.Frame, présentée ci-dessous. L’attribut closingRequested est true si le jeu doit se terminer. Les attributs bufferStrategy et graphics permettent de gérer un rendu par double tampon.

La méthode init() est la même que dans l’article précédent, sinon la création d’un double tampon d’affichage avec la ligne window.createBufferStrategy(2);. Les méthodes setClosingRequested() et isClosingRequested() sont des assesseurs de l’attribut closingRequested. La méthode dispose() commande la destruction de la fenêtre window.

Les méthodes beginPaint() et endPaint() gèrent le cycle d’affichage. Pour la première, le tampon actuel est obtenu (l. 37), puis un java.awt.Graphics est déduit de celui-ci (l. 40). Dans les deux cas, diverses raisons peuvent interdire ces obtentions, d’où le renvoie d’une valeur false lorsque ceux-ci se présentent. La fin de la méthode beginPaint() efface tout le contenu: cette approche peut être intéressante ou non, suivant les cas. La méthode endPaint() détruit graphics (l. 56) et inverse les deux tampons (l. 57). Enfin, la méthode drawLine() utilise graphics pour dessiner une ligne: il est facile d’imaginer d’autres cas d’utilisation pour dessiner des rectangles, des cercles, etc.

La classe AWTWindow est une fenêtre AWT initialisée par la méthode init() avec une configuration précise. Lorsque sa fermeture est demandée par l’utilisateur, par exemple en cliquant sur la croix dans son cadre, la façade est informée que le jeu doit être terminé (l. 16):

public class AWTWindow extends Frame {
    
    private final AWTGUIFacade gui;

    public AWTWindow(AWTGUIFacade gui) {
        this.gui = gui;
    }
    
    public void init(String title) {
        setTitle(title);
        setSize(640, 480);
        setResizable(false);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent we) {
                gui.setClosingRequested(true);
            }
        });        
    }
}

Le code de cet article peut être téléchargé ici.
Pour compiler, saisissez: javac fr/phtools/awtfacade02/Main.java
Pour lancer, saisissez: java fr.phtools.awtfacade02.Main

Ce contenu a été publié dans Tutoriel, avec comme mot(s)-clé(s) , , . Vous pouvez le mettre en favoris avec ce permalien.