Why won't the second pushed tile show?

Question:

I placed the rectangles over the images. I then bound a click to a call that flipped tiles over by lowering the rectangle below the image. It works for the first call to the function, but when I click another tile, that one won’t flip over. The program still registers the second flip because it’ll flip everything back over if it’s an incorrect match; the only problem is that it won’t have the rectangle go under the image.

# ======================================= import statements
import tkinter as tk
import time
import random
import PIL
import PIL.Image as Image
import PIL.ImageTk as ImageTk

# ======================================= class def

class MemoryGame:

    def __init__(self):
        #initialize window
        self.window = tk.Tk()
        self.window.title("Sea Life Memory Game")
        self.window.minsize(590, 600)
        self.window.maxsize(590, 600)

        #set main canvas as background
        self.canvas = tk.Canvas(self.window, bg="lightblue",
                                bd=0, highlightthickness=0,
                                width=590, height=600)
        self.canvas.grid(row=0, column=0)
        self.canvas.bind("<Button-1>", self.chooseTile)

        #establish coordinates for tiles and shuffle image placement
        coordinates = [(5,30,105,130), (5,160,105,260), (5,290,105,390), (5,420,105,520), (125,30,225,130), (125,160,225,260), (125,290,225,390), (125,420,225,520), (245,30,345,130), (245,160,345,260), (245,290,345,390), (245,420,345,520), (365,30,465,130), (365,160,465,260), (365,290,465,390), (365,420,465,520), (485,30,585,130), (485,160,585,260), (485,290,585,390), (485,420,585,520)]
        imageChoices = ['cropped images/001-turtle.png','cropped images/007-blowfish.png','cropped images/010-jellyfish.png','cropped images/011-starfish.png','cropped images/018-lobster.png','cropped images/028-fish.png','cropped images/033-walrus.png','cropped images/042-goldfish.png','cropped images/045-seal.png','cropped images/046-penguin.png']
        random.shuffle(coordinates)

        #write title to top of canvas
        self.canvas.create_text(295, 15, text="Sea Life Memory Game!",
                                anchor="center", fill="white",
                                font="Times 24 bold")

        self.selectedTile = None

        #initialize counts
        coordinateCount = 0
        imageCount = 0
        self.imageCollection = {}
        #for loop to attach images to each rectangle on the canvas
        for i in range(len(imageChoices)):
            otherDict = {}
            x1, y1, x2, y2 = coordinates[coordinateCount]
            # if imageCount <= 9:
            self.image = ImageTk.PhotoImage(Image.open(imageChoices[imageCount]))
            self.image.img = self.image
            self.id = self.canvas.create_image(x1, y1, anchor="nw",
                                    image=self.image.img)
            self.canvas.create_rectangle(x1, y1, x2, y2, fill="white", outline="white")
            coordinateCount += 1
            x1, y1, x2, y2 = coordinates[coordinateCount]
            self.id = self.canvas.create_image(x1, y1, anchor="nw",
                                               image=self.image.img)
            self.canvas.create_rectangle(x1, y1, x2, y2, fill="white", outline="white")
            coordinateCount += 1
            imageCount += 1

            otherDict["faceDown"] = True
            self.imageCollection[self.id] = otherDict

        #create instructional text
        self.canvas.create_text(295, 550, text="Find all the pairs as fast as possible.",
                                fill="white", font="Times 18", anchor="center")
        self.canvas.create_text(295, 570, text="Click on a card to turn it over and find the same matching card.",
                                fill="white", font="Times 18", anchor="center")


    def run(self):
        self.window.mainloop()

    global list
    list = []
    def chooseTile(self, event):
        # global list
        x = event.x
        y = event.y
        item = self.canvas.find_overlapping(x-5,y-5,x+5,y+5)
        list.append(item)
        print(len(list))
        if len(list) < 2:
            self.canvas.tag_lower(list[0][1])
        elif len(list) == 2:
            self.canvas.tag_lower(list[1][1])
            if self.canvas.itemcget(list[0][0], "image") == self.canvas.itemcget(list[1][0], "image"):
                list.clear()
            else:
                time.sleep(1.0)
                self.canvas.lower(list[0][0], list[0][1])
                self.canvas.lower(list[1][0], list[1][1])
                list.clear()







# ======================================= script calls

game = MemoryGame()
game.run()
Asked By: Stephanie Miles

||

Answers:

It is because the update will be performed after chooseTile() returns to tkinter mainloop(). But the images are already reset to lower layer when the function returns, so you cannot see the second selected image.

