Serializing saves only the last entered value GUI tkinter - python

I am serializing my GUI to save the information.But the problem is that it is only saving the last value entered not all of them.
So now the problem is that when I click on the + button, the row gets incremented but only the last name entered is saved. I want to save all of them
def increment(self):
current_row=1
MoreButton=Button(self.listFrame,text="+",command=entry_1(self))
MoreButton.grid(column=1,row=0)
def entry_1(self):
self.entryName=Entry(self.listFrame)
self.entryName.grid(column=1,row=current_row,sticky="EW")
self.entryName.get()
nameLabel=Label(self.listFrame,text="NAME")
nameLabel.grid(column=0,row=current_row)
save_button=Button(self.listFrame,text="save",command=save_data(self))
save_button.grid(column=2,row=0)
current_row=current_row+1
def save_data(self):
data={
"Name":self.entryName.get(),
}
with open("test.json","wb") as f:
dill.dump(data,f)
def load_data(self):
with open("test.json","rb") as f:
data=dill.load(f)

Sorry for the past incorrect answer. I think the problem is that your entry_1 function creates entry boxes with the same name. This means when you try getting the text in it, it gets the text of the last one only. Here is the full code I created that creates entry's with different names. It is in a class but I don't know how you want them set out.
from Tkinter import *
import dill
import sys
boxes=[]
no_of_boxes=0
root=Tk()
current_row=1
current_box=0
data={}
class Main(object):
#this is used every time a new entry is created
def save_data(self):
global current_box
global current_row
global no_of_boxes
###this it the key. It creates the entries
###in a list so that we can access them
###without the name
boxes.append(Entry(root))
boxes[-1].grid(column=1, row=current_row)
###
try:
data["Name"+str(current_box)]=boxes[-2].get()
except:
data["Name"+str(current_box)]=boxes[-1].get()
current_row+=1
current_box+=1
no_of_boxes+=1
print no_of_boxes
print boxes
print data
with open("test.json","wb") as f:
dill.dump(data,f)
#to save when closing
def save_close(self):
global current_box
global current_row
boxes.append(Entry(root))
boxes[-1].grid(column=1, row=current_row)
data["Name"+str(current_box)]=boxes[-2].get()
with open("test.json","wb") as f:
dill.dump(data,f)
print no_of_boxes
print boxes
print data
sys.exit()
def load_data(self):
with open("test.json","rb") as f:
data=dill.load(f)
def entry_1(self):
global current_row
global no_of_boxes
nameLabel=Label(root,text="NAME")
nameLabel.grid(column=0,row=current_row)
self.save_data()
app=Main()
MoreButton=Button(root,text="+",command=app.entry_1)
MoreButton.grid(column=1,row=0)
CloseButton=Button(root, text="Close and save", command=app.save_close)
CloseButton.grid(column=2, row=0)
root.mainloop()
The saved data is saved as "Name" plus current_box in data so to get it go data["Name1"] for entry box 1 and so on.
I hope this is a better answer than my last one!
P.S if you still have problems with other parts of this code, feel free to contact me on my website.

Related

How do I update a value of a variable after a button is clicked?

def Save():
save = open("Save1.txt", "w+")
save.write(str(Coin) + "\n")
save.write(str(value))
save.close()
print("Progress Saved")
SaveBtton = Button(win, text="Save Progress", command=Save)
SaveBtton.place(x=300, y=0)
def Load():
load = open("Save1.txt", "r")
Coin = int(load.readline())
value = int(load.readline())
print("Progress Loaded")
So im trying to update a value of a variable after a button is clicked.
The value of the variable is in another txt file which I need to turn to integer form so that I can use it in my code. but my code is not updating the value of said variable.
any help is appreciated.
Here is the full code:
https://hastebin.com/kagusosiga.py
In a real app, you'd probably persist this state in an object; your Load and Save functions would be methods that share the state via self. The important thing is that the value needs to be available to both functions, and right now when you load it in Load it doesn't leave that function.
Here's a very simple non-OOP example, where Save and Load are both pure functions; Load returns the two values, and the caller saves a copy of them to make available to Save as parameters:
def Load():
load = open("Save1.txt", "r")
coin = int(load.readline())
value = int(load.readline())
print("Progress Loaded")
return coin, value
def Save(coin, value):
save = open("Save1.txt", "w+")
save.write(str(coin) + "\n")
save.write(str(value))
save.close()
print("Progress Saved")
coin, value = Load()
def save_cmd():
Save(coin, value)
SaveBtton = Button(win, text="Save Progress", command=save_cmd)
SaveBtton.place(x=300, y=0)

Calling function from another Python file

