How do you do calculations using various variables in a toplevel window? - python

I'm creating a calculator app for my company which will be used for the calculation of certain parameters.Since there are various parameters with their respective formulas,I decided to create toplevel windows for each parameter-all linked to respective buttons. But I can't get the functions to work in the toplevel windows.
I've used def calculate(): to no avail
I expect it to work, since it works in a normal window, but it fails in a toplevel window.
def open():
ldl_window = Toplevel(root)
ldl_window.geometry('500x500')
def calculate():
tc = eval(totalChol.get())
hdl=eval (hdLipo.get())
tg=eval (trig.get ())
ldl =tc-((hdl/2)+tg)
output_label.configure(text = 'LDL: {:.1f}'.format(ldl))
totalChol.delete(0,END)
hdLipo.delete(0,END)
trig.delete(0,END)
output_label = Label(font=('Verdana', 16), bg='grey',fg='white')
tc_label = Label(ldl_window,text='TC',font=('Verdana', 15))
tc_label.grid(row=0, column=0)
hdl_label = Label(ldl_window,text='HDL',font=('Verdana', 15))
hdl_label.grid(row=1, column=0)
tg_label = Label(ldl_window,text='TG',font=('Verdana', 15))
tg_label.grid(row=2, column=0)
totalChol = Entry(ldl_window,font=('Verdana', 15), width=4)
totalChol.grid(row=0, column=1)
hdLipo= Entry(ldl_window,font=('Verdana', 15), width=4)
hdLipo.grid(row=1,column=1)
trig= Entry(ldl_window,font=('Verdana', 15), width=4)
trig.grid (row=2,column=1)
calc_button = Button(ldl_window,text='CALC', font=
('CALIBRI',15),command=calculate,bg='blue',fg='white')
calc_button.grid(row=3, column=0)
output_label.grid(row=3, column=1)
btn = Button(root, text = "Calculate LDL", command = open,
bg='blue',fg='white',font=('CALIBRI', 12))
btn.grid(row=3, column=0)

Related

retrieve selected value from a binded combobox in tkinter

