首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >图像编辑工具的高级设计模式

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

Stack Overflow用户
提问于 2009-04-05 04:29:02
回答 4查看 2.6K关注 0票数 7

我最近开始创建一个图像编辑工具,它将迎合一个非常具体的需求。这对那些打算使用它的人来说就像我自己的娱乐一样多。然而,我在早期遇到了一些架构上的障碍。

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

代码语言:javascript
复制
public interface IDrawingTool
{
    void DrawEffect( Graphics g );
    // other stuff
}

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

这种方法的问题是,不同的绘图工具不能清晰地附着在单个界面上。例如,钢笔工具只需知道要绘制的点即可工作。但是,矩形需要单击的第一个点,以及当前位置。多边形工具需要跟踪多次鼠标单击。

我想不出一个好的方法来实现这一点。我现在能想到的最好的方法是为每个工具包含一个switch语句和一个case,这意味着绘制逻辑将位于Canvas类中,而不是由工具类型对象封装。因为这是练习,我想以正确的方式来做这件事。提前感谢您的帮助。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-04-05 04:41:39

好的,经验法则:如果您在代码草图中看到一条switch语句,则表明您需要改用多态性。因此,在这种情况下,您希望能够进行各种操作,并且您发现自己需要一个switch,因此您应该思考“我如何使用多态性使其成为某种东西?”

现在,让我们来看看Command模式,其中的对象是动词而不是名词。每个命令都实现一个doThis()方法;当您构造对象时,将确定命令将执行的操作。

代码语言:javascript
复制
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){ // ...
   }
}

现在,考虑一下如果您想要实现撤销,您会做些什么

更新

好的,让我们再扩展一下。使用此模式的重点是确保客户不需要知道太多,除非您正在进行原始构造。因此,在这个例子中,让我们考虑一下画一个矩形。当您选择一个矩形工具时,您将在按钮单击事件处理程序上有一些代码(这都是伪代码btw)

代码语言:javascript
复制
 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

现在,当您选择了矩形后,您可以向命令列表结构中添加一个DrawRectangle对象。一段时间后,您将遍历该列表

代码语言:javascript
复制
for cmd in cmdlist:
   cmd.doThis(Graphics g)

然后这些事情就完成了。现在应该很明显了,您可以通过向命令添加"undoThis“方法来实现撤消。当你创建一个命令时,你必须编译代码,这样对象才能知道如何撤销它自己。然后撤消意味着只从列表中删除最后一个命令对象,并执行其undoThis方法。

票数 1
EN

Stack Overflow用户

发布于 2009-04-06 22:47:59

你可以把你的界面设计得复杂一点吗?让我们从一些代码开始,然后我将解释它是如何工作的。

代码语言:javascript
复制
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
}

这个想法是,一旦用户开始使用特定的实现,就将用户输入传递给工具。这样,您就可以创建许多不同的绘图工具,所有工具都使用相同的界面。例如,一个简单的PointDrawingTool只会实现mouseClick事件来在画布上放置一个点。PolygonDrawingTool还将实现keyUp事件,以便在按下特定键(即退出键)时停止绘制线条。

一个特例是drop方法。它将被调用,以“删除”当前选择的工具。如果从工具栏或类似工具栏中选择了另一个实现,则会发生这种情况。

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

票数 1
EN

Stack Overflow用户

发布于 2009-04-05 19:29:36

当我试图重新设计我的mapping SW以同时支持GDI+和Cairo图形库时,我遇到了类似的问题。我通过将绘图接口减少到一些常见的操作/原语来解决这个问题,请参阅下面的代码。

在这之后,你想要绘制的“效果”就是命令(就像查利说的那样)。它们使用IPainter接口进行绘制。这种方法的好处是,效果与GDI+这样的具体绘图引擎完全解耦。这对我来说很方便,因为我可以通过切换到Cairo engine将我的绘图导出为SVG。

当然,如果您需要一些额外的图形操作,则必须使用它来扩展IPainter接口,但基本原理保持不变。有关这方面的更多信息,请访问:http://igorbrejc.net/development/c/welcome-to-cairo

代码语言:javascript
复制
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,
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/718342

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档