Reputation: 111
I'm writing a program for my class that allows you to make a recipe, save it and edit it even after closing the program. You obviously need a text file to do this.
I am using an OptionMenu (Tkinter, Python 3.3.3), but I cannot figure out how to keep updating it to have the first option in the list I have made in my text file. So how do I do that?
My code is thus:
###########################################
###########################################
### RECIPE BOOK TASK ##### By 18166 #######
###########################################
###########################################
from tkinter import *
def script ():
#### MAIN ####
fake_window = Tk()
new_recipe_window = fake_window
start_window = fake_window
start_window.title("Recipe Book Task")
#### MAIN ####
## DATA FILE ##
global datafile
datafile = open("StoredRecipes.txt", "a+")
## DATA FILE ##
### Functions ###
def close (x): ## Close Original Window ##
global start_window
global new_recipe_window
(x).withdraw()
def new_recipe ():
new_recipe_window = Tk() ## Making new window ##
new_recipe_window.title("New Recipe")
close(start_window)
recipe_name_label = Label(new_recipe_window, text="Recipe Name: ") ## Making new recipe label ##
recipe_name_label.grid(row=0, column=0)
recipe_name_box = Entry(new_recipe_window) ## Making new recipe entry ##
recipe_name_box.grid(row=0, column=1)
num_people_label = Label(new_recipe_window, text="Number of people: ") ## Making number of people label ##
num_people_label.grid(row=1, column=0)
num_people_box = Entry(new_recipe_window) ## Making number of people entry ##
num_people_box.grid(row=1, column=1)
item_label = Label(new_recipe_window, text="Items: ") ## Making item label ##
item_label.grid(row=2, column=0)
item_box = Entry(new_recipe_window) ## Making item entry ##
item_box.grid(row=2, column=1)
quantity_label = Label(new_recipe_window, text="Quantity: ") ## Making quantity label ##
quantity_label.grid(row=3, column=0)
quantity_box = Entry(new_recipe_window) ## Making quantity entry ##
quantity_box.grid(row=3, column=1)
unit_label = Label(new_recipe_window, text="Unit: ") ## Making unit label ##
unit_label.grid(row=4, column=0)
unit_box = Entry(new_recipe_window) ## Making unit entry ##
unit_box.grid(row=4, column=1)
def write ():
a = recipe_name_box.get()
b = num_people_box.get()
c = item_box.get()
d = quantity_box.get()
e = unit_box.get()
line = (a, b, c, d, e)
datafile.write(str(line) + "\n")
datafile.close()
saved_recipes.config(a)
close(new_recipe_window)
script()
finish_button = Button(new_recipe_window, text="Save and Finish", command=write) ## Making finish button ##
finish_button.grid(row=5, column=0, sticky=S)
# Dropdown Box #
default = StringVar(start_window, 'Recipe 1')
default.set("Select Your Recipe")
saved_recipes = OptionMenu(start_window, default, "Hi")
saved_recipes.grid(row=0, column=1)
# Dropdown Box #
# New Recipe Button #
new_recipe = Button(start_window, text="New Recipe", command=new_recipe)
new_recipe.grid(row=0, column=0)
# New Recipe Button #
script()
(Sorry for the block, I think all is useful to answering possibly?)
Upvotes: 2
Views: 1731
Reputation: 3947
To add elements to an OptionList
, you can use the following method (from http://www.prasannatech.net/2009/06/tkinter-optionmenu-changing-choices.html)
datafile = open("StoredRecipes.txt", "r")
for line in datafile.readlines():
saved_recipes['menu'].add_command(label=line,
command=lambda temp = line: saved_recipes.setvar(saved_recipes.cget("textvariable"), value = temp))
Which uses (has to use) a closure and an anonymous function -- definitely nothing you should deal with on your level of experience (guessing from the structure of your code).
This snippet adds a command for each line in your file. Because an OptionMenu
is something that executes things when elements are selected, you have to provide a command for each line. Right now this is just setting the displayed text to the selected line.
To accomplish this, it uses an anonymous function (lambda
) that sets the textvariable
of the OptionMenu
to the current line.
Upvotes: 0
Reputation: 64248
I believe you have two different options.
One option you could do is set up a timer to check the text file every couple of seconds, see if it's changed at all, and update your OptionMenu accordingly. You can find more info on how to do this here, but in a nutshell, you'd want your code to look something like:
def recheck(root, option_menu, file_name):
with open(file_name) as my_file:
lines = my_file.readlines():
# `lines` is a list where each item is a single line
# do any checks and updates you need here.
root.after(1000, recheck, root, option_menu, file_name)
# schedule the function to run again after 1000 milliseconds.
def script():
# set up your gui
start_window.after(1000, recheck, start_window, option_menu, "StoredRecipies.txt")
Note: you can find more info on the with
statement here: http://effbot.org/zone/python-with-statement.htm
The downside of this is that the update will be a little laggy -- you'll end up rechecking the file only once a second, so the update won't be instantaneous.
Alternatively, you could use something like Watchdog. It's a 3rd party library that you can set up to "watch" a particular file and run a function whenever the file changes. It's much more responsive in that you'll call the function only if the file actually changes, but it might end up being more complicated since you need to figure out how to make it work with Tkinter. I'm going to guess that your code will look roughly like this:
import os.path
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
def setup_observer(option_menu, filename):
normalized_filename = os.path.normpath(input_filename)
class MyEvent(FileSystemEventHandler):
def on_modified(self, event):
if os.path.normpath(event.src_path) == normalized_filename:
# update your option menu
observer = Observer()
observer.schedule(MyEvent(), '.', recursive=False)
return observer
def script():
# setup gui
observer = setup_observer(option_menu, "myfile.txt")
start_window.mainloop()
Upvotes: 1