I am trying to retrieve the selected value from a binded combobox.
In the below code, I have binded the combobox named “LSF_Combo” to another combobox “Queue _Combo” . I am trying to retrieve the selected value from the “Queue_Combo”, using Queue_Combo.get() method, but I am not able to do so, since its scope is limited within LSF_fields_Enable(event) inner function. I am able to retrieve the selected value of LSF_Combo using LSF_Combo.get() method.
Please let me know if anyone has suggestions for retrieving the selected value from the “Queue_Combo” combobox and furhter nested comboboxes "MT_Combo: and "Merge_Combo", so that I should be able to access and assign these to a variable outside the "LSF_Fields_Enable" function scope.
For example, If i had selected 'priority' from "Queue_Combo" and had selected "MT" from "MT_Combo", i should be able to assign these strings to variables outisde LSF_Fields_Enable(event) function. From the 'def run_program()' variable 'b' should have sting equals to 'priority' (since i have selected this) and variable 'c' should have string equals to 'MT'.
from tkinter import *
import tkinter as tk
from tkinter import ttk
root = Tk()
root.geometry("800x450")
def Gui_main():
Queue_Combo_list = ['normal', 'priority', 'devices', 'grid']
Queue_Combo = ttk.Combobox(root, values=Queue_Combo_list, width=10, state="readonly")
Merge_Combo_list = ['LST_SET_ML', 'LST_SET_EQU']
Merge_Combo = ttk.Combobox(root, values=Merge_Combo_list, width=12)
MT_Combo_list = ['MT', 'MTFLEX']
MT_Combo = ttk.Combobox(root, values=MT_Combo_list, width=10)
def LSF_Fields_Enable(event):
# global Queue_Combo, VCO_Combo, OS_Combo
VCO_1 = None
if LSF_Combo.get() == 'LSF':
# # section for Queue Type
Queue_Combo_label = tk.Label(root, text="Queue: ").grid(row=2, column=1, padx=5,sticky=W)
Queue_Combo.set("normal")
Queue_Combo.grid(row=2, column=1, padx=55, pady=5, sticky=W)
def MT_MT_flex(choice):
def Manage_run_mode(choice):
# if Merge_Combo.get() == 'LSF_SET_EQU' or 'LSF_SET_MAN':
if Merge_Combo.get() != 'LSF_SET_ML':
label = tk.Label(root, text="CPU No:").grid(row=4, column=3, padx=10,sticky=tk.W)
CPU_radio_button = tk.IntVar()
R1 = Radiobutton(root, text="2", variable=CPU_radio_button, value=1).place(x=50, y=520)
if MT_Combo.get() == 'MT':
# # section for choosing a file version
Merge_Combo_label = tk.Label(root, text="Merge: ").grid(row=6, column=2, padx=10,sticky=W)
Merge_Combo.set("LST_SET_ML")
Merge_Combo.grid(row=6, column=2, padx=65, pady=15, sticky=tk.E)
Merge_Combo.bind('<<ComboboxSelected>>',Manage_run_mode)
MT_Combo_label = tk.Label(root, text="MT/MTflex: ").grid(row=2, column=3, padx=10,sticky=W)
MT_Combo.set("MT")
MT_Combo.grid(row=2, column=4, padx=5, pady=5, sticky=tk.E)
MT_Combo.bind('<<ComboboxSelected>>',MT_MT_flex)
# LSF_Fields_Enable()
LSF_Combo_label = tk.Label(root, text="Fill: ").grid(row=2, column=0, sticky=W)
LSF_Combo_list = ['LSF', 'LOCAL']
LSF_Combo = ttk.Combobox(root, values=LSF_Combo_list, width=10, state="readonly", background='white')
LSF_Combo.set('LSF')
LSF_Combo.grid(row=2, column=0, padx=25, pady=5, sticky=W)
LSF_Combo.bind('<<ComboboxSelected>>', LSF_Fields_Enable)
Queue_Combo.bind('<<ComboboxSelected>>', lambda _: print(Queue_Combo.get()))
MT_Combo.bind('<<ComboboxSelected>>', lambda _: print(MT_Combo.get()))
Merge_Combo.bind('<<ComboboxSelected>>', lambda _: print(Merge_Combo.get()))
# a = LSF_Combo.bind("<Return", LSF_Fields_Enable)
def run_program():
a = LSF_Combo.get()
print(a)
b = Queue_Combo.get()
print(b)
c = MT_Combo.get()
d = Merge_Combo.get()
close = Button(root, text ='close', command= root.destroy).grid(row=10, column=2, pady=60, sticky=E)
check_combo_get =Button (root, text ='check_combo_get', command = run_program).grid(row=10, column=1, padx=15,pady=60, sticky=E)
root.mainloop()
if __name__ == "__main__":
Gui_main()
There is not an easy way to fix this problem in your setup.
But the solution is easy, if you just go ahead and restructure your code a little:
Define the combobox outside the LSF_Fields_Enable function and also asign its values at startup.
Queue_Combo_list = ['normal', 'priority', 'devices', 'grid']
Queue_Combo = ttk.Combobox(root, values=Queue_Combo_list, width=10, state="readonly")
Now bind the ComboboxSelected Event to whatever function you want to have (in this example a simple print).
Queue_Combo.bind('<<ComboboxSelected>>', lambda _: print(Queue_Combo.get()))
And there you go!
Now the print function is executed every time the selection changes for the queue-combobox.
Hope this helps :)
EDIT:
In the updated Code below I reformated your code to make it more readable and to achieve what you wanted to have.
The Value of the ComboBoxes are now assigned to variables ("Queue_Combo_variable", "LSF_Combo_variable").
You can access their values using:
Queue_Combo_variable.get()
I tried my best to comment the entire to be as understandable as possible. Let me now if this is how you imagined it to be!
NEW CODE:
from tkinter import ttk, Tk, Label, Button, StringVar
from tkinter.constants import W, E
def Gui_main():
# Create tkinter (window) instance
root = Tk()
root.geometry("300x250")
# Define LSF_Combox (Combobox)
LSF_Combo_variable = StringVar()
LSF_Combo_label = Label(root, text="Fill: ") # Label
LSF_Combo_label.grid(row=2, column=0, sticky=W)
LSF_Combo_list = ['LSF', 'LOCAL']
LSF_Combo = ttk.Combobox(root, values=LSF_Combo_list, textvariable=LSF_Combo_variable, width=10, state="readonly", background='white')
LSF_Combo.set('LSF')
LSF_Combo.grid(row=2, column=0, padx=25, pady=5, sticky=W) # and place it on the screen
# Define Queue_Combo (Combobox)
Queue_Combo_variable = StringVar()
Queue_Combo_label = Label(root, text="Queue: ") # Label
Queue_Combo_list = ['normal', 'priority', 'devices', 'grid']
Queue_Combo = ttk.Combobox(root, values=Queue_Combo_list, textvariable=Queue_Combo_variable, width=10, state="readonly")
# ==> The Queue_Combo_variable now always stores the value which is currently selected in the queue_combo (box)
#################################################################################################################################
#### ==> Through the following code the specfied function (LSF_Combo_changed) is always called, once the variable value changes #
#################################################################################################################################
LSF_Combo_variable.trace_add("write", lambda _0, _1, _2: LSF_Combo_changed())
Queue_Combo_variable.trace_add("write", lambda _0, _1, _2: print(Queue_Combo_variable.get()))
# If you don't understand, what all of this does, it doesn't matter just now, that you can change the print function to be the function you want to call instead!
# This function is now executed every time when the LSF_Combo (box) is changed (=> "Something has been selected in the left combobox")
def LSF_Combo_changed():
# If "LSF" has been selected, show the Queue_Combo Box
if LSF_Combo.get() == 'LSF':
Queue_Combo.set("normal")
Queue_Combo.grid(row=2, column=1, padx=55, pady=5, sticky=W)
Queue_Combo_label.grid(row=2, column=1, padx=10,sticky=W)
return Queue_Combo.get()
else: # If that hasn't been selected, "forget" the position of the Queue_Combo Box & Label ("Hide them")
Queue_Combo.grid_forget()
Queue_Combo_label.grid_forget()
return None
# Close Button
close_button = Button(root, text ='close', command= root.destroy)
close_button.grid(row=10, pady=60, sticky=E)
# Show window (tkinter instance)
root.mainloop()
if __name__ == "__main__":
Gui_main()

