【问题标题】:GEF + EMF: Why doesn't my editor remove the Figure for a removed object when refreshChildren() is called?GEF + EMF:为什么我的编辑器在调用 refreshChildren() 时不删除已删除对象的图形?
【发布时间】:2012-06-29 10:54:59
【问题描述】:

我已经为类似图形的 EMF 模型实现了 GEF 编辑器,其中包含用于图形中某种类型节点的删除命令。我想我已经完成了所有必要的步骤来完成这个设置(vainoloblog 帮助很大)。

但是,当我删除模型元素时,视图不会刷新,即模型元素的图形没有从编辑器视图中删除,我没有知道为什么。如果有人可以查看我的消息来源并指出任何问题(以及可能的解决方案:)),我将非常感激。非常感谢!

以下是我认为解决此问题的重要类。如果我添加更多代码/编辑代码等,请告诉我(我省略了我认为没有帮助的代码,例如 getter 和 setter、类变量)。谢谢!

图表编辑部分

public class DiagramEditPart extends AbstractGraphicalEditPart {

    public DiagramEditPart(Diagram model) {
        this.setModel(model);
        adapter = new DiagramAdapter();
    }

    @Override protected IFigure createFigure() {
        Figure figure = new FreeformLayer();
        return figure;
      }

      @Override protected void createEditPolicies() {
        installEditPolicy(EditPolicy.LAYOUT_ROLE, new DiagramXYLayoutPolicy());
      }

      @Override protected List<EObject> getModelChildren() {
          List<EObject> allModelObjects = new ArrayList<EObject>();
          if (((Diagram) getModel()).getMyNodes() != null)
          allModelObjects.addAll(((Diagram) getModel()).getMyNodes());
          return allModelObjects;
      }

      @Override public void activate() {
          if(!isActive()) {
              ((Diagram) getModel()).eAdapters().add(adapter);
          }
          super.activate();
      }


      @Override public void deactivate() {
          if(isActive()) {
              ((Diagram) getModel()).eAdapters().remove(adapter);
          }
          super.deactivate();
      }

    public class DiagramAdapter implements Adapter {

          @Override public void notifyChanged(Notification notification) {
              switch (notification.getEventType()) {
            case Notification.REMOVE: refreshChildren();
                break;
            default:
                break;
            }
          }

          @Override public Notifier getTarget() {
              return (Diagram) getModel();
          }

          @Override public void setTarget(Notifier newTarget) {
              // Do nothing.
          }

          @Override public boolean isAdapterForType(Object type) {
              return type.equals(Diagram.class);
          } 

      }

}

MyNodeEditPart

public class MyNodeEditPart extends AbstractGraphicalEditPart {

    public MyNodeEditPart(MyNode model) {
         this.setModel(model);
         adapter = new MyNodeAdapter();
    }

    @Override protected IFigure createFigure() {
        return new MyNodeFigure();
    }

    @Override protected void createEditPolicies() {
        installEditPolicy(EditPolicy.COMPONENT_ROLE, new MyNodeComponentEditPolicy());
    }

    @Override protected void refreshVisuals() {
        MyNodeFigure figure = (MyNodeFigure) getFigure();
        DiagramEditPart parent = (DiagramEditPart) getParent();
        Dimension labelSize = figure.getLabel().getPreferredSize();
        Rectangle layout = new Rectangle((getParent().getChildren().indexOf(this) * 50), 
                (getParent().getChildren().indexOf(this) * 50), (labelSize.width + 20), 
                (labelSize.height + 20));
        parent.setLayoutConstraint(this, figure, layout);
    }

    public List<Edge> getModelSourceConnections() {
        if ((MyNode) getModel() != null && ((MyNode) getModel()).getDiagram() != null) {
            ArrayList<Edge> sourceConnections = new ArrayList<Edge>();
            for (Edge edge : ((MyNode) getModel()).getDiagram().getOutEdges(((MyNode) getModel()).getId())) {
                sourceConnections.add(edge);
            }
            return sourceConnections;
        }
        return null;
    }

    // + the same method for targetconnections

    @Override public void activate() {
        if (!isActive()) {
            ((MyNode) getModel()).eAdapters().add(adapter);
        }
        super.activate();
    }

    @Override public void deactivate() {
        if (isActive()) {
            ((MyNode) getModel()).eAdapters().remove(adapter);
        }
        super.deactivate();
    }

    public class MyNodeAdapter implements Adapter {

        @Override
        public void notifyChanged(Notification notification) {
            refreshVisuals();
        }

        @Override
        public Notifier getTarget() {
            return (MyNode) getModel();
        }