I am trying to call a function from another Python file after a button is click. I have imported the file and used the FileName.fuctionName() to run the function. The problem is my exception keeps catching. I am guessing that the data from the function being called is not being grabbed.What I am trying to do is have a user fill out a Tkinter gui then click a button. Once the button is click the user will then be asked to scan their tag (rfid) and that data will then be sent to a firebase real time database which will store the user's inputted info along with the card_id and user_id that was created when the tag was scanned.
Im kinda at a loss because other than the exception catching I am not getting any other errors, any thoughts? I have posted the code below along with comments.
error : local variable 'user_id' referenced before assignment
from tkinter import *
#Second File
import Write
from tkcalendar import DateEntry
from firebase import firebase
data = {}
global user_id
# Firebase
firebase= firebase.FirebaseApplication("https://xxxxxxx.firebaseio.com/",None)
# button click
def sub ():
global user_id
#setting Variables from user input
name = entry_1.get()
last = entry_2.get()
number = phone.get()
try:
#Calling Function from other file
Write.scan()
if Write.scan():
#getting the New User Id
user_id= new_id
#User Info being sent to the Database
data = {
'Name #': name,
'Last': last,
'Number': number,
'Card #':user_id
}
results = firebase.post('xxxxxxxx/User',data)
except Exception as e:
print(e)
# setting main frame
root = Tk()
root.geometry('850x750')
root.title("Registration Form")
label_0 = Label(root, text="Registration form",width=20,font=("bold", 20))
label_0.place(x=280,y=10)
label_1 = Label(root, text="First Name",width=20,font=("bold", 10))
label_1.place(x=80,y=65)
entry_1 = Entry(root)
entry_1.place(x=240,y=65)
label_2 = Label(root, text="Last Name",width=20,font=("bold", 10))
label_2.place(x=68,y=95)
entry_2 = Entry(root)
entry_2.place(x=240,y=95)
phoneLabel = Label(root, text="Contact Number : ",width=20,font=("bold", 10))
phoneLabel.place(x=400,y=65)
phone = Entry(root)
phone.place(x=550,y=65)
Button(root, text='Submit',command = sub,width=20,bg='brown',fg='white').place(x=180,y=600)
root.mainloop()
Write.py file being Imported
import string
from random import*
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
reader = SimpleMFRC522()
#Function being called
def scan():
try:
#Creating user hash
c = string.digits + string.ascii_letters
new_id = "".join(choice(c) for x in range(randint(25,25)))
print("Please Scan tag")
#Writing to tag
reader.write(new_id)
if reader.write(new_id):
print("Tag Scanned")
else:
print("Scan Tag First")
print("Scanning Complete")
finally:
GPIO.cleanup()
I see that the value new_id in one file isn't going to influence the value with the same name in the other file, for a similar reason as for the first problem. In both places it appears, new_id is a local variable that only exists in the enclosing function.
Another issue I see is that you're calling Write.scan() twice in a row. Do you mean to be calling it twice? I expect not.
Also, you're testing the return value of Write.scan(), but that function doesn't return a value. So I think that the code in the if block in the first file will never run.
Globals are a bad idea in general, as they're easy to get wrong and they tend to obscure what the code is really doing. "Never say never", but I'll say that I very rarely find the need for a global variable in Python. In your case, I think it would be much better to have Write.scan() return the value of the new user id instead of passing it back as a global. Since you're testing the value of Write.scan(), maybe this is what you were thinking of doing already. Here are the changes I'd make to address these three issues and hopefully get your code working the way you want...
...
def sub ():
...
try:
#Calling Function from other file
new_id = Write.scan()
if new_id:
#getting the New User Id
user_id= new_id
...
...
def scan():
try:
...
new_id = "".join(choice(c) for x in range(randint(25,25)))
...
return new_id
finally:
GPIO.cleanup()
It's impossible to tell what your problem is, because there is no place in your code that references user_id and hence the error message you cite can't come from the code you provide. However, I see a pretty common mistake that your code appears to be making that could very well account for why you expect user_id to be defined somewhere in your code and yet it is not...
In your first block of code, the global user_id is not being set by the sub function. Rather, when the sub function calls user_id=new_id, it is creating and setting a variable that is local to that function. When that function ends, the result of that call is lost and the global user_id is still undefined.
What you want is to define user_id as being global inside of the sub() function. Just add global user_id anywhere near the top of the function definition.
Here's an example of what I'm talking about:
global x
def sub():
x = 3
sub()
print(x)
result:
Traceback (most recent call last):
File "t", line 7, in <module>
print(x)
NameError: global name 'x' is not defined
whereas:
global x
def sub():
global x
x = 3
sub()
print(x)
result:
3

