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