I have some code below that draws lines on a circle but the lines aren't deleted during each iteration. Does anyone know how to delete object from the window?
I tried win.delete(l) but it didn't work. Thanks.
import graphics
import math
win.setBackground("yellow")
x=0
y=0
x1=0
y1=0
P=graphics.Point(x,y)
r=150
win.setCoords(-250, -250, 250, 250)
for theta in range (360):
angle=math.radians(theta)
x1=r*math.cos(angle)
y1=r*math.sin(angle)
Q=graphics.Point(x1,y1)
l=graphics.Line(P,Q)
l.draw(win)
As far as I know, normally we draw things to some buffer memory, then draw the stuff in this buffer to the screen, what you said, to me, sounds like you draw the buffer to the screen, then delete the object from the buffer, I think this won't affect your screen.
I think you may need to redraw the part of the 'previous' line with background color, or just redraw the whole screen with what you really want.
I haven't used the graphics module, but hope my idea helpful to you.
Yeah I was in the same position, I found a good solution:
l.undraw()
You can check for more information here:
http://mcsp.wartburg.edu/zelle/python/graphics/graphics.pdf
Your code doesn't run as posted so let's rework it into a complete solution incorporating #oglox's undraw() suggestion:
import math
import graphics
win = graphics.GraphWin(width=500, height=500)
win.setCoords(-250, -250, 250, 250)
win.setBackground("yellow")
CENTER = graphics.Point(0, 0)
RADIUS = 150
line = None
for theta in range(360):
angle = math.radians(theta)
x = RADIUS * math.cos(angle)
y = RADIUS * math.sin(angle)
point = graphics.Point(x, y)
if line: # None is False in a boolean context
line.undraw()
line = graphics.Line(CENTER, point)
line.draw(win)
win.close()
This presents a somewhat wispy, flickering line. We can do slightly better by drawing and undrawing in the reverse order:
old_line = None
for theta in range(360):
angle = math.radians(theta)
x = RADIUS * math.cos(angle)
y = RADIUS * math.sin(angle)
point = graphics.Point(x, y)
new_line = graphics.Line(CENTER, point)
new_line.draw(win)
if old_line: # None is False in a boolean context
old_line.undraw()
old_line = new_line
This gives a thicker looking line and slightly less flicker.
Related
This question already has answers here:
Drawing line with infinity length in the direction of cursor in Pygame
(2 answers)
Closed 1 year ago.
I want to draw a line using pygame.draw.line(), and make that line go from any coordinates, through the mouse position, and onward. I know how to make a line from any coordinates go to the mouses position and stop there, so that's not the problem.
mpos is the mouse position (mouse.pos) and x and y the start co-ords. width is the width of the surface. Switch it around to draw in other directions:
dx = abs(self.mpos[0] - x)
dy = abs(self.mpos[1] - y)
x_dist = width - self.mpos[0]
y_dist = height - self.mpos[1]
new_x = self.mpos[0]
new_y = self.mpos[0]
while x_dist < width:
new_x += dx
new_y += dy
x_dist += dx
pygame.draw.line(self, white, (x,y), (new_x, new_y), 2)
You already have two points on the line: your start point, and the mouse position. Derive the equation of that line.
Now, look at the two points, determining your direction. Let's work with horizontal: what is the x-coordinate of the screen edge in the direction you will draw this line? Call that x_limit. Plug that value into your linear equation (call it f) to get y_limit = f(x_limit).
Now you have a simple check: is the point (x_limit, y_limit) on the edge of the screen? If not, then your y value runs off the screen before the x value does. In that case, set y_limit to the edge in the y direction. Use this y_limit value to compute a new x_limit. This is guaranteed to give you a point on the edge -- your desired endpoint.
I have to make a change to this specific code, which produces a square grid of circles, I have to change the code to make a triangle grid of circles.
import turtle
window = turtle.Screen()
my_boi = turtle.Turtle()
my_boi.speed(0)
for y in range(-200,200,50):
for x in range(-200,200,50):
my_boi.penup()
my_boi.setposition(x,y)
my_boi.pendown()
my_boi.circle(20)
window.exitonclick()
I'm sure there is a smarter approach, but this is one way to do it:
import turtle
window = turtle.Screen()
my_boi = turtle.Turtle()
my_boi.speed(0)
for (i,y) in enumerate(range(-200,200,50)):
for x in range(-200+(25*i),200-(25*i),50):
my_boi.penup()
my_boi.setposition(x,y)
my_boi.pendown()
my_boi.circle(20)
window.exitonclick()
turtle.done()
In the second for-loop the range is iteratively decreased by 1/2 of the circle diameter in each side.
I'd simplify things somewhat:
from turtle import Screen, Turtle
window = Screen()
my_boi = Turtle()
my_boi.speed('fastest')
my_boi.penup()
for y in range(1, 9):
my_boi.setposition(-25 * y + 25, 50 * y - 250)
for x in range(y):
my_boi.pendown()
my_boi.circle(20)
my_boi.penup()
my_boi.forward(50)
my_boi.hideturtle()
window.exitonclick()
Only the starting position of each row has to be calculated and placed via setposition(). The column positions can be a simple forward() statement.
I know this is an old post, but I was looking for the answer and managed to figure it out, so to help everyone else out, All you need to do is change the stop range in the nested loop to be y. I switched the x and y variables because I wanted the triangle to be flat, but if you need it the other way that also works.
import turtle
window = turtle.Screen()
my_boi = turtle.Turtle()
my_boi.speed(0)
for x in range(-200,200,50):
for y in range(-200,x,50):
my_boi.penup()
my_boi.setposition(x,y)
my_boi.pendown()
my_boi.circle(20)
window.exitonclick()
I need help to design my graphics, without turtle nor tkinter, but with Zelle graphics.py. The problem is that I need to run 4 circles moving at the same time. Here's the code I have so far:
from graphics import *
import time #import time module
from random import randrange
def rand_color():#generates a random color and returns that color
return(color_rgb(randrange(256),randrange(256),randrange(256)))
def main():
win = GraphWin("My Circle",500,500)
c = Circle(Point(20,20),20)
c.setFill(rand_color())
c.draw(win)
for i in range(1,461):
c.move(1,1)
time.sleep(.005)
c = Circle(Point(20,20),20)
c.setFill(rand_color())
c.draw(win)
for i in range(1,461):
c.move(-1,1)
time.sleep(.005)
c = Circle(Point(20,20),20)
c.setFill(rand_color())
c.draw(win)
for i in range(1,461):
c.move(1,-1)
time.sleep(.005)
c = Circle(Point(20,20),20)
c.setFill(rand_color())
c.draw(win)
for i in range(1,461):
c.move(1,1)
time.sleep(.005)
main()
I don't know how to move multiple objects at once. How would one go about this?
Rather move each circle completely in turn, chop up the movements and alternate them so each circle moves a little at a time in round robin. I'm guessing this is close to what you're trying to do:
from random import randrange
from graphics import *
def rand_color():
""" Generate a random color and return it. """
return color_rgb(randrange(256), randrange(256), randrange(256))
win = GraphWin("My Circle", 500, 500)
circles = []
for x in [-1, 1]:
for y in [-1, 1]:
circle = Circle(Point(250, 250), 20)
circle.setFill(rand_color())
circle.draw(win)
circles.append((circle, (x, y)))
for _ in range(250):
for circle, (x, y) in circles:
circle.move(x, y)
win.getMouse() # Pause to view result
win.close() # Close window when done
I am new to Python. I need to write a program to move my ball or circle when I click the mouse. How do I achieve this? I have the below code that I got started with:
from graphics import *
import time
def MouseTracker():
win = GraphWin("MyWindow", 500, 500)
win.setBackground("blue")
cir = Circle(Point(250,250) ,20)
cir.setFill("red")
cir.draw(win)
while(win.getMouse() != None):
xincr = 0
yincr = 0
for i in range(7):
cir.move(xincr, yincr)
time.sleep(.2)
win.getMouse()
Assuming you are not bound to some specific tools or implementation, you may find matplotlib useful. You can plot a circle onto the drawing area using a circle patch (http://matplotlib.org/api/patches_api.html) and then move it around when there is mouse-click in the graph axes. You will need to connect to the event-click listener and define a callback function which handles the drawing update - see http://matplotlib.org/users/event_handling.html for examples of how to do this. You can get the coordinates of the mouse press using the xdata and ydata methods.
This worked for me in python 2.7:
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
fig = plt.figure()
ax = fig.add_subplot(111)
circ = Circle((0.5,0.5), 0.1)
ax.add_patch(circ)
def update_circle(event):
ax.cla()
circ = Circle((event.xdata, event.ydata), 0.1)
ax.add_patch(circ)
fig.canvas.draw()
fig.canvas.mpl_connect('button_press_event', update_circle)
plt.show()
Assuming you want to stick with the graphics package you started with, you can do it but you're missing code to save the mouse position and compare it to the circle's center position:
from graphics import *
WIDTH, HEIGHT = 500, 500
POSITION = Point(250, 250)
RADIUS = 20
STEPS = 7
def MouseTracker(window, shape):
while True:
position = window.getMouse()
if position != None: # in case we want to use checkMouse() later
center = shape.getCenter()
xincr = (position.getX() - center.getX()) / STEPS
yincr = (position.getY() - center.getY()) / STEPS
for _ in range(STEPS):
shape.move(xincr, yincr)
win = GraphWin("MyWindow", WIDTH, HEIGHT)
win.setBackground("blue")
cir = Circle(POSITION, RADIUS)
cir.setFill("red")
cir.draw(win)
MouseTracker(win, cir)
You will need to close the window to break out of the tracking loop -- in a real program you'd handle this as part of the design (i.e. some user action causes a break in the while True: loop.)
I am currently having trouble with an assignment, and I've been trying to pinpoint my error for hours.
I have a circle and a rectangle (both drawn by user clicks). As shown here:
i.stack.imgur (dot) com/4aXIw.png
Using the center point of the rectangle, I want to calculate a new center point (for the rectangle) that lies on the circle. I achieve this by calculating the angle (theta) and using trigonometry to get the new centerpoint.
i.stack.imgur (dot) com/NoCBS.png
However, when I run my program I am not getting the correct results. Shown here:
i.stack.imgur (dot) com/ZG9Ld.png
I've checked a hundred times, and I can't seem to pinpoint where I messed up. I've checked theta, and the resulting degrees is correct. Here is the relevant code, where I suspect I made an error:
theta = math.atan((initialrec_y-click1.y)/(initialrec_x-click1.x))
theta = int(math.degrees(theta))
rec_x = click1.x + radius*math.cos(theta)
rec_y = click1.y + radius*math.sin(theta)
Here is the full code if you would like to run it:
from graphics import *
import math
def main():
#setup window
win = GraphWin("Traveling Rectangle",600,450)
win.setCoords(0,0,600,450)
click1 = win.getMouse()
click2 = win.getMouse()
radius = click2.x - click1.x
circle = Circle(click1, radius)
circle.draw(win)
click3 = win.getMouse()
click4 = win.getMouse()
rect = Rectangle(click3, click4)
rect.draw(win)
rect.setFill("red")
rect.setOutline("red")
#the centerpoint of the initial rectangle
initialrec_x = (click3.x + click4.x) / 2
initialrec_y = (click3.y + click4.y) / 2
#the trig to calculate the point on the circle
theta = math.atan((initialrec_y-click1.y)/(initialrec_x-click1.x))
theta = int(math.degrees(theta))
#the new centerpoint values of x and y
rec_x = click1.x + radius*math.cos(theta)
rec_y = click1.y + radius*math.sin(theta)
main()
Help would be greatly appreciated!
I apologize, the site did not let me post images. The graphics library can be found here: mcsp.wartburg (dot) edu/zelle/python/graphics.py
I am using a different graphics package, but the following works for me:
...
initialrec_y = (click3.y + click4.y) / 2
theta = math.atan2(initialrec_y - click1.y, initialrec_x - click1.x)
rec_x = click1.x + radius * math.cos(theta)
rec_y = click1.y + radius * math.sin(theta)
This uses the atan2 function, which takes note of the signs on the y and x inputs to correctly calculate the quadrant the point is in and return an angle accordingly. Other than that, the only difference from your code is that there is no conversion from radians (which atan2 returns) to degrees. sin and cos want radians.