代码之家  ›  专栏  ›  技术社区  ›  William

海龟鼠标事件仅在超时后响应,而不是在您单击时响应

  •  0
  • William  · 技术社区  · 6 年前

    在随机方块中单击时,它会显示“您单击了!”仅当它绘制下一个正方形时,而不是最初单击时。

    import turtle
    import random
    import time
    t1 = turtle.Turtle()
    t2 = turtle.Turtle()
    s = turtle.Screen()
    
    def turtle_set_up():
        t1.hideturtle()
        t2.hideturtle()
        t2.penup()
        s.tracer(1, 0)
    
    def draw():
        for i in range(2):
            t1.fd(400)
            t1.lt(90)
            t1.fd(400)
            t1.lt(90)
    
    def drawbox():
        t2.pendown()
        for i in range(2):
            t2.fd(50)
            t2.lt(90)
            t2.fd(50)
            t2.lt(90)
        t2.penup()
    
    def box1():
        X = random.randint(0, 350)
        Y = random.randint(0, 350)
        Xleft = X
        Xright = X + 50
        Ytop = Y + 50
        Ybottom = Y
        t2.goto(X, Y)
        drawbox()
    

    这里检查鼠标单击是否在绘制的框内。如果是,它会擦除旧框,以便每3秒绘制一个新框。

    我不明白为什么它会等着说“你点击了!”直到循环的3秒钟结束,而不是在最初单击时说出来。

    我无法在打印“You clicked!”的print语句后放置break命令因为它在循环之外。

    在此之间:

        t_end = time.time() + 60 * 0.05
        while time.time() < t_end:
            def get_mouse_click_coor(x, y):
                X_click = x
                Y_click = y
                if Xright > X_click > Xleft and Ytop > Y_click > Ybottom:
                    print('You clicked!')
            s.onclick(get_mouse_click_coor)
        t2.clear()
    

    这里:

    def starter():
        turtle_set_up()
        draw()
        while 1:
            box1()
    starter()
    
    3 回复  |  直到 6 年前
        1
  •  1
  •   sciroccorics    6 年前

    具有交互式GUI(图形用户界面)的应用程序是基于事件的,这意味着它们在某些事件发生时执行其操作。对于此类应用程序,如果在给定的时间内创建一个等待循环(就像代码一样),整个应用程序将在这段时间内被阻止。这就是为什么 print 仅在3s延迟后执行。

    所有GUI库都包含一个激活一些计时器事件的方案。对于turtle API,有一个 on_timer(func, delay) 调用函数的方法 func 在一些之后 delay (以毫秒为单位)。我们的想法是反复给你的 drawbox 每3000ms运行一次。因此,您的代码将基于两个主要回调函数: get_mouse_click 单击事件时调用,以及 抽屉 在计时器事件上调用。以下是修改后的代码,我建议:

    import turtle
    import random
    
    t1 = turtle.Turtle()
    t2 = turtle.Turtle()
    s = turtle.Screen()
    
    def turtle_set_up():
        t1.hideturtle()
        t2.hideturtle()
        s.tracer(1, 0)
        s.onclick(get_mouse_click)   # define the 'click' event callback
    
    def draw():
        for i in range(2):
            t1.fd(400)
            t1.lt(90)
            t1.fd(400)
            t1.lt(90)
    
    def drawbox():
        global box                   # store box coordinates as global variable
        X = random.randint(0, 350)   # so that they are available for testing
        Y = random.randint(0, 350)   # in the mouse click callback
        box = (X, Y, X+50, Y+50)
        t2.clear()                   # clear previous box before drawing new one
        t2.penup()
        t2.goto(X, Y)
        t2.pendown()
        for i in range(2):
            t2.fd(50)
            t2.lt(90)
            t2.fd(50)
            t2.lt(90)
        s.ontimer(drawbox, 3000)     # define timer event callback
    
    def get_mouse_click(x, y):
        if box[0] <= x <= box[2] and box[1] <= y <= box[3]:
            print('You clicked!')
    
    def starter():
        turtle_set_up()
        draw()
        drawbox()
    
    starter()
    
        2
  •  1
  •   Oscar    6 年前

    计算机必须按顺序运行,以便一次只能处理一行,因此,除非我弄错了,否则您的程序会被计时器“捕获”,然后运行整个程序并返回到开始。 如果海龟有datetime,您可以使用嵌套的if语句开发while循环,该语句从设备获取datetime

        3
  •  1
  •   cdlane    6 年前

    我相信你可以简化这个问题。主要是做海龟 内部盒子,而不是 绘画 内盒。这简化了绘图、擦除和事件处理。避免调用 tracer() 方法,直到您有了一个工作程序,因为它只会使调试复杂化。我们也可以 邮票 而不是 边界。

    如果我们只想单击内部框并将其随机移动到新位置:

    from turtle import Turtle, Screen
    from random import randint
    
    BORDER_SIZE = 400
    BOX_SIZE = 50
    CURSOR_SIZE = 20
    
    def move_box():
        x = randint(BOX_SIZE/2 - BORDER_SIZE/2, BORDER_SIZE/2 - BOX_SIZE/2)
        y = randint(BOX_SIZE/2 - BORDER_SIZE/2, BORDER_SIZE/2 - BOX_SIZE/2)
    
        turtle.goto(x, y)
    
    def on_mouse_click(x, y):
        print("You clicked!")
        move_box()
    
    screen = Screen()
    
    turtle = Turtle('square', visible=False)
    turtle.shapesize(BORDER_SIZE / CURSOR_SIZE)
    turtle.color('black', 'white')
    turtle.stamp()
    
    turtle.shapesize(BOX_SIZE / CURSOR_SIZE)
    turtle.onclick(on_mouse_click)
    turtle.penup()
    turtle.showturtle()
    
    move_box()
    
    screen.mainloop()
    

    如果我们想让程序更像游戏,并要求用户在每次移动后的3秒钟内单击内框,否则会输掉游戏,那么我们可以引入 ontimer() 正如@sciroccorics建议的事件:

    from turtle import Turtle, Screen
    from random import randint
    
    BORDER_SIZE = 400
    BOX_SIZE = 50
    CURSOR_SIZE = 20
    CLICK_TIMEOUT = 3000  # milliseconds
    
    def move_box():
        x = randint(BOX_SIZE/2 - BORDER_SIZE/2, BORDER_SIZE/2 - BOX_SIZE/2)
        y = randint(BOX_SIZE/2 - BORDER_SIZE/2, BORDER_SIZE/2 - BOX_SIZE/2)
    
        turtle.goto(x, y)
    
        screen.ontimer(non_mouse_click, CLICK_TIMEOUT)
    
    def on_mouse_click(x, y):
        global semaphore
    
        print("You clicked!")
        semaphore += 1
        move_box()
    
    def non_mouse_click():
        global semaphore
    
        semaphore -= 1
    
        if semaphore < 1:
            turtle.onclick(None)
            turtle.color('black')
            print("Game Over!")
    
    screen = Screen()
    
    semaphore = 1
    
    turtle = Turtle('square', visible=False)
    turtle.shapesize(BORDER_SIZE / CURSOR_SIZE)
    turtle.color('black', 'white')
    turtle.stamp()
    
    turtle.shapesize(BOX_SIZE / CURSOR_SIZE)
    turtle.onclick(on_mouse_click)
    turtle.penup()
    turtle.showturtle()
    
    move_box()
    
    screen.mainloop()