Printing list to Tkinter Label - python

Trying to print the reviews array as a list to my label so it doesn't just come out in a single line.
import pandas as pd
import numpy as np
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showwarning, showinfo
movies = pd.read_csv('C:/Users/Admin/Python Programs/ml-latest-small/movies.csv')
ratings = pd.read_csv('C:/Users/Admin/Python Programs/ml-latest-small/ratings.csv')
ratings.drop(['timestamp'], axis=1, inplace= True)
class App(Frame):
def replace_name(x):
return movies[movies['movieId']==x].title.values[0]
ratings.movieId = ratings.movieId.map(replace_name)
M = ratings.pivot_table(index=['userId'], columns=['movieId'], values='rating')
def pearsons(s1, s2):
s1_c = s1 - s1.mean()
s2_c = s2 - s2.mean()
return np.sum(s1_c * s2_c) / np.sqrt(np.sum(s1_c ** 2) * np.sum(s2_c ** 2))
def get_recs(self):
movie_name = self.mn.get()
num_recs_str = self.nr.get()
num_recs = int(num_recs_str)
reviews = []
for title in App.M.columns:
if title==movie_name:
continue
cor = App.pearsons(App.M[movie_name], App.M[title])
if np.isnan(cor):
continue
else:
reviews.append((title, cor))
reviews.sort(key=lambda tup: tup[1], reverse=True)
for x in reviews:
self.label3.config(text= "\n" + str(reviews[:num_recs]))
#self.label3.config(text=reviews[:num_recs])
return reviews[:num_recs]
def __init__(self, master):
Frame.__init__(self, master)
self.filename = None
label1=Label(master, text="Movie: ").grid(row=0)
label2=Label(master, text="Recommendations: ").grid(row=1)
self.label3=Label(master, text = "", font = 'Purisa', fg='blue')
self.label3.grid(row = 3)
self.mn = Entry(master)
self.mn.grid(row = 0, column = 1)
#self.mn.delete(0, END)
self.mn.insert(0, "Enter Movie Name")
self.nr = Entry(master)
self.nr.grid(row = 1, column = 1)
#self.nr.delete(0, END)
self.nr.insert(0, "Enter Number of Recommendations")
button1 = Button(self, text="Start", command=self.get_recs)
button2 = Button(self, text="Exit", command=master.destroy)
button1.grid(row = 2, padx= 5)
button2.grid(row = 2, column = 1, padx = 5)
self.grid()
root = Tk()
root.title("Recommender")
root.geometry("500x500")
app = App(root)
root.mainloop()
Here is an image of the current output

I couldn't modify your code because I don't have the files you opened in your code. However, this is an idea to solve your question:
from tkinter import *
things_to_print=['something','one thing','another']
root=Tk()
for i in range(len(things_to_print)):
exec('Label%d=Label(root,text="%s")\nLabel%d.pack()' % (i,things_to_print[i],i))
root.mainloop()
I think you can solve your problem by substituting your reviews into my things_to_print and maybe some other slight modifications.

Related

clearing multiple labels values

