Preocupaciones sobre la función de JPanel: paintcomponent ()

hola soy nuevo en la progtwigción de Java, y necesito que alguien me explique estas líneas de código:

public class drawpanel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); ... } } 

No entiendo la línea public void paintComponent(Graphics g) : ¿por qué tengo que declarar esa función así si está predefinida en JPanel?

Y esta línea super.paintComponent(g) : no la entiendo en absoluto. Gracias por tu ayuda.

La estructura básica:

La palabra clave extends significa que DrawPanel hereda de JPanel . En otras palabras, DrawPanel “es un” JPanel . Como tal, puede anular sus métodos (los que no están marcados como final ). Es posible que desee hacer eso por varias razones. Por ejemplo, es posible que desee obtener acceso a la clase de Graphics del panel, que puede usar para dibujar un círculo en el panel, o un gráfico de barras, o una cadena de texto.

Si no anulas ningún método, cuando extiendes JPanel obtienes algo como esto:

 public class DrawPanel extends JPanel { //TODO not much } 

Sin embargo, eso no es muy útil … a menos que simplemente no te guste el nombre JPanel y quieras llamarlo AwesomePanel ( nota: no hagas eso ). Si eso es todo lo que tiene, es mejor que simplemente cree una instancia de JPanel , como esta: JPanel drawPanel = new JPanel();


paintComponent:

El propósito de extender un JPanel es anular el método paintComponent . El JPanel es invisible hasta que anula paintComponent ( nota: ser invisible es lo que lo convierte en un contenedor útil para botones y otros componentes ). Tiene razón en que el método paintComponent está predefinido (en la clase JComponent si se lo estaba preguntando), pero todo lo que hace es crear un JPanel vacío. Si desea dibujar algo en el panel, debe anularlo, así:

 public class DrawPanel extends JPanel { @Override public void paintComponent(Graphics g) { // < -- HERE! //TODO draw stuff } } 

Nota: la parte @Override no es estrictamente necesaria, pero es una buena práctica incluirla porque reduce los errores de tiempo de ejecución y mejora la legibilidad del código.

Ahora tiene acceso al objeto Graphics g para el panel. Graphics es una clase de ayuda que te permite dibujar cosas en el panel, como esta:

 public class DrawPanel extends JPanel { @Override public void paintComponent(Graphics g) { g.drawOval(50, 50, 50, 50); // < -- draws an oval on the panel } } 

super.paintComponent:

metáfora útil (que acabo de inventar): JPanel es el canvas, el objeto Graphics es tu pincel y super.paintComponent(g) es tu borrador. (Además, JFrame es tu caballete).

Así que super.paintComponent(g) invoca el método paintComponent de la superclase de JPanel (la clase JComponent ) para borrar lo que actualmente está dibujado en el panel. Esto es útil para la animación.

Por ejemplo, considere dibujar un reloj analógico en el panel. Debe actualizarlo cada segundo, por lo que cada segundo debe borrar el reloj anterior y volver a dibujar el reloj, ajustando la manecilla de los segundos. Si no invoca super.paintComponent(g) antes de volver a dibujar el reloj, seguirá dibujando relojes nuevos encima de los relojes antiguos y en 60 segundos lo que tendrá es simplemente un círculo relleno, más o menos.

Solo una cosa más para recordar: siempre llame a super.paintComponent(g) primero en el método paintComponent , así:

 public class DrawPanel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); // < -- HERE! g.drawOval(50, 50, 50, 50); } } 

Eso es. No dude en ponerse en contacto conmigo.


Ejemplo:

Creé un ejemplo simple que utiliza estos conceptos para mostrar una cadena de texto en un panel (que se coloca dentro de un marco). Guarde en su IDE como TestPanel.java .

 import java.awt.*; import java.util.*; import javax.swing.*; /** * A frame containing a panel that is sometimes red and sometimes * blue. Also, it displays the word to go with it. * * Inspired by www.sometimesredsometimesblue.com. * */ public class TestPanel extends JPanel { private Random random = new Random(); private boolean isRed; private String s = ""; public TestPanel() { //randomly determine whether the background should be red isRed = random.nextBoolean(); //set the background to blue setBackground(Color.BLUE); s = "BLUE"; //if 'isRed' is true, set the background to red if (isRed) { setBackground(Color.RED); s = "RED"; } } @Override public void paintComponent(Graphics g) { super.paintComponent(g); //write either "RED" or "BLUE" using graphics g.setColor(Color.WHITE); g.setFont(new Font("serif", Font.BOLD, 60)); g.drawString(s, getWidth() / 2 - g.getFontMetrics().stringWidth(s) / 2, getHeight() / 2 + g.getFontMetrics().getHeight() / 2); } //main method: create an instance of TestPanel and output it on a JFrame public static void main(String[] args) { JFrame f = new JFrame(); f.setSize(500, 500); f.setTitle("Sometimes Red, Sometimes Blue"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setContentPane(new TestPanel()); f.setVisible(true); } } 

paintComponent() es un método originalmente definido en la clase abstracta JComponent. Los componentes que extienden JComponent directamente de forma indirecta (si están expuestos) tienen la opción de anular paintComponent (). la llamada a super.paintComponent(g) llama a la implementación de paintComponent() de paintComponent() (en tu caso es de JPanel). paintComponent() sobrescribir paintComponent() si quiere hacer otras cosas con Graphics g además de lo que ya hace JPanel.

Solo necesita definir paintComponent() en su clase si desea cambiar la forma en que se dibuja su componente. En su implementación personalizada, debe llamar a super.paintComponent(g); es decir, una versión de clase base de paintComponent() , porque hace un trabajo necesario para preparar el componente para el dibujo.