2

Background: I have a small feature in my Tkinter application which randomizes two random values from list and prints them to GUI. But I'm struggling to get right image (team logo) with random value.

Goal: is to random team name (from list of 28 teams) and GUI should show team logo also. Pressing button "RANDOM" and it generates Team1 & Team2 and both should have logos next of the texts.

enter image description here

I have done research about: I had time with this answer, but I could not figure it out. This dice game kinda does it but I need two values instead of one and my list is full of strings.

Example: https://stackoverflow.com/a/27913052/5132305

import random
import tkinter as tk
from PIL import ImageTk, Image

 # Use a class that hold all Team data
class Team():
   def __init__(self, name, img_filename):
    self.name = name
    self.img_filename = img_filename

   @property
   def image(self):
    # TODO: Open image file and return .PhotoImage object
    team_logo = Image.open("%s.jpg" % (self.img_filename))
    render = ImageTk.PhotoImage(team_logo)
    self.img_filename.image = render
    return self.img_filename

   #This is how the class prints
   def __str__(self):
    return "Name: {} Image:{}".format(self.name, self.img_filename)


class MainWindow(tk.Frame):
      def __init__(self, parent, *args, **kwargs):
       tk.Frame.__init__(self, parent,  *args, **kwargs)
       root.geometry("700x450")
       text_1 = tk.Label(text="VS", fg="red", anchor="center")
       text_1.place(relx=.5, rely=.5, anchor="center")
       text_2 = tk.Label(text="RANDOM GAME", fg="green", anchor="n")
       text_2.pack(side="top")

       # Button for randomize
       self.parent = parent
       self.frame = tk.Frame(self.parent)
       self.randomButton = tk.Button(self.frame, text = 'RANDOM', 
       command=self.genRanTeam)
       self.randomButton.pack(side="bottom")
       self.frame.pack(side="bottom")

       self.home_name = tk.StringVar()
       self.visitor_name = tk.StringVar()

       if 0: # TODO: Implement Team.image
           # Images, I should somehow use this with home/visitor label?
           # Yes, look at TODO in def genRanTeam(...

           load = Image.open("%s.jpg" % (self.home.image))
           render = ImageTk.PhotoImage(load)
           # ONLY, if you decide to use OWN Label for Image
           # What you suggest for this? So if I decide to only use home/visitor labels, I don't need next 4 lines of code (after this text?)
           self.team_logo = tk.Label(parent, image=render)
           self.team_logo.image = render
       else:
           self.team_logo = None


       # Home team
       self.home_label = tk.Label(Image = self.team_logo, textvariable=self.home_name) 
       self.home_label.pack(side="left")
       # Visitor team
       self.visitor_label = tk.Label(Image = self.team_logo, textvariable=self.visitor_name) 
       self.visitor_label.pack(side="right")

       self.__init__Teams()

      # Hold this in a own function for brevity
      def __init__Teams(self):
        self.teams = [Team('Chicago Fire', 'chicago'), Team('New York \
        Red Bulls', 'newyork'), Team('Philadelphia Union', 'phila'), 
        Team('Toronto FC', 'toronto')]
        # Init defaults
        self.home = self.teams[0]
        self.visitor = self.teams[0]

      def genRanTeam(self):
        # Use the initalized Teams from MainWindow..__init__
        self.__init__Teams()
        self.home = random.choice(self.teams)
        self.visitor = None
        # Loop while home == visitor
        while self.visitor is None or self.home.name is self.visitor.name:
         self.visitor = random.choice(self.teams)

        self.home_name.set(self.home.name)
        self.visitor_name.set(self.visitor.name)   

        # TODO: Configure .team_label with Team.image
        # self.home_label.configure(image=self.home.image)
        self.home_label.configure(image=self.home.image)
        self.visitor_label.configure(image=self.visitor.image)

if __name__ == "__main__":
         root = tk.Tk()
         main = MainWindow(root)
         main.pack(side="top", fill="both", expand=True)
         root.mainloop()

Now when I am pressing RANDOM-button, it does random correctly values to variables x & y from list.

I also have 28 images in folder project/images. All of the images are "team_name.jpg"

Question 1: How do I loop list and match team name and logo?

All help is appreciated and some code review would be great also! (First question in SO!)

ponkape
  • 487
  • 8
  • 15

1 Answers1

1

Comment: Implement Team.image

Running your Team.image gives me:

self.img_filename.image = render
AttributeError: 'str' object has no attribute 'image'

You can't add a new attribute to buildin str object. This will work, change to:

self.render = ImageTk.PhotoImage(team_logo)
return self.render

Comment: Do I need to make another tk.Label for team image?

There is no need to do so, this depends on your desired layout.
Start with one tk.Label(self, image=image, textvariable=name)
This looks like:
enter image description here Relevant: label-on-top-of-image-in-python

Comment: Is it possible that self.visitor can show team+logo?

It's not the function of class Team() to show anything, it's the job of tk.Lable(....
Relevant: updating-tkinter-label-with-an-image


Question: Two random values from list needs to match with images

This approach don't use two lists, it defines both values(team name, team image) in one class. Therefore no matching is needed.
For example:

# Use a class that hold all Team data
class Team():
    def __init__(self, name, img_filename):
        self.name = name
        self.img_filename = img_filename

    # This is how the class prints
    def __str__(self):
        return "Name: {} Image:{}".format(self.name, self.img_filename)

class MainWindow(tk.Frame):
    def __init__(self, parent, *args, **kwargs):

        # Up to 28 teams - Defined in __init__ only once
        # Create a list with all Teams using class Team
        self.teams = [Team('Chicago Fire', 'logo1.jpg'), Team('New York Red Bulls', 'logo2.jpg'), Team('Philadelphia Union', 'logo3.jpg'), Team('Toronto FC', 'logo4')]
        # Init defaults
        self.home = self.teams[0]
        self.visitor = self.teams[0]

    def genRanTeam(self):
        # Use the initalized Teams from __init__
        self.home = random.choice(self.teams)

        self. visitor = None
        # Loop while home == visitor
        while self.visitor is None or self.home is self.visitor:
            self.visitor = random.choice(self.teams)

if __name__ == "__main__":
    import time

    root = tk.Tk()
    main = MainWindow(root)
    for _ in range(3):
        main.genRanTeam()
        print("home:{} :\tvisitor:{}".format(main.home, main.visitor))
        time.sleep(1)

Output:

home:Name: Toronto FC Image:logo4 : visitor:Name: Chicago Fire Image:logo1.jpg
home:Name: New York Red Bulls Image:logo2.jpg : visitor:Name: Toronto FC Image:logo4
home:Name: Toronto FC Image:logo4 : visitor:Name: New York Red Bulls Image:logo2.jpg

Tested with Python: 3.4.2

stovfl
  • 14,998
  • 7
  • 24
  • 51
  • Looks just like it, the idea! Do I need to make another tk.Label for team image? I tried to add this solution for my example code, but had no luck still. Is it possible that self.visitor can show team+logo? Forgot to mention that teams can be against each other also. But I really appreciate this solution already! – ponkape Oct 10 '18 at 17:23
  • Added few questions in code, sorry not that skilled yet! First: Should I add teams list in Teams class? When we are talking about __init__ only is it about MainWindow __init__ or Team (actually should this be separate file, __init__.py example? From external resrouces you linked I got the idea for Images and text, but I have hard time to get how to link them.. I mean we need to change that print to something else right? Is this #Image block any near about handling images? Yes, that picture is what I am looking for! – ponkape Oct 13 '18 at 12:31
  • Edited code. Made changes to TODOs expect for images. What approach you would suggest? Now code prints the stuff like return does in line 13. Did my edit work as expected? (Not sure but I cannot highlight your nickname with @) – ponkape Oct 19 '18 at 05:46
  • Bit stuck, edited code and made few comments. I really liked this example about property [link text](https://stackoverflow.com/a/5130337/5132305) but I'm still missing some logic here. – ponkape Oct 27 '18 at 09:47
  • Edited code. I wanna check is image function understood correctly and .configure on def genRanTeam? I wrote question about Implement Team.image so what should I do or what you suggest? We can handle this with one label home_label / visitor_label so I guess we don't need other label for Image? So what should I try to check next? – ponkape Nov 10 '18 at 12:07
  • 1
    @ponkape: Updated my Answer. Doing changes as described it will work with a minor faulty: **The Label doesn't show the text anymore**. Reread already linke to [label-on-top-of-image-in-python](https://stackoverflow.com/questions/33460872/label-on-top-of-image-in-python). We have reached our comments limt. To continue I have setup a [gist.github.com](https://gist.github.com/WK-GiHu/12f6e5fadf6b83c0e67525fddfd47a7f) showing my working implementation. – stovfl Nov 10 '18 at 17:29
  • Great mentoring and helping to understand how things roll. I will edit my orginal post while I need to clean my own code a bit and take a look tips from your solution. You totally made my day, hooray! – ponkape Nov 12 '18 at 16:50