I am losing my peanuts here. I am trying to clear two label values but i get an error
AttributeError: 'Label' object has no attribute 'delete'
basically if i were to click the calculate subtotal button then click the divide total button. I get my intended values. Now if I were to click on the clear values button i get an error. Literally shaking my head as I type this. Anyone care to explain why this is the case?
try:
import Tkinter as tk
except:
import tkinter as tk
class GetInterfaceValues():
def __init__(self):
self.root = tk.Tk()
self.totalValue = tk.StringVar()
self.root.geometry('500x200')
self.calculateButton = tk.Button(self.root,
text='Calculate Subtotal',
command=self.getSubtotals)
self.divideTotalButton = tk.Button(self.root,
text='Divide total',
command=self.divide)
self.textInputBox = tk.Text(self.root, relief=tk.RIDGE, height=1, width = 6, borderwidth=2)
self.firstLabel = tk.Label(self.root, text="This is the subtotal:")
self.secondLabel = tk.Label(self.root, text="This is the Divide Total:")
self.clearTotalButton = tk.Button(self.root, text='clear the values',command = self.clear)
self.firstLabel.pack(side="bottom")
self.secondLabel.pack(side="bottom")
self.textInputBox.pack()
self.calculateButton.pack()
self.divideTotalButton.pack()
self.clearTotalButton.pack()
self.root.mainloop()
def getTextInput(self):
result = self.textInputBox.get("1.0", "end")
return result
def getSubtotals(self):
userValue = int(self.getTextInput())
self.firstLabel["text"] = self.firstLabel["text"] + str(userValue * 5)
def divide(self):
userValue = int(self.getTextInput())
self.secondLabel["text"] = self.secondLabel["text"] + str(userValue / 10)
def clear(self):
self.firstLabel["text"] = self.firstLabel.delete("1.0","end")
app = GetInterfaceValues()
try:
import Tkinter as tk
except:
import tkinter as tk
class GetInterfaceValues():
def __init__(self):
self.root = tk.Tk()
self.totalValue = tk.StringVar()
self.root.geometry('500x200')
self.calculateButton = tk.Button(self.root,
text='Calculate Subtotal',
command=self.getSubtotals)
self.divideTotalButton = tk.Button(self.root,
text='Divide total',
command=self.divide)
self.textInputBox = tk.Text(self.root, relief=tk.RIDGE, height=1, width = 6, borderwidth=2)
self.firstLabelDefault = "This is the subtotal:"
self.secondLabelDefault = "This is the Divide Total:"
self.firstLabel = tk.Label(self.root, text=self.firstLabelDefault)
self.secondLabel = tk.Label(self.root, text=self.secondLabelDefault)
self.clearTotalButton = tk.Button(self.root, text='clear the values',command = self.clear)
self.firstLabel.pack(side="bottom")
self.secondLabel.pack(side="bottom")
self.textInputBox.pack()
self.calculateButton.pack()
self.divideTotalButton.pack()
self.clearTotalButton.pack()
self.root.mainloop()
def getTextInput(self):
result = self.textInputBox.get("1.0", "end")
return result
def getSubtotals(self):
userValue = int(self.getTextInput())
self.firstLabel["text"] = self.firstLabel["text"] + str(userValue * 5)
def divide(self):
userValue = int(self.getTextInput())
self.secondLabel["text"] = self.secondLabel["text"] + str(userValue / 10)
def clear(self):
self.firstLabel["text"] = self.firstLabelDefault
self.secondLabel["text"] = self.secondLabelDefault
self.textInputBox.delete("1.0", "end")
app = GetInterfaceValues()
You may have confused the methods of tkinter.Text and tkinter.Label. The method you called was tkinter.label.delete, which is not defined (does not exist), however it does exist for the tkinter.Text. Therefore, the only way to 'reset' would be to change the text attribute of the tkinter.Labels back to a 'default' string. It would perhaps be more appropriate to use another widget instead.

Python tkinter Clearing Label Text

