In a Swing application, I'm drawing elements on a JPanel
overriding the paintComponent
method.
I have to draw cats, dogs, camels, and more... I guess that polluting paintComponent
with a series of if (... instanceof ...)
statements would be a bad thing, so I'm looking for another way to draw my pets.
With WPF ( C# ), I'd have used Data Templates, i.e. a way to tell the View how to display a Model entity.
So, I came up with a solution ported from JS:
import my.super.Callback; // Because Runnable does not take parameters.
/**
* The class that draws in the canvas.
*/
public class CanvasDrawer {
private HashMap<Class, Callback<Graphics2D, Object>> drawers;
private Graphics2D graphics;
public CanvasDrawer(Graphics2D g) {
graphics = g;
drawers = new HashMap<Class, Callback<Graphics2D, Object>>();
}
/**
* Defines a way to draw the objects of a certain type in the canvas.
*/
public <T> void setDataTemplate(Class<T> type, Callback<Graphics2D, T> drawer) {
drawers.put(type, (Callback<Graphics2D, Object>)drawer);
}
/**
* Actually draws an object in the canvas.
*/
public void draw(Object object) {
drawers.get(object.getClass()).run(graphics, object);
}
}
... Which could be used like this:
class HuntingPartyView extends JPanel {
CanvasDrawer drawer;
public HuntingPartyView() {
drawer = new CanvasDrawer((Graphics2D)getGraphics());
// Where the drawImage method is intentionally skipped in this code.
drawer.setDataTemplate( Cat.class, (g, o) -> drawImage(g, 'res/cat.png', o.x, o.y));
drawer.setDataTemplate( Dog.class, (g, o) -> drawImage(g, 'res/dog.png', o.x, o.y));
drawer.setDataTemplate(Sniper.class, (g, o) -> drawImage(g, 'res/sniper.png', o.x, o.y));
drawer.setDataTemplate(Ranger.class, (g, o) -> drawImage(g, 'res/ranger.png', o.x, o.y));
}
@Override
public void repaintComponent(Graphics g) {
// Where Game is part of the Model layer.
for (Animal animal : Game.singleton.animalList) drawer.draw(animal);
for (Hunter hunter : Game.singleton.hunterList) drawer.draw(hunter);
}
}
... But the code of the CanvasDrawer
above gives me an unchecked warning when I compile it:
$ javac *.java -d out -Xdiags:verbose -Xlint:unchecked
CanvasDrawer.java:15: warning: [unchecked] unchecked cast
drawers.put(type, (Callback<Graphics2D, Object>)drawer);
^
required: Callback<Graphics2D,Object>
found: Callback<Graphics2D,T>
where T is a type-variable:
T extends Object declared in method <T>setDataTemplate(Class<T>,Callback<Graphics2D,T>)
1 warning
Question 1. Did I miss something during my research? I mean: do Data Templates exist in Java Swing?
Question 2. Is there another way to do what I want to do? Am I going the right way?
Question 3. Do I really have to use @SuppressWarnings("unchecked")
?