Tkinter is opening a second windows when the first one is closing - python

I am creating a budget manager and I have added a textBox in the main window.
However, there seems to be a bug: When I close the window while running the script for the first time since I started my IDE, the window opens, then restarts when I close it, but I can't figure it out.
Here are all the programs:
Main
from moneyTable import moneyTable
from textBoxManager import textBox
import tkinter as tk
import fileLoader as fl
import miscAdditions as ma
import categoryAddOrRemove as caor
filesLoaded = fl.loadFile('/home/thanatos_0173/Desktop')
isFileNotEmpty = filesLoaded[0]
moneyClass = filesLoaded[1]
moneyQuantity = filesLoaded[2]
mainWindow = tk.Tk()
mainWindow.resizable(True, True)
mainWindow.title("budgetGestionnary.th")
mainWindow.attributes('-zoomed',True)
mainWindow.config(background=(ma.rgb_to_hex(100, 100, 100)))
moneyTable(mainWindow,moneyClass,moneyQuantity,350,350,isFileNotEmpty)
textBox = tk.Text(mainWindow,height=10,width = 228)
textBox.place(x=10,y=830)
textBox.config(state = tk.DISABLED)
sb = tk.Scrollbar(tk.Frame(mainWindow))
sb.pack(side=tk.RIGHT, fill=tk.BOTH)
textBox.config(yscrollcommand=sb.set)
sb.config(command=textBox.yview)
def removeCategory():
window = tk.Toplevel()
window.minsize(200,200)
window.resizable(False,False)
clicked = tk.StringVar()
clicked.set(moneyClass[0])
dropdown = tk.OptionMenu(window, clicked, *moneyClass)
dropdown.place(x=10,y=10)
def remove():
window.destroy()
elementRemoved = caor.removeElement(moneyClass,moneyQuantity,clicked.get(),moneyQuantity[moneyClass.index(clicked.get())])
moneyTable(mainWindow,elementRemoved[0],elementRemoved[1],350,350,isFileNotEmpty)
if len(moneyClass) == 0:
remove_category_button.config(state=tk.DISABLED)
button = tk.Button(window,text = "Delete category", command = remove)
button.place(x=10,y=50)
def addCategory():
window = tk.Toplevel()
window.minsize(200,200)
window.resizable(False,False)
clicked = tk.StringVar()
clicked.set('Category Name')
nameEntry = tk.Entry(window,textvariable=clicked)
nameEntry.place(x=10,y=10)
clicked2 = tk.StringVar()
clicked2.set('Category Default Money')
moneyEntry = tk.Entry(window,textvariable=clicked2)
moneyEntry.place(x=10,y=40)
def add():
window.destroy()
elementAdded = caor.addElement(moneyClass,moneyQuantity,clicked.get(),clicked2.get())
moneyTable(mainWindow,elementAdded[0],elementAdded[1],350,350,isFileNotEmpty)
remove_category_button.config(state='normal')
button = tk.Button(window,text = "Add category", command = add)
button.place(x=10,y=150)
def addMessageMain(message):
textBox.config(state = tk.NORMAL)
textBox.insert('end',message+"\n")
textBox.config(state = tk.DISABLED)
remove_category_button = tk.Button(mainWindow,text="Remove a category",command = removeCategory)
add_category_button = tk.Button(mainWindow,text="Add a category",command = addCategory)
remove_category_button.place(x=30, y=785, height=33)
add_category_button.place(x=190, y=785, height=33)
if not isFileNotEmpty:
remove_category_button.config(state=tk.DISABLED)
mainWindow.mainloop()
moneyTable.py
import tkinter as tk
from tkinter import ttk
import miscAdditions as ma
def moneyTable(window,categoryList:list,quantityList:list,sizeX:int,sizeY:int,isEmpty:bool,*arg:str):
if len(categoryList) != len(quantityList):
raise ValueError("The list:",categoryList,"haven't the same length than the list:",quantityList)
elementList = []
total = 0
for i in range(len(categoryList)):
tempList = []
tempList.append(categoryList[i])
tempList.append(str(quantityList[i])+" €")
total += quantityList[i]
elementList.append(tempList)
elementList.append(["TOTAL", str(total) + " €"])
frame = tk.LabelFrame(window)
frame.grid(padx=30, pady=30,ipadx=sizeX, ipady=sizeY, row=0)
frame.config(background=(ma.rgb_to_hex(100, 100, 100)),bd=3)
tree = ttk.Treeview(frame)
column_list = ["Category", "Money"]
tree['columns'] = column_list
tree["show"] = "headings"
for column in column_list:
tree.heading(column, text=column)
max = 0
for i in range(len(categoryList)):
if len(categoryList[i]) > max:
max = len(categoryList[i])
if column == column_list[0]:
tree.column(column, width=max*8)
else:
tree.column(column, width=50)
tree.place(relheight=1, relwidth=1)
treescrollY = tk.Scrollbar(frame)
treescrollY.configure(command=tree.yview)
tree.configure(yscrollcommand=treescrollY.set)
treescrollY.pack(side="right", fill="y")
treescrollX = tk.Scrollbar(frame, orient=tk.HORIZONTAL)
treescrollX.configure(command=tree.xview)
tree.configure(xscrollcommand=treescrollX.set)
treescrollX.pack(side="bottom", fill="x")
def handle_click(event):
if tree.identify_region(event.x, event.y) == "separator":
return "break"
tree.bind('<Button-1>', handle_click)
if not isEmpty or arg[0] == "--devmode":
ma.reloadTreeview(tree, elementList)
return tree
textBoxManager.py
import tkinter as tk
def textBox(window,x,y,height,width):
textBox = tk.Text(
window,
height=height,
width = width,
wrap = 'word'
)
textBox.place(x=x,y=y)
textBox.config(state = tk.DISABLED)
sb = tk.Scrollbar(tk.Frame(window))
sb.pack(side=tk.RIGHT, fill=tk.BOTH)
textBox.config(yscrollcommand=sb.set)
sb.config(command=textBox.yview)
return textBox
fileLoader.py
import miscAdditions as ma
import customFileSaver as cfs
#Create the arrays outside of the function to access it from other class
__spec__ = 'test'
def loadFile(defaultPath:str):
moneyComingCategory = []
moneyAvailableComingCategory = []
cfs.loadOrCreateDirectory(defaultPath,".budgetGestionnary")
defaultPath += "/.budgetGestionnary"
cfs.loadOrCreateFile(defaultPath,".savedata.txt")
with open(".savedata.txt") as f:
lines = f.readlines()
cfs.loadOrCreateDirectory(defaultPath,".removedMoney")
defaultPath += "/.removedMoney"
cfs.loadOrCreateFile(defaultPath, ".removedMoney.txt")
with open('.removedMoney.txt') as f:
lines2 = f.readlines()
removedMoneyList = []
for i in lines2:
removedMoneyList.append(ma.str_to_list(i))
if lines != []:
moneyComingCategory = ma.str_to_list(lines[0])
moneyAvailableComingCategory = [eval(i) for i in ma.str_to_list(lines[1])]
isFileNotEmpty = True
else:
isFileNotEmpty = False
return [isFileNotEmpty,moneyComingCategory,moneyAvailableComingCategory]
miscAdditions.py
import tkinter as tk
def rgb_to_hex(r, g, b):
return("#"+"0"*(2-len(hex(r)[2:]))+hex(r)[2:]+"0"*(2-len(hex(g)[2:]))+hex(g)[2:]+"0"*(2-len(hex(b)[2:]))
+ hex(b)[2:])
def str_to_list(arg):
arg = arg.split()
return arg
def list_to_string(arg):
strl1 = ""
for ele in arg:
strl1 += str(ele) + " "
return strl1
def reloadTreeview(tree, list):
tree.delete(*tree.get_children())
for row in list:
tree.insert("", "end", values=row)
def convertActualMoneyList(list, char, list1, list2):
list.clear()
total = 0
for i in range(len(list)):
tempList = []
tempList.append(list1[i])
tempList.append(str(list2[i])+" "+char)
total += list2[i]
list.append(tempList)
list.append(["TOTAL", str(total) + " €"])
return list
def disableAndEnabledDropdownWhenListContainOneElement(list, element, dropdown):
if len(list) == 1 and list == [element]:
dropdown.config(state=tk.DISABLED)
else:
dropdown.config(state="normal")
def dropdownReloader(screen,StringVar,list,dropdown,x,y):
StringVar = tk.StringVar()
StringVar.set(list[0])
dropdown = tk.OptionMenu(screen, StringVar,*list)
dropdown.place(x=x,y=y)
def listTransformer(list:list):
for k in list:
tempList = []
for i in range(len(list)):
if i <= 2:
tempList.append(k[i])
elif i == 3:
tempList.append(str(k[i]+" €"))
else:
tempVariable = ""
for v in range(4, len(k)):
tempVariable += k[v] + " "
tempList.append(tempVariable)
list[list.index(k)] = tempList
return list
space = " "
customFileSaver.py
import os
import miscAdditions as ma
def loadOrCreateDirectory(path, dirToCheckOrCreate):
os.chdir(path)
customDir = path +"/"+ dirToCheckOrCreate
if not os.path.exists(customDir):
os.system("mkdir " + dirToCheckOrCreate)
def loadOrCreateFile(path,fileToCheckOrCreate):
os.chdir(path)
customdir = path + "/" + fileToCheckOrCreate
if not os.path.exists(customdir):
os.system("touch " + fileToCheckOrCreate)
def saveRemovedMoney(list,path,fileToOpen):
os.chdir(path)
with open(fileToOpen,"a") as file:
file.write(ma.list_to_string(list)+os.linesep)
def saveActualMoney(list1,list2,path,fileToOpen):
os.chdir(path)
file = open(fileToOpen,"a")
l1 = ma.list_to_string(list1)
l2 = ma.list_to_string(list2)
file.writelines([l1+os.linesep, l2+os.linesep])

