It is two weeks now that I full-time look for a solution to a relevant problem: How to create Commands within dynamic loops? The subject is simple (to image it I took food elements): to initiate the programme, I have a number of packs to determine (for instance 5, then press Enter). Then thanks to created Comboboxes, for each case, specify whether it is fruits, vegetable, or other. The aim of each Combobox is to create again a Widget proper to value executed. The problem is that when Bind is executed, loops works for the whole sequence and duplicate anterior widget. the problem may be resolved by adding an instruction at line 48 such as:
if 'Selection'.get() == self.Combo_Food_liste[i]:
but I look for 'Selection' meaning Object I cannot reach it! Or if you have a better Idea, I would be very pleased to know it!
Thank you!!
from ttk import *
from Tkinter import *
class Postproc:
def __init__(self, parent, title):
self.variable_Title_Frame = []
self.variable_Title =[]
self.Combo_Food_Select=[]
self.Combo_Food_stock=[]
self.Combo_Food_liste=[]
self.Combo_Food_Pos_Select={}
self.Combo_Food_Pos_stock={}
self.Combo_Food_Pos_liste={}
self.Combo_Food_Pos_Entry={}
self.parent = parent
self.parent.title(title)
self.parent.protocol("WM_DELETE_WINDOW", self.Closes)
Frame1 = Frame(self.parent,borderwidth=.5,relief=GROOVE)
Frame1.pack(side=LEFT,padx=1,pady=1)
### Define the number of packs then press 'Enter'
self.variables_Title_number=IntVar()
self.Field_Ouputs = Entry(Frame1, textvariable=self.variables_Title_number, bg ='bisque', fg='maroon')
self.Field_Ouputs.pack(side=LEFT,padx=1,pady=1)
self.Field_Ouputs.bind("<Return>", self.Launch_Outputs)
def Closes(self, event=None):
self.parent.destroy()
def Launch_Outputs(self, event=None):
self.Nombr = self.variables_Title_number.get()
self.Create_Outputs(self.Nombr)
def Create_Outputs(self, Nombr):
#### Define for each pack the kind of food
for i in range (0,Nombr):
self.variable_Title_Frame.append(Frame(MainWin,borderwidth=.5,relief=GROOVE))
self.variable_Title_Frame[i].pack(side= LEFT,expand=YES)
Label(self.variable_Title_Frame[i],text=i).pack(padx=1,pady=1)
self.Combo_Food_Select.append(StringVar())
self.Combo_Food_stock.append(('Fruit', 'Vegetable', 'Other'))
self.Combo_Food_liste.append(Combobox(self.variable_Title_Frame[i], textvariable = self.Combo_Food_Select[i], \
values = self.Combo_Food_stock[i], state = 'readonly'))
self.Combo_Food_liste[i].bind("<<ComboboxSelected>>", self.Position_Magnitude)
self.Combo_Food_liste[i].pack()
def Position_Magnitude(self, index):
##### Define for each kind the variety
for i in range (0, self.Nombr):
if self.Combo_Food_liste[i].get() == 'Fruit':
self.Combo_Food_Pos_Select[i]=(StringVar())
self.Combo_Food_Pos_stock[i]=(['Apple', 'Orange'])
self.Combo_Food_Pos_liste[i]=(Combobox(self.variable_Title_Frame[i], textvariable = self.Combo_Food_Pos_Select[i], \
values = self.Combo_Food_Pos_stock[i], state = 'readonly'))
self.Combo_Food_Pos_liste[i].pack(side=BOTTOM)
if self.Combo_Food_liste[i].get() == 'Vegetable':
self.Combo_Food_Pos_Select[i]=(StringVar())
self.Combo_Food_Pos_stock[i]=(['Tomatoe', 'Pepper', 'Peas'])
self.Combo_Food_Pos_liste[i]=(Combobox(self.variable_Title_Frame[i], textvariable = self.Combo_Food_Pos_Select[i], \
values = self.Combo_Food_Pos_stock[i], state = 'readonly'))
self.Combo_Food_Pos_liste[i].pack(side=BOTTOM)
if self.Combo_Food_liste[i].get() == 'Other':
self.Combo_Food_Pos_Select[i]=(StringVar())
self.Combo_Food_Pos_Entry[i]=Entry(self.variable_Title_Frame[i], textvariable=self.Combo_Food_Pos_Select[i], bg ='bisque', fg='maroon')
self.Combo_Food_Pos_Select[i].set("Specify")
self.Combo_Food_Pos_Entry[i].pack(side=BOTTOM)
if self.Combo_Food_liste[i].get() == "":
next
if __name__ == '__main__':
MainWin = Tk()
app = Postproc(MainWin, "Main Window")
MainWin.mainloop()
You can use lambda function to send i to Position_Magnitude()
self.Combo_Food_liste[i].bind("<<ComboboxSelected>>", lambda event, index=i:self.Position_Magnitude(event,index))
In Position_Magnitude you can use event.widget in place of self.Combo_Food_liste[i]
from ttk import *
from Tkinter import *
class Postproc:
def __init__(self, parent, title):
self.variable_Title_Frame = []
self.variable_Title =[]
self.Combo_Food_Select=[]
self.Combo_Food_stock=[]
self.Combo_Food_liste=[]
self.Combo_Food_Pos_Select={}
self.Combo_Food_Pos_stock={}
self.Combo_Food_Pos_liste={}
self.Combo_Food_Pos_Entry={}
self.parent = parent
self.parent.title(title)
self.parent.protocol("WM_DELETE_WINDOW", self.Closes)
Frame1 = Frame(self.parent,borderwidth=.5,relief=GROOVE)
Frame1.pack(side=LEFT,padx=1,pady=1)
### Define the number of packs then press 'Enter'
self.variables_Title_number=IntVar()
self.Field_Ouputs = Entry(Frame1, textvariable=self.variables_Title_number, bg ='bisque', fg='maroon')
self.Field_Ouputs.pack(side=LEFT,padx=1,pady=1)
self.Field_Ouputs.bind("<Return>", self.Launch_Outputs)
def Closes(self, event=None):
self.parent.destroy()
def Launch_Outputs(self, event=None):
self.Nombr = self.variables_Title_number.get()
self.Create_Outputs(self.Nombr)
def Create_Outputs(self, Nombr):
#### Define for each pack the kind of food
for i in range(Nombr):
self.variable_Title_Frame.append(Frame(MainWin,borderwidth=.5,relief=GROOVE))
self.variable_Title_Frame[i].pack(side= LEFT,expand=YES)
Label(self.variable_Title_Frame[i],text=i).pack(padx=1,pady=1)
self.Combo_Food_Select.append(StringVar())
self.Combo_Food_stock.append(('Fruit', 'Vegetable', 'Other'))
self.Combo_Food_liste.append(Combobox(self.variable_Title_Frame[i], textvariable = self.Combo_Food_Select[i], \
values = self.Combo_Food_stock[i], state = 'readonly'))
self.Combo_Food_liste[i].bind("<<ComboboxSelected>>", lambda event, index=i:self.Position_Magnitude(event,index))
self.Combo_Food_liste[i].pack()
def Position_Magnitude(self, event, index):
#print event.widget, index
if event.widget.get() == 'Fruit':
self.Combo_Food_Pos_Select[index]=(StringVar())
self.Combo_Food_Pos_stock[index]=(['Apple', 'Orange'])
self.Combo_Food_Pos_liste[index]=(Combobox(self.variable_Title_Frame[index], textvariable = self.Combo_Food_Pos_Select[index], \
values = self.Combo_Food_Pos_stock[index], state = 'readonly'))
self.Combo_Food_Pos_liste[index].pack(side=BOTTOM)
if event.widget.get() == 'Vegetable':
self.Combo_Food_Pos_Select[index]=(StringVar())
self.Combo_Food_Pos_stock[index]=(['Tomatoe', 'Pepper', 'Peas'])
self.Combo_Food_Pos_liste[index]=(Combobox(self.variable_Title_Frame[index], textvariable = self.Combo_Food_Pos_Select[index], \
values = self.Combo_Food_Pos_stock[index], state = 'readonly'))
self.Combo_Food_Pos_liste[index].pack(side=BOTTOM)
if event.widget.get() == 'Other':
self.Combo_Food_Pos_Select[index]=(StringVar())
self.Combo_Food_Pos_Entry[index]=Entry(self.variable_Title_Frame[index], textvariable=self.Combo_Food_Pos_Select[index], bg ='bisque', fg='maroon')
self.Combo_Food_Pos_Select[index].set("Specify")
self.Combo_Food_Pos_Entry[index].pack(side=BOTTOM)
if event.widget.get() == "":
next
if __name__ == '__main__':
MainWin = Tk()
app = Postproc(MainWin, "Main Window")
MainWin.mainloop()
EDIT:
by the way: you will have to remove old combobox/entry if you select new thing in top combobox
def Position_Magnitude(self, event, index):
#print event.widget, index
try:
if self.Combo_Food_Pos_liste[index]:
self.Combo_Food_Pos_liste[index].pack_forget()
except:
pass
try:
if self.Combo_Food_Pos_Entry[index]:
self.Combo_Food_Pos_Entry[index].pack_forget()
except:
pass
if event.widget.get() == 'Fruit':
self.Combo_Food_Pos_Select[index]=(StringVar())
self.Combo_Food_Pos_stock[index]=(['Apple', 'Orange'])
self.Combo_Food_Pos_liste[index]=(Combobox(self.variable_Title_Frame[index], textvariable = self.Combo_Food_Pos_Select[index], \
values = self.Combo_Food_Pos_stock[index], state = 'readonly'))
self.Combo_Food_Pos_liste[index].pack(side=BOTTOM)
if event.widget.get() == 'Vegetable':
self.Combo_Food_Pos_Select[index]=(StringVar())
self.Combo_Food_Pos_stock[index]=(['Tomatoe', 'Pepper', 'Peas'])
self.Combo_Food_Pos_liste[index]=(Combobox(self.variable_Title_Frame[index], textvariable = self.Combo_Food_Pos_Select[index], \
values = self.Combo_Food_Pos_stock[index], state = 'readonly'))
self.Combo_Food_Pos_liste[index].pack(side=BOTTOM)
if event.widget.get() == 'Other':
self.Combo_Food_Pos_Select[index]=(StringVar())
self.Combo_Food_Pos_Entry[index]=Entry(self.variable_Title_Frame[index], textvariable=self.Combo_Food_Pos_Select[index], bg ='bisque', fg='maroon')
self.Combo_Food_Pos_Select[index].set("Specify")
self.Combo_Food_Pos_Entry[index].pack(side=BOTTOM)
if event.widget.get() == "":
next
Related
I am using Tkinter/Python to get the selected option on the window when the button is pressed. On clicking the button - only the value from list should get printed. As of now, it's printing any value typed into combobox. Any help/suggestion will be appreciated.
from tkinter import *
from tkinter import ttk
class Run:
def __init__(self, master):
self.lst = ["Apples", "Oranges", "Pears", "Grapes"]
self.master = master
self.toplevels = 0
master.title("CB")
master.geometry("300x200")
label = Label(master, text = "ABC")
label.pack()
self.combo_box = ttk.Combobox(master,value=self.lst)
self.combo_box.set('')
self.combo_box.pack()
self.combo_box.bind('<KeyRelease>', self.search)
button = Button(master, text="btn", command=self.make_new)#self.make_new)
button.pack()
def make_new(self):
if not self.toplevels:
#new = tk.Toplevel(self.master)
my_label = Label(self.master, text=self.combo_box.get(), font=("Helvetica", 14))#, fg="grey")
my_label.pack(padx=10, pady=10)
self.toplevels += 1
def search(self, event):
value = event.widget.get()
if value == '':
self.combo_box['values'] = self.lst
else:
data = []
for item in self.lst:
if value.lower() in item.lower():
data.append(item)
self.combo_box['values'] = data
master1 = Tk()
i = Run(master1)
master1.mainloop()
The answer is simple. You just have to a condition which will detect if the text of the combo box is in the list or not. That condition would be: if self.combo_box.get() in self.lst:. And for the corrected code:
from tkinter import *
from tkinter import ttk
class Run:
def __init__(self, master):
self.my_label = Label(master, text="")
self.lst = ["Apples", "Oranges", "Pears", "Grapes"]
self.master = master
self.toplevels = 0
master.title("CB")
master.geometry("300x200")
label = Label(master, text="ABC")
label.pack()
self.combo_box = ttk.Combobox(master, value=self.lst)
self.combo_box.set('')
self.combo_box.pack()
self.combo_box.bind('<KeyRelease>', self.search)
button = Button(master, text="btn", command=self.make_new) # self.make_new)
button.pack()
def make_new(self):
if not self.toplevels:
# new = tk.Toplevel(self.master)
if self.combo_box.get() in self.lst:
self.my_label.config(text=self.combo_box.get(), font=("Helvetica", 14)) # , fg="grey")
self.my_label.pack(padx=10, pady=10)
self.toplevels += 1
def search(self, event):
value = event.widget.get()
if value == '':
self.combo_box['values'] = self.lst
else:
data = []
for item in self.lst:
if value.lower() in item.lower():
data.append(item)
self.combo_box['values'] = data
master1 = Tk()
i = Run(master1)
master1.mainloop()
Hope this helps
I I have 2 functions and the second function should run after the button in the first one has been clicked. This works fine, however I need the number that has been entered to go into a variable and so far the .get() function is not working and im not sure what to do.
I have looked at a lot of different examples, including login and sign up gui's however none of them have been able to help.
from tkinter import *
import tkinter.messagebox as box
def enter_rle_1():
enter_rle = Tk() #do not remove
enter_rle.title('Enter RLE') #do not remove
frame = Frame(enter_rle) #do not remove
label_linecount = Label(enter_rle,text = 'Linecount:')
label_linecount.pack(padx=15,pady= 5)
linecount = Entry(enter_rle,bd =5)
linecount.pack(padx=15, pady=5)
ok_button = Button(enter_rle, text="Next", command = linecount_button_clicked)
ok_button.pack(side = RIGHT , padx =5)
frame.pack(padx=100,pady = 19)
enter_rle.mainloop()
def linecount_button_clicked():
Linecount = linecount.get()
if int(Linecount) < 3:
tm.showinfo("Error", "Enter a number over 3")
elif int(Linecount) > 1000000000:
tm.showinfo("Error", "Enter a number under 1,000,000,000")
else:
print("fdsfd")
enter_rle_1()
I expect there to be a popup telling me the number is too big or too small, depending on wether the number is or not, and if it is a good number, i just have it set as a print as some code to test to see if it works before i move on.
Define a String variable for the Entry widget (Make sure it is global defined):
global linecount_STR
linecount_STR = StringVar()
linecount_STR.set('Enter value here')
linecount = Entry(enter_rle,bd =5,textvariable=linecount_STR)
linecount.pack(padx=15, pady=5)
The number entered there can then be read with int(linecount_STR.get()).
i suggest an OO approach, look this code
#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class Main(ttk.Frame):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.vcmd = (self.register(self.validate), '%d', '%P', '%S')
self.linecount = tk.IntVar()
self.init_ui()
def init_ui(self):
self.pack(fill=tk.BOTH, expand=1)
f = ttk.Frame()
ttk.Label(f, text = "Linecount").pack()
self.txTest = ttk.Entry(f,
validate='key',
validatecommand=self.vcmd,
textvariable=self.linecount).pack()
w = ttk.Frame()
ttk.Button(w, text="Next", command=self.on_callback).pack()
ttk.Button(w, text="Close", command=self.on_close).pack()
f.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
def on_callback(self,):
#print ("self.text = {}".format(self.linecount.get()))
x = self.linecount.get()
if x < 3:
msg = "Enter a number over 3"
elif x > 1000000000:
msg = "Enter a number under 1,000,000,000"
else:
msg = "You ahve enter {0}".format(x)
messagebox.showinfo(self.parent.title(), msg, parent=self)
def on_close(self):
self.parent.on_exit()
def validate(self, action, value, text,):
# action=1 -> insert
if action == '1':
if text in '0123456789':
try:
int(value)
return True
except ValueError:
return False
else:
return False
else:
return True
class App(tk.Tk):
"""Start here"""
def __init__(self):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_exit)
self.set_title()
self.set_style()
frame = Main(self,)
frame.pack(fill=tk.BOTH, expand=1)
def set_style(self):
self.style = ttk.Style()
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
self.style.theme_use("clam")
def set_title(self):
s = "{0}".format('Enter RLE')
self.title(s)
def on_exit(self):
"""Close all"""
if messagebox.askokcancel(self.title(), "Do you want to quit?", parent=self):
self.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()
notice this line at the begin....
self.linecount = tk.IntVar()# declare an integer variable
self.vcmd = (self.register(self.validate), '%d', '%P', '%S')#register a function to allow only integer in your text widget.
I have one Entry field and popup Keypad window.Whenever user clicked on entry field it accept input through Keypad.One of the problem which I faced it whenever I am reading current cursor position while entering user input it always showing cursor position at 'zero' and also user is not seeing any cursor in entry field while entering input through Keypad.
Code:
from tkinter import *
from tkinter import simpledialog
class Gui(Toplevel):
def __init__(self, parent,*args):
Toplevel.__init__(self, parent)
self.title('User input window')
self.geometry('450x350')
self.EntryVar=StringVar()
self.label = Label(self, text='User Input:', width=15, background='white', justify=CENTER,
font='-weight bold')
self.entry = Entry(self, width=15, background='white', textvariable=self.EntryVar,
font='-weight bold')
self.label.grid(row=2,padx=10, pady=5, column=0, sticky='E')
self.entry.grid(row=2,padx=10, pady=5, column=1, sticky='E')
self.entry.bind('<FocusIn>', self.keypad_popup)
def keypad_popup(self,event):
new = numPad(self, event.widget)
class numPad(simpledialog.Dialog):
def __init__(self, parent, *args):
self.focus = args[0]
self.parent = parent
self.top = Toplevel(parent)
self.top.title('Keypad')
self.top.grab_set()
self.createWidgets()
def createWidgets(self):
btn_list = ['6', '1', '2', '3', '0','C', 'D']
r = 1
c = 0
n = 0
btn = []
for label in btn_list:
cmd = lambda x=label: self.click(x)
button = Button(self.top, text=label, width=10, height=5, command=cmd)
btn.append(button)
btn[-1].grid(row=r, column=c)
n += 1
c += 1
if c == 3:
c = 0
r += 1
def click(self, label):
if label == 'D' and self.focus == self.parent.entry:
currentText = self.parent.EntryVar.get()
self.parent.EntryVar.set(currentText[:-1])
elif label == 'C':
self.top.destroy()
self.top.master.focus()
elif self.focus == self.parent.entry:
currentText = self.parent.entry.get()
self.parent.EntryVar.set(currentText + label)
print('Cursor position:', self.parent.entry.index(INSERT))
if __name__ == '__main__':
root = Tk()
root.title('root window')
root.geometry("150x150")
app = Gui(root)
root.mainloop()
Setting the value via the associated variable doesn't change the cursor position, unless the previous position was beyond the end of the new value. Since the cursor position starts at 0 and you don't change it, it's always going to be zero.
If you want to make sure the insertion cursor is at the end after you change the value, you can use the icursor method.
Example:
self.parent.entry.icursor("end")
I'm new here and new in PY, I'm trying to write a simple GUI with Tkinter (py 2.7.10) where there are two buttons: the first one starts printing stuff and the second one quits.
I'd like the first button to change the text after the first click from "START" to "STOP" and of course to stop the loop, so I can pause instead of closing and reopen every time.
Also feel free to give any advice to improve it :)
I hope it's clear, here is the code.
import random, time
from Tkinter import *
START, STOP = "start", "stop"
class AppBase:
def __init__(self, root):
self.myRoot = root
self.frame1 = Frame(root)
self.frame1["background"] = "LightSteelBlue"
self.frame1.pack()
self.delay = Scale(self.frame1, from_=100, to=0)
self.delay.pack(side = LEFT, padx=5, pady=15)
self.label0 = Label(self.frame1, text="Notes", background="LightSteelBlue", foreground="darkblue")
self.label0.pack(padx=5, pady=15)
self.label1 = Label(self.frame1, text="NOTE", background="LightSteelBlue", foreground="SteelBlue")
self.label1.pack(padx=30, pady=10)
self.label2 = Label(self.frame1, text="STRING", background="LightSteelBlue", foreground="SteelBlue")
self.label2.pack(padx=30, pady=7)
self.label3 = Label(self.frame1, text="FINGER", background="LightSteelBlue", foreground="SteelBlue")
self.label3.pack(padx=30, pady=7)
self.puls1 = Button(self.frame1)
self.puls1.configure(text = "Start", background = "CadetBlue", borderwidth = 3, command = self.generate_notes)
self.puls1.pack(side = LEFT, padx=5, pady=15)
self.puls2 = Button(self.frame1)
self.puls2.configure(text = "Exit", background = "CadetBlue", borderwidth = 3)
self.puls2.pack(side = LEFT, padx=5, pady=15)
self.puls2.bind("<Button-1>", self.close_all)
self.notes_process=1
def generate_notes(self):
self.notes = ['DO','DO#','RE','RE#','MI','MI#','FA','FA#','SOL','SOL#','LA','LA#','SI','SI#']
self.strings = ['1^ corda','2^ corda','3^ corda','4^ corda','5^ corda','6^ corda']
self.fingers = ['Indice','Medio','Anulare','Mignolo']
self.note = random.randrange(0, len(self.notes))
self.string = random.randrange(0, len(self.strings))
self.finger = random.randrange(0, len(self.fingers))
self.timer=self.delay.get()
if self.timer == '':
self.timer = 500
elif int(self.timer) < 1:
self.timer = 500
else:
self.timer=int(self.delay.get())*100
self.label1["text"] = self.notes[self.note]
self.label2["text"] = self.strings[self.string]
self.label3["text"] = self.fingers[self.finger]
self.myRoot.after(self.timer, self.generate_notes)
def close_all(self, evento):
self.myRoot.destroy()
self.myRoot.quit()
def main():
master = Tk()
master.title("Notes")
appBase = AppBase(master)
master.mainloop()
main()
I found a solution, thanks to everybody for their help and of course if you want to keep talking about different and (sure) better way to do, you are more than welcome!
Here my solution:
step 1, add this to the button:
self.puls1.bind("<Button-1>", self.puls1Press1)
step 2, add a new variable:
self.active = True
step 3, create a new function:
def puls1Press1(self, evento):
if self.puls1["text"] == "Start":
self.puls1["text"] = "Stop"
self.active = True
else:
self.puls1["text"] = "Start"
self.active = False
step 4, modify the function that I want to stop:
def generate_notes(self):
if self.active == True:
[some code]
[some code]
else:
return
You need to save the return value of the after, so that you can use it when you cancel the loop using after_cancel(the_return_value_of_after).
def generate_notes(self):
if self.puls1['text'] == 'Start':
# Change button text to Stop, and call the original loop function
self.puls1['text'] = 'Stop'
self._generate_notes()
else:
# cancel timer
self.puls1['text'] = 'Start'
self.myRoot.after_cancel(self.timer_handle)
def _generate_notes(self):
...(old codes)..
self.timer_handle = self.myRoot.after(self.timer, self._generate_notes)
StringVar() from variable class can be used to update text as well as a looping condition. Example code:
ButtonText=StringVar()
ButtonText.set("START")
button1 = tkinter.Button(self.frame1, text=ButtonText, width=25, command= lambda: do_something(ButtonText))
Elsewhere where you are looping check for the value of the variable:
My_Loop():
if(ButtonText.get()=="STOP"):
break
else:
#some print statements
Now in function do_something(ButtonText), which will be called after each button press, change the string to "STOP" or vice versa :
do_something(ButtonText):
if(ButtonText.get()=="START): #Change text
ButtonText.set("STOP")
else:
ButtonText.set("START") #Change text and call function to loop again
My_Loop()
Hope this helps.
I thought I know the fundamentals of python, but this problem seems to prove that wrong.
Problem is, when I pass a class to a function, that function will not recognize the class that I passed, but instead just recognize that parent class.
This is the class.
from tkinter import *
from one_sample_t_test_dialog import One_T_Test_Dialog
from about_us_dialog import About_Us_Dialog
class Gui(Frame):
def __init__(self, master):
Frame.__init__(self, master, background="white")
self._master = master
# Main Window
frame = Frame(master, width = 800, height = 600)
self._master.title("Statistics Program")
# Menus
menu = Menu(master)
master.config(menu=menu)
# --Tests
test_menu = Menu(menu)
menu.add_cascade(label = "Tests", menu = test_menu)
# ----T-Tests
t_test_menu = Menu(test_menu)
test_menu.add_cascade(label = "T-Tests", menu = t_test_menu)
t_test_menu.add_command(label="One Sample t-test", command = self.one_sample_t_test)
t_test_menu.add_command(label="Two Sample t-test", command = self.two_sample_t_test)
t_test_menu.add_command(label="Paired t-test", command = self.about_us)
# --Help
help_menu = Menu(menu)
menu.add_cascade(label = "Help", menu = help_menu)
help_menu.add_command(label="About Us", command = self.about_us)
# Toolbar
# --t-test
toolbar = Frame(master)
l = Label(toolbar, text="Mean Comparison:")
l.pack(side=LEFT, padx = 5, pady = 5)
b=Button(toolbar, text = "One Sample t-test", command=self.one_sample_t_test)
b.pack(side=LEFT)
b=Button(toolbar, text = "Two Sample t-test", command=self.two_sample_t_test)
b.pack(side=LEFT)
b=Button(toolbar, text = "Paired t-test", command=self.two_sample_t_test)
b.pack(side=LEFT)
# --anova
l=Label(toolbar, text="ANOVA:")
l.pack(side=LEFT, padx = 5, pady = 5)
b=Button(toolbar, text = "One Way Anova", command=self.two_sample_t_test)
b.pack(side=LEFT)
# --Multiple-comparison Tests
toolbar_02 = Frame(master)
l=Label(toolbar_02, text="Multiple Mean Comparison:")
l.pack(side=LEFT, padx = 5, pady = 5)
b=Button(toolbar_02, text = "Tukey", command=self.two_sample_t_test)
b.pack(side=LEFT)
b=Button(toolbar_02, text = "Bonferroni", command=self.two_sample_t_test)
b.pack(side=LEFT)
toolbar.pack(fill=BOTH)
toolbar_02.pack(fill=BOTH)
# Spreadsheet.
self.canvas = canvas = Canvas(self._master)
self.canvas_frame = canvas_frame = Frame(canvas)
# Scrollbars
vbar=Scrollbar(self._master,orient=VERTICAL, command=self.canvas.yview)
hbar=Scrollbar(self._master,orient=HORIZONTAL, command=self.canvas.xview)
# Further configuration
canvas.configure(yscrollcommand=vbar.set, xscrollcommand=hbar.set)
# Initialize scrollbars
vbar.pack(side=RIGHT,fill=Y)
hbar.pack(side=BOTTOM,fill=X)
canvas.pack(side=LEFT, expand=True, fill="both")
canvas.create_window((4,4), window=canvas_frame, anchor="nw")
canvas_frame.bind("<Configure>", self.OnFrameConfigure)
self.grid()
#canvas_frame.pack()
self._master.geometry("800x600+50+50")
#self.pack(fill=BOTH, expand=1)
def get_master(self):
return self._master
def OnFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def about_us(self):
d = About_Us_Dialog(self._master)
root.wait_window(d.parent)
def grid(self):
"""
Make the grid here.
"""
grid_frame = self.canvas_frame
self.entry = []
for i in range(40):
self.entry.append([])
for i in range(len(self.entry)):
for j in range(80):
self.entry[i].append(Entry(grid_frame, width=10))
self.entry[i][j].grid(row=j, column=i)
# grid_frame.pack(padx=2, pady=2)
def one_sample_t_test(self):
d = One_T_Test_Dialog(self)
value = self._master.wait_window(d.parent)
# Check if an error occured.
result = None # We will store the result here.
if value is None:
return
else:
# perform the t-test here.
pass
# If we made it at this point, there's no error and
# the result have been acquired. We can now display
# the result.
def two_sample_t_test(self):
# Testing Ground
#print(self.get_variables())
#print(self.get_values(3))
pass
def get_variables(self):
"""
This method will return a dictionary of variable names and their corresponding
index, that is located in index zero of the double array. For instance,
self.entry[3][0] is a variable name, so is self.entry[5][0], and so on.
"""
variable_name_dict = {}
for i in range(len(self.entry)):
temp = self.entry[i][0].get()
if temp is not "":
variable_name_dict[i] = temp
return variable_name_dict
def get_values(self, variable_index):
"""
This method will return a list of values that is located under the variable.
Use this in conjunction with get_variables().
"""
values = []
if self.entry[variable_index][0] is not "": # Make sure that it's not empty.
for v in self.entry[variable_index]:
if v.get() is not "":
values.append(v.get())
# Since the first cell is in the column is always a variable name, we can
# pop the first element.
values.pop(0)
return values
root = Tk()
app = Gui(root)
root.mainloop()
This is the other class, with a method being called by the class above. the class above pass itself as an argument.
from tkinter import *
from tkinter import messagebox
import dialog
class One_T_Test_Dialog(dialog.Dialog):
def body(self, gui):
master = gui.get_master()
# Entry Labels.
Label(master, text="Mean:").grid(row=0)
Label(master, text="Standard Deviation:").grid(row=1)
Label(master, text="Sample Size:").grid(row=2)
Label(master, text="Sample Size:").grid(row=3)
Label(master, text="Test Value:").grid(row=4)
# Data entry class members.
# The for loop initialize the list as an entry list.
num_of_entry = 5
self.entry = [] #entry list
for i in range(num_of_entry):
self.entry.append(Entry(master))
# Data entry location initialization.
for i in range(num_of_entry):
self.entry[i].grid(row=i,column=1)
# Or, the user can just select a mean from the drop down list and
# enteryt the test value.
Label(master, text="Select Values Instead:").grid(column = 0, row=5)
self.dropdown_val = StringVar(master)
# initial value
self.dropdown_val.set('Select a values.')
choices = ['red', 'green', 'blue', 'yellow','white', 'magenta']
option = OptionMenu(master, self.dropdown_val, *choices).grid(column = 1, row=5)
button = Button(master, text="check value slected").grid(column=1, row=6)
# Further initialization.
# --At the Test Value, or null hypothesis, we want to have a default
# value. Assuming this is a 151/252 level course, the default value
# is always 0.
self.entry[4].insert(0, "0")
return self.entry[0] # initial focus
def apply(self):
# Collect the data first.
data_list = []
for e in self.entry:
data_list.append(e.get())
# Validate
for d in data_list:
# Make sure it's not empty.
# Make sure the value is float.
empty_flag = False
not_float_flag = False
if len(d) == 0:
empty_flag = True
if empty_flag is False:
try:
float(d)
except ValueError:
not_float_flag = True
if empty_flag is True or not_float_flag is True:
# Report an input error.
if empty_flag is True and not_float_flag is False:
messagebox.showerror("INPUT ERROR", "There's an empty input box.")
elif not_float_flag is True and empty_flag is False:
messagebox.showerror("INPUT ERROR", "Check your input. Make sure its a number.")
elif not_float_flag is True and empty_flag is True:
messagebox.showerror("INPUT ERROR", "There's an empty input box and non-numerical input.")
return None
# If everything went well, convert the validated data.
for i in range(len(data_list)):
data_list[i] = float(data_list[i])
return data_list
The problem is the line
master = gui.get_master()
in the second class gives an error because
AttributeError: 'Frame' object has no attribute 'get_master'
Frame being the parent of the class Gui.