Creating check-button using for loop and extracting the value (whether it is checked or unchecked)
Hello all,
I am a beginner to python GUI and planning to create a GUI with many check-buttons and write the value of each check-button in a text file on clicking a submit button.
from tkinter import *
import tkinter as tk
fields_output=["option 01","option 02","option 03","option 04","option 05","option 06","option 07","option 08","option 09","option 10","option 11"]
def my_function_01():
f = open("C:\\Users\\atulh\\Desktop\\Atul_Python\\demofile2.txt", "a")
f.write("Following is the summary !")
f.write("\n")
r=0
for each_field in fields_output:
f.write(each_field + " = " )
f.write("\n")
f.close()
root = tk.Tk()
frame_lh =LabelFrame(root, text="Field Outputs")
frame_lh.grid(row=1, sticky=W)
r=0
for each_field in range(len(fields_output)):
tk.Checkbutton(frame_lh,text=fields_output[each_field],).grid(row=r, sticky=W)
r=r+1
b = tk.Button(root,text="Submit_data",command=my_function_01()).grid(row=1,column=1)
A few things:
Import tkinter only once. Several imports of the same module may become confusing. Importing as tk is the usual way.
To get the states of the Checkbuttons you'll have to associate each one with a variable, and then save references to all these variables. I have saved them to a dictionary with the field as key.
I changed the for loop to be more Pythonic. The loop is over the fields_output list and the enumerate() function generates the index starting from 0.
In the loop I associate each Checkbutton with a BooleanVar() and save a reference to the button_dict. Later the my_function_01() uses the button_dict to get the states of all the Checkbuttons.
Added root.mainloop() at the end. If you are developing the program in IDLE the program will work regardless using the mainloop in IDLE. But the program may not run outside your development environment.
I changed the file path and the options list.
import tkinter as tk
fields_output = ["option 01", "option 02", "option 03", "option 04"]
def my_function_01():
f = open("demofile2.txt", "a")
f.write("Following is the summary !")
f.write("\n")
for field in fields_output:
f.write(field + " = " + str(button_dict[field].get()))
f.write("\n")
f.close()
root = tk.Tk()
frame_lh = tk.LabelFrame(root, text="Field Outputs")
frame_lh.grid(row=0, column=0, sticky=tk.W, padx=10, pady=10)
button_dict = {}
for index, field in enumerate(fields_output):
var = tk.BooleanVar() # Create a variable for each Checkbutton
c = tk.Checkbutton(frame_lh, text=field, variable=var)
c.grid(row=index, sticky=tk.W)
button_dict[field] = var # save reference to the variable
b = tk.Button(root, text="Submit_data", command=my_function_01)
b.grid(row=0, column=1, padx=10, pady=10)
root.mainloop()
Related
When using the feeder button, the script for F runs through entirely through to the print before the 'master' box appears, then does not react to the inputs from the 'master' box. This results in the output being 0.0 kW because the input is a long decimals followed by an L, when what I, the user inputs is 8777
I have been roaming the internet for about a day now with no luck finding anything. I am very new to TK but have been trying to learn it.
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry1 = tk.Entry(master)
entry1.grid(row=0, column=1)
button2 = tk.Button(master,
text=' Confirm',
command=entry1.get())
button2.pack()
button2.grid(row=0, column=2)
fn = entry1.pack()
print fn
feed = filtered['Feeder']==fn
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
print 'The total PV on this feeder is:', AcPv, 'kW'
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
button = tk.Button(frame,
text='Exit',
fg='red',
command=quit)
button.pack()
button.grid(row=1, column=1)
Fee = tk.Button(frame,
text='Feeder',
command=F)
Fee.pack()
Fee.grid(row=0, column=1)
root.mainloop()
Expected 27.702
Output 0.0
Given that I will not be posting the csv,
entry1/fn should be 8777
currently 'none'
UPDATE
I am now receiving an output of PY_VAR when printing fn, I understand that the code is running all the way through before taking an input. Any recommendations for how to take the input before the filters are run?
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry1 = tk.Entry(master)
entry1.grid(row=0, column=1)
button2 = tk.Button(master,
text=' Confirm',
command=entry1.get())
button2.grid(row=0, column=2)
fn = tk.IntVar()
print fn
feed = filtered['Feeder']==fn
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
print 'The total PV on this feeder is:', AcPv, 'kW'
For those interested in the final code (Which worked for me):
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry = tk.Entry(master)
entry.grid(row=0, column=1)
def pint():
data = entry.get()
master.destroy()
feed = filtered['Feeder']==data
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
fdf = tk.Tk()
tk.Label(fdf, text = AcPv).grid(row=0)
button4 = tk.Button(fdf,
text = ' Exit',
fg='red',
command=fdf.destroy)
button4.grid(row=1)
button2 = tk.Button(master,
text=' Confirm',
command = pint)
button2.grid(row=0, column=2)
button3 = tk.Button(master,
text = ' Exit',
fg='red',
command=master.destroy)
button3.grid(row=0, column=3)
master.mainloop()
There a few mistake in your code that lead to the different output you have received.
First, why is your code executing without showing the master box :
Your tkinter need a mainloop() call if you want a persistent window.
master.mainloop()
You did that right with your root, but your master lacks that mainloop. This line is what basically keeping your GUI alive and looping over it for changes until it is destroyed one way or another. You need to add this line after creating your widgets in order to be able to interact with the window. Anything written after this line (but still indented in the definition) will be executed when your window is closed, either manually or with the command :
master.destroy()
Next, although this will yield a working window, you can still interact with your root window while the master window is up, which can lead to problems if you are expecting variable from master. I suggest you read about the Toplevel widget which is made specifically for cases like yours. (http://effbot.org/tkinterbook/toplevel.htm) Alternatively, you could also use tkinter's tkSimpleDialog.askinteger or askfloat functions which seems perfect for your application.
Finally, the entry allows you to write text but how to access the text? you can use Entry1.get() to extract the content of the entry, or as you have started to to in your update, you can assign a tkinter variable to the entry. This variable will be updated as you change write strings or numbers in the entry. To bind the variable to your entry, you must state it in the entry's creation :
fn = tk.StringVar(value = '000')
entry1 = tk.Entry(master, textvariable = fn)
*Note, this will require your fn variable to be initialized before the entry. Also, you can initialize a value for that variable upon creation
the tkinter variable is an object which is why when you print it, you get PY_VAR. (the type of object) To access the value, you need to use the get() method :
print(fn.get())
I made a fairly simple To - Do task manager or task list, I put on a Tkinter Label on the bottom right corner that displays the number of tasks in the data file (the .txt where the tasks are stored) But I can't seem to get it to update after the number changes either by adding a task or deleting one. I'm trying to make the StringVar work, though there might be another solution. I'm pretty new to python, I hope I managed to explain myself.
I've tried converting the "with open data.txt" into a function and then calling it so it gets updated but that gave me multiple errors as I apparently can't set a StringVar that's outside a function from within a function, or at least I couldn't do it. I also thought of counting the items in the Textbox instead of the text file, but sadly I still couldn't make it update after the first time it works (after I open the program).
As I said before, I'm very new to programming so I apologize if my code isn't very understandable, I tried to keep things orderly. I thought a simple while True: would solve it but I had forgotten that wouldn't be possible in Tkinter. I have a theory maybe using threads could fix it but I don't think that would a very efficient fix.
I'm sorry to show most of my code but I'm not entirely sure on what could be relevant or not
root = Tk()
# List
Lista = []
# Defines
def update_list():
clear_list()
for task in Lista:
Box.insert("end", task)
def clear_list():
Box.delete(0,"end")
def window(sike):
sike.title('To Do')
sike.geometry("450x450+750+200")
def del_task():
task = Box.get(ACTIVE)
if task in Lista:
Lista.remove(task)
update_list()
with open ("data.txt", "w") as data:
data.writelines(Lista)
def add_task():
task = Entry1.get()
if task !="":
with open ("data.txt", "a") as data:
data.write(task)
data.write('\n')
Lista.append(task)
Entry1.delete(0, "end")
update_list()
# numbers variable (here's the issue)
with open("data.txt", "r") as data:
numero = data.readlines()
numberof = len(numero)
var = StringVar()
var.set(numberof)
# Inside the window
window(root)
Title = Label(root, text='My To-Do List', font = "default 10 bold")
Title.place(x=173, y=20)
Quote = Label(root, text='"You can’t build a reputation based on what you are going to do"', font="default 10 italic")
Quote.place(x=35, y=55)
By = Label(root, text='-Henry Ford', font = "default 10 italic")
By.place(x=180, y=85)
AddTask = ttk.Button(root, text='Add Task')
AddTask.place(x=70, y=150)
AddTask.config(command=add_task)
DeleteTask = ttk.Button(root, text='Delete Task')
DeleteTask.place(x=70, y=300)
DeleteTask.config(command=del_task)
Entry1 = Entry(root, width=35)
Entry1.place(x=200, y=150)
Box = Listbox(root, width=35, height=10)
Box.place(x=200, y=240)
numberoftasks = Label(root, textvariable=var)
numberoftasks.place(x=420, y=420)
# Importing from list save
with open ("data.txt") as data:
line = data.readlines()
for thing in line:
Lista.append(thing)
update_list()
# Just the loop
root.mainloop()
Folks I'm trying to make a tool which gets user path and file name in one entry and new file name with path in another entry, My aim is to use os.rename(oldname, newname) to rename the given file, but its throwing me some error.
My code
from tkinter import *
import os
def Rename_Function(*args):
os.rename(oldname2,newname)
oldname.set(oldname)#"Renamed Successfully !!! ")
root = Tk()
root.title("MyPython App")
root.geometry("250x250+100+50")
oldname = StringVar()
oldname2= StringVar()
newname= StringVar()
Title1 = Label(root,text="FileName (with path):")
Title1.grid(row=0, column=0)
Oldfilename = Entry(root, textvariable=oldname2)
Oldfilename.grid(row=0, column=1)
Title2 = Label(root, text="New Filename:")
Title2.grid(row=1, column=0)
Newfilename = Entry(root, textvariable=newname)
Newfilename.grid(row=1, column=1)
RenameButton = Button(root, text="RENAME MY FILE", command=Rename_Function)
RenameButton.grid(row=3,columnspan=2, sticky="NWES")
FinalOutput = Label(textvariable=oldname)
FinalOutput.grid(row=4, columnspan=2, sticky = "NWES")
root.mainloop()
I'm getting the above error when I click the button,
Can someone guide me how to make it work.
I have a doubt that os.rename() function should be accessed in some other way since its another module's function. Since I'm learner I don't have any clue how to use them effeciently. Please guide me and explain me so that I would understand this concept better.
To expand upon what #SuperSaiyan said in the comment(s).
You are using a StringVar, which has the method .get() available to it. When you pass the variable which is set to this stringvar you are just passing the reference to this object. You need to actually use the .get() method to get the string.
e.g. - oldname2.get()
Also, for selecting the path you could just use a filedialog, and use os.path.splitext to get the base path + entry in the renaming widget to use as the second parameter with os.rename
You are using StringVar, whereas rename needs Strings. Use oldname.get():
import tkinter as tk
import os
def rename(oldname, oldname2, newname):
os.rename(oldname2.get(),newname.get())
oldname.set("Renamed Successfully !!! ")
def main():
root = tk.Tk()
root.title("MyPython App")
root.geometry("250x250+100+50")
oldname = tk.StringVar()
oldname2= tk.StringVar()
newname= tk.StringVar()
tk.Label(root, text="FileName (with path):").grid(row=0, column=0)
tk.Entry(root, textvariable=oldname2).grid(row=0, column=1)
tk.Label(root, text="New Filename:").grid(row=1, column=0)
tk.Entry(root, textvariable=newname).grid(row=1, column=1)
tk.Button(root, text="RENAME MY FILE", command=lambda: rename(oldname, oldname2, newname)).grid(row=3,columnspan=2, sticky="NWES")
tk.Label(textvariable=oldname).grid(row=4, columnspan=2, sticky = "NWES")
root.mainloop()
if __name__ == '__main__':
main()
I am trying to make a simple GUI calculator just for addition/subtraction in the beginning. I am able to print the result to the console but I want to print it to the Entry box like the First Name entry box for example but not able to do it. I would really appreciate if you could help.(*Please neglect the alignment right now of the buttons I am focusing on the functioning, trying to get it right)
from Tkinter import *
import tkMessageBox
import sys
class scanner:
list1 = []
def __init__(self,parent):
self.entrytext = StringVar()
self.entrytext1 = StringVar()
Label(root, text="first name", width=10).grid(row=0,column=0)
Entry(root, textvariable=self.entrytext, width=10).grid(row=0,column=1)
Label(root, text="last name", width=10).grid(row=1,column=0)
Entry(root, textvariable=self.entrytext1, width=10).grid(row=1,column=1)
Button(root, text="ADD", command=self.add).grid()
Button(root, text="SUBTRACT", command=self.subtract).grid()
def add(self):
global a
global b
self.a=int(self.entrytext.get())
self.b=int(self.entrytext1.get())
print "result is", self.a+self.b
def subtract(self):
global a
global b
self.a=int(self.entrytext.get())
self.b=int(self.entrytext1.get())
print "result is", self.a-self.b
root= Tk()
root.geometry("300x300")
calc = scanner(root)
root.mainloop()
If you want to show the result of the operation as a label's text, just create a new label and configure it with the text option and the string you are printing as its value. As a side note, you don't need the global statements, and the use of instance variables is not necessary either. However, it is very important to check that the content of the entries are actually valid numbers:
def __init__(self,parent):
# ...
self.result = Label(root, text='')
self.result.grid(row=4, column=0)
def add(self):
try:
a = int(self.entrytext.get())
b = int(self.entrytext1.get())
self.result.config(text=str(a+b))
except ValueError:
print("Incorrect values")
To add entry text to the widget, use the insert method. To replace the current text, you can call delete before you insert the new text.
e = Entry(master)
e.pack()
e.delete(0, END)
e.insert(0, "a default value")
The first parameter in the delete method is which number character to delete from and the second parameter is where to delete too. Notice how END is a tkinter variable.
The parameters for the insert function is where the text will be inserted too, and the second parameter is what will be inserted.
In the future, I recommend going to Effbot and reading about the widget that you are trying to use to find out all about it.
I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?
It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.
You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.
A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.
you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)
Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()