Ok. So, the error is that I imported main (testeeeeee.py) into categoryAddOrRemove. The window initialization was not in a function, so it was initializing the window at once.

Related

Python Tkinter: How to delete all child widgets with a single deletion of a parent widget?

I have a HangMan game created using a class. I want to delete all the child widgets with a single deletion of the parent window.
My game shows a difficulty window, which is being destroyed after the user selects a difficulty and the main game window appears; which is destroyed too after the user completes the game and then a replay window appears; which is destroyed too after the user clicks yes and a new instance of the difficulty pop-up appears again and the whole thing happens intetely until the user says no.
My code looks like this:
class HangMan:
font = ('Comic Sans MS', 20, 'bold')
theme = 'Dark'
allWords = []
stages = None
title = None
def __init__(self):
self.tries = None
self.pWord = None
self.word = None
self.used = []
self.char = None
def setup(self, path, stges, title="HangMan"):
with open(path, 'r') as file:
self.allWords = file.read().split()
del file
self.stages = stges
self.title = title
def play(self):
def setTheme(theme, place):
if theme == 'Dark':
b = 'black'
f = 'white'
else:
b = 'white'
f = 'black'
if place == 'askDiff':
self.diffWindow.config(bg = b)
self.diffFrame['bg'] = b
i = [self.diffLabel, self.db1, self.db2, self.db3]
elif place == 'Main':
self.window.config(bg = b)
inputEntry['insertbackground'] = f
for i in [frame1, frame2]:
i['bg'] = b
i = [wordLabel, themeButton, ph, inputEntry, triesLabel, usageLabel, logLabel]
elif place == 'askReplay':
self.replayWindow.config(bg = b)
self.reFrame['bg'] = b
i = [self.reLabel, self.reb1, self.reb2]
for j in i:
j['bg'] = b
j['fg'] = f
def changeTheme():
if self.theme == 'Dark':
self.theme = 'Light'
else:
self.theme = 'Dark'
themeButton['text'] = self.theme
setTheme(self.theme, 'Main')
def replay():
self.replayWindow.destroy()
self.__init__()
self.play()
def askReplay(event):
#Destroying the running game
self.window.destroy()
#Creating the replay Window
self.replayWindow = Tk()
self.replayWindow.title('Re-Experience?')
self.reLabel = Label(master = self.replayWindow, font = self.font, text = "Wanna replay?\nSwear it'll be a different word...")
self.reLabel.pack()
self.reFrame = Frame(master = self.replayWindow)
self.reFrame.pack()
self.reb1 = Button(master = self.reFrame, font = self.font, text = 'Yup', command = replay)
self.reb1.pack(side = 'left')
self.reb2 = Button(master = self.reFrame, font = self.font, text = 'Later.', command = lambda: self.replayWindow.destroy())
self.reb2.pack(side = 'left')
setTheme(self.theme, 'askReplay')
self.replayWindow.mainloop()
def askDiff():
def returnStage(num):
nonlocal x
x = num
self.diffWindow.destroy()
self.diffWindow = Tk()
self.diffWindow.title('Difficulty')
self.diffLabel = Label(master = self.diffWindow, font = self.font, text = 'Choose your level of difficulty: ')
self.diffLabel.pack()
self.diffFrame = Frame(master = self.diffWindow)
self.diffFrame.pack()
x=None
self.db1 = Button(master = self.diffFrame, font = self.font, text = self.stages[0]['stage'], command = lambda: returnStage(0))
self.db1.pack(side = 'left')
self.db2 = Button(master = self.diffFrame, font = self.font, text = self.stages[1]['stage'], command = lambda: returnStage(1))
self.db2.pack(side = 'left')
self.db3 = Button(master = self.diffFrame, font = self.font, text = self.stages[2]['stage'], command = lambda: returnStage(2))
self.db3.pack(side = 'left')
setTheme(self.theme, 'askDiff')
self.diffWindow.mainloop()
return x
def setDiff(i):
from random import choice
wordLenRange = (self.stages[i]['wordLen']['min'], self.stages[i]['wordLen']['max'])
possibleWords = []
for j in self.allWords:
if len(j) in range(wordLenRange[0], wordLenRange[1] + 1):
possibleWords.append(j)
self.word = list(choice(possibleWords).lower())
self.pWord = ''.join(self.word)
self.allWords.remove(self.pWord)
self.tries = self.stages[i]['tries']
def isValid(string):
if len(string)==1 and string.isalpha():
return True
else:
return False
def isUsed(string):
if string in self.used or string in wordLabel['text']:
return True
else:
return False
def isRight(string):
if string in self.word:
return True
else:
return False
def updateLog(x):
if x == 'invalid input':
logLabel['text'] = 'Enter a valid single alphabet'
elif x == 'in word':
logLabel['text'] = 'This letter is revealed'
elif x == 'in used':
logLabel['text'] = 'You have already used this letter'
elif x == 'right':
logLabel['text'] = 'Good Guess...'
elif x == 'wrong':
logLabel['text'] = 'You missed it.'
elif x == 'win':
logLabel['text'] += '\nYou Win...Press any key...'
else:
logLabel['text'] += '\nYou Lost...The word is revealed.\nPress any key...'
def updateWord():
txt = list(wordLabel['text'])
while self.char in self.word:
index = self.word.index(self.char)
txt[index] = self.char
self.word[index] = '*'
txt = ''.join(txt)
wordLabel['text'] = txt
def updateTries():
self.tries -= 1
triesLabel['text'] = '{} Oops left'.format(self.tries)
def updateUsage():
self.used.append(self.char)
usageLabel['text'] = 'Used Letters: {}'.format(', '.join(self.used))
def processGame(event):
self.char = inputEntry.get().strip()
if isValid(self.char):
self.char = self.char.lower()
if isUsed(self.char):
if self.char in wordLabel['text']:
updateLog('in word')
else:
updateLog('in used')
else:
if isRight(self.char):
updateWord()
updateLog('right')
else:
updateTries()
updateUsage()
updateLog('wrong')
else:
updateLog('invalid input')
inputEntry.delete(0, 'end')
if '*' not in wordLabel['text']:
updateLog('win')
inputEntry.bind('<Key>', askReplay)
if self.tries == 0:
updateLog('lost')
wordLabel['text'] = self.pWord
inputEntry.bind('<Key>', askReplay)
## GUI Design
from tkinter import Tk, Label, Entry, Button, Frame
#Diffficulty PopUp
diff = askDiff()
setDiff(diff)
# Main Window
self.window = Tk()
self.window.title(self.title)
# Frames and Buttons
frame1 = Frame(master = self.window)
frame1.pack(fill = 'x')
wordLabel = Label(master = frame1, font = self.font, text = '*'*len(self.word))
wordLabel.pack()
themeButton = Button(master = frame1, font = ("Comic Sans MS", 12), text = self.theme, command = changeTheme)
themeButton.pack(side = 'right')
frame2 = Frame(master = self.window)
frame2.pack()
ph = Label(master = frame2, font = self.font, text = 'Guess a Letter: ')
ph.pack(side = 'left')
inputEntry = Entry(master = frame2, font = self.font, width = 5)
inputEntry.focus_set()
inputEntry.pack(side = 'left')
triesLabel = Label(master = frame2, font = self.font, text = '{} Oops left'.format(self.tries))
triesLabel.pack(side = 'left')
usageLabel = Label(master = self.window, font = self.font, text = 'Used Letters: -')
usageLabel.pack()
logLabel = Label(master = self.window, font = self.font, text = "-:Log:-")
logLabel.pack()
setTheme(self.theme, 'Main')
#Event Handler and MainLoop
self.window.bind('<Return>', processGame)
self.window.mainloop()
path = "words.txt"
stages = ({'stage': 'Cool', 'tries':10, 'wordLen':{'min':3, 'max':5}}, {'stage': 'Engaging', 'tries':6, 'wordLen':{'min':6, 'max':8}}, {'stage': 'Intense', 'tries': 4, 'wordLen': {'min': 9, 'max': 15}})
game1 = HangMan()
game1.setup(path, stages)
game1.play()
At 3 places, I'm destroying the parent window - in the askReplay() fucntion of the class.play() function, in the returnStage() function of the askDiff() function in the class.play() function & in the replay() function of the class.play() function. I tried self.window.destroy(), but it is only destroying the root window and all its child widgets are still occupying the memory (I know this because I tried to print one of the child widgets after the window was destroyed). How can I do this?
This would be a problem if an obsessive player plays my game for a
thousand times, creating more than 7000 trash widgets in the memory.
One implementation would be to have the top-level object track its widgets via a list, then have a .close() method that looks something like:
def close(self):
for widget in self.widgets:
widget.destroy()
self.destroy()

