Java Swing相当于WPF的数据模板

时间:2017-05-31 15:23:16

标签: java swing datatemplate

在Swing应用程序中,我在JPanel上绘制了覆盖paintComponent方法的元素。

我必须画猫,狗,骆驼等......我想用一系列paintComponent语句污染if (... instanceof ...)会是一件坏事,所以我一直在寻找以另一种方式画我的宠物。

使用WPF(C#),我使用了Data Templates,即告诉View如何显示模型实体。

所以,我提出了一个从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);
    }
}

......可以这样使用:

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);
    }
}

...但是上面CanvasDrawer的代码在编译时给了我一个未经检查的警告:

$ 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

问题1。我在研究过程中是否遗漏了什么?我的意思是:Java Swing中存在数据模板吗? 问题2。还有其他办法可以做我想做的事吗?我走对了路吗? 问题3。我真的必须使用@SuppressWarnings("unchecked")吗?

2 个答案:

答案 0 :(得分:1)

  

我想用一系列if(... instanceof ...)语句污染paintComponent会是一件坏事

正确。

一种方法是只保留一个Animals的ArrayList,其中每只动物都有一个绘制方法来绘制自己。

类似的东西:

@Override
protected void paintComponent(Graphics g)
{
    super.paintComponent(g);

    for (Animal animal: animals)
    {
        animal.draw(g);
    }
}

Animal可以是简单的接口或抽象类。

答案 1 :(得分:1)

参考A Swing Architecture Overview,Swing设计的完整指南超出了本网站的范围,但一些指南可能会帮助您继续前进。

  1. 我在研究过程中是否遗漏了什么?我的意思是:Java Swing中是否存在Data Templates?没有明确。关注教程示例,Swing JList显示ListModel<E>。直接子类AbstractListModel<E>使用所检查的方案here添加事件监听器管理。具体的子类DefaultListModel<E>是一个典型的实现。根据需要,您的模型可以直接实现接口,利用抽象模型的事件管道或简单地包含具体的模型实例,如How to Use Lists: Creating a Model中所述。

  2. 还有其他办法可以做我想做的事吗?我是否采取正确的方式?提到了实现观察者模式的几种常用方法here

  3. 我是否真的必须使用@SuppressWarnings(“未选中”)?您可以指定类型参数,例如{{1},而不是像Object这样的原始类。如here所述。另请参阅Class Literals as Runtime-Type Tokens

  4. 将这样的视图绘制逻辑放在所谓的解耦模型中不是一件坏事吗? example outlined是一个视图组件; 模型可能包含CanvasDrawer<T>,当观察视图更新自身以响应事件时,会访问该文件。

  5. 听起来List<Animal>类是控制器;因为一个控制器可能是一个匿名类,所以它们会崩溃。一个吸引人的设计方法允许客户注入一个新的控制器,如here 所示。

  6. 您是否建议我以某种方式使用这些数据模型?仅在适当情况下使用。有太多方法可以显示…Listener来说明更多内容。