代码之家  ›  专栏  ›  技术社区  ›  Ed Swangren

图像编辑工具的高级设计模式

  •  6
  • Ed Swangren  · 技术社区  · 17 年前

    与任何图像编辑器一样,用户将使用“工具”绘制和操作图像。我的第一次尝试包括一个简单的界面:

    public interface IDrawingTool
    {
        void DrawEffect( Graphics g );
        // other stuff
    }
    

    这(我认为)将是好的和干净的,并将允许易于维护和扩展。只需在中添加接口对象,并在运行时调用所选对象的DropeEffect方法。

    我很难想出一个好的方法来实现这一点。我现在能想到的最好的方法是使用switch语句和每个工具的case,这意味着绘图逻辑将在Canvas类中,而不是由工具类型的对象封装。因为这是实践,我想用正确的方法来做。提前谢谢你的帮助。

    3 回复  |  直到 17 年前
        1
  •  1
  •   Charlie Martin    17 年前

    switch 语句,这是您需要使用多态性的标志。因此,在这种情况下,您希望能够进行各种操作,并且您发现自己需要一个 转换

    现在,看一下命令模式,对象在其中 动词 而不是 名词 . 每个命令实现一个 doThis() 方法构造对象时,需要确定命令将执行的操作。

    public interface Command {
       public void doThis(Graphics g);  // I don't promise returning 
                                        // void is the best choice
       // Would it be better to return a Graphics object?
    }
    
    public class DrawRectangle implements Command {
       public DrawRectagle( Point topLeft, Point btmRight) { // ...
       }
       public void doThis(Graphics g){ // ...
       }
    }
    

    现在,考虑一下你想做什么,如果你想实现的话 ?

    使现代化

    好的,让我们把这个扩展一点。使用此模式的目的是确保客户端

     cmdlist = [] // empty list
     bool firstClick = true
     Point tl = br = new Point(0,0)
     onClick:
       if firstClick:
         get mouse position into tl
         firstClick = false
       else:
         get mouse position into br
         cmdlist.append(new DrawRectangle(tl, br))
         firstClick = true
    

    for cmd in cmdlist:
       cmd.doThis(Graphics g)
    

    这些事情都完成了。现在很明显,您将通过向命令中添加一个“undoThis”方法来实现undo。创建命令时,必须生成代码,以便对象知道如何撤消自身。然后“撤消”意味着仅从列表中删除最后一个命令对象,并使用此方法执行其撤消操作。

        2
  •  1
  •   Stefan Schmidt    17 年前

    你把界面设计得更复杂一点怎么样?让我们从一些代码开始,然后我将解释它应该如何工作。

    public class AbstractDrawingTool {
    
        private Graphics g;
    
        void AbstractDrawingTool( Graphics g ) {
            this.g = g;
        }
    
        void keyDown(KeyEvent e);
        void keyUp(KeyEvent e);
        void mouseMove(MouseEvent e);
        void mouseClick(MouseEvent e);
        void drop();
        // other stuff
    }
    

    您还可以将此定义与命令模式相结合。在这种情况下,AbstractDrawingTool的一个实现将负责创建命令接口的实例,并可能在操作完成后将它们放在堆栈上(即在画布上放置一个点)。

        3
  •  0
  •   Igor Brejc    17 年前

    mapping SW 支持GDI+和Cairo图形库。我通过将绘图界面简化为一些常见的操作/原语解决了这个问题,请参见下面的代码。

    IPainter 要绘制的接口。这种方法的好处是效果与具体的绘图引擎(如GDI+)完全解耦。这对我来说很方便,因为我可以通过切换到Cairo引擎将图形导出到SVG。

    伊帕因特 接口,但基本原理保持不变。请参见此处的更多信息: http://igorbrejc.net/development/c/welcome-to-cairo

    public interface IPainter : IDisposable
    {
        void BeginPainting ();
        void Clear ();
        void DrawLines (int[] coords);
        void DrawPoint (int x, int y);
        void EndPainting ();
        void PaintCurve (PaintOperation operation, int[] coords);
        void PaintPolygon (PaintOperation operation, int[] coords);
        void PaintRectangle (PaintOperation operation, int x, int y, int width, int height);
        void SetHighQualityLevel (bool highQuality);
        void SetStyle (PaintingStyle style);
    }
    
    public class PaintingStyle
    {
        public PaintingStyle()
        {
        }
    
        public PaintingStyle(int penColor)
        {
            this.penColor = penColor;
        }
    
        public int PenColor
        {
            get { return penColor; }
            set { penColor = value; }
        }
    
        public float PenWidth
        {
            get { return penWidth; }
            set { penWidth = value; }
        }
    
        private int penColor;
        private float penWidth;
    }
    
    public enum PaintOperation
    {
        Outline,
        Fill,
        FillAndOutline,
    }
    
        4
  •  0
  •   Marek Niepiekło    5 年前

    您的确切问题将在下面的文章中用编辑器模式进行描述和解决 Kent Beck和Ralph Johnson模式生成架构:

    https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.46.8603&rep=rep1&type=pdf