Issue retrieving values from objects created by button function

I'm working on a small project and I'm having issues retrieving the values stored in combo boxes. The program has a "plus" button that creates additional boxes beneath the existing ones. They are created by calling a "create" function that makes a new instance of the ComboBox class, where the box is created and put onto the screen. A separate "submit" function is then supposed to loop through and retrieve all of the box values and store them in a list. My main flaw is that I used data in the variable names, but I have no clue how else to do this in this scenario. Does anyone have an alternative solution?
(there are some off screen variables that are show used here as parameters, but there are definitely not the source of the issue)
class ComboBox:
def __init__(self, master, counter, fields):
self.master = master
self.counter = counter
self.fields = fields
self.field_box = ttk.Combobox(width=20)
self.field_box["values"] = fields
self.field_box.grid(row=counter + 1, column=0, pady=5)
def get_value(self):
value = self.field_box.get()
return value
def create():
global entry_counter
name = "loop"+str(entry_counter-1)
name = ComboBox(window, entry_counter, fields)
values.append(name.get_value())
entry_counter += 1
def submit():
for i in range(1, entry_counter):
name = "loop" + str(entry_counter-1)
values.append(name.get_value())
For example, if I created 2 boxes and selected the options "test1" and "test2" I would want the my values list to contain ["test1, "test2"]
Not sure I understand the question right, but I guess you are asking about how to loop throw all instances of ComboBox. You can just create an global array, append new instance into it in create() method:
comboboxes = []
def create():
...
comboboxes.append(new_instance)
def submit():
for combobox in comboboxes:
...
You're on the right track with .get(). I believe your solution is that your get_value function also needs an event parameter:
def get_value(self, event):
value = self.field_box.get()
return value
See the following:
Getting the selected value from combobox in Tkinter
Retrieving and using a tkinter combobox selection

Tkinter buttons which require their command to return a value

I have an odd question about tkinter entry boxes:
I know that I can write
add_charge = tk.Button(self, text='Add Data', command=function)
and that if the function is dependent on parameters I can write it as
add_charge = tk.Button(self, text='Add Data', command=lambda: function(parameters)
but my issue is this, I have a function defined as this
def add_charge(x,y,i, data):
""" x,y are locations if the charge, i is the value of charge, data is existing charges"""
temp = data.append(Charge(x,y,i)) #Charge is a predefined class which creates the charge object
return temp
What I need to do is save temp to a variable and replace the pre-existing data, but I can't figure out how to save the value that the function returns once the button has been pressed. Any help is appreciated!
Thanks to the commenters, I have established a workaround, instead of
def add_charge(x,y,i,data):
temp = data.append(Charge(x,y,i))
return temp
I can write
global charge_data
charge_data = []
Then later, I can write
def add_charge(x,y,i):
charge_data.append(Charge(x,y,i))
Which allows me to effectively eliminate the need to store the result of the function.

Python 3 Save Buttons

I have a button that can create another buttons, but when I close the program, the buttons I just created disappear.
I know how to save things in a file using pickle, but how should I write the code so that it saves the buttons and creates them again when I open the program.
code:
def CreateButton():
global name,clicked,started
started=True
name = str(input("Write a Student Name..."))
print('variable changed...')
clicked=True
def update():
global MainWindow,changed,clicked,name
#global clicked
if clicked and started:
#name = input("Write a Student Name: ")
button_new=needed_but(MainWindow=MainWindow,color="#E6E6E6",text=name)
clicked=False
buttonred=False
MainWindow.after(1*1000,update)
class needed_but:
def __init__(self,MainWindow,color,text):
console = Button(MainWindow, text=text,bg=color, command=self.changecolor)
console.pack()
self.instance=console
def changecolor(self):
buttonred,buttongreen,buttonblue=get_color()
global clicked,misses_dict
#clicked=True
#global buttoncolor
if buttonred == True:
self.instance.configure(bg = "#ff0000")
dun = self.instance.cget('text')
print(dun)
if dun in misses_dict:
misses_dict[('%s' %(dun))] += 1
else:
misses_dict[('%s' %(dun))] = 1
pickle.dump(dictionary, open("%s\SI\SIA.dat" %(path), 'wb'))
print(misses_dict)
buttonred = False
elif buttongreen == True:
self.instance.configure(bg = "#00ff00")
elif buttonblue == True:
self.instance.configure(bg = "#2e9afe")
how should I write the code so that it saves the buttons and creates them again when I open the program.
You can't. The objects are actually objects within an embedded tcl interpreter. There's no way to save the state of the interpreter.
You'll have to write code to save all of the information about the widgets in some sort of format where you can read it back and recreate the widgets.

Categories

Resources