This code works fine.
CalculateButton = tk.Button(self.root, text="Calculate", command=lambda: calc.GrandTotal()).grid(row=6, column=0, sticky=tk.W+tk.E)
But this code results in an error: "NameError: global name 'app' is not defined"
CalculateButton = tk.Button(self.root, text="Calculate", command=calc.GrandTotal()).grid(row=6, column=0, sticky=tk.W+tk.E)
So why is it that removing Lambda causes an error?
Source code itself is:
# -*- coding: cp1252 -*-
import Tkinter as tk
import tkMessageBox
# Classes
class Application(tk.Frame):
def __init__(self):
# Create G.U.I. Framework
self.root = tk.Tk()
tk.Frame.__init__(self)
self.root.title("Job Estimator")
self.root.geometry("290x152")
self.root.resizable(0,0)
# Create G.U.I. Widgets
tk.Label(self.root, text="Labour: " + unichr(163) + "40.00 x Hours") .grid(row=0, column=0, sticky=tk.W)
tk.Label(self.root, text="Travel: " + unichr(163) + "1.00 x Miles") .grid(row=1, column=0, sticky=tk.W)
tk.Label(self.root, text="Plastic: " + unichr(163) + "2.00 x Metres").grid(row=2, column=0, sticky=tk.W)
tk.Label(self.root, text="Copper: " + unichr(163) + "3.00 x Metres").grid(row=3, column=0, sticky=tk.W)
tk.Label(self.root, text="Chrome: " + unichr(163) + "4.00 x Metres") .grid(row=4, column=0, sticky=tk.W)
tk.Label(self.root, text="Total: " + unichr(163)) .grid(row=5, column=0, sticky=tk.W)
self.totalLabel = tk.Label(self.root, text="0.00")
self.totalLabel.grid(row=5, column=0, sticky=tk.W, padx=42, pady=0)
self.LabourInput = tk.Entry(self.root)
self.LabourInput.grid(row=0, column=1)
self.LabourInput.insert(0, "0")
self.TravelInput = tk.Entry(self.root)
self.TravelInput.grid(row=1, column=1)
self.TravelInput.insert(0, "0")
self.PlasticInput = tk.Entry(self.root)
self.PlasticInput.grid(row=2, column=1)
self.PlasticInput.insert(0, "0")
self.CopperInput = tk.Entry(self.root)
self.CopperInput.grid(row=3, column=1)
self.CopperInput.insert(0, "0")
self.ChromeInput = tk.Entry(self.root)
self.ChromeInput.grid(row=4, column=1)
self.ChromeInput.insert(0, "0")
CalculateButton = tk.Button(self.root, text="Calculate", command=calc.GrandTotal()).grid(row=6, column=0, sticky=tk.W+tk.E)
class Calculator():
def __init__(self):
pass
def Multiply(self, number, rate):
try:
NumFloat = float(number)
RateFloat = float(rate)
return NumFloat * RateFloat
except (ValueError):
raise tkMessageBox.showerror("Error", "One or more text fields contains non-numerical characters.")
def GrandTotal(self): # Adds each entry field to produce and return a grand total.
# Set Variables
self.LabourTotal = self.Multiply(app.LabourInput. get(), 40)
self.TravelTotal = self.Multiply(app.TravelInput. get(), 1)
self.PlasticTotal = self.Multiply(app.PlasticInput.get(), 2)
self.CopperTotal = self.Multiply(app.CopperInput. get(), 3)
self.ChromeTotal = self.Multiply(app.ChromeInput. get(), 4)
self.CompleteTotal = self.LabourTotal + self.TravelTotal + self.PlasticTotal + self.CopperTotal + self.ChromeTotal
return app.totalLabel.config(text=self.CompleteTotal) # Return the total value.
calc = Calculator()
app = Application()
app.mainloop()
Any ideas?
app is not defined until after the Application() instance is created, which means that Application.__init__ must have completed first.
By removing the lambda, you directly call the calc.GrandTotal() method, and that method relies on app already existing. It does not, as Application.__init__ is not done yet.
The whole point of the command argument however is to pass in something that will be called later. That's why the lambda works, it produces a function to call calc.GrantTotal() later on, when the Calculate button is pressed. By calling it directly you short-circuited this normal path.
You can pass in calc.GrantTotal without calling it, by removing the ():
CalculateButton = tk.Button(
self.root, text="Calculate", command=calc.GrandTotal)
CalculateButton.grid(row=6, column=0, sticky=tk.W+tk.E)
Note that I called the Button.grid() method in a separate expression. Button.grid() returns None; there is no point in storing that return value in a variable. Store the tk.Button() return value instead.
lambda is used to create a function that, when called (i.e., when you click the button), will call calc.GrandTotal. Without it, you are assigning the return value of an immediate call to GrantTotal instead as the callback.
Related
I'm writing a simple unit converter where the user can pick which units they want to convert from two options. I'm using radio-buttons for the choice, but can't seem to get the value of the chosen one to work in the conditions at the bottom of the program.
I tried several solutions suggested here on stack overflow, but none of them worked. At one point, I got the selected() to print the value of the button, but it still didn't work in the condition. Am I missing something obvious here?
Please, note, the converter is not finished yet, there is still some more polishing to do after this issue is solved.
from tkinter import *
window = Tk()
window.title("Unit converter")
window.minsize(width=300, height=300)
window.config(padx=50, pady=50)
def lbs_kgs():
user_input = float(unit_A1.get())
result = round((user_input / 2.2046), 2)
unit_B1.config(text= f"{result}")
def mil_km():
user_input = float(unit_A1.get())
result = round((user_input * 1.6), 2)
unit_B1.config(text= result)
def selected():
return radio_state.get()
intro_label = Label(text = "What units would you like to convert?")
intro_label.grid(column=0, row=0, columnspan=4, pady=10)
radio_state = StringVar()
radiobutton1 = Radiobutton(text="Pounds to kilograms", value="pk", variable=radio_state, command=selected)
radiobutton2 = Radiobutton(text="Miles to kilometers", value="mk", variable=radio_state, command=selected)
radiobutton1.grid(column=0, row=1, columnspan=4)
radiobutton2.grid(column=0, row=2, columnspan=4)
instructions_label = Label(text = "Enter the number:")
instructions_label.grid(column=0, row=3, columnspan=4, pady=10)
unit_A1 = Entry(width=5)
unit_A1.grid(column=1, row=4, sticky="e")
unit_A1_label = Label(text = "unit A1")
unit_A1_label.grid(column=2, row=4, sticky="w")
equal_label = Label(text = "is equal to")
equal_label.grid(column=1, row=5, sticky="e")
unit_B1 = Label(text = "0")
unit_B1.grid(column=2, row=5, sticky="w")
unit_B1_label = Label(text = "result unit")
unit_B1_label.grid(column=3, row=5, sticky="w")
button = Button(text="Calculate")
button.grid(column=0, row=6, columnspan=4, pady=10)
if selected() == "pk":
button.config(command=lbs_kgs)
elif selected() == "mk":
button.config(command=mil_km)
window.mainloop()
Move the if/else check into the selected function so the conditions can be checked each time the selection changes
def selected():
selection = radio_state.get()
if selection == "pk":
button.config(command=lbs_kgs)
elif selection == "mk":
button.config(command=mil_km)
In line 29 should be radio_state = StringVar(window, '1'). Without this when executed both radiobutton are on, but that not right.
def selected():
if (selection := radio_state.get()) == "pk":
button.config(command=lbs_kgs)
elif selection == "mk":
button.config(command=mil_km)
Output:
Output pound to Kilograms:
Output Miles to Kilometers:
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()
I am working with tkinter library in python. I have a main window which has several buttons and when clicked those buttons a new window will popup which also has a button called cancel. I want to make that cancel button to all the windows.
I tried the following solution, which only closes the current window.
from tkinter import *
from tkinter import ttk
import tkinter.messagebox
import datetime
import tkinter as tk
class AlertDialog:
def __init__(self):
self.invalidDiag = tk.Toplevel()
invalidInput = tk.Label(master=self.invalidDiag,
text='Error: Invalid Input').grid(row=1, column=1)
closeButton = tk.Button(master=self.invalidDiag,
text='Close',
command=self.invalidDiag.destroy).grid(row=2, column=1)
def start(self):
# self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
self.invalidDiag.wait_window()
class QuitDialog():
def __init__(self, ):
self.quitDialog = tk.Toplevel()
warnMessage = tk.Label(master=self.quitDialog,
text='Are you sure that you want to quit? ').grid(row=1, column=1)
cancelButton = tk.Button(master= self.quitDialog ,
text='Cancel',
command = self.quitALL).grid(row=2, column=1)
def start(self):
# self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
self.quitDialog.wait_window()
def quitALL(self):
self.quitDialog.destroy()
tc =TimeConverter()
tc.destroyit()
class TimeConverter:
def __init__(self):
self.mainWindow = tk.Tk()
self.mainWindow.title("Seconds Converter")
self.results = tk.StringVar()
self.inputSecs = tk.StringVar()
secLabel = tk.Label(master=self.mainWindow,
text="Seconds:").grid(row=0, sticky="W")
resultLabel = tk.Label(master=self.mainWindow,
text="Converted Time:\n(H:M:S)").grid(row=1, sticky="W")
calcResults = tk.Label(master=self.mainWindow,
background='light gray', width=20,
textvariable=self.results,
anchor="w").grid(row=1, column=1)
secEntry = tk.Entry(master=self.mainWindow,
width=24,
textvariable=self.inputSecs).grid(row=0, column=1)
calcButton = tk.Button(master=self.mainWindow,
text='Calculate',
command=self.SecondsToHours).grid(row=2,
column=0, sticky="w")
# quitButton = tk.Button(master=self.mainWindow,
# text='Quit',
# command=self.mainWindow.destroy).grid(row=2, column=1, sticky="E")
quitButton = tk.Button(master=self.mainWindow,
text='Quit',
command=self.showQuitDialog).grid(row=3, column=1, sticky="E")
def invalidInputEntered(self):
errorDiag = AlertDialog()
errorDiag.start()
def showQuitDialog(self):
quitdialog = QuitDialog()
quitdialog.start()
def startDisplay(self) -> None:
self.mainWindow.mainloop()
def destroyit(self):
self.mainWindow.destroy()
def SecondsToHours(self):
try:
inputseconds = int(self.inputSecs.get())
seconds = int(inputseconds % 60)
minutes = int(((inputseconds - seconds) / 60) % 60)
hours = int((((inputseconds - seconds) / 60) - minutes) / 60)
tempResults = str(hours) + ':' + str(minutes) + ':' + str(seconds)
self.results.set(tempResults)
return
except ValueError:
self.invalidInputEntered()
#self.showQuitDialog()
if __name__ == '__main__':
TimeConverter().startDisplay()
You are importing tkinter 2 times here. Onces with * and ones as tk.
Just use:
import tkinter as tk
this will help you avoid overriding anything that other libraries imports or having tkinter's functions overwritten by other imports.
You have a very unorthodox way of creating your tkinter app but if you wish to keep everything as is here is what you need to change:
Lets remove the cancel button from your quitDialog window and then add a yes and no button. This will server to allow you to either say yes to destroy all windows or to say no to only destroy the quitDialog window.
First we need to add an arguement to your QuitDialog class so we can pass the any window or frame we want to it.
So add the instance argument to your QuitDialog() class like below:
class QuitDialog():
def __init__(self, instance):
self.instance = instance
Now replace:
cancelButton = tk.Button(master= self.quitDialog ,
text='Cancel',
command = self.quitALL).grid(row=2, column=1)
With:
quitButton = tk.Button(master= self.quitDialog ,
text='Yes', command = self.quitALL).grid(row=2, column=1)
cancelButton = tk.Button(master= self.quitDialog,
text='No', command = lambda: self.quitDialog.destroy()).grid(row=2, column=2)
Then lets change your quitALL() method to:
def quitALL(self):
self.quitDialog.destroy()
self.instance.destroy()
This will use our instance argument to destroy a window we pass in.
Now change your showQuitDialog() method to:
def showQuitDialog(self):
quitdialog = QuitDialog(self.mainWindow)
quitdialog.start()
As you can see we are now passing the the tk window self.mainWindow to the QuitDialog class so we can decide on weather or not to close it.
Below is the copy past version of your code that should work as you need it to:
import tkinter as tk
from tkinter import ttk
import tkinter.messagebox
import datetime
class AlertDialog:
def __init__(self):
self.invalidDiag = tk.Toplevel()
invalidInput = tk.Label(master=self.invalidDiag,
text='Error: Invalid Input').grid(row=1, column=1)
closeButton = tk.Button(master=self.invalidDiag,
text='Close',
command=self.invalidDiag.destroy).grid(row=2, column=1)
def start(self):
# self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
self.invalidDiag.wait_window()
class QuitDialog():
def __init__(self, instance):
self.instance = instance
self.quitDialog = tk.Toplevel()
warnMessage = tk.Label(master=self.quitDialog,
text='Are you sure that you want to quit? ').grid(row=1, column=1, columnspan=2)
quitButton = tk.Button(master= self.quitDialog ,
text='Yes',
command = self.quitALL).grid(row=2, column=1)
cancelButton = tk.Button(master= self.quitDialog,
text='No',
command = lambda: self.quitDialog.destroy()).grid(row=2, column=2)
def start(self):
# self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
self.quitDialog.wait_window()
def quitALL(self):
self.quitDialog.destroy()
self.instance.destroy()
class TimeConverter:
def __init__(self):
self.mainWindow = tk.Tk()
self.mainWindow.title("Seconds Converter")
self.results = tk.StringVar()
self.inputSecs = tk.StringVar()
secLabel = tk.Label(master=self.mainWindow,
text="Seconds:").grid(row=0, sticky="W")
resultLabel = tk.Label(master=self.mainWindow,
text="Converted Time:\n(H:M:S)").grid(row=1, sticky="W")
calcResults = tk.Label(master=self.mainWindow,
background='light gray', width=20,
textvariable=self.results,
anchor="w").grid(row=1, column=1)
secEntry = tk.Entry(master=self.mainWindow,
width=24,
textvariable=self.inputSecs).grid(row=0, column=1)
calcButton = tk.Button(master=self.mainWindow,
text='Calculate',
command=self.SecondsToHours).grid(row=2,
column=0, sticky="w")
quitButton = tk.Button(master=self.mainWindow,
text='Quit',
command=self.showQuitDialog).grid(row=3, column=1, sticky="E")
def invalidInputEntered(self):
errorDiag = AlertDialog()
errorDiag.start()
def showQuitDialog(self):
quitdialog = QuitDialog(self.mainWindow)
quitdialog.start()
def startDisplay(self) -> None:
self.mainWindow.mainloop()
def destroyit(self):
self.mainWindow.destroy()
def SecondsToHours(self):
try:
inputseconds = int(self.inputSecs.get())
seconds = int(inputseconds % 60)
minutes = int(((inputseconds - seconds) / 60) % 60)
hours = int((((inputseconds - seconds) / 60) - minutes) / 60)
tempResults = str(hours) + ':' + str(minutes) + ':' + str(seconds)
self.results.set(tempResults)
return
except ValueError:
self.invalidInputEntered()
#self.showQuitDialog()
if __name__ == '__main__':
TimeConverter().startDisplay()
Interesting question. As I know, you can also use just quit() in order to quit from program by closing everything.
quit()
I created a class in order to create a batch of checkbuttons as follows.
I'm trying to get the chekbutton's number to indicate which one was pressed( with no success ).
stat functio, when called, sends status of all checkbuttons.
any ideas ?
class dev_buttons2(object):
def __init__(self,master,buts_list):
self.status=[]
for i in range(len(buts_list)):
self.var = IntVar()
self.name=buts_list[i]
self.c = Checkbutton(master,text=buts_list[i], variable=self.var,
indicatoron=0,command=self.cb,width=10,height=2)
self.c.grid(column=i, padx=5,row = 10)
self.status.append(self.var)
def cb(self):
print(self.name)
def stat():
return self.status
Using Lambda function - I passed as much values as I want to arg ( see comment at code ).
class SwitchButtons:
def __init__(self, master, frame, num_of_buttons):
self.master = master
self.status = []
self.buts = []
self.leds = []
bg_window = "DeepSkyBlue4"
self.framein = Frame(frame)
self.framein.grid(padx=5, pady=5)
#Create Widgets of buttons
for i in range(num_of_buttons):
button_var = StringVar()
entry_var = IntVar()
led_var = StringVar()
t = 35
ent = Entry(self.framein, textvariable=entry_var, width=4, justify="center")
ent.grid(column=i, row=2, sticky=W, padx=t)
led = Label(self.framein, textvariable=led_var, width=4, bg="red", fg="white", relief="ridge")
led_var.set("off")
led.grid(row=0, column=i, pady=0)
c = Checkbutton(self.framein, text="Switch " + str(i), variable=button_var, indicatoron=0,
width=10, height=2, onvalue="on", offvalue="off",
command=lambda arg=[i, button_var, entry_var]: #### Use Lambda to pass several arguments to "arg"
self.cb(arg))
c.grid(column=i, padx=30, pady=5, row=1)
button_var.set("off")
mins = Label(self.framein, text="min.", width=4, justify="center", fg="black")
mins.grid(column=i, row=2, sticky=E, padx=t)
self.status.append([button_var, led_var, entry_var])
self.buts.append(c)
self.leds.append(led)
###
def cb(self, but, state='', a=''):
# but = [ switch#, switch state, delay] ## explanatory
##In use only in CB_DELAYED
if state != '':
but[1].set(state)
def switch_onoff():
if but[1].get() == "on":
self.leds[but[0]].config(bg="green")
self.status[but[0]][1].set("on")
elif but[1].get() == "off":
self.leds[but[0]].config(bg="red")
self.status[but[0]][1].set("off")
if but[2].get() > 0 and but[1].get() == "on":
a = ", Auto shutdown in %s minutes." % (but[2].get())
switch_onoff()
print("Delayed", but[1].get())
self.cb_delayed(but)
else:
switch_onoff()
self.master.loop.device_chage_state(but[0], but[1].get(), text=a)
def cb_delayed(self, but):
self.framein.after(but[2].get() * 1000, self.cb, but, "off")
l would like to create a control system for administrator on Tkinter and some functions (add, delete, update and load) are main part of control system but when l run the code , these functions do not work and there is no error message. But ,l could not figure out where the problem is. My code is still not completed yet. İf l solve it, then l will move to another step.
import tkinter
from tkinter import *
userlist = [
['Meyers', '12356'],
['Smith','abcde'],
['Jones','123abc34'],
['Barnhart','12//348'],
['Nelson','1234'],
["Prefect",'1345'],
["Zigler",'8910'],
['Smith','1298']]
def domain():
def whichSelected () :
print ("At %s of %d" % (select.curselection(), len(userlist)))
return int(select.curselection()[0])
def addEntry():
userlist.append ([nameVar.get(), passwordVar.get()])
setSelect()
def updateEntry():
userlist[whichSelected()] = [nameVar.get(), passwordVar.get()]
setSelect()
def deleteEntry():
del userlist[whichSelected()]
setSelect()
def loadEntry():
name, password = userlist[whichSelected()]
nameVar.set(name)
passwordVar.set(password)
def makeWindow():
win=Tk()
global nameVar, passwordVar, select
frame1 = Frame(win)
frame1.pack()
Label(frame1, text="Name").grid(row=0, column=0, sticky=W)
nameVar = StringVar()
name = Entry(frame1, textvariable=nameVar)
name.grid(row=0, column=1, sticky=W)
Label(frame1, text="Password").grid(row=1, column=0, sticky=W)
passwordVar= StringVar()
password= Entry(frame1, textvariable=passwordVar)
password.grid(row=1, column=1, sticky=W)
frame2 = Frame(win) # Row of buttons
frame2.pack()
b1 = Button(frame2,text=" Add ",command=addEntry)
b2 = Button(frame2,text="Update",command=updateEntry)
b3 = Button(frame2,text="Delete",command=deleteEntry)
b4 = Button(frame2,text=" Load ",command=loadEntry)
b1.pack(side=LEFT); b2.pack(side=LEFT)
b3.pack(side=LEFT); b4.pack(side=LEFT)
frame3 = Frame(win) # select of names
frame3.pack()
scroll = Scrollbar(frame3, orient=VERTICAL)
select = Listbox(frame3, yscrollcommand=scroll.set, height=6)
scroll.config (command=select.yview)
scroll.pack(side=RIGHT, fill=Y)
select.pack(side=LEFT, fill=BOTH, expand=1)
return win
def setSelect():
userlist.sort()
select.delete(0,END)
for name in userlist:
select.insert(END,name)
win=makeWindow()
setSelect()
win.mainloop()
page1=Tk()
but1=Button(page1,text="Domain",command=domain).pack()
It is bad practice to define your functions in a function and makes debugging pretty difficult. I would start by using an object to create this GUI. Object variables:
passwordVar and nameVar,
select
userlist
win
There's a lot going wrong for your code.
For instance, you don't need to import tkinter twice. Your casing of the variable names doesn't follow PEP8. You could benefit from an OOP approach.
I would suggest finding a good IDE to code in that can highlight your formatting and errors.
Take a look at the provided code:
import tkinter as tk
user_list = [
['Meyers', '12356'],
['Smith','abcde'],
['Jones','123abc34'],
['Barnhart','12//348'],
['Nelson','1234'],
["Prefect",'1345'],
["Zigler",'8910'],
['Smith','1298']]
class Domain(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.name_var = tk.StringVar()
self.password_var = tk.StringVar()
self.make_window()
def which_selected(self):
print("At %s of %d" % (self.select.curselection(), len(user_list)))
return int(self.select.curselection()[0])
def add_entry(self):
user_list.append([self.name_var.get(), self.password_var.get()])
self.set_select()
def update_entry(self):
user_list[self.which_selected()] = [
self.name_var.get(), self.password_var.get()]
self.set_select()
def delete_entry(self):
del user_list[self.which_selected()]
self.set_select()
def load_entry(self):
name, password = user_list[self.which_selected()]
self.name_var.set(name)
self.password_var.set(password)
def make_window(self):
frame1 = tk.Frame(self.parent)
frame1.pack()
tk.Label(frame1, text="Name").grid(row=0, column=0, sticky=tk.W)
name = tk.Entry(frame1, textvariable=self.name_var)
name.grid(row=0, column=1, sticky=tk.W)
tk.Label(frame1, text="Password").grid(row=1, column=0, sticky=tk.W)
password = tk.Entry(frame1, textvariable=self.password_var)
password.grid(row=1, column=1, sticky=tk.W)
frame2 = tk.Frame(self.parent) # Row of buttons
frame2.pack()
b1 = tk.Button(frame2, text=" Add ", command=self.add_entry)
b2 = tk.Button(frame2, text="Update", command=self.update_entry)
b3 = tk.Button(frame2, text="Delete", command=self.delete_entry)
b4 = tk.Button(frame2, text=" Load ", command=self.load_entry)
b1.pack(side=tk.LEFT)
b2.pack(side=tk.LEFT)
b3.pack(side=tk.LEFT)
b4.pack(side=tk.LEFT)
frame3 = tk.Frame(self.parent) # select of names
frame3.pack()
scroll = tk.Scrollbar(frame3, orient=tk.VERTICAL)
self.select = tk.Listbox(frame3, yscrollcommand=scroll.set, height=6)
scroll.config(command=self.select.yview)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.select.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
def set_select(self):
user_list.sort()
self.select.delete(0, tk.END)
for name in user_list:
self.select.insert(tk.END, name)
if __name__ == '__main__':
root = tk.Tk()
Domain(root)
root.mainloop()
Note:
There's still errors here, but I don't exactly know what you're trying to do so I've just restructured it here so you can start on a better path.