I have just started utilizing Python's tkinter module to create some basic GUIs. In the GUI shown below, the user is prompted to select an oil index and subsequent pricing information will appear (the price information is web scraped). However, I have not found a convenient way to clear the pricing label text for when the user selects another oil index. I have the full code attached below. Any suggestions would be greatly appreciated. Thank you.
# Import Python Modules
from tkinter import *
from ttk import *
import urllib2
from bs4 import BeautifulSoup
import re
# Generate Basic Window
root = Tk()
root.geometry("225x125")
root.resizable(0,0)
root.title("Global Oil Price GUI")
# Functions
def fetchdata(event):
index = combo.current() # Get index of combobox selection
# Obtain HTML
url = 'http://oilprice.com/oil-price-charts/45' # URL to be scraped
content = urllib2.urlopen(url)
parsed = BeautifulSoup(content,'html.parser')
# Parse HTML
oilprice = parsed.findAll('td',attrs = {'class': 'last_price'})
change = parsed.findAll('td',{'class':['change_up flat_change_cell','change_down flat_change_cell','change_up','change_down']})
change_percent = parsed.findAll('td',{'class':['change_up_percent percent_change_cell','change_down_percent percent_change_cell','change_up_percent','change_down_percent']})
# Pre-Initialize Arrays
oilprice_extract = []
change_extract = []
change_percent_extract = []
time_extract = []
# Loop and Extract Text
for ele_price, ele_change, ele_change_percent in zip(oilprice,change,change_percent):
oilprice_extract.append(float(ele_price.text))
change_extract.append(ele_change.text)
change_percent_extract.append(ele_change_percent.text.split('%')[0] + '%')
time_extract.append(re.sub('\n\t',' ',ele_change_percent.text.split('%')[1]))
# Fill Field Based Upon Selection
price_label = Label(root,text = oilprice_extract[index]).grid(row = 2,column = 2)
change_label = Label(root,text = change_extract[index]).grid(row = 3,column = 2)
change_percent_label = Label(root,text = change_percent_extract[index]).grid(row = 4,column = 2)
update_label = Label(root,text = time_extract[index]).grid(row = 5,column = 2)
# Driver Code
combo_label = Label(root,text = "Futures & Indexes",justify = LEFT).grid(row = 0, column = 0)
combo = Combobox(root,values = ["WTI Crude","Brent Crude","Mars US","OPEC Basket","Canadian Crude Index"],width = 17)
combo.grid(row = 1, column = 0)
combo.bind("<<ComboboxSelected>>",fetchdata)
price_display = Label(root,text = " Price (USD):").grid(row = 2,column = 0)
change_display = Label(root,text = "Change:").grid(row = 3,column = 0)
change_percent_display = Label(root,text = "Change Percent:").grid(row = 4,column = 0)
update_display = Label(root,text = "Last Updated:").grid(row = 5,column = 0)
root.mainloop() # Run window continuously**
Update:
Still a slight problem.
Scenario: User selects WTI Crude as first choice which shows: 'Last Update: (11 Minutes Delay)'
User then selects Mars US which should show something like 'Last Update: (2 Days Delay)'
Problem: The labels overlap each other as shown in this photo EXAMPLE PHOTO
Any solution to this?
The correct way is to use a StringVar to set the initial value of the Label, then you just need to call the .set() method of the StringVar instance you want to update.
Example:
price_str = StringVar()
prica_label = Label(root, textvariable=price_str).pack()
price_str.set("new price")
Clearing Label Text:
as jasonharper said. Use label.config(text="something")
The following script shows an example, where a label is dynamically incremented by 1 until the stop button is pressed:
import tkinter as tk
counter = 0
def counter_label(label):
def count():
global counter
counter += 1
label.config(text=str(counter))
label.after(1000, count)
count()
root = tk.Tk()
root.title("Counting Seconds")
label = tk.Label(root, fg="green")
label.pack()
counter_label(label)
button = tk.Button(root, text='Stop', width=25, command=root.destroy)
button.pack()
root.mainloop()
reference: https://www.python-course.eu/tkinter_labels.php
labels overlap:
you shouldn't recreate label over and over again.
Besides, I think the following example will be better.
from tkinter import *
from tkinter.ttk import *
import requests
from tkinter.ttk import Combobox
from bs4 import BeautifulSoup, SoupStrainer
# import re # As long as you can make do with str.replace(), you should use it instead of re.sub.
class CQueryOil(Tk):
def __init__(self, query_country: list):
super().__init__() # init Tk
self.__url = 'http://oilprice.com/oil-price-charts/45'
self._query_country = query_country
self._intvar_price = IntVar()
self._strvar_change = StringVar(value='')
self._strvar_change_percent = StringVar(value='')
self._strvar_update_time = StringVar(value='')
self.init_ui()
#property
def url(self):
return self.__url
#property
def query_list(self):
return self._query_country
def run(self):
self.mainloop()
def init_ui(self) -> None:
self.geometry("225x125")
self.resizable(0, 0)
self.title("Global Oil Price GUI")
[self.grid_columnconfigure(col, weight=1) for col in (1, 2)]
n_padx = 5
Label(self, text="Futures & Indexes", justify=LEFT).grid(row=0, column=0, padx=n_padx, sticky='w')
combo = Combobox(self, values=self.query_list, width=17)
combo.grid(row=1, column=0, padx=n_padx, columnspan=2, sticky='w')
combo.bind("<<ComboboxSelected>>", lambda event: self.update(event, combo=combo))
for cur_row, label_name in enumerate(['Price (USD):', 'Change:', 'Change Percent:', 'Last Updated:']):
Label(self, text=label_name, width=14).grid(row=2 + cur_row, column=0, padx=n_padx, sticky='e')
Label(self, textvariable=self._intvar_price).grid(row=2, column=1, sticky='w')
Label(self, textvariable=self._strvar_change).grid(row=3, column=1, sticky='w')
Label(self, textvariable=self._strvar_change_percent).grid(row=4, column=1, sticky='w')
Label(self, textvariable=self._strvar_update_time).grid(row=5, column=1, sticky='w')
def update(self, event, combo) -> None:
resp = requests.get(self.url)
if resp.status_code != 200:
return
filter_data = SoupStrainer('tr', attrs={'class': ['stripe show_graph', 'stripe show_graph update_on_load']
# 'data-id': ['45', '46', '50', '29', '68']
})
parsed = BeautifulSoup(resp.text, 'lxml', parse_only=filter_data)
idx = combo.current() # Get index of combobox selection
try:
dst_td_tags = parsed.find('td', string=self.query_list[idx]).find_next_siblings()
except:
import traceback
print(traceback.format_exc())
raise NameError(f'====Must match the data on the web page. Name:{self.query_list[idx]}=====') # literal format Py3.6↑
dst_list = [td.text for td in dst_td_tags]
price, change, change_percent, update_time = dst_list
change_percent = change_percent.split('%')[0] # As long as you can make do with str.replace(), you should use it instead of re.sub.
update_time = update_time.replace('\n\t', ' ')
change_percent = change_percent
update_time = update_time
self._intvar_price.set(price)
self._strvar_change.set(change)
self._strvar_change_percent.set(change_percent)
self._strvar_update_time.set(update_time)
if __name__ == '__main__':
obj = CQueryOil(["WTI Crude", "Brent Crude", "Mars US", "Opec Basket", "Canadian Crude Index"]) # Must match the data on the web page
obj.run()