How to enable a disabled Button after filling Entry widgets?

I have 2 Entrys and one button. I want to make that button's state disabled until the two Entrys are filled in. How can I achieve that?
howManyStocksLabel = Label(root, text = "How many stocks do you want to evaluate?")
howManyStocksLabel.grid(row = 1, column = 0)
howManyStocksEntry = Entry(root, borderwidth = 3)
howManyStocksEntry.grid(row = 1, column = 1)
riskLabel = Label(root, text = "Enter risk %")
riskLabel.grid(row = 2, column = 0, sticky = 'w')
riskEntry = Entry(root, borderwidth = 3)
riskEntry.grid(row = 2, column = 1)
nextButton = Button(root, text = "Next!", width = 20, height = 2,state = DISABLED,
fg = 'green', bg = 'white',
command= lambda: myClick(riskEntry, howManyStocksEntry, var))
nextButton.grid(row = 4, column = 1)
I tried to check whether the entries are filled in or not by:
if(riskEntry.get() != ""):
....................
but it just doesn't work.
You need to check if the value is there after the user inputs it. Also, you can use tk.StringVar() as a text variable and trace it.
Here is an example:
import tkinter as tk
def check_entry(*args):
if r1.get() and r2.get():
b1.config(state='normal')
else:
b1.config(state='disabled')
root = tk.Tk()
r1 = tk.StringVar(master=root)
r2 = tk.StringVar(master=root)
e1 = tk.Entry(root, textvariable=r1)
e1.pack()
e2 = tk.Entry(root, textvariable=r2)
e2.pack()
b1 = tk.Button(root, text='Click Me!', state='disabled')
b1.pack()
r1.trace('w', check_entry)
r2.trace('w', check_entry)
root.mainloop()
You will need to use a binding on your entry widgets to check whether the user has entered anything into the entry or not.
This code will fire the check_entry function every time the user types in one of the entry boxes:
riskEntry.bind('<KeyRelease>', check_entry)
howManyStocksEntry.bind('<KeyRelease>', check_entry)
Then your check_entry function might look like this:
def check_entry(event): #event is required for all functions that use a binding
if riskEntry.get() and howManyStocksEntry.get():
nextButton.config(state=NORMAL)
else:
nextButton.config(state=DISABLED)
One way to do it would be to utilize the ability to "validate" their contents that Entry widgets support — see adding validation to an Entry widget — but make it check the contents of multiple Entry widgets and change the state of a Button accordingly.
Below shows how to do this via a helper class that encapsulates most of the messy details needed to make doing it relatively painless. Any number of Entry widgets can be "watched", so it scales well to handle forms consisting of many more than merely two entries.
from functools import partial
import tkinter as tk
from tkinter.constants import *
class ButtonEnabler:
""" Enable/disable a Button depending on whether all specified Entry widgets
are non-empty (i.e. contain at least one character).
"""
def __init__(self, button, *entries):
self.button = button
self.entries = entries
for entry in self.entries:
func = root.register(partial(self.check_entries, entry))
entry.config(validate="key", validatecommand=(func, '%P'))
def check_entries(self, this_entry, new_value):
other_entries = (entry for entry in self.entries if entry is not this_entry)
all_others_filled = all(entry.get() for entry in other_entries)
combined = bool(new_value) and all_others_filled
self.button.config(state=NORMAL if combined else DISABLED)
return True
root = tk.Tk()
howManyStocksLabel = tk.Label(root, text="How many stocks do you want to evaluate?")
howManyStocksLabel.grid(row=1, column=0)
howManyStocksEntry = tk.Entry(root, borderwidth=3)
howManyStocksEntry.grid(row=1, column=1)
riskLabel = tk.Label(root, text="Enter risk %")
riskLabel.grid(row=2, column=0, sticky='w')
riskEntry = tk.Entry(root, borderwidth=3)
riskEntry.grid(row=2, column=1)
nextButton = tk.Button(root, text="Next!", width=20, height=2, state=DISABLED,
fg='green', bg='white', disabledforeground='light grey',
command=lambda: myClick(riskEntry, howManyStocksEntry, var))
nextButton.grid(row=4, column=1)
enabler = ButtonEnabler(nextButton, howManyStocksEntry, riskEntry)
root.mainloop()

