1

So I have a couple of images in a folder and I want to do a little pack opener on tkinter where if I press on a button it randomly opens an Image of that folder and shows it. So I did this:

import os
import random
from PIL import Image
from tkinter import *

def pack():
    path ='C:\\Users\\matt\OneDrive\Images\cards'
    files = os.listdir(path)
    index = random.randrange(0, len(files))
    image = Image.open(files[index])
    image.show()

pack_button = Button(window,text = " Pack ",fg="white",bg = 'black',command = pack)
pack_button.grid(row = 2,column = 1,padx = 10,pady = 5)

window.mainloop()

The problem is that this function doesn't want to work and it always tells me:

AttributeError: type object 'Image' has no attribute 'open'

Can someone please help me? And does someone know how to do a button out of an image? Thank you in advance.☺

3 Answers3

0

Assuming you're using Python 3, and you have a folder named card images in the same directory as your Python script, and that folder contains .png images of your playing cards, then the following should work:

import tkinter as tk


def get_random_image_path():
    from random import choice
    from pathlib import Path

    return str(choice(list(Path("card images").glob("*.png"))))


class Application(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.title("Random card")
        self.geometry("171x239")
        self.resizable(width=False, height=False)

        self.image = tk.PhotoImage(file=get_random_image_path())
        self.button = tk.Button(self, image=self.image, command=self.assign_new_image)
        self.button.pack()

    def assign_new_image(self):
        self.image = tk.PhotoImage(file=get_random_image_path())
        self.button.configure(image=self.image)


def main():

    application = Application()
    application.mainloop()

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

Note: I just grabbed three public domain card images from Wikimedia Commons. You can download them either in .svg or .png format in different resolutions. In my case I downloaded them as .pngs with a resolution of 171x239, which is why I picked the same dimensions for the tkinter window. Since I've only downloaded three images, sometimes it appears as though clicking the button doesn't seem to do anything, which isn't the case - it's just that, with only three images to choose from, we're likely to pick the same image multiple times in a row.

Paul M.
  • 10,481
  • 2
  • 9
  • 15
0

To get your example running, see a minimal solution below. For a ready Tkinter program and to avoid PIL use Paul M.'s solution.

import os
import random
from PIL import Image
  
# assuming that this dir contains only images
# otherwise test if r is an image
img_folder = r'/home/ktw/Desktop/test_img'

def pack():
    r = random.choice(os.listdir(img_folder))
    image = Image.open(os.path.join(img_folder, r))
    image.show()


if __name__=='__main__':
    pack()

EDIT: This should work for you. Just change the path to the full path of your image folder. choice(os.listdir(img_folder)) gives you only the name of the random file. os.path.join(img_folder, choice(os.listdir(img_folder))) builds an absolute path from the image folder and the random image so Tk.PhotoImage should work.


import tkinter as tk
import os
from random import choice
from pathlib import Path

img_folder = r'/home/ktw/Desktop/images'

def get_random_image_path():
    return os.path.join(img_folder, choice(os.listdir(img_folder)))


class Application(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.title("Random card")
        self.geometry("171x239")
        self.resizable(width=False, height=False)

        self.image = tk.PhotoImage(file=get_random_image_path())
        self.button = tk.Button(self, image=self.image, command=self.assign_new_image)
        self.button.pack()

    def assign_new_image(self):
        self.image = tk.PhotoImage(file=get_random_image_path())
        self.button.configure(image=self.image)


if __name__=='__main__':
    application = Application()
    application.mainloop()

ktw
  • 98
  • 9
0
import tkinter as tk
import os
from random import choice
from pathlib import Path
from PIL import Image

img_folder = r'C:\\Users\\matt\OneDrive\Images\cards'

def get_random_image_path():
    return os.path.join(img_folder, choice(os.listdir(img_folder)))


class Application(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)
        self.title("Random card")
        self.resizable(width=False, height=False)

        self.image = tk.PhotoImage(get_random_image_path())
        self.button = tk.Button(self, image=self.image, command=self.assign_new_image)
        self.button.pack()

    def assign_new_image(self):
        self.image = tk.PhotoImage(file=get_random_image_path())
        self.button.configure(image=self.image)


if __name__=='__main__':
    application = Application()
    application.mainloop()

and it says this:

  File "C:\Users\matt\OneDrive\Images\cards\pack opener.py", line 31, in <module>
    application = Application()
  File "C:\Users\matt\OneDrive\Images\cards\pack opener.py", line 22, in __init__
    self.button = tk.Button(self, image=self.image, command=self.assign_new_image)
  File "C:\Users\matt\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 2679, in __init__
    Widget.__init__(self, master, 'button', cnf, kw)
  File "C:\Users\matt\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 2601, in __init__
    self.tk.call(
_tkinter.TclError: image "C:\\Users\\matt\OneDrive\Images\cards\Vettel.png" doesn't exist
  • Your path seems not to be correct. "C:\\Users\\matt\OneDrive\Images\cards\Vettel.png" should be "C:\\Users\matt\OneDrive\Images\cards\Vettel.png". If you struggle withe the backslash Windows plague see https://stackoverflow.com/questions/2953834/windows-path-in-python – ktw Jan 22 '22 at 14:46
  • Don't post another question as an answer. – acw1668 Jan 22 '22 at 15:44