Python Forum
tkinter moving an class object with keybinds
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
tkinter moving an class object with keybinds
#1
ive been pulling out my hair trying to figure out how to get this to work correctly, i dont fully understand why i got this to work. could someone explain this to me, i have been messing around with this for a few days now.. the xv and yv are my constants i was fighting with the class variables so i just set those.
and that is i think on of the keys to my issue.. but i have tried many ways to get this image to move, and i just landed on this..
is the event.symkey needing to be replaced with a while loop of some kind?

from tkinter import *
from PIL import ImageTk,Image
r=Tk()
c1 =Canvas(r,height=400,width=720)
c1.pack()
xv = 1
xy = 1

class ship():
    def __init__(self, x=0,y=0):
        self.img = PhotoImage(file="./8bitship.png")
        self.id = c1.create_image(0,0,anchor=NW,image=self.img)
        self.x = x
        self.y = y

    def move(self,x,y):
        c1.move(self.id, x, y)

    def right(self):
       c1.move(1,0)

    def key(self,event):
        #r.bind("<Right>",right)
        #r.bind("Right", lambda x: s.move(x = 5,y=0))
        if event.symkey == 'Right': self.xv =1
            
    r.bind("<Right>", lambda x: s.move(x=5,y=0))



s = ship(c1)

#r.bind("<Right>",lambda x: s.move(x = 5,y = 0 ))   
#r.bind("<Right>",right)



r.mainloop()
Reply
#2
First a note about coding style.

Using global statements outside of a class is better done using a function, generally placed at the end of your script.
Placing it all at the top of the script makes it ugly, and difficult to read.

General suggested script structure:
  1. imports
  2. class definitions
  3. Dispatcher (outside of class, at bottom of script)
    this is a function that:
    • Collects and passes needed arguments for clases used
    • Instantiates needed classes with collected argument data.
    • any external processing, like mainloop for tkinter
  4. An entry that will allow the script to be executed on its own,
    without interfering with the ability to import from another script.
    this usually is something like this:
       if __name__ == '__main__':
           dispatch()
       
    dispatch can be replaced with your dispatcher function name.
Reply
#3
You were closer that you thought. Here is a working example :

from tkinter import *
from PIL import ImageTk,Image
r=Tk()
c1 =Canvas(r,height=400,width=720)
c1.pack()
 
class ship():
	def __init__(self, x=0,y=0):
		self.img = PhotoImage(file="./alien.png")
		self.id = c1.create_image(0,0,anchor=NW,image=self.img)
		self.x = x
		self.y = y
		r.bind("<Right>", lambda x: s.move(x=5,y=0))
		r.bind("<Left>", lambda x: s.move(x=-5,y=0))
		r.bind("<Up>", lambda x: s.move(x=0,y=-5))
		r.bind("<Down>", lambda x: s.move(x=0,y=5))

	def move(self,x,y):
		c1.move(self.id, x, y)
 
s = ship()
r.mainloop()
gr3yali3n likes this post
Reply
#4
I would pass the canvas as an argument to ship.__init__ instead of depending on the global c1 and move bind outside the ship class.

I'd also toss the ship.x and ship.y since they are unused, or modify the ship.move() method to keep track of where the ship is.
def move(self,x,y):
    self.x += x
    self.y += y
    self.move(self.id, x, y)
Reply
#5
thank all of you, bashbedlam especially, i don't know why that did not occur to me to try :( , but that got it moving...! and whats better about it is i understand why it is working now.
as far as binding outside of the ships class , at the start of this i was attempting to but i moved it inside of the class because i couldn't get that to work.
Reply
#6
The main purpose of a class is to define a template for reusable code. Your ship class can never be used anywhere that doesn't have a canvas named c1, a main window named r, and worst of all, an instance of ship named s. It is rare that a class references an instance of itself unless it is a singleton, or maintains a list of instances for some reason (pool allocation for example). My inclination is to write the code like this:
from tkinter import *

class Ship():
    def __init__(self, parent, wide, high):
        self.canvas = Canvas(parent, width=wide, height=high)
        self.canvas.pack()
        self.img = PhotoImage(file = "test_image.png")
        img_wide = self.img.width()
        img_high = self.img.height()
        self.xmax = wide - img_wide
        self.ymax = high - img_high
        self.x = int((wide - img_wide) / 2)
        self.y = int((high - img_high) / 2)
        self.img_id = self.canvas.create_image(self.x, self.y, anchor=NW, image=self.img)

    def move(self, x, y):
        x = max(-self.x, min(x, self.xmax - self.x))
        y = max(-self.y, min(y, self.ymax - self.y))
        self.x += x
        self.y += y
        self.canvas.move(self.img_id, x, y)
 
root = Tk()
ship = Ship(root, 500, 400)
root.bind("<Right>", lambda event: ship.move(x=5, y=0))
root.bind("<Left>", lambda event: ship.move(x=-5, y=0))
root.bind("<Up>", lambda event: ship.move(x=0, y=-5))
root.bind("<Down>", lambda event: ship.move(x=0, y=5))
root.mainloop()
I also changed things so the ship starts out in the middle of the sea (canvas) and is prevented from sailing off the edge.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  tkinter AttributeError: 'GUI' object has no attribute pfdjhfuys 3 1,549 May-18-2023, 03:30 PM
Last Post: pfdjhfuys
  Tkinter object scope riversr54 6 1,956 Feb-17-2023, 05:40 AM
Last Post: deanhystad
Lightbulb Using Tkinter With Concurrent.Futures / ThreadPoolExecutor Class AaronCatolico1 1 1,474 Dec-14-2022, 08:01 PM
Last Post: deanhystad
Lightbulb [Tkinter] Tkinter Class Import Module Issue AaronCatolico1 6 3,114 Sep-06-2022, 03:37 PM
Last Post: AaronCatolico1
  [Tkinter] Redirecting all print statements from all functions inside a class to Tkinter Anan 1 2,649 Apr-24-2021, 08:57 AM
Last Post: ndc85430
  [Tkinter] Troubles with accessing attr from other class zarize 3 2,634 Aug-20-2020, 06:05 PM
Last Post: deanhystad
  [Tkinter] Use function from other class (Tkinter) zarize 8 4,813 Aug-17-2020, 09:47 AM
Last Post: zarize
  [Tkinter] how to draw dynamic moving scale and potting trace point on waveform in tkinter pytho sameer_1985 0 2,031 May-31-2020, 01:52 PM
Last Post: sameer_1985
  Unable fetch fucntion data in class in tkinter jenkins43 2 3,883 Nov-30-2019, 09:47 PM
Last Post: jenkins43
  Tkinter Class pythonenthusiast2 1 2,623 Nov-24-2019, 03:51 AM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020