¡Hola muy buenas noches!, tengo cierto problema en java que ya me esta desconcertando bastante, ya que no pensé que algo que yo pensaría que sería "relativamente sencillo", resultase en que llevo 1 día y medio pensando en porque el programa no me funciona bien... (Tener en cuenta que casi no se nada de Java), soy un completo novato.
El lenguaje de programación con el que estoy familiarizado es javascript (Bastante familizarizado de hecho), pero mirando ahora a Java y el uso de las librerías graficas awt, me quede ya un poco perdido... tan perdido que no tengo idea de si lo que estoy haciendo esta correctamente organizado y estructurado para lo que estoy haciendo.
Para poner rápido en contexto lo que debo hacer (Es una tarea de la universidad), debo crear un "paint", pero sencillo, el cual me permita dibujar trazos a pulso, (Como si de la herramienta lapiz de paint se tratase), el programa debe permitir cambiar de "herramienta de dibujo", y debe permitir realizar formas primitivas, por ejemplo un rectangulo, un circulo y ademas permitir cambiar el color del trazó y relleno.
Por supuesto, esto de agregar herramientas seleccionarlas cambiar el color de trazado y de relleno y hacer diferentes formas una vez logre hacer que funcione el objeto Graphics2D, las implementare luego de que logre hacer funcionar Graphics2D...
Aquí esta el código de las diferentes clases que tengo ya creadas del programa:
clase principal (magicBoard):
package magicBoard;
import java.awt.*;
public class MagicBoard {
public static void main(String[] args) {
Board board = new Board("¡Tablero magico!",Color.orange, 800,600);
board.settings();
}
}
Clase board:
package magicBoard;
import java.awt.*;
import javax.swing.*;
public class Board extends JFrame{
protected Canvas canvas;
protected String title;
protected Color color;
protected Container container;
protected Dimension screenSize;
Board(String title, Color color, int width, int height){
this.canvas = new Canvas(width, height);
this.title = title;
this.color = color;
this.container = getContentPane();
this.screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
}
public void settings() {
setTitle(this.title);
this.setSize(this.canvas.width , this.canvas.height);
this.canvas.setBackground(this.color);
container.setLayout(new BorderLayout());
container.add(this.canvas, BorderLayout.CENTER);
this.setLocation(
this.screenSize.width / 2 - this.canvas.width / 2,
this.screenSize.height / 2 - this.canvas.height / 2
);
this.show(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
Clase canvas:
package magicBoard;
import java.awt.event.*;
import java.util.EventListener;
import javax.swing.*;
public class Canvas extends JPanel{
protected EventListener listeners;
protected Pointer pointer;
protected int width,height;
Canvas(int w, int h){
//Tamaño de la ventana
this.pointer = new Pointer(0,0);
this.width = w;
this.height = h;
//Pocisiones X y Y actuales del cursor en el canvas
listeners = new EventManager(this);
addMouseListener((MouseListener) listeners);
addMouseMotionListener((MouseMotionListener) listeners);
}
}
Clase pointer (Ojo, esta clase va a tener mas funciones luego, en ella pondría las funciones de dibujado, de momento estas las implemente fue directamente en la clase que maneja los eventos (Como prueba), luego serán migradas una vez funcionen):
package magicBoard;
import java.awt.*;
public class Pointer {
protected int x,y;
Pointer(int x,int y){
this.x = x;
this.y = y;
}
public void updatePoint(Point p){
this.x = p.x;
this.y = p.y;
}
}
Clase EventManager:
package magicBoard;
import java.awt.*;
import java.awt.event.*;
public class EventManager implements MouseListener,MouseMotionListener {
protected boolean mouseIsPressed;
protected Canvas canvas;
protected Graphics2D ctx;
public EventManager(Canvas canvas) {
this.mouseIsPressed = false;
this.canvas = canvas;
this.ctx = (Graphics2D) canvas.getGraphics();
System.out.println((Graphics2D) this.canvas.getGraphics());
}
@Override
public void mouseDragged(MouseEvent e) {
Point p = e.getPoint();
if(this.mouseIsPressed) {
this.ctx.drawLine(this.canvas.pointer.x,this.canvas.pointer.y, p.x,p.y);
this.canvas.pointer.updatePoint(p);
}
}
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseClicked(MouseEvent ev) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent ev) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent ev) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent ev) {
this.canvas.pointer.updatePoint(ev.getPoint());
this.mouseIsPressed = true;
}
@Override
public void mouseReleased(MouseEvent ev) {
this.mouseIsPressed = false;
}
}
El problema se da en la clase EventManager, donde al tratar de asignar una instancia nueva de tipo Graphics2D al atributo ctx de la clase EventManager, esta se guarda como null, dando como resultado que al iniciarse el programa dará este error:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at magicBoard.EventManager.mouseDragged(EventManager.java:27)
Mi pregunta es...
Si el atributo de la clase EventManager llamado canvas no es null (Ya que lo comprobé imprimiendolo en consola), entonces... ¿por qué no puedo obtener correctamente por parte de este objeto un objeto Graphics2D en el constructor de la clase??
Nota importante: Intente simplemente hacer lo siguiente en el método mouseDragged y funciona! (Existe la referencia).
En vez de:
public class EventManager implements MouseListener,MouseMotionListener {
protected boolean mouseIsPressed;
protected Canvas canvas;
protected Graphics2D ctx;
public EventManager(Canvas canvas) {
this.mouseIsPressed = false;
this.canvas = canvas;
this.ctx = (Graphics2D) canvas.getGraphics();
System.out.println((Graphics2D) this.canvas.getGraphics());
}
@Override
public void mouseDragged(MouseEvent e) {
Point p = e.getPoint();
if(this.mouseIsPressed) {
this.ctx.drawLine(this.canvas.pointer.x,this.canvas.pointer.y, p.x,p.y);
this.canvas.pointer.updatePoint(p);
}
}
//Resto de código
Hacer esto:
public class EventManager implements MouseListener,MouseMotionListener {
protected boolean mouseIsPressed;
protected Canvas canvas;
public EventManager(Canvas canvas) {
this.mouseIsPressed = false;
this.canvas = canvas;
}
@Override
public void mouseDragged(MouseEvent e) {
Point p = e.getPoint();
Graphics2D ctx = (Graphics2D) this.canvas.getGraphics();
if(this.mouseIsPressed) {
ctx.drawLine(this.canvas.pointer.x,this.canvas.pointer.y, p.x,p.y);
this.canvas.pointer.updatePoint(p);
}
}
//Resto de código
sin embargo me gustaría tener la referencia digamos lo así... Global, para poder que todas los métodos puedan acceder a un único objeto y no tener que estar creando uno por cada método...
Esto en javascript podría solucionarse fácilmente simplemente asignando el objeto en el constructor, pero esto no parece funcionar correctamente en java o no lo estoy haciendo bien... (También intente hacer el atributo ctx de tipo public y no funciono, sigue siendo null la referencia)... alguna manera de hacerlo global sin que la referencia termine siendo null para poderla usar de manera global en mis metodos??