如何在 Python 中进行游标锁定?
How can I make a cursor lock in Python?
我正在 Python 中使用 Turtle 制作“3D”立方体。我正在尝试找到一种方法,以便我可以锁定光标,或者当您按住右键单击时,您可以从不同角度查看立方体。由于我不会这样做,所以我有一个旋转功能。
我当前的代码:
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
首先,我只想说 Turtle 对鼠标事件和其他框架所具有的其他有趣功能的支持不多。
由于海龟在通过屏幕事件触发时不支持鼠标弹起事件,这将允许您右键单击而不是按住它,并且它将在设置鼠标之前继续获取鼠标移动的增量回到原来的位置。完成拖动鼠标后,再次单击鼠标右键即可松开鼠标。
增量会很低,通常在 1-3 之间。如果这太低,则添加 time.sleep(1/60)
。这会将 fps 锁定为 60 帧,并允许鼠标在锁定回其原始位置之前移动更多。
我也想炫耀这个问题,因为它似乎有一种方法可以添加鼠标弹起并将事件移动到乌龟,但我会让你看看它来决定你是否想走那条路。
祝你好运。
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()
您应该可以使用 ondrag()
事件处理程序来执行此操作。下面是对代码的修改,以删除自动移动并通过单击红色角并在继续按住按钮(拖动)的同时移动鼠标来替代手动移动立方体的能力:
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()
鼠标位置到立方体位置的映射显然不是最优的,但应该足以让您相信这是可能的并提供一个起点。
我正在 Python 中使用 Turtle 制作“3D”立方体。我正在尝试找到一种方法,以便我可以锁定光标,或者当您按住右键单击时,您可以从不同角度查看立方体。由于我不会这样做,所以我有一个旋转功能。
我当前的代码:
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
首先,我只想说 Turtle 对鼠标事件和其他框架所具有的其他有趣功能的支持不多。
由于海龟在通过屏幕事件触发时不支持鼠标弹起事件,这将允许您右键单击而不是按住它,并且它将在设置鼠标之前继续获取鼠标移动的增量回到原来的位置。完成拖动鼠标后,再次单击鼠标右键即可松开鼠标。
增量会很低,通常在 1-3 之间。如果这太低,则添加 time.sleep(1/60)
。这会将 fps 锁定为 60 帧,并允许鼠标在锁定回其原始位置之前移动更多。
我也想炫耀这个问题,因为它似乎有一种方法可以添加鼠标弹起并将事件移动到乌龟,但我会让你看看它来决定你是否想走那条路。
祝你好运。
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()
您应该可以使用 ondrag()
事件处理程序来执行此操作。下面是对代码的修改,以删除自动移动并通过单击红色角并在继续按住按钮(拖动)的同时移动鼠标来替代手动移动立方体的能力:
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()
鼠标位置到立方体位置的映射显然不是最优的,但应该足以让您相信这是可能的并提供一个起点。