如何修复使用turtle和tkinter制作的绘画应用程序的撤消功能

问题描述 投票:0回答:1

我正在用Python制作一个绘画应用程序。它具有通过单击和拖动来制作形状和绘图的功能。

我一直在尝试在我的应用程序中实现撤消按钮。它可以很好地撤消形状,但不能很好地撤消单击和拖动线。

我的职能:

def undo ():
    if la[len(la)-1] =='s' : 
        turtle.undo()
        del(la[len(la)-1])
        while(turtle.isdown()==True) :
            turtle.undo()
        turtle.undo()
        turtle.undo()
    if la[len(la)-1]=='d' :
        turtle.undo()
        del(la[len(la)-1])
        while turtle.xcor()!=xp[len(xp)-1] and turtle.ycor()!=yp[len(yp)-1] :
            turtle.undo()
        del(xp[len(xp)-1])
        del(yp[len(yp)-1])

la 是一个数组,用于记住最后一个操作是画线还是形状。

如果它是一个形状('s'),则在笔放下时会撤消(因为形状是使用海龟动作制作的,所以笔不会在这些动作之间抬起)。

如果是一条线('d'),则应撤消直到海龟的坐标与线开头的坐标相同(存储在 xp 和 yp 中)。

有时候它会撤销比应有的更多的操作,有时它根本不会撤销。问题是大多数时候它工作得很好,所以我不知道是什么原因导致了问题。最常见的是,当线之前有一个形状时,它会出现问题,它也会撤消部分形状。当然,如果你多次越过这条线的拐点,它就会停止撤销,但可以通过计算你越过它的次数来解决这个问题。

编辑:

最小工作程序:

from tkinter import *
from functools import partial
from turtle import TurtleScreen, RawTurtle, Shape


menu = Tk()

frame=Frame(menu, bd=1, bg='#d1c7c7')
frame.grid(row=1, column=6, rowspan=26 )
canvas=Canvas(frame,width=1000, height=700)
canvas.grid(column=6,row=1, rowspan=26)

size=5

la=['n']
xp=[]
yp=[]

# turtle actions
def draw(x, y):
    turtle.ondrag(None)
    turtle.down()
    turtle.goto(x, y)
    turtle.up()
    screen.update()
    turtle.ondrag(draw)
def move(x, y):
    global xp
    global yp
    global la
    xp.append(turtle.xcor())
    yp.append(turtle.ycor())
    la.append('d') 
    screen.onscreenclick(None)
    turtle.goto(x, y)
    screen.onclick(move)
    screen.update()
def main():
    turtle.shape("circle")
    polygon = turtle.get_shapepoly()
    fixed_color_turtle = Shape("compound")
    fixed_color_turtle.addcomponent(polygon, "", "")
    screen.register_shape('fixed', fixed_color_turtle)
    turtle.shape("fixed")
    turtle.penup()
    turtle.pensize(5)
    turtle.turtlesize(2000,2000)
    turtle.ondrag(draw)
    screen.onscreenclick(move)
    screen.update()

def setcolor (color) :
    turtle.pencolor(color)
    turtle.fillcolor(color)




bblack = Button(
    menu,
    bg='black',
    width=10,
    command=partial(setcolor,'black')
).grid(column=1, row=2)
bred = Button(
    menu,
    bg='red',
    width=10,
    command=partial(setcolor,'red')
).grid(column=1, row=3)

bdraw = Button(
    menu,
    text='pen',
    width=10,
    command=main
).grid(column=1, row=4)

def square(x, y):
    global la
    la.append('s')
    turtle.turtlesize(1,1)
    screen.onclick(None)
    turtle.ondrag(None)
    turtle.goto(x-size*8.3, y-size*8.3)
    turtle.pendown()
    turtle.begin_fill()
    for i in range(4):
        turtle.forward(size*18)
        turtle.left(360 / 4)
    turtle.end_fill()
    turtle.penup()
    possqr()
def possqr():
    screen.onclick(square)
bsquare = Button(
    menu,
    text='square',
    width=10,
    command=possqr
).grid(column=1, row=5)
def triangle(x, y):
    global la
    la.append('s')
    turtle.turtlesize(1,1)
    screen.onclick(None)
    turtle.ondrag(None)
    turtle.goto(x-size*8.5, y-size*6)
    turtle.pendown()
    turtle.begin_fill()
    for i in range(3):
        turtle.forward(size*18)
        turtle.left(360 / 3)
    turtle.end_fill()
    turtle.penup()
    postriangle()
def postriangle():
    screen.onclick(triangle)
btriangle = Button(
    menu,
    text='triangle',
    width=10,
    command=postriangle
).grid(column=1, row=6)

Label(menu, text='COLORS').grid(column=1, row=1)



def undo ():
    if la[len(la)-1] =='s' : 
        turtle.undo()
        del(la[len(la)-1])
        while(turtle.isdown()==True) :
            turtle.undo()
        turtle.undo()
        turtle.undo()
    if la[len(la)-1]=='d' :
        turtle.undo()
        del(la[len(la)-1])
        while turtle.xcor()!=xp[len(xp)-1] and turtle.ycor()!=yp[len(yp)-1] :
            turtle.undo()
        del(xp[len(xp)-1])
        del(yp[len(yp)-1])
bundo = Button(
    menu,
    text='undo',
    width=10,
    command=undo
).grid(column=2, row=1)

screen = TurtleScreen(canvas)
screen.tracer(False)

pen_color = 'black'

turtle = RawTurtle(screen)
main()
mainloop()
python tkinter tkinter-canvas python-turtle
1个回答
0
投票

您可以修复代码中的一个问题,以解决

undo()
函数逻辑中的缺陷:

    elif la[len(la)-1]=='d' : ### <<< ###

使用单个

if
,您可能会面临两个
if
块都在一个
undo()
操作上执行的风险。

要改进一点行为,您可以添加:

    screen.update()
    screen.getcanvas().update_idletasks()

update()
函数的末尾。

需要提到的是,

turtle
模块的设计是为了简单起见,因此在
undo()
操作之后更新图形的可靠性可能在某些场景中,例如在您的应用程序中,它是
tkinter
turtle的组合
导致屏幕无法正确更新。

如果您在使用

turtle
模块时想要可靠的行为,则需要重写代码并将所有绘图操作存储在数组中,并在撤消时重置整个海龟窗口并从头开始重新绘制,尽管依赖于
 undo()

© www.soinside.com 2019 - 2024. All rights reserved.