How do I make it so a button can only be clicked if a condition is met that is set in another class?

In the ShowMoneyButton class, I want the activation function to only activate if self.button_activated is False, and I set it as False when the SongButton class's activation function is triggered, yet it's not registering. It stays True. Is there a way I can make it so the ShowMoneyButton class's activation function is executed only if the SongButton class's activation function is executed, except for the first time?
import tkinter as tk, random, subprocess, time, os, datetime, pprint
class Song:
def __init__(self):
self.files = []
self.path = "/users/eliasrahoui/desktop/songy"
for filename in os.listdir(self.path):
self.files.append(self.path + "/" + filename)
class Money_Value:
def __init__(self):
with open("money_counter.txt", "r") as f:
a = f.read()
a = int(a)
self.current_value = a
class Clock:
def __init__(self, root):
money = Money_Value()
self.money = money.current_value
self.root = root
self.label = tk.Label(self.root, text = "$" + str(self.money), foreground = "green", font = ('calibri', 100, 'bold'))
self.label.pack()
def countup(self, *args):
root = self.root
money_per_hour = 1000
self.money += 1
self.label['text'] = "$" + str(self.money)
self.root_id = root.after(money_per_hour, self.countup)
def stop(self):
root = self.root
root.after_cancel(self.root_id)
with open("money_counter.txt", "w") as f:
f.write(str(self.money))
def save(self):
with open("money_counter.txt", "w") as f:
f.write(str(self.money))
self.root.destroy()
class Button:
all_buttons = {}
windows = []
return_code = []
button_activated = False
def __init__(self, root, text, command):
self.text = text
button = tk.Button(root, text = text, command = command)
self.all_buttons[self.text] = button
def remove(self, button):
button.pack_forget()
def show_button(self, button):
button.pack(side ="bottom")
class SongButton(Button):
def __init__(self, root, clock):
self.root = root
self.root_clock = clock
super().__init__(self.root, text = "stop song", command = self.activation)
def activation(self):
windows = self.windows
for i in windows:
i.destroy()
code = self.return_code[-1]
code.kill()
self.remove(self.all_buttons["stop song"])
self.root_clock.countup()
self.button_activated = False
class ShowMoneyButton(Button):
def __init__(self, root, clock):
self.root = root
super().__init__(self.root, "show me the money", self.activation)
song = Song()
self.songs = song.files
money_show_button = self.all_buttons["show me the money"]
self.show_button(money_show_button)
self.pic = tk.PhotoImage(file = "/users/eliasrahoui/desktop/IMG_7465.png")
#self.button_activated = False
self.label = tk.Label(self.root, text = "")
self.root_clock = clock
def activation(self):
if self.button_activated == False:
self.root_clock.stop()
num = Money_Value()
money = num.current_value
self.label.config(text =f'Money {money}')
self.label.pack()
random_song = random.choice(self.songs)
a = SongButton(self.root, self.root_clock)
return_cod = subprocess.Popen(["afplay", random_song])
self.return_code.append(return_cod)
self.show_button(self.all_buttons["stop song"])
self.button_activated = True
for _ in range(30):
root = self.root
window = tk.Toplevel(self.root)
self.windows.append(window)
window.minsize(100, 100)
window_label = tk.Label(window, image = self.pic)
window_label.pack()
ws = root.winfo_screenwidth() # width of the screen
hs = root.winfo_screenheight() # height of the screen
x = random.randint(0, ws)
y = random.randint(0, hs)
w = 200
h = 200
window.geometry('%dx%d+%d+%d' % (w, h, x, y))
class Timer(Button):
def __init__(self, root, start_time, name, counter = False):
self.count_down_start_time = start_time
self.root = root
self.name = name
self.counter = counter
self.tmp_counter = counter
super().__init__(self.root, text = name, command = self.timer_window)
self.show_button(self.all_buttons[self.name])
self.timer_id = None
self.window_label = None
self.orignial = start_time
self.window = None
self.current_question = 1
self.questions_answered = {}
self.times = [self.orignial]
self.positive = False
self.min_max = {}
def timer_window(self):
self.window = tk.Toplevel(self.root)
self.window.geometry('%dx%d+%d+%d' % (300, 200, 500, 300))
self.window_label = tk.Label(self.window, text = "", font = ('calibri', 100, 'bold'))
self.counter_label = tk.Label(self.window, text = f'Current Question: {self.current_question}')
self.window_label.pack()
self.timer()
def timer(self):
mins, secs = divmod(self.count_down_start_time, 60)
mins = abs(mins)
secs = abs(secs)
timerr = '{:02d}:{:02d}'.format(mins, secs)
if self.count_down_start_time == -1:
self.positive = True
self.window_label["foreground"] = "red"
if self.positive:
self.count_down_start_time += 1
else:
self.count_down_start_time -= 1
self.window_label["text"] = timerr
self.window.protocol("WM_DELETE_WINDOW", self.callback)
if self.counter == True:
button = tk.Button(self.window, text = "Question Done!", command = self.counter_func)
button.pack(side = "bottom")
button_report = tk.Button(self.window, text = "Report", command = self.report)
self.counter = False
self.counter_label.pack()
button_report.pack(side = "bottom")
self.timer_id = self.window.after(1000, self.timer)
def callback(self):
self.window.after_cancel(self.timer_id)
self.window.destroy()
self.count_down_start_time = self.orignial
if self.tmp_counter == True:
self.counter = True
self.current_question = 1
self.questions_answered = {}
self.positive = False
self.times = [self.orignial]
def counter_func(self):
self.questions_answered[self.current_question] = str(datetime.timedelta(seconds = self.times[-1] - self.count_down_start_time))
self.times.append(self.count_down_start_time)
self.current_question += 1
self.counter_label["text"] = f'Current Question: {self.current_question}'
def report(self):
vals = self.times_min_max()
new_window = tk.Toplevel(self.window)
new_window.minsize(300,300)
a = self.questions_answered[1]
data_pretty = pprint.pformat(self.questions_answered)
label = tk.Label(new_window, text = data_pretty)
label.pack()
mx = {f'Maximum time took per question: {vals[0]} question numbers': vals[2]}
mn = {f'Minimum time took per question: {vals[1]} question numbers': vals[-1]}
mx_label = tk.Label(new_window, text = mx, font = ('calibri', 14, 'bold'))
mn_label = tk.Label(new_window, text = mn, font = ('calibri', 14, 'bold'))
mn_label.pack(side = "bottom")
mx_label.pack(side = "bottom")
def times_min_max(self):
f = {}
big = []
small = []
for i in range(1, len(self.questions_answered) + 1):
val = self.questions_answered[i]
if ":" in val:
q = val.split(":")
secs = int(q[-1])
mins = q[0]
secs = secs/60
secs = str(secs)
secs = secs.split(".")
secs = secs[-1]
final = mins + "." + secs
final = (float(final)) * 60
final = round(final)
f[i] = final
else:
f[i] = int(val)
max_val = max(f, key = f.get) #max(f.items(), key=operator.itemgetter(1))[0]
min_val = min(f, key=f.get)#min(f.keys(), key=(lambda key: f[key]))#min(f.items(), key = operator.intemgetter(1))[0]
min_val = f[min_val]
max_val = f[max_val]
for i in f.keys():
if f[i] == max_val:
big.append(i)
if f[i] == min_val:
small.append(i)
return (self.questions_answered[big[0]], self.questions_answered[small[0]], big, small)
main function:
import clocky_classy as cm
import tkinter as tk
root = tk.Tk()
root.minsize(400,200)
my_clock = cm.Clock(root)
money_button = cm.ShowMoneyButton(root, my_clock)
root.protocol("WM_DELETE_WINDOW", my_clock.save)
timer = cm.Timer(root, 120, "2 min timer")
timer = cm.Timer(root, 1800, "30 min timer", counter = True)
my_clock.countup()
root.mainloop()