Can't write full text in an Entry - tkinter

I'm working on a GUI software with Tkinter which basically print a general plane of the product after pushing the "Crear" button, as you can see at the following images:
GUI Interface
After pushing "Crear" Button
As you may have appreciated, once you give the full information at the entries and push the "Crear" button, a dynamic table (made with labels and entries in a for cycle) appear with the dimensions of the modules seen at the "Esquema" frame. The problem I have is that, when I edit the information at the dynamic table, I have an immediate change on the graph (which is possible thanks to the trace method) without letting me finish the number I'm already writing; I mean: I can't write the full number at the entries on the dynamic table before it make the changes on the graph. So, my question is: which function or command can I apply to make the program stop and reactivate after I finish writing the full number at the entries on the table?
Any help will be highly appreciated,
PS: I have already tried the "time.stop" and "after" functions. The first one crashed the program, which is unacceptable, and the second one increased the waiting time before I could continue writing numbers at the table. The full code of the program is really extensive, but here I share a runnable code:
Code
from tkinter import *
from tkinter import filedialog as fd
from tkinter import messagebox as ms
from tkinter import ttk
from io import open
import tkinter as tk
from pathlib import Path
import PIL
from PIL import Image, ImageTk
import glob
import sys
import numpy as np
import os
import os, os.path
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import time
#Made by:
#Juan David Argüello Plata
#----------------------------------------------CLASSES AND FUNCTIONS-----------------------------------------------------
class Interface():
def __init__(self, inter, w=860,h=700, titulo = "Example", titulo_principal = "EXAMPLE"):
inter.title(titulo)
inter.resizable(False, False)
#Dimensions of the screen
ws = inter.winfo_screenwidth()
hs = inter.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
#Position of the interface
inter.geometry('%dx%d+%d+%d' % (w, h, x, y))
titulo = Label(inter, text = titulo_principal, font=(fuente,24, "bold italic"))
titulo.pack()
self.inter = inter
#---Frames, labels and general data---
self.Principal_frames()
self.subframes()
self.Data()
#---Actions to execute---
Action(self)
def Principal_frames(self):
self.Frame_Table = Frame(self.inter)
self.Frame_Table.config(width = "400", height = "600", bd = 2, relief = "groove")
self.Frame_Table.place(x=10, y=50)
titulo = Label(self.Frame_Table, text = "Data", font=(fuente,20, "bold italic"))
titulo.place(x=180, y=5)
self.Frame_graph = Frame(self.inter)
self.Frame_graph.config(width = "400", height = "600", bd = 2, relief = "groove")
self.Frame_graph.place(x=450, y=50)
titulo = Label(self.Frame_graph, text = "Graph", font=(fuente,20, "bold italic"))
titulo.place(x=150, y=5)
def subframes(self):
self.subframe_Data = Frame(self.Frame_Table)
self.subframe_Data.config(width = "300", height = "200", bd = 2, relief = "groove")
self.subframe_Data.place(x=80, y=50)
self.subframe_graph = Frame(self.Frame_graph)
self.subframe_graph.config(width = "395", height = "400", bd = 2, relief = "flat")
self.subframe_graph.place(x=0, y=50)
def Data(self):
Length = Label(self.subframe_Data, text = "Length", font = Font)
Length.grid(row=0, column = 0, sticky=W, padx=3)
self.Length=Entry(self.subframe_Data, width=8)
self.Length.grid(row=0,column=1, sticky=W, padx=3)
self.Sub_Length=Entry(self.subframe_Data, width=8)
self.Sub_Length.grid(row=0,column=2, sticky=W, padx=3)
Width = Label(self.subframe_Data, text = "Width", font = Font)
Width.grid(row=1, column = 0, sticky=W, padx=3)
self.Width=Entry(self.subframe_Data, width=8)
self.Width.grid(row=1,column=1, sticky=W, padx=3)
self.Sub_Width=Entry(self.subframe_Data, width=8)
self.Sub_Width.grid(row=1,column=2, sticky=W, padx=3)
class Action(Interface):
def __init__(self, inter):
self.Interface = inter
self.modification = 0
Create = Button(self.Interface.subframe_Data, text="Create", font = Font, command = self.Table)
Create.grid(row=1,column=3)
def Table(self):
self.Table = Frame(self.Interface.Frame_Table)
self.Table.config(width = "150", height = "400", bd=2, relief="groove")
self.Table.place(x=80, y=150)
#Dimensions of the labels and entries of the table
Length = 176
Width = 200
#Reading of Data
self.Data = np.zeros(4)
self.Data[0] = float(self.Interface.Length.get())
self.Data[1] = float(self.Interface.Sub_Length.get())
self.Data[2] = float(self.Interface.Width.get())
self.Data[3] = float(self.Interface.Sub_Width.get())
#---Dynamic table ---
if self.Data[1] > self.Data[3]:
self.Max = self.Data[1]
else:
self.Max = self.Data[3]
#-Variables-
label = "label"
Entry_length = "length"
Entry_width = "width"
Numbers_label = [""]*(int(self.Max)+1)
self.width_data = [""]*(int(self.Max)+1)
self.length_data=[""]*(int(self.Max)+1)
self.First_Time = 0 #Counter that depends of the size of the table (help the program to recognize if it's the first time the "Create" button is pressed)
self.Modules = np.zeros((int(self.Max),2)) #Matrix which contains the table info
#--Scorllbar--
self.canvas_table = Canvas(self.Table)
self.canvas_table.pack(side="left", fill="both", expand = True)
self.canvas_table.config(width=str(Width), height=str(Length))
self.Frame_table = Frame(self.canvas_table)
self.Frame_table.config(width=str(Width), height=str(Length), relief="flat")
self.canvas_table.create_window(0,0,window= self.Frame_table, anchor = 'nw')
self.yscroll = Scrollbar(self.Table, orient = "vertical", command = self.canvas_table.yview)
self.yscroll.pack(side='right', fill='y')
self.canvas_table['yscrollcommand'] = self.yscroll.set
self.Frame_table.bind("<Configure>", self.AuxscrollFunction)
self.yscroll.grid_forget()
Number = Label(self.Frame_table, text="", width=4, font = Font, bd = 2, relief="groove")
Number.grid(row=0,column=0,sticky=W)
L = Label(self.Frame_table, text="L", width=8, font = Font, bd = 2, relief="groove")
L.grid(row=0,column=1,sticky=W)
Wid = Label(self.Frame_table, text="W", width=8, font = Font, bd = 2, relief="groove")
Wid.grid(row=0,column=2,sticky=W)
#Subdivisions (defect values)
Wth = self.Data[2]/self.Data[3]
l = self.Data[0]/self.Data[1]
self.var_length = []
self.var_width = []
for i in range(int(self.Max)+1):
if i != 0:
Numbers_label[i] = label + str(i)
Numbers_label[i] = Label(self.Frame_table, text=str(i), width=4, font = Font, bd = 2, relief="groove")
Numbers_label[i].grid(row=i,column=0,sticky=W)
if i <= self.Data[1]:
text = str(l)
else:
text = "0.0"
var_length = StringVar()
self.var_length.append(var_length)
self.length_data[i] = Entry_length + str(i)
self.length_data[i] = Entry(self.Frame_table, width=9, font = Font, bd = 2, relief="groove", textvariable = self.var_length[i-1])
self.var1 = self.length_data[i]
self.var_length[i-1].trace("w", lambda name, index, mode, envio=self: Action.callback(envio))
self.length_data[i].grid(row=i,column=1,sticky=W)
self.length_data[i].insert(0, text)
if i <= self.Data[3]:
text = str(Wth)
else:
text = "0.0"
var_width = StringVar()
self.var_width.append(var_width)
self.width_data[i] = Entry_width + str(i)
self.width_data[i] = Entry(self.Frame_table, width=9, font = Font, bd = 2, relief="groove", textvariable = self.var_width[i-1])
self.var1 = self.width_data[i]
self.var_width[i-1].trace("w", lambda name, index, mode, envio=self: Action.callback(envio))
self.width_data[i].grid(row=i,column=2,sticky=W)
self.width_data[i].insert(0, text)
self.yscroll.pack(side='right', fill = 'y')
def AuxscrollFunction(self,event):
self.canvas_table.configure(scrollregion=self.canvas_table.bbox("all"))
def callback(self, *args):
self.First_Time = self.First_Time+1
if self.First_Time >= 2*int(self.Max) and self.modification == 0:
try:
for i in range(int(self.Max)+1):
if i != 0:
self.Modules[i-1][0] = float(self.length_data[i].get())
self.Modules[i-1][1] = float(self.width_data[i].get())
self.Data[0] = 0
self.Data[2] = 0
for i in range(int(self.Max)):
self.Data[0] = self.Data[0]+self.Modules[i][0]
self.Data[2] = self.Data[2]+self.Modules[i][1]
self.Interface.Length.delete(0, 'end')
self.Interface.Width.delete(0, 'end')
self.Interface.Length.insert(0, str(self.Data[0]))
self.Interface.Width.insert(0, str(self.Data[2]))
#self.var1.focus()
self.Graph()
except ValueError:
pass
def Graph(self):
#---Area---
f=Figure(figsize=(3,3), dpi=100)
a=f.add_subplot(111)
type_line = 'r--' #Línea de borde de área
a.plot([0,self.Data[2]], [0,0], type_line)
a.plot([0,self.Data[2]], [self.Data[0],self.Data[0]], type_line)
a.plot([0,0], [0,self.Data[0]], type_line)
a.plot([self.Data[2],self.Data[2]], [0,self.Data[0]], type_line)
canvas = FigureCanvasTkAgg(f, self.Interface.subframe_graph)
canvas.draw()
canvas.get_tk_widget().place(x=0,y=0)
#--------------------------------------------------------INTERFACE-----------------------------------------------
#---Beginning of the interface---
root = Tk()
#Font
fuente = "TkFixedFont"
Font = (fuente, 10)
Interface(root)
root.mainloop()