Python GUI with user input area similar to excel

I am attempting to create a GUI that allows for users to copy and paste data straight into the interface. There will be three columns and anywhere between 1 - 500 rows with the possibility of 3,000+ The raw text will come via email, word, PDF, or excel so I need the user input field to be similar to excel in that you can copy/paste more than 1 line at a time.
I have followed a couple YouTube guides on creating tables/grids with tkinter however I cannot figure out a way to allow text entry via copy/paste.
One of the only ways I found to make tables with tkinter since tktable isn't a part of it is the following example. This still does not allow for user input via copy/paste.
class Table:
def __init__(self,root):
# code for creating table
for i in range(total_rows):
for j in range(total_columns):
self.e = Entry(root, width=20, fg='blue',
font=('Arial',16,'bold'))
self.e.grid(row=i, column=j)
self.e.insert(END, lst[i][j])
# take the data
lst = [(1,'Raj','Mumbai',19),
(2,'Aaryan','Pune',18),
(3,'Vaishnavi','Mumbai',20),
(4,'Rachna','Mumbai',21),
(5,'Shubham','Delhi',21)]
# find total number of rows and
# columns in list
total_rows = len(lst)
total_columns = len(lst[0])
# create root window
root = Tk()
t = Table(root)
root.mainloop()
Can anyone suggest an alternative to tkinter or point me in the direction of a guide for this type of user input?
I finally figured out why I couldn't get python to allow me to use tkinter and was able to do what I was trying to do, more or less.
import tkinter as tk
from tkinter import *
from tkinter import BOTH, END, LEFT
HEIGHT = 970
WIDTH = 1500
root = tk.Tk()
root.title( 'Daves Generator')
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()
background_image = tk.PhotoImage(file='david.png')
background_label = tk.Label(root, image=background_image)
background_label.place(relwidth=1, relheight=1)
frame_one = tk.Frame(root, bg='#003d70',bd=5)
frame_one.place(relx=0.17, rely=.15, relwidth=0.3,relheight=0.8, anchor='n')
customer_description = tk.Text(frame_one, state=NORMAL, width=125, wrap=WORD, height=500,font=("Courier", 8))
customer_description.place(relwidth=1, relheight=1)
frame_two = tk.Frame(root, bg='#003d70',bd=5)
frame_two.place(relx=0.5, rely=.15, relwidth=0.3,relheight=0.8, anchor='n')
dave_description = tk.Text(frame_two, width=125, height=500,font=("Courier", 8))
dave_description.place(relwidth=1, relheight=1)
frame_three = tk.Frame(root, bg='#003d70',bd=5)
frame_three.place(relx=0.83, rely=.15, relwidth=0.3,relheight=0.8, anchor='n')
sap_code = tk.Label(frame_three, width=125, height=500,font=("Courier", 8))
sap_code.place(relwidth=1, relheight=1)
header_frame_one = tk.Label(root, text="Customer Descriptions", font=("Courier", 14), fg='#003d70')
header_frame_one.place(relx=0.17, rely=0.13, relwidth=0.2, relheight=0.025, anchor='n')
header_frame_two = tk.Label(root, text="PJ Descriptions", font=("Courier", 14), fg='#003d70')
header_frame_two.place(relx=0.5, rely=0.13, relwidth=0.2, relheight=0.025, anchor='n')
header_frame_three = tk.Label(root, text="SAP Code", font=("Courier", 14), fg='#003d70')
header_frame_three.place(relx=0.83, rely=0.13, relwidth=0.2, relheight=0.025, anchor='n')
generate_button = tk.Button(root,text="Generate!", font=("Courier", 14), fg='white', bg='#003d70', command=lambda: get_customer_description())
generate_button.place(relx=0.5, rely=0.08, relwidth=0.15, relheight=0.025, anchor='n')

