Python & Tkinter - Interface freezes by clicking on a button
Question: I'm working on a project where I must create a Mastermind game interface using
Python language, so I use Tkinter.

The program itself seems to work fine: you can choose the length of the color
code to find and the number of turns you have to find the good color code,
using the Option Menu, and when you click on "Start" the game launch at the
very first turn (you have a line of buttons who changes their color by
clicking on them, and an "OK" button to go to the next turn).

And here's the problem: a very few times the game runs correctly, but almost
always, the game "freezes" when you click on the "OK" button : nothing
happens, you can't interact no more with the game and you can't even close it
by clicking on the close button.

So here is the code:

    
    
    import RPi.GPIO as GPIO
    import time
    import smbus
    import my_lcd_lib
    import os
    #import mpg321
    from Tkinter import *
    from random import randint
    
    
    
    # creation de l'interface -------------------------------
    
    
    
    
    class Menu(Frame):
    
        def __init__(self, fenetre, **kwargs):
            Frame.__init__(self, fenetre, width=768, height=568, **kwargs)
            self.pack(fill=BOTH)
    
            self.message = Label(self, text="Menu")
            self.message.pack()
    
            self.Longcode = 5
            self.Nbtours = 10
            self.Tour = 1
            self.Couleurs = ['red', 'yellow', 'green', 'blue', 'pink','purple', 'brown', 'gray', 'black', 'white', "red"]
    
            self.bouton_demarrer = Button(self, text="Start",command=self.Play)
            self.bouton_demarrer.pack()
            self.bouton_options = Button(self, text="Options",command=self.Options)
            self.bouton_options.pack()
            self.bouton_quitter = Button(self, text="Quitter", command=self.quit)
            self.bouton_quitter.pack()
    
        def Options(self):
            Frame.__init__(self, fenetre, width=768, height=568)
            self.pack(fill=BOTH)
            self.message = Label(self, text="Options")
            self.message.place(x = '200', y = '0')
            #ligne pour modifier la longueur du code
            self.texte1 = Label(self, text="Longueur du code")
            self.texte1.place(x = '0', y = '20')
            self.plus1 = Button(self, text="+", command=self.AugLongcode)
            self.plus1.place(x = '460', y = '20')
            self.montrer1 = Label(self, text=self.Longcode)
            self.montrer1.place(x = '430', y = '20')
            self.moins1 = Button(self, text="-", command=self.DimLongcode)
            self.moins1.place(x = '380', y = '20')
            #ligne pour modifier le nombre de tours
            self.texte2 = Label(self, text="Nombre de tours")
            self.texte2.place(x = '0', y = '80')
            self.plus2 = Button(self, text="+", command=self.AugNbtours)
            self.plus2.place(x = '460', y = '80')
            self.montrer2 = Label(self, text=self.Nbtours)
            self.montrer2.place(x = '430', y = '80')
            self.moins2 = Button(self, text="-", command=self.DimNbtours)
            self.moins2.place(x = '380', y = '80')
            #bouton pour revenir au Menu
            self.bouton_quitter = Button(self, text="Retour", command=self.Retour)
            self.bouton_quitter.place(x = '200', y = '250')
    
        def DimLongcode(self):
            if self.Longcode > 4:
                self.Longcode -= 1
                self.montrer1["text"] = self.Longcode
    
        def AugLongcode(self):
            if self.Longcode < 8:
                self.Longcode += 1
                self.montrer1["text"] = self.Longcode
    
        def DimNbtours(self):
            if self.Nbtours > 1:
                self.Nbtours -= 1
                self.montrer2["text"] = self.Nbtours
    
        def AugNbtours(self):
            if self.Nbtours < 15:
                self.Nbtours += 1
                self.montrer2["text"] = self.Nbtours
    
        def Retour(self):       #bouton pour revenir au Menu
    
            Frame.__init__(self, fenetre, width=768, height=568)
            self.pack(fill=BOTH)
    
    
            self.message = Label(self, text="Menu")
            self.message.pack()
    
            self.bouton_demarrer = Button(self, text="Start",command=self.Play)
            self.bouton_demarrer.pack()
            self.bouton_options = Button(self, text="Options",command=self.Options)
            self.bouton_options.pack()
            self.bouton_quitter = Button(self, text="Quitter", command=self.quit)
            self.bouton_quitter.pack()
    
    #----------------------------OK Button command-------------------------------------------------
    
    
        def Play(self):
            Frame.__init__(self, fenetre, width=768, height=568)
            self.pack(fill=BOTH)
            #self.IA = ["" ,"" ,"" ,"" ,"" ,"" ,"" , ""]
            self.IA = []
            self.r = 0
            while self.r < self.Longcode:       #boucle pour eviter les doublons
                temp = randint(0, 9)
                verif = 0
                while verif == 0:       #etat 0 : les valeurs sont differentes (initialisation)
                    if self.r != 0:
                        a = 0
                        for a in range(0, self.r):
                            if self.Couleurs[temp] == self.IA[a]:
                                verif = 1   #etat 1 : une valeur egale (doublon)
                            if (a == self.r - 1 and verif == 0):
                                verif = 2   #etat 2 : aucune valeur egale
    
                            if (a == self.r - 1):
                                a += 1
                    else:
                        if self.r == 1:
                            if self.Couleurs[temp] == self.IA[a]:
                                verif = 1   #etat 1 : une valeur egale (doublon)
                            if (a == self.r - 1 and verif == 0):
                                verif = 2   #etat 2 : aucune valeur egale
    
                        else:
                            verif = 2
                if verif == 2:
                    self.IA.append(self.Couleurs[temp])
                    self.r += 1
            print self.IA
    
            divid = 500/(self.Longcode + 1)
            val = 0
            self.bouton_test = ['0', '1', '2', '3', '4', '5', '6', '7', '8']
            self.colors = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
            self.bouton_valid = []
            for n in range(0,self.Longcode):
                self.colors[n] = self.Couleurs[n]
                self.bouton_test[n] = Button(self, bg = self.colors[n], text=n+1, command =lambda n=n: self.Colorchange(n, self.bouton_test[n]["bg"]))
                self.bouton_test[n].place(x=val, y = '460')
                val = val + divid
    
            self.bouton_valid.append(Button(self, text="OK", command = self.Fintour))
            self.bouton_valid[0].place(x=val, y = '460')
    
        def Fintour(self):                  #bug lors de l'appel de la fonction par une deuxieme fonction. Idee : deplacer le premier bouton et rajoutter des parametres d'entree
            self.combinaison = []
            self.Blanc = 0
            self.Noir = 0
            for c in range(0, self.Longcode):       #boucle pour ranger la combinaison
                tempo = int(c + self.Longcode*(self.Tour - 1))
                self.combinaison.append(self.bouton_test[tempo]["bg"])
            print self.combinaison
            for d in range(0, self.Longcode):       #boucle pour determiner le nombre de couleurs correcte    if self.combinaison[d+ (self.Longcode*(self.Tour - 1))] == self.IA[d]:
                    self.Blanc += 1
    
            self.compa = []
            for e in range(0, self.Longcode):       #boucle pour determiner le nombre de couleurs mal placees
                for f in range(0, self.Longcode):
                    if self.combinaison[e+ (self.Longcode*(self.Tour - 1))] == self.IA[f]:
                        if e == 0:
                            self.compa.append(self.IA[f])
                            self.Noir += 1
                        else:
                            verif = 0
                            while verif == 0:
                                for g in range(0, len(self.compa)):
                                    if self.IA[f] == self.compa[g]:
                                        verif = 1
                                        f = self.Longcode
                                    if (verif == 0 and g == len(self.compa) - 1):
                                        g +=1
                                        verif = 2
                            if verif == 2:
                                self.compa.append(self.IA[f])
                                self.Noir +=1
    
    
            for h in range(0, self.Longcode):               #empeche les anciens boutons de changer de couleur
                self.bouton_test[h+ (self.Longcode*(self.Tour - 1))]["state"] = 'disabled'
    
            self.bouton_valid[self.Tour- 1].destroy()
            divid2 = 460/(self.Nbtours + 1)
            self.NHauteur = (460 - ((self.Tour) * divid2))
            divid = 500/(self.Longcode + 1)
            val = 0
            for i in range(0 ,self.Longcode):
                self.colors.append(self.bouton_test[i]["bg"])
                self.colors[i] = self.Couleurs[i]
                self.bouton_test[i] = Button(self, bg = self.colors[i], text=i+1, command =lambda i=i: self.Colorchange(i, self.bouton_test[i]["bg"]))
                self.bouton_test[i].place(x=val, y = self.NHauteur)
                val = val + divid
            self.bouton_valid.append(Button(self, text="OK", command = self.Fintour))
            self.bouton_valid[self.Tour].place(x=val, y = self.NHauteur)
            self.blanc = Label(self, text="Bonnes couleurs :")
            self.blanc.place(x=val, y = (460 - ((self.Tour - 1) * divid2)))
            self.blanc = Label(self, text="Couleurs mal placées :")
    
            self.Tour += 1
    
      #-----------------------------------------------------------------------------------------------          
    
    
        def Colorchange(self, ind, color):
            for z in range(0,10):
                if self.Couleurs[z] == color:
                    self.var = z
            if self.var == 9:
                self.bouton_test[ind].config(bg = self.Couleurs[0])
            else:
                self.bouton_test[ind].config(bg = self.Couleurs[self.var + 1])
            return
    
    
    
        def quit(self):
            fenetre.destroy()
    
    
    fenetre = Tk()
    fenetre.title("BananaMind v0.1") ##Titre de la fenetre 
    fenetre.geometry("500x500")  ##taille de la fenetre
    
    interface = Menu(fenetre)
    interface.mainloop()
    #interface.destroy()
    

I putted the full code in case the error could be from another command (even
if the program only freezes with the "OK" button). This is an old version of
the code with maybe some other errors, but I want to focus on the main problem
please :)


Answer: Okay so,

It was just an error in the index, using the function len (I forgot a list
starts at 0, so to have the good index I must put len(list) - 1

The problem is solved, I don't have any infinite loop anymore

Thanks :)