Creating a settings text file for python tkinter form widgets

I am creating a form for session variables in python and (currently) store the inputs in separate text files. How could I use a single file to hold all session variables in lists (there will be more than 2 in the final form)? What would I need to change in my code to make this more efficient? Any help is greatly appreciated.
import tkinter
from tkinter import *
from tkinter import ttk
regionList = open('regions.txt','r')
optionList = open('options.txt','r')
class MainWindow(Frame):
def __init__(self,master = None):
Frame.__init__(self,master)
self.master = master
self.init_window()
self.grid()
self.create_widgets()
def create_widgets(self):
"""Create Window Layout"""
Boxfont = ('Lucida Grande', 12)
self.label1 = Label(self, font=Boxfont,
text="Regions").grid(row=2,column=0)
self.regcombo = ttk.Combobox(self, font = Boxfont, width = 20, textvariable = varRegions)
self.regcombo.bind("<Return>", self.regcombo_onEnter)
self.regcombo.bind('<<ComboboxSelected>>',self.regcombo_onEnter)
self.regcombo['values'] = regionList.readlines()
self.regcombo.grid(row=2, column=1,sticky = W)
self.label2 = Label(self, font=Boxfont, text="Options").grid(row=4,column=0)
self.optcombo = ttk.Combobox(self, font = Boxfont, width = 20, textvariable = varOptions)
self.optcombo.bind("<Return>", self.optcombo_onEnter)
self.optcombo.bind('<<ComboboxSelected>>',self.optcombo_onEnter)
self.optcombo['values'] = optionList.readlines()
self.optcombo.grid(row=4, column=1,sticky = W)
def init_window(self):
self.master.title("User Settings")
self.pack(fill=BOTH, expand=1)
def regcombo_onEnter(self,event):
varRegions.set(varRegions.get().lower())
mytext = varRegions.get()
vals = self.regcombo.cget('values')
self.regcombo.select_range(0,END)
print(mytext)
if not vals:
self.regcombo.configure(values = (mytext.strip,))
elif mytext not in vals:
with open('regions.txt','a') as f:
f.write('\n'+ mytext)
self.regcombo.configure(values = vals + (mytext,))
f.close
return 'break'
def optcombo_onEnter(self,event):
varOptions.set(varOptions.get().lower())
mytext = varOptions.get()
vals = self.optcombo.cget('values')
self.optcombo.select_range(0,END)
print(mytext)
if not vals:
self.optcombo.configure(values = (mytext.strip,))
elif mytext not in vals:
with open('options.txt','a') as f:
f.write('\n'+ mytext)
self.optcombo.configure(values = vals + (mytext,))
f.close
return 'break'
root = tkinter.Tk()
root.geometry("600x600")
varRegions = tkinter.StringVar(root, value='')
varOptions = tkinter.StringVar(root, value='')
app = MainWindow(root)
root.mainloop()

