I simply want to use the turtle method onscreenclick to find the coordinates of a mouse click. Currently, I have a grid on which I am playing Othello. I already have the algorithm to convert the raw coordinates to specific grid coordinates that can be interpreted by the game. I cannot seem to get the onscreenclick method working. On the docs, it says to use a 'fun' function with two arguments. I believe I have this, but it is not working. I am a beginner with python and turtle so any help would be appreciated :)
import turtle
xclick = 0
yclick = 0
def getcoordinates():
turtle.onscreenclick(modifyglobalvariables())
def modifyglobalvariables(rawx,rawy):
global xclick
global yclick
xclick = int(rawx//1)
yclick = int(rawy//1)
print(xclick)
print(yclick)
getcoordinates()
You got so close!
import turtle
xclick = 0
yclick = 0
def getcoordinates():
turtle.onscreenclick(modifyglobalvariables) # Here's the change!
def modifyglobalvariables(rawx,rawy):
global xclick
global yclick
xclick = int(rawx//1)
yclick = int(rawy//1)
print(xclick)
print(yclick)
getcoordinates()
Catch the change? Syntactically, remove the parentheses after modfiyglobalvariables. What you want is to pass the function, what you are doing is passing the output of the function.
If you ran the code, you would get an exception (TypeError) saying you haven't passed the correct arguments; that's because it's trying to actually call modifyglobalvariables. Reduced, what you wanted was
bind_to_mouseclick( my_function )
In which case, at each mouse click, my_function will be called. At that point, it may or may not have the correct arguments supplied. Instead you said
bind_to_mouseclick( my_function() )
Python evaluates my_function and binds the result of the call to the mouse click. If my_function happens to return a function, that's great (maybe what we intended). If it returns an integer or a string, no good. The key is the exception, as noted above; if the function had required no arguments, this may have been subtler to detect
It's actually alot easier to detect where you clicked it. Here's the code:
from turtle import *
mouseclickx = 0
mouseclicky = 0
def findcoords(x,y):
print(x)
print(y)
mouseclickx = x
mouseclicky = y
onscreenclick(findcoords,1)
EDIT:
That doesn't work... well idk but it should be something like that :/ if you want a thing so it goes where you click, its one line;onscreenclick(goto,1)
from turtle import Turtle, Screen
screen = Screen()
def get_mouse_click(x, y):
print(x, Y)
screen.onscreenclick(get_mouse_click)
screen.mailoop()
Related
I'm editing a Turtle Pong template and realized that two paddles can't move at the same time, so I'm trying to fix that bug by having it so, when a key is pressed, a boolean is set to true, and that is referenced in an if statement to move up or down if True. However, whenever I try to create this system, the boolean will always stay as it is declared, so I start off declaring it as False and no matter how many times I set it to True using the key press, it gets set back to False. I am confused about this, because I tried placing a print below the declaration and that never ran at all, but this False declaration seems to keep running over and over again. I wonder if it's because of the window.listen function, but then the print would theoretically run too. I'm just confused so any assistance would be greatly appreciated, thank you! Here' the relevant code.
import turtle
wn = turtle.Screen()
wn.title('Pong')
wn.bgcolor('black')
WIDTH, HEIGHT = 800, 600
wn.setup(width=WIDTH, height=HEIGHT)
wn.tracer(0)
# Paddle A
paddle_a = turtle.Turtle()
paddle_a.speed(0)
paddle_a.shape('square')
paddle_a.color('white')
paddle_a.penup()
paddle_a.goto(-WIDTH/2, 0)
paddle_a.shapesize(5, 1)
#THIS here is the bit where I'm stuck
paddle_a_up = False
print(paddle_a_up)
def move_paddle_a_up():
paddle_a_up = True
print("I cant understand you")
print(paddle_a_up)
def move_paddle_a_down():
print(paddle_a_up)
wn.onkeypress(move_paddle_a_up, 'w')
wn.onkeypress(move_paddle_a_down, 's')
wn.listen()
if paddle_a_up == True:
y = paddle_a.ycor()
y += 20
paddle_a.sety(y)
while True:
wn.update()
The way to use a global variable in python is different than in other languages. To use the global variable inside a method, You must need to declare the variable as global inside the method otherwise python will consider it as a new local variable.
So, to use the global variable inside the method, you need to make these changes in your method move_paddle_a_up
def move_paddle_a_up():
global paddle_a_up
paddle_a_up = True
print("I can understand you now")
print(paddle_a_up)
I have a script for a simple turtle race and I want the race to start when the user clicks the left-mouse-button so i have this code
def tur_race():
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race())
turtle.mainloop()
Assume that I have all variables defined.
when I run this code the race starts automatically and doesn't wait for the click.
onscreenclick takes a function as its parameter. You shouldn't be calling tur_race, turtle will do that when there is a click, rather you should pass tur_race itself. This is called a callback, you provide a function or method to be called by some event listener(e.g. the mouse being clicked on the screen).
In addition to #nglazerdev excellent answer, this would be your code after you apply what he said.
from turtle import *
def tur_race():
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race)
turtle.mainloop()
You take out the () in the tur_race function. Otherwise, it will be called immediately.
Hope this helps!!
You need turtle.onscreenclick( tur_race ) without () after tur_race
Python can assign function's name (without () and arguments) to variable and use it later - like in example
show = print
show("Hello World")
It can also use function's name as parameter in other function and this function will use it later.
Offen (in different programming languages) this funcion's name is called "callback"
In turtle.onscreenclick( tur_race ) you send name to function onscreenclick and turtle will use this function later - when you click screen.
If you use () in turtle.onscreenclick( tur_race() ) then you have situation
result = tur_race()
turtle.onscreenclick( result )
which doesn't work in you code but can be useful in another situations.
In addition to everyone's answer, you need to add x and y parameters in the tur_race function. This is because turtle passes x and y parameters to the function, so your code would look like:
from turtle import *
def tur_race(x, y):
for step in range(0, 135):
tur1.forward(randint(1, 5))
tur2.forward(randint(1, 5))
turtle.pu()
turtle.goto(-250, -150)
turtle.write("click the mouse to start")
turtle.ht()
turtle.onscreenclick(tur_race)
turtle.mainloop()
In this code I can't see why it isn't printing a hexagon 24 times. I tell it to make a 6 sided shape with 60 degrees between lines ( a hexagon) and tell it do turn 15 degrees each time. This ends up being a even 24 for the picture I'm trying to draw.
import turtle
Hex_Count = 0
x = turtle.Turtle()
x.speed(.25)
def Hexagon():
for i in range(24):
for i in range(6):
x.forward(100)
x.left(60)
Hex_Count = Hex_Count + 1
x.left(15)
print(Hex_Count)
Hexagon
But, for some reason, when I run this code the turtle screen pops up for about a half second then closes. How do I get it to perform in the way I want it to?
You have several errors that I corrected for you; I added the explanation in the comments:
import turtle
hexagons_count = 0
my_turtle = turtle.Turtle() # x is not a good name for a Turtle object
# my_turtle.speed(.25) # see #cdlane comment reported in a note under.
def draw_hexagon(): # use explicit names respecting python conventions (no camel case)
global hexagons_count # need global to modify the variable in the function scope
for idx in range(24): # use different dummy variable names in your loops
for jdx in range(6): # use different dummy variable names in your loops
my_turtle.forward(100)
my_turtle.left(60)
hexagons_count += 1
my_turtle.left(15)
print(hexagons_count)
draw_hexagon() # need parenthesis to call the function
turtle.exitonclick() # this to exit cleanly
Note: I know you simply copied it from the OP but my_turtle.speed(.25)
doesn't make sense as the argument should be an int from 0 to 10 or a
string like 'slow', 'fastest', etc. I especially don't understand why
beginners with turtle code that isn't working call turtle.speed() at
all -- it seems to me a function to be tweaked after everything is
working. #cdlane
You have some reference issue, you just need to put the variable hex_count where it needs to be so you don't have error accessing it.
import turtle
x = turtle.Turtle()
x.speed(.25)
def Hexagon():
Hex_Count = 0
for i in range(24):
for i in range(6):
x.forward(100)
x.left(60)
Hex_Count += 1
x.left(15)
print(Hex_Count)
Hexagon()
prints 24
You have several problems with your program. One is that it will when after running through the program, closing the window it created. You can add turtle.exitonclick() to the end of your script which tells python to wait for a click in the graphics window, after which it will exit.
The second problem is that you don't call the Hexagon function because you're missing the parentheses. Even if a function takes no arguments, you still need to call it like:
Hexagon()
The final problem is that you need to define Hex_Count before you try to increment it. Hex_Count + 1 will thrown an error if Hex_Count wasn't already assigned to. You can fix this by putting
Hex_Count = 0
before your for loop in Hexagon.
An approach different in a lot of the details but primarily in its use of circle() to more rapidly draw the hexagons:
from turtle import Turtle, Screen # force object-oriented turtle
hex_count = 0 # global to count all hexagons drawn by all routines
def hexagons(turtle):
global hex_count # needed as this function *changes* hex_count
for _ in range(24): # don't need explicit iteration variable
turtle.circle(100, steps=6) # use circle() to draw hexagons
turtle.left(15) # 24 hexagons offset by 15 degrees = 360
hex_count += 1 # increment global hexagon count
print(hex_count)
screen = Screen()
yertle = Turtle(visible=False) # keep turtle out of the drawing
yertle.speed('fastest') # ask turtle to draw as fast as it can
hexagons(yertle)
screen.exitonclick() # allow dismiss of window by clicking on it
I have some code, and my goal is to make it so that when left button is clicked it will post text saying "Programming is fun!" and when it is pressed again, it will change that text to "It is fun to program", my idea was to make x = 0 if I wanted the first statement, and x = 1 if I wanted the second statement, but it keeps saying x is not defined, I've tried returning x but it simply won't... I've tried a variety of different methods but I can't figure it out. Thoughts? I'd like an alternative method to this, because I'm not sure that mine will work.
def text():
pf = Label(window2,text="Programming is fun")
pf.pack()
x = 0
def text2():
fp = Label(window2,text="It is fun to program")
fp.pack()
x = 1
def bt(event):
if x == 0:
text()
elif x == 1:
text2()
window2 = Tk()
window2.geometry("500x500")
The problem is that, in the scope of your functions, the variable x is indeed undefined.
An example:
height = 5
def some_function():
# code here can not access height just like that
When you want to access variables in functions, you generally have three options:
1) Put your code in a class instead. This requires some understanding of object oriented programming, and if you're a beginner this might not be the best choice for you
2) Pass the variable as an argument to the function and add it to the function's parameter list, for example like this:
def my_function(height):
# here height can be used
And when calling the function:
height_of_bob = 2
my_function(height_of_bob)
3) Use a global variable. This is usually not necessary, and is considered bad practice in general, but it will solve your problem just fine.
I found a way to do this below, the down low is that it's creating the text through that function, and then it's rebinding the key to do other function and then that function deletes previous text, creates the new text and then rebinds to the previous function, and the cycle continues. Here's the code.
def text(event):
global pf
fp.pack_forget()
pf = Label(window2,text="Programming is fun")
pf.pack()
window2.bind("<Button-1>", text2)
def text2(event):
global fp
pf.pack_forget()
fp = Label(window2,text="It is fun to program")
fp.pack()
window2.bind("<Button-1>", text)
window2 = Tk()
window2.geometry("500x500")
pf = Label(window2,text="Programming is fun")
fp = Label(window2,text="It is fun to program")
window2.bind("<Button-1>", text)
I'm trying to make Connect 4 in python, but I can't figure out how to get the coordinates of the screen click so I can use them. Right now, I want to draw the board, then have someone click, draw a dot, then go back to the top of the while loop, wipe the screen and try again. I've tried a couple different options but none have seemed to work for me.
def play_game():
"""
When this function runs, allows the user to play a game of Connect 4
against another person
"""
turn = 1
is_winner = False
while is_winner == False:
# Clears screen
clear()
# Draws empty board
centers = draw_board()
# Decides whose turn it is, change color appropriately
if turn % 2 == 0:
color = RED
else:
color = BLACK
# Gets coordinates of click
penup()
onscreenclick(goto)
dot(HOLE_SIZE, color)
turn += 1
As well intentioned as the other answers are, I don't believe either addresses the actual problem. You've locked out events by introducing an infinite loop in your code:
is_winner = False
while is_winner == False:
You can't do this with turtle graphics -- you set up the event handlers and initialization code but turn control over to the main loop event handler. My following rework show how you might do so:
import turtle
colors = ["red", "black"]
HOLE_SIZE = 2
turn = 0
is_winner = False
def draw_board():
pass
return (0, 0)
def dot(color):
turtle.color(color, color)
turtle.stamp()
def goto(x, y):
global turn, is_winner
# add code to determine if we have a winner
if not is_winner:
# Clears screen
turtle.clear()
turtle.penup()
# Draws empty board
centers = draw_board()
turtle.goto(x, y)
# Decides whose turn it is, change color appropriately
color = colors[turn % 2 == 0]
dot(color)
turn += 1
else:
pass
def start_game():
"""
When this function runs, sets up a new
game of Connect 4 against another person
"""
global turn, is_winner
turn = 1
is_winner = False
turtle.shape("circle")
turtle.shapesize(HOLE_SIZE)
# Gets coordinates of click
turtle.onscreenclick(goto)
start_game()
turtle.mainloop()
Run it and you'll see the desired behavior you described.
I'm assuming that your using Turtle in python(hence the name.)
If that's the case, Here's a link to a helpful post: Turtle in python- Trying to get the turtle to move to the mouse click position and print its coordinates
I know, i know. I hate just link answers as much as the next guy. But The post I gave a link to can probably do a much better job of answering your question than I can.
~Mr.Python
Assuming you're using turtle as mentioned in your title:
>>> import turtle
>>> help(turtle.onscreenclick)
Help on function onscreenclick in module turtle:
onscreenclick(fun, btn=1, add=None)
Bind fun to mouse-click event on canvas.
Arguments:
fun -- a function with two arguments, the coordinates of the
clicked point on the canvas.
num -- the number of the mouse-button, defaults to 1
Example (for a TurtleScreen instance named screen)
>>> onclick(goto)
>>> # Subsequently clicking into the TurtleScreen will
>>> # make the turtle move to the clicked point.
>>> onclick(None)
That means that your callback function, which you have apparently named goto, will take two parameters, an X and Y location.
import turtle
def goto(x, y):
print('Moving to {}, {}'.format(x,y))
turtle.goto(x, y)
turtle.onscreenclick(goto)
turtle.goto(0,0)
Each click that you make will move the turtle to a different position. Note that turtle already has an event loop - you don't need one of your own. Just respond to the clicks.
basically, you need to add an 'x' and 'y' parameter for the onclick and onscreenclick functions. You don't need to use them, they're just dummy params. After filling those out the clicks will work no problem:
window = turtle.Screen()
This function uses the x, y params because i'm saving the clicks in order to specify an area to fill with turtles
def on_left_click_save_coordinates(x, y):
global counter, Fill_COORS1, Fill_COORS2
counter += 1
print(x, y)
if counter == 1:
Fill_COORS1 = (x, y)
elif counter == 2:
Fill_COORS2 = (x, y)
counter = 0
This one doesn't use the x,y params because they are dummies, this one is used to allow multiple options, one of which exits, another tells the turtle to fill in the specified area saved in clicks above.
def on_right_click_open_options(x, y):
global going
last_color = options(window, filler, Fill_COORS1, Fill_COORS2, LAST_BLOCK_USED)
if type(Last_COLOR) == type(bool):
going = True
window.onscreenclick(on_click, btn=1)
window.onscreenclick(open_options, btn=3)
This is an example of a snippet of my code. hope this helps.
btn 3 refers to the right click
btn 1 is the default and isn't necessary to specify and refers to left click
btn 2 is the scroll wheel click, not scroll.
and sorry if this isn't formatted the best, it's my first time posting to stackoverflow. Hope it helps nonetheless