naapperas
naapperas

Reputation: 11

Drawing a image to a tkinter canvas

I've already searched and found nothing about this topic, so I'll ask here.

I'm starting to develop very basic games, and I want to load a picture into my background. I'm using a eBook on Python to help me do this and, according to it, the following code is right:

from tkinter import *
import time
import random

Width = 1000
Height = (Width/12)*9

class Game:

    def __init__(self):
        self.tk = Tk()
        self.tk.title("Monster Rush")
        self.tk.resizable(0, 0)
        self.tk.wm_attributes("-topmost", 1)
        self.canvas = Canvas(self.tk, width=Width, height=Height, highlightthickness=0)
        self.canvas.pack()
        self.tk.update()
        self.canvas_height = 500
        self.canvas_width = 500
        self.bg = PhotoImage(file="anipedra.gif")
        w = self.bg.width()
        h = self.bg.height()
        for x in range(0, 5):
            for y in range(0, 5):
                self.canvas.create_image(x * w, y * h, image=self.bg, anchor='nw')
        self.sprites = []
        self.running = True

    def mainloop(self):
        while 1:
            if self.running == True:
                for sprite in self.sprites:
                    sprite.move()
                    self.tk.update_idletasks()
        self.tk.update()
        time.sleep(0.01)

class Enemy(Game):
    def __init__(self):
        self.e = Game()
        self.e.mainloop()

class Player(Game):
    def __init__(self):
        self.e = Game()
        self.e.mainloop()

Troll = Enemy()
Grunt = Enemy()
Minion = Enemy()
Player = Player()

But every time I run this:

  1. If it's a .gif, the IDLE normally shows this:
  Traceback (most recent call last):
    File "C:\Users\Nuno\Desktop\Python\Projectos\Monster Rush\Monster Rush (T.D.).py", line 47, in <module>
  Troll = Enemy()
    File "C:\Users\Nuno\Desktop\Python\Projectos\Monster Rush\Monster Rush (T.D.).py", line 39, in __init__
  self.e = Game()
    File "C:\Users\Nuno\Desktop\Python\Projectos\Monster Rush\Monster Rush (T.D.).py", line 20, in __init__
  self.bg = PhotoImage(file="background.gif")
    File "C:\Users\Nuno\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 3393, in __init__
  Image.__init__(self, 'photo', name, cnf, master, **kw)
    File "C:\Users\Nuno\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 3349, in __init__
  self.tk.call(('image', 'create', imgtype, name,) + options)
  _tkinter.TclError: couldn't recognize data in image file "background.gif"
  1. If it is the .gif in the above code (or any other format):

      The file stops responding and crashes.

Can anyone help me?

Upvotes: 1

Views: 1625

Answers (2)

rodeone2
rodeone2

Reputation: 109

Maybe this ! Some image software's can and do at times change the extension endings to image files. They can capitalize the extensions on demand. Such as .gif to .GIF or jpeg to JPEG etc. You wont realize this until you upload the files onto a website, then you will see the capitalized extensions. Googles infamous Picaso Download did this to my computer and i had to do a re system install to fix it. Not related but Windows alters the jpeg format also in secrecy in some older XP versions. Have someone test your code on another machine.

Upvotes: 0

Bryan Oakley
Bryan Oakley

Reputation: 386352

The error in your stack trace is saying that the file isn't really a GIF file. Are you certain it is actually a gif file, or could it be some other file that someone renamed to have .gif as a suffix?

You also have several critical design flaws.

  1. In a well designed tkinter app you must always have exactly one root window. You're creating four (or eight...) -- one for each player and enemy object.

  2. You have classes that both inherit from Game and create a Game instance itself. This makes absolutely no sense. Either inherit from Game or create an instance, but don't do both. Though, since Game creates a root window, it makes no sense to create more than one Game object.

  3. You aren't using the event loop properly. You aren't ever letting tkinter process certain events. You have your own infinite loop in which you call update_idletasks(), but that only handles screen refreshes and other "idle" events. It won't handle key presses or mouse clicks. You call update but it outside of the infinite loop so it never gets called.

    1. As a general rule of thumb you shouldn't be calling sleep in a GUI. It does exactly what it says: it puts your application to sleep. While it's sleeping it won't refresh the screen and it won't process mouse or keyboard events. The application is truly dead.

While I don't know exactly what your intentions are, you can probably rewrite your own custom mainloop to leverage the real event loop by doing something like this:

def mainloop(self): 
    if self.running == True: 
        for sprite in self.sprites: 
            sprite.move() 
        self.tkafter(30, self.mainloop)

You need to set 30 to represent how fast you want the display to update. The value is in milliseconds, so 30 represents 30fps. Also, you need to call the mainloop function of the root window exactly once so that it can process events.

Upvotes: 2

Related Questions