the code is a bit long, hope you understand it, i have this small app, where i have to implement data from 2 files, and then showing some of the values(of data) in list box. on the other side i have combined the values in nested dictionary. Now i have to recommend movie according the the value i will select from list box. Maybe the code i have written is wrong in some parts, though in the last part, when i have to write the code of recommendation, i have no clue how i have to write the code, i so it will recommend me movie, for further explanation, i will be writing in comments part if needed. (Data&recommendations file: https://www.dropbox.com/sh/b949hapk5lmm94i/AAD29ykbvWq83wZbFpvvqw69a?dl=0)
from Tkinter import *
import tkFileDialog
import csv
from recommendations import *
class STproject:
def __init__(self): #1
self.variableclasses()
self.buttonsnlabels()
self.dictionary()
def variableclasses(self):
self.all_vars = [StringVar() for _ in range(2)]
self.var1 = StringVar()
self.var2 = StringVar()
self.var1.set(0)
self.var2.set(0)
def buttonsnlabels(self):
self.rdbttn=Radiobutton(root,text='user based recommendation',variable = self.var1,value=1,command=lambda:self.dictionary())#, command=lambda :self.selec1())
self.rdbttn.grid(row=0,column=0)
self.rdbttn2=Radiobutton(root,text='movie based recommendation',variable = self.var1,value=2,command=lambda:self.dictionary())#,command=lambda :self.selec1())
self.rdbttn2.grid(row=1,column=0)
self.rdbttn3=Radiobutton(root,text='pearson',variable = self.var2,value=1)#,command=lambda :self.selec2())
self.rdbttn3.grid(row=2,column=0)
self.rdbttn4=Radiobutton(root,text='euclidean',variable = self.var2,value=2)#,command=lambda :self.selec2())
self.rdbttn4.grid(row=3,column=0)
self.ratingbutton=Button(root,text='Upload Rating',command=lambda :self.file(self.all_vars[0]))
self.ratingbutton.grid()
self.ratingbutton=Button(root,text='Upload Movies',command=lambda :self.file(self.all_vars[1]))
self.ratingbutton.grid()
self.lb1 = Listbox(root)
self.lb1.grid(row=0,column=1)
self.lb2 = Listbox(root)
self.lb2.grid(row=0,column=1)
self.lb3 = Listbox(root)
self.lb3.grid(row=0,column=1)
def file(self, v):
result = tkFileDialog.askopenfilename()
if result:
v.set(result)
# self.dictionary()
def dictionary(self):
# self.lb1.delete(END, 0) #clear listbox
# self.lb1.update_idletasks()
if self.var1.get()==1:
self.d = {}
if all(i.get() for i in self.all_vars): #process only if all 2 files are selected
with open(self.all_vars[0].get(),"r") as a, open(self.all_vars[1].get(),"r") as b:
for line1,line2,line3 in zip(csv.reader(a),csv.reader(b),csv.reader(a)):
self.d[line1[0]]={line2[1]:line3[2]}
self.lb1.insert('end',line2[1])
print self.d
else:
self.d = {}
if all(i.get() for i in self.all_vars): #process only if all 2 files are selected
with open(self.all_vars[0].get(),"r") as a, open(self.all_vars[1].get(),"r") as b:
for line1,line2,line3 in zip(csv.reader(a),csv.reader(b),csv.reader(a)):
self.d[line1[0]]={line2[1]:line3[2]}
self.lb1.insert('end', line1[1])
print self.d
def recoms(self):
# selection=self.lb1.curselection()
# print selection
if self.var2.get()==1:
getRecommendations()
else:
pass
root=Tk()
root.title('SteelBox Inc. Calculator')
application=STproject() #2
root.mainloop() #3
Related
I'm working on a project and i would like to get the Value of an Entry created in a def (turned on by a button on Tkinter)
So I have my main tkinter menu, with a button which will call the def "panier".
The def "panier" is creating the Entry "value" and another button to call a second def "calcul".
The second def "calcul" will do things with the value of Entry...
But then, in the def "calcul", when i'm trying to do value.get() it tells "NameError: name 'value' is not defined"
Here is the code, btw the Entry must be created by the def...
from tkinter import *
def panier():
value=Entry(test)
value.pack()
t2=Button(test,text="Validate",command=calcul)
t2.pack()
def calcul(value):
a=value.get()
#here will be the different calculations I'll do
test=Tk()
t1=Button(test,text="Button",command=panier)
t1.pack()
test.mainloop()
Appreciate every feedback :)
You can make the variable global like this:
from tkinter import *
def panier():
global value
value = Entry(test)
value.pack()
t2 = Button(test, text="Validate", command=calcul)
t2.pack()
def calcul():
a = value.get()
print(a)
#here will be the different calculations I'll do
test = Tk()
t1 = Button(test, text="Button", command=panier)
t1.pack()
test.mainloop()
The global value line makes the variable global so you can use it anywhere in your program.
You can also pass in the variable as an argument like what #JacksonPro suggested
t2 = Button(test, text="Validate", command=lambda: calcul(value))
This is one way to do it. Globally create a collection (list or dictionary) to hold a reference to the Entry. When you create the Entry, add it to the collection. I made it with either a list or dictionary for holding the references, so toggle the commented variations in all three places to try it both ways.
import tkinter as tk
def panier():
for item in ('value', ):
ent = tk.Entry(test)
collection.append(ent)
# collection[item] = ent
ent.pack()
t2 = tk.Button(test,text="Validate",command=calcul)
t2.pack()
def calcul():
a = collection[0].get()
# a = collection['value'].get()
print(a)
collection = []
# collection = {}
test = tk.Tk()
t1 = tk.Button(test, text="Button", command=panier)
t1.pack()
test.mainloop()
I have an instance of two different "Listbox" objects
I save each of them in a different reference name
example:
l1 = tkinter.Listbox(exampleFrame)
l2 = tkinter.Listbox(exampleFrame)
l1.setvar("check", "1")
l2.setvar("check", "2")
print("var is - " + l1.getvar("check"))
the problem is whenever I call getvar of l1 the output will be the var of l2
output:
var is - 2
I can assume from this result that the Listbox setvar/getvar functions are staticmethod for all Listbox objects?
if so is there any option to store data for each Listbox object with built-in functions?
my goal is to be able to store an id for each listbox option
for example:
Listbox1:
Albert
Michel
Drake
will store the id of each user option inside a var.
so when I call the insert method
I store the user.id for each index in the setvar
l1.insert(index, user.name)
l1.setvar("var_"+index, user.id)
so when I call getvar("var_"+index)
I'll get the ID of the selected user
the current solution will work good only if I have one listbox in my entire project.
any good solution to store data for multi listbox objects?
-- Edit --
What I've tried to achieve is an option to store more values inside a Listbox option
Example:
l1 = Listbox(frame)
l1.insert(0, 'Drake')
l1.insert(1, 'Jacob')
so instead of having only the index and the string in the Listbox I'll have more stored data of each option.
#1966bc suggested to create a dict and use the option index as the key
so if I want to store more data in example for Drake I can do something like:
l1.anydictname = {}
l1.anydictname[0] = {'Name' : 'Drake', 'data' : 'moredata'}
so now I can check data of Drake I can use Drake list index and point for the data as l1.anydictname[index].data or name or whatever data I'm storing inside.
Thanks, works like magic. If someone have even a cleaner way of doing it you may suggest
If I understand correctly, to do what you want you have to associate the listbox index with a dictionary.
I attach a working example
When you select a line of listbox you get something as
on_listbox_select: index = 2, pk = 3 values = Drake
where index is the listbox index and pk is the id of the selected record.
In the example I've populate the listbox with an immaginary recordset composed of a primary key, a name and a field to enhance its status
rs = [(1,"Albert",1), (2,"Michel",1), (3,"Drake",0), (4,"Alan",1),(5,"George",0)]
#!/usr/bin/python3
import sys
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class App(tk.Tk):
"""Application start here"""
def __init__(self):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_close)
self.title("Simple App")
self.init_ui()
self.set_values()
def init_ui(self):
w = ttk.Frame(self, padding=8)
r = 0
c = 1
self.lstItems = tk.Listbox(w)
self.lstItems.bind("<<ListboxSelect>>", self.on_listbox_select)
self.lstItems.grid(row=r, column=c, padx=5, pady=5)
w.grid(row=0, column=0, sticky=tk.N+tk.W+tk.S+tk.E)
def set_values(self):
self.lstItems.delete(0, tk.END)
index = 0
self.dict_items = {}
#simulate a recordset the fields are: pk, name, enable,
#if enable == 0 paint line gray
rs = [(1,"Albert",1),
(2,"Michel",1),
(3,"Drake",0),
(4,"Alan",1),
(5,"George",0)]
if rs:
for i in rs:
s = "{:}".format(i[1])
self.lstItems.insert(tk.END, s)
if i[2] != 1:
self.lstItems.itemconfig(index, {"bg":"light gray"})
self.dict_items[index] = i[0]
index += 1
def on_listbox_select(self, evt=None):
if self.lstItems.curselection():
index = self.lstItems.curselection()[0]
pk = self.dict_items.get(index)
s = self.lstItems.get(index)
print("on_listbox_select: index = {0}, pk = {1} values = {2}".format(index, pk, s))
def on_close(self,evt=None):
"""Close all"""
if messagebox.askokcancel(self.title(), "Do you want to quit?", parent=self):
self.destroy()
def main():
app = App()
app.mainloop()
if __name__ == '__main__':
main()
I recently started doing python. The course I was on ended with an introduction to testing with doctest. I have written a program that uses Tkinter to display widgets and it works :-) . I am using version 3.7. However, testing it is another matter. I can test simple functions and methods, but I hit difficulties when I have a function inside a method. I am pasting below a stripped-down version of what I am trying to achieve. I tried first with doctest and it threw up an error:
"AttributeError: 'function' object has no attribute 'c_square'".
# counter.py
from tkinter import *
import doctest
count = 0
delay = 1000
class MyClass:
def __init__(self, master):
master.geometry("1000x500")
master.resizable(0, 0)
master.title("Display a counter")
frame1 = Frame(master)
frame1.pack()
label1 = Label(frame1, font = ('Courier', 15 , 'bold'))
label1.grid(row = 0, column = 0)
self.my_counter(label1)
label2 = Label(frame1, font = ('Courier', 15 , 'bold'))
label2.grid(row = 0, column = 1)
self.square_of_count(label2)
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text = string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_c_square(number):
"""
>>> test_c_square(2)
4
"""
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font = ('Courier', 15 , 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
""" # main body commented out for test purposes.
root = Tk()
a = MyClass(root)
root.mainloop()
"""
doctest.testmod(verbose=True)
if __name__ == "__main__":
main()
I am using a separate test function, so that I can initialise my counter.
Then someone suggested that I try unittest, so I wrote this :
import unittest
import counter
class TestCounter(unittest.TestCase):
counter.count = 2
print("count = ", counter.count)
def square_of_count(self):
result = counter.c_square()
self.assertEqual(result, 4)
result = counter.c_square()
self.assertNotEqual(result, 3)
if __name__ == '__main__':
unittest.main()
This runs without throwing up any errors, the purpose of it is to set a value to the variable 'count' and read back the result. But I get the same response whatever value I test for, so I do not believe it is working right. I also tried variations on a theme, but I just got error messages.
Can someone please point out what I am doing wrong, I have looked about various forums and tutorials but have not seen this question asked before.
I would appreciate an answer that is easy to follow, I am asperger / dyslexic and find it difficult to learn new material. A correction with explanation would be most helpful. Thank you.
First of all, avoid this kind of nesting the functions. In your particular case I would highly suggest refactoring of a code in manner of creating some help private methods which you will call from the main ones, or even create whole new utility class:
class Util:
def _init_(self):
self.name = "Utility"
def add_two_numbers(self, first, second):
if(isinstance(first, int) and isinstance(second, int)):
return first+second
class SomeFancyClass:
def __init__(self):
self.util = Util()
self.constant = 4
# This method recursively increments a counter and displays the count.
def my_fancy_math(self, first, second):
return self.constant * self.util.add_two_numbers(first, second)
FancyVar = SomeFancyClass()
print(FancyVar.my_fancy_math(5, 6))
In case you dont want to change your code (for some reason), there is extremely dirty way to access your inner function. Again, a bit stupidly modified example made from your code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# counter.py
from tkinter import *
import doctest
import types
count = 0
delay = 1000
class MyClass:
def __init__(self, smth1):
self.something = smth1
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text=string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def test_function1(self, first, second):
return first+second
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_function(self, st1):
print(st1)
def test_c_square(number):
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font=('Courier', 15, 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
doctest.testmod(verbose=True)
if __name__ == '__main__':
# main()
print('done')
test_function = types.FunctionType(MyClass.square_of_count.__code__.co_consts[1],
{}, None, (), ())
obj = MyClass("Hi")
sum1 = test_function("", 1, 2)
print(sum1)
I want to make a python program to look like this
so I have made a code similar looking this:
from Tkinter import *
import Tkinter
import tkMessageBox
top=Tkinter.Tk()
def and1(a,b):
print int(a and b)
def or1(a,b):
print int(a or b)
def not1(a):
print int(not a)
def xor1(a,b):
print int((a and not b) or (not a and b))
def exit1(top):
top.destroy()
def exit2(top):
top.destroy()
def expl():
top=Tkinter.Tk()
l1=Label(top,text="Number 1").grid(row=0,column=0)
e1=Entry(top,bd=5)
e1.grid(row=0,column=1)
e3=Entry(top,bd=5)
l3=Label(top,text="Binary Number 1").grid(row=0,column=2)
e3.grid(row=0,column=3)
l2=Label(top,text="Number 2").grid(row=1,column=0)
e2=Entry(top,bd=5)
e2.grid(row=1,column=1)
l4=Label(top,text="Binary Number 2").grid(row=1,column=2)
e4=Entry(top,bd=5)
e4.grid(row=1,column=3)
l5=Label(top,text="t.f.p.r.s").grid(row=2,column=2) #says text from previous radiobutton selection
e5=Entry(top,bd=5)
e5.grid(row=2,column=3)
l6=Label(top,text="Decimal Result").grid(row=3,column=1)
e6=Entry(top,bd=5)
e6.grid(row=3,column=2)
b1=Tkinter.Button(top,bd=5,text="Exit",command=lambda top=top:exit2(top)).grid(row=4,column=0)
top.mainloop()
L1=Label(top,text="Number 1").grid(row=0,column=0)
E1=Entry(top,bd=5)
E1.grid(row=0,column=1)
L2=Label(top,text="Number 2").grid(row=0,column=2)
E2=Entry(top,bd=5)
E2.grid(row=0,column=3)
var=IntVar()
R1=Radiobutton(top,text="AND",variable=var,value=1,command="and1")
R1.grid(row=1,column=0)
R2=Radiobutton(top,text="OR",variable=var,value=2,command="or1")
R2.grid(row=1,column=1)
R3=Radiobutton(top,text="NOT",variable=var,value=3,command="not1")
R3.grid(row=2,column=0)
R4=Radiobutton(top,text="XOR",variable=var,value=4,command="xor1")
R4.grid(row=2,column=1)
label=Label(top)
label.grid()
B1=Tkinter.Button(top,text="Result is:",command="result",bd=5)
B1.grid(row=3,column=0)
B2=Tkinter.Button(top,text="Explanation",command=expl,bd=5)
B2.grid(row=3,column=1)
B3=Tkinter.Button(top,bd=5,text="Exit",command=lambda top=top:exit1(top)).grid(row=3,column=2)
L3=Label(top,text="Result is:").grid(row=4,column=0)
E3=Entry(top,bd=5)
E3.grid(row=4,column=1)
top.mainloop()
Now modified. I want that user should input values in first frame and get result accordingly, also on explanation click, other frame opens and explains using that previous values only.
I don't know what to say. I prefer not to completely solve the problem for you, but I wanted to get a better understanding of Python's Tkinker. Read up on classes, it will help in the future.
#!/usr/bin/python
from Tkinter import *
import Tkinter
import tkMessageBox
top=Tkinter.Tk()
res = 0
tfprs = ""
def and1(a,b):
global res
res = int(a and b)
def or1(a,b):
global res
res = int(a | b)
def not1(a):
global res
res = int(not a)
def xor1(a,b):
global res
res = int((a and not b) or (not a and b))
def result(event=None):
global top,res,E3
text = StringVar()
E3=Entry(top,textvariable=text,bd=5)
E3.grid(row=4,column=1)
text.set(str(res))
def exit1(top):
top.destroy()
def exit2(top):
top.destroy()
def selected():
global tfprs
tfprs = var.get()
def expl(a,b):
global top,tfprs,res
binary1 = StringVar()
binary2 = StringVar()
top1=Tkinter.Toplevel(top)
value1 = IntVar()
l1=Label(top1,text="Number 1").grid(row=0,column=0)
e1=Entry(top1,textvariable = value1,bd=5)
value1.set(a)
e1.grid(row=0,column=1)
e3=Entry(top1,textvariable = binary1,bd=5)
l3=Label(top1,text="Binary Number 1").grid(row=0,column=2)
binary1.set(format(a,'b'))
e3.grid(row=0,column=3)
value2 = IntVar()
l2=Label(top1,text="Number 2").grid(row=1,column=0)
e2=Entry(top1,textvariable = value2,bd=5)
value2.set(b)
e2.grid(row=1,column=1)
l4=Label(top1,text="Binary Number 2").grid(row=1,column=2)
e4=Entry(top1,textvariable = binary2,bd=5)
binary2.set(format(b,'b'))
e4.grid(row=1,column=3)
l5=Label(top1,text="t.f.p.r.s").grid(row=2,column=2) #says text from previous radiobutton selection
operator = StringVar()
e5=Entry(top1,textvariable = operator,bd=5)
operator.set(tfprs)
operator.set(tfprs)
e5.grid(row=2,column=3)
dres = IntVar()
l6=Label(top1,text="Decimal Result").grid(row=3,column=1)
e6=Entry(top1,textvariable = dres ,bd=5)
dres.set(res)
e6.grid(row=3,column=2)
b1=Tkinter.Button(top1,bd=5,text="Exit",command=lambda top=top1:exit2(top1)).grid(row=4,column=0)
top.mainloop()
def dotwo(a,b):
selected()
expl(a,b)
num1 = IntVar()
L1=Label(top,text="Number 1").grid(row=0,column=0)
E1=Entry(top,textvariable = num1,bd=5)
num1.set(1)
E1.grid(row=0,column=1)
num2 = IntVar()
L2=Label(top,text="Number 2").grid(row=0,column=2)
E2=Entry(top,textvariable =num2,bd=5)
num2.set(1)
E2.grid(row=0,column=3)
var=StringVar()
R1=Radiobutton(top,text="AND",variable=var,value="AND",command=lambda: and1(int(E1.get()),int(E2.get())))
R1.grid(row=1,column=0)
R2=Radiobutton(top,text="OR",variable=var,value="OR",command=lambda: or1(int(E1.get()),int(E2.get())))
R2.grid(row=1,column=1)
R3=Radiobutton(top,text="NOT",variable=var,value="NOT",command=lambda: not1(int(E1.get())))
R3.grid(row=2,column=0)
R4=Radiobutton(top,text="XOR",variable=var,value="XOR",command=lambda: xor1(int(E1.get()),int(E2.get())))
R4.grid(row=2,column=1)
label=Label(top)
label.grid()
B1=Tkinter.Button(top,text="Result is:",command=result,bd=5)
B1.grid(row=3,column=0)
B2=Tkinter.Button(top,text="Explanation",command=lambda:dotwo(int(E1.get()),int(E2.get())),bd=5)
B2.grid(row=3,column=1)
B3=Tkinter.Button(top,bd=5,text="Exit",command=lambda top=top:exit1(top)).grid(row=3,column=2)
L3=Label(top,text="Result is:").grid(row=4,column=0)
E3=Entry(top,bd=5)
E3.grid(row=4,column=1)
top.mainloop()
I'm currently trying to create a GUI for interacting with lines in a .txt file in order to sort the content of some freezer boxes. However it's difficult for me to interact with a specific line when i create a lot of buttons with a for-loop such as this:
def create_boxes(self):
for r in range(0,10):
for c in range(0,10):
self.button = Button(root, text='%s.%s'%(r,c),borderwidth=1 ,command= lambda: self.replace_line("Freezercontent.txt", r*10+c , input("What would you like in this slot"))).grid(row=r,column=c+5)
In the replace line function the second parameter is the linenumber the specific button needs to change. The solution i have does not work because when the lambda function is called upon with command the for-loop has finished. Meaning every button i click only changes the last line...
How can i access the buttons name given with the text="somename" argument? Or is there an even smarter way of doing it?
Thanks and kind regards Emil H.
The problem lies elsewhere.
I suggest not using lambda but instead creating a class which can be initialized during call to button with those coords of buttons.
The inner working would be in the class itself and it would know of its coords. You should create arrays of buttons also as suggested before me.
class Some:
def __init__(self, r, c):
self.r = r
self.c = c
def __call__(self):
# do what you need and access coords as self.c and self.r
Button(root, text='%s.%s' % (r,c), borderwidth=1, command=Some(r, c) ...
The way you've currently coded it, it will let you access the last button created with self.button. You could change this into a dictionary, and store them all there:
def create_boxes(self):
self.buttons = {}
for r in range(10):
for c in range(10):
text = '%s.%s' % (r, c)
self.buttons[text] = Button(root, text=text, borderwidth=1, command=...)
Then you can use self.buttons['1.1'] to get the button you need, etc.
You could use a list comprehension to store all the buttons:
def create_boxes(self):
def make_replacer(r, c):
def replacer():
prompt = "What would you like in this slot"
self.replace_line("Freezercontent.txt",
r * 10 + c,
input(prompt))).grid(row=r,column=c+5)
return replacer
self.buttons = [Button(root,
text='%s.%s' % (r,c),
borderwidth=1,
command=make_replacer(r, c))
for r in range(0,10)
for c in range(0,10)]