用pygame和lambdas实现undo和redo

2024-04-18 19:02:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图使用lambdas在pygame应用程序中实现undo和redo,但与引用或我对list.remove()实现的理解有关的东西导致我的程序崩溃。创建可撤销操作的代码如下

elif MOUSEBUTTONUP == event.type:
    x, y = pygame.mouse.get_pos()
    if leftClick:
        if len( objects ) > 0 and objects[ -1 ].is_open():
            actions.do( \
                [ lambda: objects[ -1 ].add( Point( x, y, 0 ) ) ], \
                [ lambda: objects[ -1 ].remove( Point( x, y, 0 ) ) ] \
            )
        else:
            actions.do( \
                [ lambda: objects.append( Polygon( ( 255, 255, 255 ) ).add( Point( x, y, 0 ) ) ) ],
                [ lambda: objects.pop() ] \
            )

其中objects是Polygon的列表,定义为

^{pr2}$

添加的点定义为

class Point:
    def __init__( self, x, y, z ):
        self.x = x
        self.y = y
        self.z = z

    def rel_to( self, point ):
        x = self.move( point.z, point.x, self.z, self.x )
        y = self.move( point.z, point.y, self.z, self.y )
        return ( x, y )

    def move( self, viewer_d, displacement, object_d, object_h ):
        over  = object_h * viewer_d + object_d * displacement
        under = object_d + viewer_d + 1
        return over / under

    def __str__( self ):
        return "(%d, %d, %d)" % ( self.x, self.y, self.z )

    def __eq__( self, other ):
        return self.x == other.x and self.y == other.y and self.z == other.z

    def __ne__( self, other ):
        return not ( self == other )

在第一个片段中,actions是{}的一个实例,其定义如下

class Actions:
    #TODO implement immutability where possible
    def __init__( self ):
        self.undos = []
        self.redos = []

    def do( self, do_steps, undo_steps ):
        for do_step in do_steps:
            do_step()
        self.undos.append( ( do_steps, undo_steps ) )
        self.redos = []

    def can_undo( self ):
        return len( self.undos ) > 0

    def undo( self ):
        if self.can_undo():
            action = self.undos.pop()
            _, undo_steps = action
            for undo_step in undo_steps:
                undo_step()
            self.redos.append( action )

    def can_redo( self ):
        return len( self.redos ) > 0

    def redo( self ):
        if self.can_redo():
            action = self.redos.pop()
            redo_steps, _ = action
            for redo_step in redo_steps:
                redo_step()
            self.undos.append( action )

所以问题是,当我点击两次以上并试图调用actions.undo()时,我得到了一个list.remove(x)的异常,它说{}不在列表中,我想是因为它试图删除同一个点两次。在前两次单击之前不会发生这种情况的原因是第一次撤消尝试删除最近的点,而第二次撤消只是将多边形从对象堆栈中弹出。我的问题是,为什么actions.undo()Point尝试两次删除同一个点,即使第一个点应该从self.undos堆栈中弹出并推送到self.redos堆栈中?非常感谢您的反馈。在


Tags: selfactionsreturnobjectsdefstepactionsteps
1条回答
网友
1楼 · 发布于 2024-04-18 19:02:25

我想我已经想好了,不管怎样,它还是像预期的那样有效。我推断出的理论是lambda操作在xy和{}参数上创建闭包,因此在创建匿名函数时,它没有复制这些变量的值,而是保留了指向它们值的指针。所以我可以删除最近的一个点,因为xy和{}仍然引用了一个现有的点,但是在第二次撤消时失败,因为该点不再存在。我使用了stackp在http://stackp.online.fr/?cat=8上的undo/redo教程中的一个叶,并将参数作为一个列表传递给了匿名函数action.do(),这意味着在执行do()函数时对参数进行了计算,因此正确的参数被发送到do()。很抱歉问了这么长时间。在

相关问题 更多 >