Python self.after() changes running order

I am (still!) writing a Noughts and Crosses program using Tkinter in Python 3.
I wanted to implement a short pause between the player's move and the computer's move, so in the add_move_comp() method implemented self.after() function.
I expected this to pause the program for 1000ms then continue by 'drawing' on the computer's move.
However when I run my code, the program only recognises the computer's move the next move after, causing problems with identifying a 3-in-a-row.
I think this is due to line 62 running after 1000ms while the rest of the program continues running, but I don't know how to stop the whole program and continue running with line 62 after the pause.
from tkinter import *
from functools import partial
from itertools import *
import random
class Window(Frame):
def __init__(self, master = None): # init Window class
Frame.__init__(self, master) # init Frame class
self.master = master # allows us to refer to root as master
self.rows = 3
self.columns = 3
self.guiGrid = [[None for x in range(self.rows)] for y in range(self.columns)] # use this for the computer's moves
self.noText = StringVar(value = '')
self.cross = StringVar(value = 'X')
self.nought = StringVar(value = 'O')
self.button_ij = None
self.myMove = True
self.create_window()
self.add_buttons()
def create_window(self):
self.master.title('Tic Tac Toe')
self.pack(fill = BOTH, expand = 1)
for i in range(0,3): # allows buttons to expand to frame size
self.grid_columnconfigure(i, weight = 1)
self.grid_rowconfigure(i, weight = 1)
def add_buttons(self):
rows = 3
columns = 3
for i in range (rows):
for j in range(columns):
self.button_ij = Button(self, textvariable = self.noText, command = lambda i=i, j=j: self.add_move(i,j))
self.guiGrid[i][j] = self.button_ij
self.button_ij.grid(row = i,column = j, sticky =E+W+S+N)
def add_move(self, i,j):
# player's move
while self.myMove:
pressedButton = self.guiGrid[i][j]
self.guiGrid[i][j].config(textvariable = self.cross)
# computer's turn
self.myMove = False
while (self.myMove == False):
self.add_move_comp()
def add_move_comp(self):
repeat = True
while repeat:
i = random.randint(0,0) # row - only allow O to be drawn on 1st row for testing purposes
j = random.randint(0,2) # column
testText = self.guiGrid[i][j].cget('text')
if testText == '':
self.after(1000,lambda i = i, j = j :self.guiGrid[i][j].config(textvariable = self.nought)) # search up rules with returning values using lambda
print('Should plot O at row: ',i,' column: ',j)
print('TEXT ACTUALLY PLOTTED IS: ',self.guiGrid[i][j].cget('text'))
self.myMove = True
repeat = False
print(self.guiGrid[0][0].cget('text'), self.guiGrid[0][1].cget('text'), self.guiGrid[0][2].cget('text')+'THIS IS PRINTING')
root = Tk() # creating Tk instance
rootWidth = '500'
rootHeight = '500'
root.geometry(rootWidth+'x'+rootHeight)
ticTacToe = Window(root) # creating Window object with root as master
root.mainloop() # keeps program running
This is due to the fact that self.after imeadiately returns and starts the given function after passing trough a queque to prevent the actual Window from beeing unable to responde because there is some code running. A way to work around this is to create a BooleanVariable for validation and using self.wait_variable as follows:
from tkinter import *
from functools import partial
from itertools import *
import random
class Window(Frame):
def __init__(self, master = None): # init Window class
Frame.__init__(self, master) # init Frame class
self.master = master # allows us to refer to root as master
self.rows = 3
self.columns = 3
self.guiGrid = [[None for x in range(self.rows)] for y in range(self.columns)] # use this for the computer's moves
self.noText = StringVar(value = '')
self.cross = StringVar(value = 'X')
self.nought = StringVar(value = 'O')
self.button_ij = None
self.myMove = True
self.validationVar = BooleanVar(self)
self.create_window()
self.add_buttons()
def create_window(self):
self.master.title('Tic Tac Toe')
self.pack(fill = BOTH, expand = 1)
for i in range(0,3): # allows buttons to expand to frame size
self.grid_columnconfigure(i, weight = 1)
self.grid_rowconfigure(i, weight = 1)
def add_buttons(self):
rows = 3
columns = 3
for i in range (rows):
for j in range(columns):
self.button_ij = Button(self, textvariable = self.noText, command = lambda i=i, j=j: self.add_move(i,j))
self.guiGrid[i][j] = self.button_ij
self.button_ij.grid(row = i,column = j, sticky =E+W+S+N)
def add_move(self, i,j):
# player's move
while self.myMove:
pressedButton = self.guiGrid[i][j]
self.guiGrid[i][j].config(textvariable = self.cross)
# computer's turn
self.myMove = False
while (self.myMove == False):
self.add_move_comp()
def add_move_comp(self):
repeat = True
while repeat:
i = random.randint(0,0) # row - only allow O to be drawn on 1st row for testing purposes
j = random.randint(0,2) # column
testText = self.guiGrid[i][j].cget('text')
if testText == '':
self.after(1000, self.validationVar.set, True)
self.wait_variable(self.validationVar)
self.guiGrid[i][j].config(textvariable = self.nought) # search up rules with returning values using lambda
print('Should plot O at row: ',i,' column: ',j)
print('TEXT ACTUALLY PLOTTED IS: ',self.guiGrid[i][j].cget('text'))
self.myMove = True
repeat = False
print(self.guiGrid[0][0].cget('text'), self.guiGrid[0][1].cget('text'), self.guiGrid[0][2].cget('text')+'THIS IS PRINTING')
root = Tk() # creating Tk instance
rootWidth = '500'
rootHeight = '500'
root.geometry(rootWidth+'x'+rootHeight)
ticTacToe = Window(root) # creating Window object with root as master
root.mainloop() # keeps program running

