简体   繁体   中英

How can I make a cursor lock in Python?

I am working on a "3D" cube in Python with Turtle. I am trying to find a way so I can make a cursor lock, or just so when you hold right click you can look at the cube from different angles. Since I do not know how to do this, I have a rotating function.

My current code:

import turtle

VERTEXES = [(-1, -1, -1), ( 1, -1, -1), ( 1,  1, -1), (-1,  1, -1),
            (-1, -1,  1), ( 1, -1,  1), ( 1,  1,  1), (-1,  1,  1)]

TRIANGLES = [
    (0, 1, 2), (2, 3, 0),
    (0, 4, 5), (5, 1, 0),
    (0, 4, 3), (4, 7, 3),
    (5, 4, 7), (7, 6, 5),
    (7, 6, 3), (6, 2, 3),
    (5, 1, 2), (2, 6, 5)
]

FOV = 400

# Create turtle,
pointer = turtle.Turtle()

# Turn off move time, makes drawing instant,
turtle.tracer(0, 0)
pointer.up()

def rotate(x, y, r):
  s, c = sin(r), cos(r)
  return x * c - y * s, x * s + y * c

counter = 0
while True:
    # Clear screen,
    pointer.clear()

    # Draw,
    for triangle in TRIANGLES:
        points = []
        for vertex in triangle:
            # Get the X, Y, Z coords out of the vertex iterator,
            x, y, z = VERTEXES[vertex]

            # Rotate,
            x, z = rotate(x, z, counter)
            y, z = rotate(y, z, counter)
            x, y = rotate(x, y, counter)

            # Perspective formula,
            z += 5
            f = FOV / z
            sx, sy = x * f, y * f

            # Add point,
            points.append((sx, sy))
        
        # Draw triangle,
        pointer.goto(points[0][0], points[0][1])
        pointer.down()

        pointer.goto(points[1][0], points[1][1])
        pointer.goto(points[2][0], points[2][1])
        pointer.goto(points[0][0], points[0][1])
        pointer.up()

    # Update,
    turtle.update()

    counter += 0.01

First off I just wanna say that Turtle does not have a lot of support for mouse events and other fun things that other frameworks have.

Because of turtles lack of support for mouse up events when it is triggered via screen events this will allow you to right click and not hold it down and it will continue to get the delta of your mouse movements before setting the mouse back to the original position. Once you done dragging the mouse just right click again and it will release the mouse.

The delta will be low, usually between 1-3. If this is to low then add in a time.sleep(1/60) . This will lock the fps to 60 frames and will allow the mouse to move more before being locked back to its original position.

I also want to show off this question cause it seems like it has a way of adding in on mouse up and move events to turtle but ill let you look at it to decide if you want to go that route.

Find the cursor's current position in Python turtle

Good luck.

from ctypes import windll, Structure, c_long, byref
from turtle import Turtle, Screen, update


is_dragging = False
start_mouse_pos = (0, 0)


class POINT(Structure):
    _fields_ = [("x", c_long), ("y", c_long)]
    x: int
    y: int


def getMousePosition():
    pt = POINT()
    windll.user32.GetCursorPos(byref(pt))
    return (pt.x, pt.y)


def setMousePosition(pos: tuple):
    windll.user32.SetCursorPos(int(pos[0]), int(pos[1]))


def onScreenClick(x, y):
    global is_dragging, start_mouse_pos
    is_dragging = not is_dragging
    start_mouse_pos = getMousePosition()


turtle = Turtle()
screen = Screen()
screen.onscreenclick(onScreenClick, 3)

while True:
    if is_dragging:
        pos = getMousePosition()
        delta_pos = (start_mouse_pos[0] - pos[0], start_mouse_pos[1] - pos[1])

        # Do something with how much the mouse has moved then set the mouse position back

        setMousePosition(start_mouse_pos)
    update()

You should be able to do this with an ondrag() event handler. Below is a rework of your code to remove the automatic movement and substitute the ability to manually move the cube by clicking on the the red corner and moving the mouse while continuing to hold the button down (dragging):

from math import sin, cos, atan2 as atan
from turtle import Screen, Turtle

VERTEXES = [
    (-1, -1, -1), (1, -1, -1), (1, 1, -1), (-1, 1, -1),
    (-1, -1, 1), (1, -1, 1), (1, 1, 1), (-1, 1, 1)
]

TRIANGLES = [
    (0, 1, 2),
    (2, 3, 0),
    (0, 4, 5),
    (5, 1, 0),
    (0, 4, 3),
    (4, 7, 3),
    (5, 4, 7),
    (7, 6, 5),
    (7, 6, 3),
    (6, 2, 3),
    (5, 1, 2),
    (2, 6, 5)
]

FOV = 400

def rotate(x, y, r):
    s, c = sin(r), cos(r)

    return x * c - y * s, x * s + y * c

orientation = 0  # radians

def draw():
    global orientation

    turtle.clear()

    for triangle in TRIANGLES:
        for flag, vertex in enumerate(triangle):
            # Get the X, Y, Z coords out of the vertex iterator
            x, y, z = VERTEXES[vertex]

            # Rotate
            x, z = rotate(x, z, orientation)
            y, z = rotate(y, z, orientation)
            x, y = rotate(x, y, orientation)

            # Perspective formula
            z += 5
            f = FOV / z
            s = x * f, y * f

            # Draw line
            turtle.setposition(s)
            turtle.pendown()

            if not flag:
                start = s

        turtle.setposition(start)
        turtle.penup()

    screen.update()

def orient(x, y):
    global orientation

    turtle.ondrag(None)  # disable handler inside handler

    orientation = atan(y, x)
    draw()

    turtle.ondrag(orient)  # reenable handler

# Turn off move time, makes drawing instant,
screen = Screen()
screen.tracer(False)

# Create turtle,
turtle = Turtle('circle')
turtle.fillcolor('red')
turtle.shapesize(0.5)
turtle.penup()

draw()

turtle.ondrag(orient)

screen.mainloop()

The mouse position to cube position mapping clearly isn't optimal, but should be enough to convince you it is possible and provide a starting point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM