## Cómo utilizar la Clase Canvas

La clase Canvas existe para tener descendientes. No hace nada por sí misma; sólo proporciona una forma para implemetar un componente personalizado. Por ejemplo, los Lienzos (Canvas) son útiles para áreas de dibujo para imágines y gráficos del cliente, tanto si se desea o no manejar eventos que ocurran dentro del área de pantalla.

Los Canvas también son útiles cuando se quiera un control -- un botón, por ejemplo -- que se parezca a la implementación por defecto de ese control. Como no se puede cambiar la apariencia de los controles estandards creando una subclase de la clase Component correspondiente (Button, por ejemplo), en su lugar se puede crear una subclase de Canvas que tenga el comportamiento que se quiera y el mismo comportamiento que la implementación por defecto del control.

Cuando se implemente una subclase de Canvas, ten cuidado al implementar los métodos minimumSize() y preferredSize() para que reflejen adecuadamente el tamaño de su lienzo. De otro modo, dependiendo del controlador de disposición que utilice el contenedor de su Canvas, su podría terminar demasiado pequeño -- quizás invisible.

Aquí tienes un applet que utiliza dos ejemplares de una subclase de Canvas: ImageCanvas.

Abajo tienes el código de ImageCanvas. (Podrás encontrarlo en la forma electrónica en el fichero ImageApplet.java.) Como los datos de la imagen se cargan asíncronamente, un ImageCanvas no conoce el tamaño que debería tener hasta algún momento después de haberse creado. Por esta razón, ImageCanvas utiliza la anchura y altura sugeridos por su creador hasta que esté disponible el dato de su tamaño. Cuando el tamaño de la imagen se vuelve disponible, el ImageCanvas cambia el tamaño que devuelven sus métodos preferredSize() y minimumSize(), intenta redimensionarse, y luego pide al contenedor de más alto nivel que se ajuste de forma adecuada al nuevo tamaño y que se redibuje.

    class ImageCanvas extends Canvas {
        Container pappy;
        Image image;
        boolean trueSizeKnown = false;
        Dimension minSize;
        int w, h;

        public ImageCanvas(Image image, Container parent,
                                  int initialWidth, int initialHeight) {
            if (image == null) {
                System.err.println("Canvas got invalid image object!");
                return;
            }

            this.image = image;
            pappy = parent;

            w = initialWidth;
            h = initialHeight;

            minSize = new Dimension(w,h);
        }

        public Dimension preferredSize() {
            return minimumSize();
        }

        public synchronized Dimension minimumSize() {
            return minSize;
        }

        public void paint (Graphics g) {
            if (image != null) {
                if (!trueSizeKnown) {
                    int imageWidth = image.getWidth(this);
                    int imageHeight = image.getHeight(this);

                    if ((imageWidth > 0) && (imageHeight > 0)) {
                        trueSizeKnown = true;

                        //Ooh... component-initiated resizing.
                        w = imageWidth;
                        h = imageHeight;
                        minSize = new Dimension(w,h);
                        resize(w, h);
                        pappy.layout();
                        pappy.repaint();
                    }
                }

                g.drawRect(0, 0, w - 1, h - 1);
                g.drawImage(image, 0, 0, this);
            }
        }
    }

Para más información sobre el dibujo de gráficos, puedes ver la lección Trabajar con Gráficos. Para ver un ejemplo de implementación de la clase Canvas que dibuja gráficos del cliente y maneja eventos, puedes ver el código del applet RectangleDemo. Puedes ver RectangleDemo en acción en Dibujar Formas.

Ozito