here in this code when i select option A i am getting total = 0 as a output instead of output total = 10, how to solve it?

total = 0
def round1():
import tkinter
t =tkinter. Tk()
t.title('Round 1')
t.geometry('1000x800')
v1 = tkinter.IntVar()
def marks():
global total
if v1.get() == 1:
total = total + 10
print("total", total)
l1 = tkinter.Label(t,text = "Q 1 - Is python a case sensitive language?").grid(row = 1)
r1 = tkinter.Radiobutton(t,text = "A - true",variable = v1,value = 1).grid(row = 2)
r2 = tkinter.Radiobutton(t,text = "B - false",variable = v1,value = 2).grid(row = 3)
b = tkinter.Button(t, text = 'Submit',command = marks).place(x = 300, y = 300)
t.mainloop()
def call():
import tkinter
t = tkinter.Tk()
t.title('Instruction')
t.geometry('1000x800')
b1 = tkinter.Button(t, text = 'next',command = round1).pack()
t.mainloop()
call()
This is a well known side effect of using Tk more than once. Use Tk to create the first window, and use Toplevel to make additional windows. It works the same but you don't need a mainloop call.
Also, imports always go on the top, never in a function, and don't initialize and layout a widget on the same line (leads to common bugs).
import tkinter
total = 0
def round1():
t =tkinter.Toplevel()
t.title('Round 1')
t.geometry('1000x800')
v1 = tkinter.IntVar()
def marks():
global total
if v1.get() == 1:
total = total + 10
print("total", total)
l1 = tkinter.Label(t,text = "Q 1 - Is python a case sensitive language?")
l1.grid(row = 1)
r1 = tkinter.Radiobutton(t,text = "A - true",variable = v1,value = 1)
r1.grid(row = 2)
r2 = tkinter.Radiobutton(t,text = "B - false",variable = v1,value = 2)
r2.grid(row = 3)
b = tkinter.Button(t, text = 'Submit',command = marks)
b.place(x = 300, y = 300)
def call():
t = tkinter.Tk()
t.title('Instruction')
t.geometry('1000x800')
b1 = tkinter.Button(t, text = 'next',command = round1)
b1.pack()
t.mainloop()
call()

