我正在用Python制作一个绘画应用程序.它具有使用点击和拖动制作形状和绘制的功能.

我一直在try 在我的应用程序中实现一个撤销按钮.撤销形状效果良好,但撤销点击和拖动线效果不佳.

我的功能:

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 '),它会在笔向下时撤销(由于形状是使用 turtle 动作制成的,因此笔不会在这些动作之间抬起).

如果是一条线(' d '),则应该撤销,直到 turtle 的坐标与线开头的坐标相同(记住在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()

推荐答案

您可以修复代码中的一个问题来解决undo()函数逻辑中的缺陷:

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

对于单个if,您可能会在一个undo()操作上执行这两个if个块,从而导致意外行为.

要改善未正确更新图形的行为,您可以添加:

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

undo()功能结束时.

也就是说,需要提到的是,turtle模块的设计是为了简单而设计的,因此undo()操作后更新图形的可靠性在一些复杂的场景下可能会导致屏幕更新不正确.

请注意,徒手绘制或添加大量正方形和三角形时撤销操作的默认限制可能会导致无法删除屏幕上看到的所有内容.

对于RawTurtle,如果您想要比默认撤销级别更高的撤销级别数量(在此类绘制场景中很容易耗尽),则需要将"私有"变量设置为更高的值,例如:

turtle._undobuffersize=1_000_000

您还可以try 用基于turtle的按钮替换tkinter部分,单击用作按钮的 turtle .这样可以降低屏幕更新的复杂性,这可能会在撤销操作后对整个图形进行更可靠的更新.

Python相关问答推荐

Pandas基于另一列的价值的新列

已安装' owiener ' Python模块,但在导入过程中始终没有名为owiener的模块

想要使用Polars groupby_Dynamic来缩减时间序列收件箱(包括空垃圾箱)

我可以使用极点优化这个面向cpu的pandas代码吗?

如何在Python中按组应用简单的线性回归?

Chatgpt API不断返回错误:404未能从API获取响应

Python 3.12中的通用[T]类方法隐式类型检索

如何在箱形图中添加绘制线的传奇?

对整个 pyramid 进行分组与对 pyramid 列子集进行分组

图像 pyramid .难以创建所需的合成图像

使用@ guardlasses. guardlass和注释的Python继承

两个pandas的平均值按元素的结果串接元素.为什么?

删除字符串中第一次出现单词后的所有内容

如何获取numpy数组的特定索引值?

从一个系列创建一个Dataframe,特别是如何重命名其中的列(例如:使用NAs/NaN)

为什么np. exp(1000)给出溢出警告,而np. exp(—100000)没有给出下溢警告?

如何在BeautifulSoup/CSS Select 器中处理regex?

Python—转换日期:价目表到新行

重置PD帧中的值

使用Openpyxl从Excel中的折线图更改图表样式