Can't overwrite labels Tkinter

get_recs is triggered by the start button. A loop in get_recs trys to first delete any existing labels (but always fails), then creates the label, writes to it and then adds it to the grid. However each time start is pressed the existing labels are not destroyed and new labels are created instead of being replaced. I can only assume this means that each time the loop is executed it creates separate labels, which would explain why they are never destroyed but i dont understand why. Here is the code:
import pandas as pd
import numpy as np
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showwarning, showinfo
movies = pd.read_csv('C:/Users/Admin/Python Programs/ml-latest-small/movies.csv')
ratings = pd.read_csv('C:/Users/Admin/Python Programs/ml-latest-small/ratings.csv')
ratings.drop(['timestamp'], axis=1, inplace= True)
class App(Frame):
def replace_name(x):
return movies[movies['movieId']==x].title.values[0]
ratings.movieId = ratings.movieId.map(replace_name)
M = ratings.pivot_table(index=['userId'], columns=['movieId'], values='rating')
def pearsons(s1, s2):
s1_c = s1 - s1.mean()
s2_c = s2 - s2.mean()
return np.sum(s1_c * s2_c) / np.sqrt(np.sum(s1_c ** 2) * np.sum(s2_c ** 2))
def get_recs(self):
movie_name = self.mn.get()
num_recs_str = self.nr.get()
num_recs = int(num_recs_str)
reviews = []
for title in App.M.columns:
if title==movie_name:
continue
cor = App.pearsons(App.M[movie_name], App.M[title])
if np.isnan(cor):
continue
else:
reviews.append((title, cor))
reviews.sort(key=lambda tup: tup[1], reverse=True)
Frame3= Frame(root, bg= 'red')
Frame3.grid()
#for i in range(num_recs):
#exec("Label%d=Label(Frame3,text='', fg = 'blue')\nLabel%d.grid()" % (i,i))
#var_exists = 'Label0' in locals() or 'Label0' in globals()
for i in range(num_recs):
try:
exec("Label%d.destroy()" % (i))
except (NameError):
pass
exec("Label%d=Label(Frame3,text='', fg = 'blue')\n" % (i))
exec("Label%d.config(text=%s)" % (i,reviews[i]))
exec("Label%d.grid()" % (i))
print ("success")
#exec("print (%d)" % (i))
#for x in reviews:
#self.label3.config(text= "\n" + str(reviews[:num_recs]))
#self.label3.config(text=reviews[:num_recs])
return reviews[:num_recs]
def __init__(self, master):
Frame.__init__(self, master)
Frame1 = Frame(master)
Frame1.grid()
Frame2 = Frame(master)
Frame2.grid()
self.filename = None
label1=Label(Frame1, text="Movie: ").grid(row=0, sticky=W)
label2=Label(Frame1, text="Recommendations: ").grid(row=1, sticky=W)
#self.label3=Label(master, text = "", font = 'Purisa', fg='blue')
#self.label3.grid(row = 3)
self.mn = Entry(Frame1)
self.mn.grid(row = 0, column = 1, sticky=W)
#self.mn.delete(0, END)
self.mn.insert(0, "Enter Movie Name")
self.nr = Entry(Frame1)
self.nr.grid(row = 1, column = 1, sticky=W)
#self.nr.delete(0, END)
self.nr.insert(0, "Enter Number of Recommendations")
button1 = Button(Frame2, text="Start", command=self.get_recs)
button2 = Button(Frame2, text="Exit", command=master.destroy)
button1.grid(row = 0, column = 0, padx= 5, pady = 5, sticky =W)
button2.grid(row = 0, column = 1, padx = 5, pady =5, sticky =W)
self.grid()
root = Tk()
root.title("Recommender")
root.geometry("500x500")
app = App(root)
root.mainloop()
Your code throws a NameError because your labels are created locally. On your second click you can't reach them and since you are just passing in except block, you don't see anything.
One approach is, you can create labels as class variables
for i in range(num_recs):
try:
exec("self.Label%d.destroy()" % (i))
except NameError:
print("A NameError has occured")
except AttributeError:
exec("self.Label%d=Label(Frame3,text='', fg = 'blue')\n" % (i))
exec("self.Label%d.config(text=%s)" % (i,reviews[i]))
exec("self.Label%d.grid()" % (i))
Instead of this approach, you can put all your labels into a list then check if said label is in list or not. Which is, IMHO, much better approach.
#a list created in global scope to store all labels
labels = []
def get_recs(self):
....
for i in range(num_recs):
try:
for label in labels:
if label["text"] == reviews[i]:
label.destroy() #destroy the matching label
labels.remove(label) #remove it from labels list
except (NameError):
#Please don't just pass Exceptions. They are there for a reason
print("A NameError has occured")
labels.append(Label(Frame3,text='', fg = 'blue'))
labels[-1].config(text=reviews[i])
labels[-1].grid()

Categories

Resources