        @Override
        public void setTarget(Notifier newTarget) {
            // Do nothing
        }

        @Override
        public boolean isAdapterForType(Object type) {
            return type.equals(MyNode.class);
        }

    }

}

MyNodeComponentEditPolicy

public class MyNodeComponentEditPolicy extends ComponentEditPolicy {

    @Override
    protected Command createDeleteCommand(GroupRequest deleteRequest) {
        DeleteMyNodeCommand nodeDeleteCommand = new DeleteMyNodeCommand((MyNode) getHost().getModel());
        return nodeDeleteCommand;
    }

}

DeleteMyNodeCommand

public class DeleteMyNodeCommand extends Command {

    public DeleteMyNodeCommand(MyNode model) {
        this.node = model;
        this.graph = node.getDiagram();
    }

    @Override public void execute() {
        getMyNode().setDiagram(null);
        System.out.println("Is the model still present in the graph? " + getGraph().getMyNodes().contains(getMyNode())); 
            // Returns false, i.e., graph doesn't contain model object at this point!
    }

    @Override public void undo() {
        getMyNode().setDiagram(getGraph());
    }

}

编辑

Re execc 的评论:是的,refreshChildren() 正在被调用。我已经通过覆盖它并添加了一个简单的System.err 行对其进行了测试,该行在删除节点时显示在控制台上:

@Override
public void refreshChildren() {
    super.refreshChildren();
    System.err.println("refreshChildren() IS being called!");
}

编辑 2

有趣(嗯...)的事情是,当我关闭编辑器并保留模型,然后重新打开同一个文件时,节点不再绘制,并且模型中不存在。但是,这是什么意思?我在做一个陈旧的模型吗?还是刷新/让模型孩子无法正常工作?


编辑 3

我刚刚发现了一件奇怪的事情,可能解释了我遇到的问题?在getModelChildren() 方法中,我调用allModelObjects.addAll(((Diagram) getModel()).getMyNodes());getMyNodes() 返回一个不可修改 EList。我发现当我尝试在删除命令中按照((Diagram) getModel()).getMyNodes().remove(getMyNode()) 的方式执行某些操作时,它抛出了一个UnsupportedOperationException...嗯。


编辑 4

呃,somebody kill me please? 我已经仔细检查过我是否一直在处理同一个 Diagram 对象,在这样做的时候我偶然发现了一件非常尴尬的事情:

最后一个版本中DiagramEditPart 中的getModelChildren() 方法大约读取。像这样:

@Override protected List<EObject> getModelChildren() {
    List<EObject> allModelObjects = new ArrayList<EObject>();
    EList<MyNode> nodes = ((Diagram) getModel()).getMyNodes();
    for (MyNode node : nodes) {
        if (node.getDiagram() != null); // ### D'Uh! ###
            allModelObjects.add(node);
    }
    return allModelObjects;
 }

我想为占用大家的时间而道歉!你的建议很有帮助,确实帮助我最终找到了这个错误!

我也学到了很多经验,其中包括:始终粘贴原始代码,过度简化可能会掩盖您的错误!我学到了很多关于 EMF、Adapter 和 GEF 的知识。还是:

【问题讨论】:

  • DiagramEditPart 的 refreshChildren() 方法是否被调用过?您可以覆盖它并添加一条简单的日志消息以查看是否存在。
  • @execc:谢谢。是的,该方法似乎被调用,cf。我的编辑。
  • 您是否也检查过getModelChildren 是否也被调用?此外,在Command 中您执行getGraph().getSNodes(),但在DiagramEditPart 中您调用getMyNodes()。它们有什么区别?
  • @vainolo:是的,正在调用getModelChildren()getMy/SNodes() 是一个错字,对不起,我已经在问题中更正了。
  • 使用setModelgetModel。但是代码看起来没问题,如果 getModelChildren 被调用,那么模型本身就有问题。在我看来,您必须调试代码才能看到发生了什么。

标签: eclipse eclipse-plugin controller eclipse-emf eclipse-gef


【解决方案1】:

以下部分代码第5行多了一个分号,即if语句后:if (node.getDiagram() != null);:

1   @Override protected List<EObject> getModelChildren() {
2       List<EObject> allModelObjects = new ArrayList<EObject>();
3       EList<MyNode> nodes = ((Diagram) getModel()).getMyNodes();
4       for (MyNode node : nodes) {
5           if (node.getDiagram() != null); 
6               allModelObjects.add(node);
7       }
8       return allModelObjects;
9    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-09
    • 1970-01-01
    相关资源
    最近更新 更多