The simple fix is calling self.canvas.update_idletasks() to force the update to show the second selected image before time.sleep(1.0):

    def chooseTile(self, event):
        # global list
        x = event.x
        y = event.y
        item = self.canvas.find_overlapping(x-5,y-5,x+5,y+5)
        list.append(item)
        print(len(list))
        if len(list) < 2:
            self.canvas.tag_lower(list[0][1])
        elif len(list) == 2:
            self.canvas.tag_lower(list[1][1])
            if self.canvas.itemcget(list[0][0], "image") == self.canvas.itemcget(list[1][0], "image"):
                list.clear()
            else:
                # force the canvas to show the second selected image
                self.canvas.update_idletasks()
                time.sleep(1.0)
                self.canvas.lower(list[0][0], list[0][1])
                self.canvas.lower(list[1][0], list[1][1])
                list.clear()
Answered By: acw1668

I finally got it to work!!

# ======================================= import statements 
import tkinter as tk
import random
import PIL.Image as Image
import PIL.ImageTk as ImageTk
# ======================================= class def

class MemoryGame:

    def __init__(self):
        #initialize window
        self.window = tk.Tk()
        self.window.title("Sea Life Memory Game")
        self.window.minsize(590, 600)
        self.window.maxsize(590, 600)

        #set main canvas as background
        self.canvas = tk.Canvas(self.window, bg="lightblue",
                                bd=0, highlightthickness=0,
                                width=590, height=600)
        self.canvas.grid(row=0, column=0)
        self.canvas.bind("<Button-1>", self.chooseTile)

        #establish coordinates for tiles and shuffle image placement
        coordinates = [(5,30,105,130), (5,160,105,260), (5,290,105,390), (5,420,105,520), (125,30,225,130), (125,160,225,260), (125,290,225,390), (125,420,225,520), (245,30,345,130), (245,160,345,260), (245,290,345,390), (245,420,345,520), (365,30,465,130), (365,160,465,260), (365,290,465,390), (365,420,465,520), (485,30,585,130), (485,160,585,260), (485,290,585,390), (485,420,585,520)]
        imageChoices = ['cropped images/001-turtle.png','cropped images/007-blowfish.png','cropped images/010-jellyfish.png','cropped images/011-starfish.png','cropped images/018-lobster.png','cropped images/028-fish.png','cropped images/033-walrus.png','cropped images/042-goldfish.png','cropped images/045-seal.png','cropped images/046-penguin.png']
        random.shuffle(coordinates)

        #write title to top of canvas
        self.canvas.create_text(295, 15, text="Sea Life Memory Game!",
                                anchor="center", fill="white",
                                font="Times 24 bold")


        #initialize counts
        coordinateCount = 0
        imageCount = 0
        self.imageCollection = []
        #for loop to attach images to each rectangle on the canvas
        for i in range(len(imageChoices)):
            x1, y1, x2, y2 = coordinates[coordinateCount]
            self.image = ImageTk.PhotoImage(Image.open(imageChoices[imageCount]))
            self.image.img = self.image
            self.id = self.canvas.create_image(x1, y1, anchor="nw",
                                    image=self.image.img)
            self.imageCollection.append(self.id)
            self.canvas.create_rectangle(x1, y1, x2, y2, fill="white", outline="white")
            coordinateCount += 1
            x1, y1, x2, y2 = coordinates[coordinateCount]
            self.id = self.canvas.create_image(x1, y1, anchor="nw",
                                               image=self.image.img)
            self.canvas.create_rectangle(x1, y1, x2, y2, fill="white", outline="white")
            coordinateCount += 1
            imageCount += 1

            self.imageCollection.append(self.id)

        #create instructional text
        self.canvas.create_text(295, 550, text="Find all the pairs as fast as possible.",
                                fill="white", font="Times 18", anchor="center")
        self.canvas.create_text(295, 570, text="Click on a card to turn it over and find the same matching card.",
                                fill="white", font="Times 18", anchor="center")


    def run(self):
        self.window.mainloop()

    global lst
    lst = []
    global matches
    matches = 0

    def chooseTile(self, event):
        global lst
        global matches
        x = event.x
        y = event.y
        item = self.canvas.find_overlapping(x-1,y-1,x+1,y+1)
        lst.append(item)
        if len(lst) < 2:
            self.canvas.tag_lower(lst[0][1], lst[0][0])
        elif len(lst) == 2:
            self.canvas.tag_lower(lst[1][1],lst[1][0])
            if self.canvas.itemcget(lst[0][0], "image") == self.canvas.itemcget(lst[1][0], "image"):
                matches += 2
                lst.clear()
            else:
                self.window.update_idletasks()
                self.window.after(1500)
                self.canvas.lower(lst[0][0], lst[0][1])
                self.canvas.lower(lst[1][0], lst[1][1])
                lst.clear()
        if matches == 20:
            self.window.update_idletasks()
            self.window.after(1000)
            self.window.destroy()

# ======================================= script calls

game = MemoryGame()
game.window.mainloop()
Answered By: Stephanie Miles
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.