Python Tkinter Graph

I'd like to make a program which takes an integer from user and makes as many entries in a Tkinkter window. Than from those entries take data and make a graph base on them. But when i turn on my program evereything is fine only a graph is wrong. It shows me an empty graph without any data on it, with no title and no "labels names". Here is my code. Please help. I'm using Python 2.7.5, PyDev for Eclipse
# -*- coding: utf-8 -*-
import matplotlib.pyplot as mp
import Tkinter as T, sys
def end():
sys.exit()
def check():
z = e.get()
try:
z = int(z)
e.config(bg = 'green')
e.after(1000, lambda: e.config(bg = 'white'))
x = []
y = []
global x1, y1
x1 = []
y1 = []
l2 = T.Label(main, text = 'X',bg = 'yellow')
l2.pack()
for i in range(0,z):
x.append(T.Entry(main, justify = 'center'))
x[i].pack()
x1.append(x[i].get())
l3 = T.Label(main, text = 'Y', bg = '#3366ff')
l3.pack()
for i in range(0,z):
y.append(T.Entry(main, justify = 'center'))
y[i].pack()
y1.append(y[i].get())
except:
e.config(bg = 'red')
e.after(1000, lambda: e.config(bg = 'white'))
return x1,y1
def graph():
mp.ion()
mp.plot(x1,y1)
mp.title('Wykres')
mp.xlabel('x')
mp.ylabel('y')
mp.draw()
#====================================================================#
y1 = []
x1 = []
z = 0
main = T.Tk()
main.title('GRAPH')
main.geometry('600x600')
main.config(bg = "#3366ff")
e = T.Entry(main,justify = 'center')
l = T.Label(main,text = 'Podaj liczbę parametrów N =',bg = '#3366ff')
b1 = T.Button(main, text = 'OK', command = check)
b2 = T.Button(main, text = 'Rysuj', command = graph)
b = T.Button(main,text = 'Zakończ', command = end)
l.pack()
e.pack()
b1.pack()
b2.pack()
b.pack()
main.mainloop()
GB: x1, x2 have only empty strings. You have to get values from Entry in graph() function when Entry have some value - and remember to convert it from string to integer.
PL: x1, x2 zawierają tylko puste stringi. Musisz pobrać wartości z Entry w funkcji graph() kiedy Entry już zawierają jakieś wartości - i pamiętaj przekonwertować je z napisów na liczby
working code / działający kod
# -*- coding: utf-8 -*-
import matplotlib.pyplot as mp
import Tkinter as T, sys
class Application():
def __init__(self, root):
self.root = root
self.x1 = []
self.y2 = []
self.z = 0
self.root.title('GRAPH')
self.root.geometry('600x600')
self.root.config(bg="#3366ff")
self.e = T.Entry(self.root, justify='center')
self.l = T.Label(self.root, text='Podaj liczbę parametrów N =', bg='#3366ff')
self.b1 = T.Button(self.root, text='OK', command=self.check)
self.b2 = T.Button(self.root, text='Rysuj', command=self.graph)
self.b = T.Button(self.root, text='Zakończ', command=self.end)
self.l.pack()
self.e.pack()
self.b1.pack()
self.b2.pack()
self.b.pack()
#------------------------------------------------------------
def run(self):
self.root.mainloop()
#------------------------------------------------------------
def end(self):
sys.exit()
#------------------------------------------------------------
def check(self):
try:
self.entry_x = []
self.entry_y = []
self.z = int(self.e.get())
self.e.config(bg='green')
self.e.after(1000, lambda: self.e.config(bg='white'))
self.l2 = T.Label(self.root, text='X', bg='yellow')
self.l2.pack()
for i in range(self.z):
self.entry_x.append(T.Entry(self.root, justify='center'))
self.entry_x[-1].pack()
self.l3 = T.Label(self.root, text='Y', bg='#3366ff')
self.l3.pack()
for i in range(self.z):
self.entry_y.append(T.Entry(self.root, justify='center'))
self.entry_y[-1].pack()
except:
self.e.config(bg='red')
self.e.after(1000, lambda: self.e.config(bg='white'))
#------------------------------------------------------------
def graph(self):
self.x1 = []
self.y1 = []
for i in range(len(self.entry_x)):
self.x1.append(float(self.entry_x[i].get()))
for i in range(len(self.entry_y)):
self.y1.append(float(self.entry_y[i].get()))
mp.ion()
mp.plot(self.x1, self.y1)
mp.title('Wykres')
mp.xlabel('x')
mp.ylabel('y')
mp.draw()
#====================================================================#
Application(T.Tk()).run()

Categories