I was writing code for a CodeGolf.SE contest and I came onto something I didn't understand. The code is not the best (e.g. I wouldn't normally use while 1) but the issue is still the same:
import time
from turtle import *
ht()
tracer(3)
while 1:
clear() #1
color("snow") #
a=time.strftime("#%H%M%S") #
bgcolor(a) #2
write(a,0,"center") #3
From the documentation it seems that tracer(3) means that each third screen update is drawn. I think this doesn't work, because when I run this I don't get clear text (it seems like it switches very fast between visible/invisible).
I tried with different arguments for tracer without success. I know a solution is to call tracer(0) instead and update() when needed, but I'd like it to work without update().
the following does solve it, just to show what I mean. As I have understood tracer(n) should propagate the changes each n-th step, and it does not seem to do that:
import time
from turtle import*
tracer(0) #turn of auto-update
while 1:
reset()
ht()
color("snow")
a=time.strftime("#%H%M%S")
write(a,0,"center")
bgcolor(a)
update() #8 propagate changes
The way I would approach this with the current Python3 turtle is avoid tracer() and take advantage of undo() instead:
from turtle import*
import time
ht()
color("snow")
write("")
while 1:
undo()
a=time.strftime("#%H%M%S")
bgcolor(a)
write(a,0,"center")
It does what you want and is fewer strokes golf-wise.
Related
I wanted to make a blinking "Press SPACE to start!" screen and if SPACE was pressed, the program should shut down but I always get the turtle.terminator error. Can someone help me please?
from turtle import *
import pygame
while True:
x = 0
penup()
tracer(0)
if x == 0:
color("black")
goto(-80,-170)
write("Press SPACE to start!",font=50)
update()
pygame.time.delay(1*800)
x = 1
if x == 1:
color("white")
goto(-90,-180)
begin_fill()
goto(90,-180)
goto(90,-140)
goto(-90,-140)
goto(-90,-180)
end_fill()
update()
x = 0
pygame.time.delay(1*800)
def close():
bye()
onkey(close(),"Space")
done()
After integrating advice from the comments, it still raises an error when I use onkey(close,...) instead of onkey(close(),..).
It is "space", not "Space". Also, it is still correct to use onkey(close, ...).
The complete function would be onkey(close, "space")
There are a few issues here. A word of advice: work in small bursts and run your code often to validate all of your assumptions at each step of the way. This code looks as if it was all written in one fell swoop, and once it didn't work, there was too much complexity to isolate the bugs. Had you run the code to test it often as you went along, you'd see those errors immediately and the solutions would be more obvious.
Try to minimize the problem space by breaking your functionality into small pieces and validating each one.
First, let me provide my solution:
import turtle
def render_white_screen():
win.ontimer(render_press_space, delay_ms)
t.clear()
turtle.update()
def render_press_space():
win.ontimer(render_white_screen, delay_ms)
t.write(
"Press SPACE to start!",
move=False,
align="center",
font=("Arial", 20, "normal"),
)
turtle.update()
delay_ms = 800
turtle.tracer(0)
win = turtle.Screen()
win.onkey(turtle.bye, "space")
win.listen()
t = turtle.Turtle()
t.hideturtle()
t.color("black")
render_press_space()
turtle.mainloop()
Turtle is surprisingly not especially beginner-friendly and has a huge list of gotchas, so it's important to check the docs and do research on Stack Overflow as soon as you encounter an error.
Errors:
turtle.onkey(some_func(), "some key") is incorrect (assuming some_func isn't a higher-order function) because you're calling some_func rather than passing it as the handler. This should be turtle.onkey(some_func, "some key"). This happens to trigger the terminator error because terminator occurs when you run turtle code after exiting, which is what your handler does. See Python Turtle.Terminator even after using exitonclick() and onkeypress( ) function in turtle module problem.
turtle.onkey(space_handler, "Space") should be turtle.onkey(space_handler, "space") (lowercase). See Couldn't get rid of (_tkinter.TclError: bad event type or keysym "UP") problem.
You must call turtle.listen() to activate key handlers that you've registered. See Turtle.onkeypress not working (Python).
Suggestions/better practices:
Always use import turtle, never from turtle import *. The reason is that from turtle import * dumps 160+ functions into the global namespace, causing potential clashes with your own functions. Many of these functions have common names like update and reset that can easily cause confusion and bugs. Turtle has a module-level instance ostensibly to avoid confusion for beginners, but it only winds up introducing more problems in the long run than simply creating a turtle instance.
Don't import pygame just to sleep. Python has a native function sleep available in the time module. But even better is to use turtle's ontimer callback as shown above.
You can clear the screen with t.clear().
This is the programme I wrote but I'm not sure what's wrong:-
import turtle
import random
bob = turtle.Turtle()
screen = turtle.Screen()
def coord(x,y):
print(x,y)
turtle.onscreenclick(None)
turtle.onscreenclick(coord)
turtle.listen()
print('hello')
turtle.done()
The programme works fine except that the print('hello') part happens first, followed by the on screen event. How do I make the onscreen event occur first before the rest of my programme?
You can simply make the rest of your code part of the coord function:
def coord():
print(x,y)
turtle.onscreenclick(None)
print("Hello")
# The rest of your program goes here.
However, a few things to note:
This isn't an amazing elegant solution, especially if you intend to set up other events further into your code. It can become quite hard to keep track of.
It's imperative that you remove the event binding (in this case the binding of coord to onscreenclick) as soon as it's been used, otherwise you could end up with multiple instances of the same code running at once if someone double-clicked the screen, for example. In your case you've already done this (with turtle.onscreenclick(None)), but it is something to keep in mind.
If you choose to go this route, don't forget to rename the coord function something more representative of what that section of your code will do.
Code doesn't work like it should. It is just a small thing i would like to learn as a new coder:
import turtle
import random
me=turtle.Turtle()
def up_right():
me.right(90)
me.forward(100)
def down_right():
me.right(90)
me.forward(100)
choose = (up_right(), down_right)
random.choice(chose)
It should pick one and do it but it picks them both.
I've tried random.sample and random.choice but cant get them to work.
Besides the typo of choose... My suggestion is that after you create a tuple of functions and choose the function using random.choice(), you should make a call to the function chosen by the random.choice().
# Notice I removed the () after up_right so it doesn't make the function call on this line
choose = (up_right, down_right)
# random.choice will return one of the two, and then the () will call whatever function was chosen
random.choice(choose)()
I see three issues with your code. The first two folks have pointed out already, the choose vs chose typo and leaving the parens () on upright when refering to it as a function (up_right(), down_right).
The third is that up_right and down_right both implement the same motion, so even if the rest of your code worked, you wouldn't see any difference! Below's a rewrite that fixes this issue:
from turtle import Screen, Turtle
from random import choice
def up_right(turtle):
turtle.setheading(90)
turtle.forward(100)
def down_right(turtle):
turtle.setheading(270)
turtle.forward(100)
choices = [up_right, down_right]
screen = Screen()
me = Turtle('turtle')
choice(choices)(me)
screen.mainloop()
Run it several times and you'll see sometimes the turtle heads up the screen, sometimes it heads down.
I've searched for a simple animation code with Tkinter but I've found very different examples and I can't understand the correct way to write an animation.
Here my working code to display a simple moving circle:
import tkinter as tk
import time
root=tk.Tk()
canvas=tk.Canvas(root,width=400,height=400)
canvas.pack()
circle=canvas.create_oval(50,50,80,80,outline="white",fill="blue")
def redraw():
canvas.after(100,redraw)
canvas.move(circle,5,5)
canvas.update()
canvas.after(100,redraw)
root.mainloop()
In this code I can't correctly understand: how the after method works, where correctly put the update and the move method (before after method ?), is there another way to write an animation code? may you post me another example and comment the code please?
Thanks :)
Calling update
You should not call canvas.update(). As a general rule of thumb you should never call update. For a short essay on why, see this essay written by one of the original developers of the underlying tcl interpreter.
If you take out the call to canvas.update(), you have the proper way to do animation in a tkinter program.
Calling after to start the animation
You don't need to call after immediately before calling root.mainloop(). This works just as well:
...
redraw()
root.mainloop()
The choice to use or not use after in this specific case is dependent on if you want the animation to start immediately (possibly even before the widget is visible) or if you want it to happen after a short delay (possibly after the widget is made visible)
How after works
mainloop is nothing more than an infinite loop that checks the event queue for events. When it finds an event, it pops it off of the list and processes it. after is nothing more than making a request that says "in 100 ms, please add a new event to the queue". When the time limit expires, an event is added to the queue that says, in effect, "run this command". The next time the loop checks for events, it sees this event, pulls it off of the queue, and runs the command.
When you call after from within a method that itself was called by after, you're saying in effect "wait 100ms and do it again", creating an infinite loop. If you put the call to after before moving the object, you're saying "every 100ms run this function". If you put it after you're saying "run this function 100 ms after the last time it was run". The difference is very subtle and usually not perceptible unless your function takes a long time to run.
my code is:
from tkinter import *
import time
tk = Tk()
płótno = Canvas(tk, width=500, height=500)
płótno.pack()
płótno.create_polygon(10,10,10,70,70,10,fill="blue",outline="black")
for x in range(0,51):
płótno.move(1,5,0)
płótno.update()
rest(0.05)
płótno means canvas
My program for creating a Mandelbrot set has a bug: whenever the pen changes colors, and every 42nd pixel after that, is lighter. This is, rather coincidentally, a mandelbug (yes, I just learned that term), as it is inconsistent for many pixels near an "edge" (it might actually be blurred between the color it's supposed to be and the color the last, or next, pixel is supposed to be), but it's always the 42nd pixel after that one until the next color change. I am using OSX 10.6.8, PYTHON 2.7. When I wrote this program at school, it worked perfectly (Windows), and then I sent it to myself, and worked on it a little more (mostly just making the sample size and therefore image larger), and ran it, I got this bug. EDIT: My bad, I forgot to mention that this only happens with my Mandelbrot program, the few other turtle programs I have at home are fine.
Parts of screenshots (so that you don't have to wait forever while the program runs to see what I'm talking about):
From my first version from home:
From the current version (sideways):
Heres the code:
import turtle
import math
turtle.speed(0)
def benoit(onelen):
turtle.left(90)
for x in range(-2*onelen, onelen):
turtle.up()
turtle.goto(x, int(-1.5*onelen)-1)
turtle.down()
for y in range(int(-1.5*onelen)-1, int(1.5*onelen)-1):
z = complex(0,0)
c = complex(x*1.0/onelen,y*1.0/onelen)
for k in range(20):
z = z*z+c
if abs(z) > 2:
g = .2 + .8*(20-k)/20
break
if k == 19:
g = 0
turtle.pencolor(0,g,0)
turtle.forward(1)
benoit(250)
x = raw_input("Press Enter to Exityadayadayada")
EDIT: A fix has been suggested by DSM, who likes this bug. However, I have no experience editing Python source code, and all the underscores are making me nervous. Can someone tell me specifically what to edit and/or how?
Wow. I think this is one of my favourite bugs ever, and believe it or not, the fact that the number happens to be 42 is actually relevant! Well, peripherally, anyhow..
In turtle.py:
def _goto(self, end):
"""Move the pen to the point end, thereby drawing a line
if pen is down. All other methodes for turtle movement depend
on this one.
[...]
###### vererbung!!!!!!!!!!!!!!!!!!!!!!
self._position = end
if self._creatingPoly:
self._poly.append(end)
if len(self.currentLine) > 42: # 42! answer to the ultimate question
# of life, the universe and everything
self._newLine()
self._update() #count=True)
So the problem comes about when it decides to break a line, apparently for performance reasons:
def _newLine(self, usePos=True):
"""Closes current line item and starts a new one.
Remark: if current line became too long, animation
performance (via _drawline) slowed down considerably.
"""
I was able to "fix" the bug by bumping up the linenumber limit and/or scattering self._pencolor references in places that didn't have any. But you're not crazy, anyway, and it's not really anything that you're doing. :-)
Can i offer a suggestion?
i tried your code and it was taking forever to run which you are aware of but what you may not be aware of is the tracer function... i simply put at the beginning of your code:
wn=turtle.Screen()
wn.tracer(10000)
that also eliminates the need for the speed(0) function :)
Try that and run it again, i did and it rendered the whole image in 62 seconds, i timed it by importing the time module by putting this code at the beginning:
import time
st=time.time()
and this code at the end:
print time.time()-st
Well done by the way, Ive just made my own thats a lot slower and lower quality then yours but was using an array of the square shape and stamping to each location i wanted in the array lol, but will be trying to improve it in the future as i only found out turtle existed less then a week ago.
One last thing, if you type:
from turtle import *
instead of "import turtle" you dont need to put turtle at the beginning of every function call :) same thing goes for every other module.
Ive included the pic of your fractal that took 62 seconds to render on my machine thats not even that powerfulYour code run on my weak machine.
I hope all this helps you greatly. also youll notice i dont have that light line problem, not sure if you fixed that issue in the original code up top?