How to format the text input from Text Widget in Tkinter

In my tkinter program I'm collecting text from the user using Text widget, this is later printed on the screen using a label widget. Although I'm able to print it onto the screen, the text is all center aligned. Since what I'm collecting is a procedure for something it gets difficult to read, so I need it to be left aligned.
This is my Procedure method -
Once the procedure is collected it is stored into a dictionary
def Procedure(self):
textfield = Text(gui, height=30, width=82)
textfield.place(x="20", y="100")
procedure_label = LabelWidget(self.screen, "Procedure", "Courier", 40)
procedure_label.Call().place(x="220", y="20")
button_save = Button(gui, text="Next", padx="50", pady="20", bg="lightgrey",
command=partial(self.CheckPage, 4, procedure=textfield))
button_save.place(x="250", y="600")
This is how I'm printing my proceudre
proc_text_label = ""
for i in fullDictProc:
proc_text_label_temp = Label(root, text=i, wraplength=900)
proc_text_label = proc_text_label_temp
proc_text_label.config(font=("Courier", 12))
proc_text_label.place(x=70, y=250)
Here is a minimal reproducible code to demonstrate the problem
Run it and see the alignment of the text.
from tkinter import *
from functools import partial
gui = Tk()
gui.geometry("700x700")
def printit(textfield):
procedure_list = [textfield.get("1.0", "end-1c")]
textfield.place_forget()
proc_text_label = ""
for i in procedure_list:
proc_text_label_temp = Label(gui, text=i, wraplength=900)
proc_text_label = proc_text_label_temp
proc_text_label.config(font=("Courier", 12))
proc_text_label.place(x=70, y=250)
textfield = Text(gui, height=30, width=82)
textfield.place(x="20", y="100")
button_save = Button(gui, text="Next", padx="50", pady="20", bg="lightgrey",
command=partial(printit, textfield))
button_save.place(x=500, y=600)
gui.mainloop()
I think what you are looking for might be justify:
proc_text_label.config(justify='left')
Have a look at The Tkinter Label Widget
I think what you're looking for is the anchor parameter.
This is how it worked with your minimal example:
from tkinter import *
from functools import partial
gui = Tk()
gui.geometry("700x700")
def printit(textfield):
procedure_list = [textfield.get("1.0", "end-1c")]
textfield.place_forget()
proc_text_label = ""
for i in procedure_list:
proc_text_label_temp = Label(gui, text=i, wraplength=900,
anchor='w',
bg='blue',
width=50)
proc_text_label = proc_text_label_temp
proc_text_label.config(font=("Courier", 12))
proc_text_label.place(x=70, y=250)
textfield = Text(gui, height=30, width=82)
textfield.place(x="20", y="100")
button_save = Button(gui, text="Next", padx="50", pady="20", bg="lightgrey",
command=partial(printit, textfield))
button_save.place(x=500, y=600)
gui.mainloop()

