For a current school project, I am making a simple animation and while trying to import threading I keep getting a not implemented error.
The animation is supposed to have two circles moving perpendicular to each other passing back and forth on the screen without colliding. I added threading, time, and simplgui to try to accomplish this but I only received the error message: "NotImplementedError: threading is not yet implemented in Skulpt".
At the very least I need to know what the error message means or an alternative way to accomplish this animation because every forum or coding site I have consulted has not given clear answers on what the issue is.
code:
import time
import threading
import simplegui
x1 = 50
y1 = 200
x2 = 200
y2 = 200
def draw_handler(canvas):
simo()
def horizontal(use2):
def reverse():
global x1
while (x1 > 50):
x1 = x1 - 5
if (x1 >= 50):
x1 = x1 - 5
canvas.draw_circle((x1, y1), 50, 1, "White", "White")
def forward():
global x1
x1 = x1 + 5
if (x1 >= 350):
reverse()
canvas.draw_circle((x1, y1), 50, 1, "White", "White")
forward()
#def verticle(use1):
def simo():
use1 = threading.thread(target=verticle)
use2 = threading.thread(target=horizontal)
frame = simplegui.create_frame('Testing', 400, 400)
frame.set_canvas_background("Black")
frame.set_draw_handler(draw_handler)
frame.start()
Related
I have this program in which I draw a rectangle on a canvas and when I press either the < arrow key or the > key the rectangle should get wider or narrower. But when I run this program and press either of those keys the python shell prints out AttributeError: 'Event' object has no attribute 'wider' (or 'narrower')... A. How can I fix this? and B. Why does it do that?
from tkinter import *
root = Tk()
canvas = Canvas(root, width=400, height=300, bg="#000000")
canvas.pack()
x1 = 150
y1 = 100
x2 = 250
y2 = 200
class ResizeRect:
def __init__(self, x1, y1, x2, y2):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.rect = canvas.create_rectangle(0,0,1,1)
def draw(self):
canvas.delete(self.rect)
self.rect = canvas.create_rectangle(x1, y1, x2, y2,outline="#00B000", width=2)
def narrower(self):
self.x1 = self.x1 + 5
self.x2 = self.x2 - 5
def wider(self):
self.x1 = self.x1 - 5
self.x2 = self.x2 + 5
r = ResizeRect(150, 100, 250, 200)
r.draw()
def left(r):
r.narrower()
def right(r):
r.wider()
canvas.bind_all('<KeyPress-Left>', left)
canvas.bind_all('<KeyPress-Right>', right)
I also don't know if/when I fix this, there will still be a ton of errors. So it would be great if you help me with the specific problem. But it would be even cooler if you could tell me if/how to fix the other errors that come after this one.
Thanks
You need to provide an argument for the event that tkinter sends when using bind:
def left(event):
r.narrower()
Those methods will also need to call canvas.coords; simply updating the numbers won't cause the display to change.
Your left() and right() routines are receiving an event, which you are not currently accepting. You can change your routines to be like this:
def left(e):
r.narrower()
def right(e):
r.wider()
This gets rid of your error messages. The routines for narrowing and widening will now be called, but they won't work. To resize the rectangle, you'll need to work with the coords() method. By changing the coordinates of the rectangle, you can effectively move or resize it.
current_coords = canvas.coords(rectangleTagId)
# update the coords to new_coords
canvas.coords(rectangleTagId, *new_coords)
I am creating a program in Python using Zelle graphics package. There is a moving circle that the user clicks on in order to make it return to the center of the screen. I cannot figure out how to identify when the user clicks inside of the circle. Here is the code I have written:
from graphics import *
from time import sleep
import random
Screen = GraphWin("BallFalling", 400 , 400);
Screen.setBackground('green')
ball = Circle(Point(200,200),25);
ball.draw(Screen);
ball.setFill('white')
ballRadius = ball.getRadius()
ballCenter = 0
directionX = (random.random()*40)-20;
directionY = (random.random()*40)-20;
clickx = Screen.getMouse().getX();
clicky = 0
while ball.getCenter().getX() + ball.getRadius() <= 400 and ball.getCenter().getY() + ball.getRadius() <= 400 and ball.getCenter().getX() >= 0 and ball.getCenter().getY() >= 0:
ball.move(ball.getRadius()//directionX,ball.getRadius()//directionY)
ballLocation = ball.getCenter().getX();
ballLocationy = ball.getCenter().getY();
sleep(1/15);
The main problem I am having is identifying the coordinates of the mouse click. I cannot find anything in the Zelle graphics package that says anything about this.
The major issues I see are: you are calling getMouse() before the loop when you should be calling checkMouse() inside the loop; you have no code to compare the distance of the click from the ball; you have no code to return the ball to the center of the screen.
Below is my complete rework of your code addressing the above issues:
from time import sleep
from random import randrange
from graphics import *
WIDTH, HEIGHT = 400, 400
RADIUS = 25
def distance(graphic, point):
x1, y1 = graphic.getCenter().getX(), graphic.getCenter().getY()
x2, y2 = point.getX(), point.getY()
return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
window = GraphWin("Ball Falling", WIDTH, HEIGHT)
window.setBackground('green')
ball = Circle(Point(WIDTH/2, HEIGHT/2), RADIUS)
ball.setFill('white')
ball.draw(window)
directionX = randrange(-4, 4)
directionY = randrange(-4, 4)
while True:
center = ball.getCenter()
x, y = center.getX(), center.getY()
if not (RADIUS < x < WIDTH - RADIUS and RADIUS < y < HEIGHT - RADIUS):
break
point = window.checkMouse()
if point and distance(ball, point) <= RADIUS:
ball.move(WIDTH/2 - x, HEIGHT/2 - y) # recenter
directionX = randrange(-4, 4)
directionY = randrange(-4, 4)
else:
ball.move(directionX, directionY)
sleep(1/30)
There may still be subtle bugs and contants tweaking for you to sort out.
My question is about displaying and updating text, in order to display the score on screen.
I would like to create a score like the real game that would appear on the screen. But after researching Google, I have not found anyone wishing to increase a score on the screen ...
Indeed, I would like the score to increase each time the bird passes between the pipes and therefore whenever the pipes have an X of 67 pixels. So does anyone know how to do this?
from tkinter import *
import random
from random import randint
def sauter(event):
canvas.move(image_oiseau, 0, -10*DY)
def deplacement():
global tuyx,tuyx2,h,H,oisx,oisy,solx,sol2x
x0, y0, x1, y1 = canvas.bbox(image_oiseau)
if y1 < 416:
canvas.move(image_oiseau, 0, DY)
canvas.coords(image_sol,solx,512)
if solx >= -144:
solx=solx-5
else:
solx=144
canvas.coords(image_sol2,sol2x,512)
if sol2x >= 144:
sol2x=sol2x-5
else:
sol2x=432
canvas.coords(image_tuyau_haut,tuyx,h)
canvas.coords(image_tuyau_bas,tuyx,h-241)
if tuyx>=-28:
tuyx=tuyx-5
else:
tuyx=316
h=randint(256,505)
canvas.coords(image_tuyau_haut2,tuyx2,H)
canvas.coords(image_tuyau_bas2,tuyx2,H-241)
if tuyx2>=-28:
tuyx2=tuyx2-5
else:
tuyx2=316
H=randint(256,505)
canvas.after(40,deplacement)
LARGEUR = 286
HAUTEUR = 510
DY = 5
tuyx=316
tuyx2=488
h=randint(256,505)
H=randint(256,505)
oisx=67
oisy=244
solx=144
sol2x=432
fenetre = Tk()
canvas = Canvas(fenetre, width=LARGEUR, height=HAUTEUR)
fond = PhotoImage(file="background-day.png")
fond2 = PhotoImage(file="background-night.png")
fond=[fond,fond2]
F= random.choice(fond)
canvas.create_image(144,256, anchor=CENTER,image=F)
tuyau_haut = PhotoImage(file="tuyau_vers_le_haut.png")
image_tuyau_haut = canvas.create_image(tuyx,h,anchor=CENTER,image=tuyau_haut)
image_tuyau_haut2 = canvas.create_image(tuyx2,H,anchor=CENTER,image=tuyau_haut)
tuyau_bas = PhotoImage(file="tuyau_vers_le_bas.png")
image_tuyau_bas = canvas.create_image(tuyx,h,anchor=CENTER,image=tuyau_bas)
image_tuyau_bas2 = canvas.create_image(tuyx2,H,anchor=CENTER,image=tuyau_bas)
sol = PhotoImage(file="sol-day.png")
image_sol = canvas.create_image(144,512, anchor=S,image=sol)
image_sol2 = canvas.create_image(432,512, anchor=S,image=sol)
oiseau = PhotoImage(file="yellowbird-midflap.png")
oiseau2 = PhotoImage(file="bluebird-midflap.png")
oiseau3 = PhotoImage(file="redbird-midflap.png")
oiseau=[oiseau,oiseau2,oiseau3]
O=random.choice(oiseau)
image_oiseau=canvas.create_image(oisx,oisy, anchor=W,image=O)
deplacement()
canvas.pack()
canvas.focus_set()
canvas.bind("<space>",sauter)
fenetre.mainloop()
Could someone explain the problem to me because I thought it would be easy :(
Here are the pictures of the game :)
Here are the pictures of the game
Here is one approach to display the scores: It uses a tk.Label, that is updated at the same time the score increases.
The trigger that increases the score is currently a random call to on_change; you can modify this to be a test if a pipe x coordinates becomes lower than the bird x coordinates (the bird successfully crossed the obstacle)
You can, if you want relocate the score label on the canvas.
import random
import tkinter as tk
WIDTH, HEIGHT = 500, 500
def create_pipes():
pipes = []
for x in range(0, WIDTH, 40):
y1 = random.randrange(50, HEIGHT - 50)
y0 = y1 + 50
pipes.append(canvas.create_line(x, 0, x, y1))
pipes.append(canvas.create_line(x, y0, x, HEIGHT))
return pipes
def move_pipes():
for pipe in pipes:
canvas.move(pipe, -2, 0)
x, y0, _, y1 = canvas.coords(pipe)
if x < 0:
canvas.coords(pipe, WIDTH+20, y0, WIDTH+20, y1)
if random.randrange(0, 20) == 10:
on_change()
root.after(40, move_pipes)
def on_change():
global score
score += 1
score_variable.set(f'score: {score}')
root = tk.Tk()
tk.Button(root, text='start', command=move_pipes).pack()
score = 0
score_variable = tk.StringVar(root, f'score: {score}')
score_lbl = tk.Label(root, textvariable=score_variable)
score_lbl.pack()
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg="cyan")
canvas.pack()
pipes = create_pipes()
root.mainloop()
I am trying to get the coordinates for each square on the board but the error UnboundLocalError: local variable 'x' referenced before assignment keeps showing up when I click on a square.
import tkinter
class RA:
def __init__(self):
self._columns = 8
self._rows = 8
self._root = tkinter.Tk()
self._canvas = tkinter.Canvas(master = self._root,
height = 500, width = 500,
background = 'green')
self._canvas.pack(fill = tkinter.BOTH, expand = True)
self._canvas.bind('<Configure>',self.draw_handler)
def run(self):
self._root.mainloop()
def draw(self):
self._canvas.create_rectangle(0,0,250,250,fill = 'blue',outline = 'white')
self._canvas.create_rectangle(250,250,499,499,fill = 'red',outline = 'white')
self._canvas.create_rectangle(499,499,250,250,fill = 'black',outline = 'white')
#
for c in range(self._columns):
for r in range(self._rows):
x1 = c * (column_width)#the width of the column
y1 = r * (row_height)
x2 = x1 + (column_width)
y2 = y1 + (row_height)
#3-5
def clicked(self,event: tkinter.Event):
x = event * x
y = event * y
rect = self._canvas.find_closest(x,y)[0]
coordinates = self._canvas.gettags(rect)
print(coordinates[0],coordinates[1])
def draw(self):
self._canvas.delete(tkinter.ALL)
column_width = self._canvas.winfo_width()/self._columns
row_height = self._canvas.winfo_height()/self._rows
for x in range(self._columns):
for y in range(self._rows):
x1 = x * column_width
y1 = y * row_height
x2 = x1 + column_width
y2 = y1 + row_height
r = self._canvas.create_rectangle(x1,y1,x2,y2,fill = 'blue')#,tag = (x,y))# added for the second time,
self._canvas.tag_bind(r,'<ButtonPress-1>',self.clicked)
self._canvas.create_rectangle(x1,y1,x2,y2)
self._canvas.bind('<Configure>',self.draw_handler)
def draw_handler(self,event):
self.draw()
r = RA()
r.run()
The problem is in these two lines:
def clicked(self,event: tkinter.Event):
x = event * x
You're using x on the right hand side of the expression, but x hasn't been defined anywhere. Also, you're going to have a problem because event is an object. Multiplying the object times some other number isn't likely going to do what you think it is going to do. Did you maybe intend to use event.x in the expression instead of event * x?
Getting the coordinates of the clicked item
Even though you specifically asked about the unbound local variable error, it appears you're attempting to get the coordinates of the item that was clicked on. Tkinter automatically gives the item that was clicked on the tag "current", which you can use to get the coordinates:
coordinates = self._canvas.coords("current")
From the official tk documentation:
The tag current is managed automatically by Tk; it applies to the
current item, which is the topmost item whose drawn area covers the
position of the mouse cursor (different item types interpret this in
varying ways; see the individual item type documentation for details).
If the mouse is not in the canvas widget or is not over an item, then
no item has the current tag.
This will happen with y as well. If you want x to be stored with the button, you'll need to create a Class for it, and store them as self.x and self.y. The clicked() event would be on the class itself, and then it will have access to it.
Looks like you used
x = event * x
y = event * y
when you probably wanted
x = event.x
y = event.y
The latter accesses the event object's x and y attributes instead of attempting to multiply it by an unbound variable.
We currently have a fully functional Gui written created using PyQt. My partner wrote a function that graphs a dataSet in Tkinter. My question is, how do we combine the two so they work together?
Here is the graphing function:
def createGraph(self):
import tkinter as tk
# Send in data as param, OR
#data = [17, 20, 15, 10, 7, 5, 4, 3, 2, 1, 1, 0]
# Recieve data within function
s.send("loadgraph")
inputString = repr(s.recv(MSGSIZE))
#inputString = "-20 15 10 7 5 -4 3 2 1 1 0"
print(inputString)
data = [int(x) for x in inputString.split()]
root = tk.Tk()
root.title("FSPwners")
screen_width = 400
screen_height = 700
screen = tk.Canvas(root, width=screen_width, height=screen_height, bg= 'white')
screen.pack()
# highest y = max_data_value * y_stretch
y_stretch = 15
# gap between lower canvas edge and x axis
y_gap = 350
# stretch enough to get all data items in
x_stretch = 10
x_width = 20
# gap between left canvas edge and y axis
x_gap = 20
for x, y in enumerate(data):
# calculate reactangle coordinates (integers) for each bar
x0 = x * x_stretch + x * x_width + x_gap
y0 = screen_height - (y * y_stretch + y_gap)
x1 = x * x_stretch + x * x_width + x_width + x_gap
y1 = screen_height - y_gap
# draw the bar
print(x0, y0, x1, y1)
if y < 0:
screen.create_rectangle(x0, y0, x1, y1, fill="red")
else:
screen.create_rectangle(x0, y0, x1, y1, fill="green")
# put the y value above each bar
screen.create_text(x0+2, y0, anchor=tk.SW, text=str(y))
root.mainloop()
When that method is run by itself, it creates a popup box with the graph. Now we want it to create a popup graph when a button is pressed in our current gui. How can we get it to work? If we just call createGraph() when a button is clicked in our GUI, we get the error:
unrecognized selector sent to instance x009x...
What is the problem? Thanks!
Here's a PyQt port:
from PyQt4 import QtCore, QtGui
class Graph(QtGui.QWidget):
def __init__(self, data, parent=None):
QtGui.QWidget.__init__(self, parent)
self._data = data
self.resize(400, 700)
self.setWindowTitle('FSPwners')
self.setAutoFillBackground(True)
self.setBackgroundRole(QtGui.QPalette.Base)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
screen_width = self.width()
screen_height = self.height()
# highest y = max_data_value * y_stretch
y_stretch = 15
# gap between lower canvas edge and x axis
y_gap = 350
# stretch enough to get all data items in
x_stretch = 10
x_width = 20
# gap between left canvas edge and y axis
x_gap = 20
for x, y in enumerate(self._data):
# calculate reactangle coordinates (integers) for each bar
x0 = x * x_stretch + x * x_width + x_gap
y0 = screen_height - (y * y_stretch + y_gap)
x1 = x0 + x_width
y1 = screen_height - y_gap
if y < 0:
painter.setBrush(QtCore.Qt.red)
else:
painter.setBrush(QtCore.Qt.green)
painter.drawRect(QtCore.QRectF(
QtCore.QPointF(x0, y0), QtCore.QPointF(x1, y1)))
print (x0, y0, x1, y1)
# put the y value above each bar
painter.drawText(x0 + 2, y0 - 2, str(y))
painter.end()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
# data to be graphed
data = [-20, 15, 10, 7, 5, -4, 3, 2, 1, 1, 0]
window = Graph(data)
window.show()
sys.exit(app.exec_())
Qt and Tkinter don't play along quite well, as you can perceive -
I had once played along Python graphical toolkits, and wrote
a 4 operation calculator that would run in either Qt, GTK or Tkinter -
or even display all at once.
In order to have both the Tkinter and Qt versions working simultaneously,
I had to fork the process - and start each toolkit in a separate
running instance;
Your case is not identical, as the Qt GUI will be already running, but maybe
having this to start up with you can come along with a work-around.
The 3-calculators code listing can be found here:
https://web.archive.org/web/20101122232402/http://www.python.org.br/wiki/CalculadoraTkGtkQt