Making a Tkinter Listbox with Scrolll

I'm currently trying to make a Listbox with a Scroll bar on the side appear on my Tkinter Window. I can't figure out how to make the Scrollbar size the same size as my listbox. Heres my code:
global R3
global lb
R3 = Tk()
gg = "white"
g = "blue"
R3.geometry('720x720')
R3.title(username + " Dropbox")
R3.resizable(width=False, height=False)
logoutbt = Button(R3, text="Logout", width=10, height=2, bg=g, fg=gg, font="5", relief=RAISED, overrelief=RIDGE, command=rectologout)
upload = Button(R3, text="Upload", width=10, height=2, bg=g, fg=gg, font="5", relief=RAISED, overrelief=RIDGE, command=rectoupload)
logoutbt.place(x=220, y=500)
upload.place(x=480, y=500)
button1 = Button(R3, text='Receive file', width=10, height=2, bg=g, fg=gg, font="5", relief=RAISED, overrelief=RIDGE,command = get_file)
lb = Listbox(R3, height=6,width = 15)
s.send("RETREIVEA-"+username)
file_list = s.recv(1024).split("-")
if file_list == [""]:
button1.config(state = DISABLED)
for file in file_list:
lb.insert("end", file)
yscroll = Scrollbar(R3, orient=VERTICAL)
lb['yscrollcommand'] = yscroll.set
yscroll['command'] = lb.yview
lb.place(x=280,y=200)
yscroll.place(x=370,y=200)
button1.place(x=400, y=200)
R3.mainloop()
Any suggestions on how to do it?
First of all, please read how to create a Minimal, Complete and Verifiable example.
Your code lacks imports and references non-initialized objects / variables / functions.
How to achieve what you want?
Either use grid instead of place or pass height parameters to lb.place(..., height=<whatever you want>) and yscroll.place(..., height=<whatever you want>)

Categories