I am following the MVC model that Bryan made on the answer to “Switch between two frames in tkinter“. He stacks the frames on top of each other (all are made at the very beginning) and then we just show them at our will.
I have two simple database tables. First one called example_ini with two columns: lin_id and lin_option. There is only 1 entry in the table (1,2) and it is used to remember the last choice of the user, The second one is example_options with also two columns: lin_id and symbol. There are 4 entries (1,AA)(2,BB)(3,CC) and (4,DD). I use mysql, but I do not believe that is relevant to the question.
Just opening and closing the code changes the value in the database. It looks like when the page is made it does the loop inside on_click when it should not. How can I stop this behavior?
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
#import Tkinter as tk # python 2
#import tkFont as tkfont # python 2
from datetime import *
import mysql.connector
global __TBL_PREFIX__
__TBL_PREFIX__ = 'example_'
global config
config = {
'db' : 'example',
'user' : 'root',
'password' : '****', # Your password
}
class ini:
def __init__(self):
self.lin_id = None
self.lin_option = 0
# return an object populated based on the record's lin id
def getById(lin_id):
i = ini()
cnx = mysql.connector.connect(**config)
cursor = cnx.cursor()
query = ("SELECT LIN_OPTION FROM %sINI WHERE LIN_ID = %d")
args = (__TBL_PREFIX__, lin_id)
query = query % args
cursor.execute(query)
results = cursor.fetchall()
cnx.commit()
if len(results) != 0 :
i.lin_option = results[0][0]
i.lin_id = lin_id
cursor.close()
cnx.close()
return i
# update an object in db
def update(i):
cnx = mysql.connector.connect(**config)
cursor = cnx.cursor()
query = ('UPDATE %sINI SET LIN_OPTION = %d WHERE LIN_ID = %d')
args = (__TBL_PREFIX__, i.lin_option, i.lin_id)
query = query % args
cursor.execute (query)
cnx.commit()
cursor.close()
cnx.close()
return
class options:
def __init__(self):
self.lin_id = None
self.symbol = ''
# return an object populated based on the record's lin id
def getById(lin_id):
o = options()
cnx = mysql.connector.connect(**config)
cursor = cnx.cursor()
query = ("SELECT SYMBOL FROM %sOPTIONS WHERE LIN_ID = %d")
args = (__TBL_PREFIX__, lin_id)
query = query % args
cursor.execute(query)
results = cursor.fetchall()
cnx.commit()
if len(results) != 0 :
o.symbol = results[0][0]
o.lin_id = lin_id
cursor.close()
cnx.close()
return o
# return all candidates
def getall():
cnx = mysql.connector.connect(**config)
cursor = cnx.cursor()
query = ("SELECT LIN_ID FROM %sOPTIONS")
args = (__TBL_PREFIX__)
query = query % args
cursor.execute(query)
result = [item[0] for item in cursor.fetchall()]
cursor.close()
cnx.close()
return result
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
self.container = tk.Frame(self)
self.container.pack(side="top", fill="both", expand=True)
self.container.grid_rowconfigure(0, weight=1)
self.container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, PageTwo):
page_name = F.__name__
frame = F(parent=self.container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
def add_new(self):
''' Create a new frame on the run '''
self.frames["StartPage"] = StartPage(parent=self.container, controller=self)
self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")
self.frames["PageOne"] = PageOne(parent=self.container, controller=self)
self.frames["PageOne"].grid(row=0, column=0, sticky="nsew")
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
i = ini.getById(1)
o = options.getById(i.lin_option)
text0 = 'Last option in database is ' + o.symbol
label = tk.Label(self, text=text0, font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One to change options",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two to update Page One",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1. Press button to chance selection", font=controller.title_font)
label.grid(row=0, column=0)
i = ini.getById(1)
candidates = options.getall()
print(str(candidates))
Order = candidates.index(i.lin_option)
for counter, lin in enumerate(candidates):
file = 1 + counter # First counter is zero
print('Start file = ' + str(file))
print ('lin = ' + str(lin))
o = options.getById(lin)
print (' o = ' + str(o.lin_id) + ', ' + o.symbol)
# Cell 0
if Order == counter :
label = tk.Button(self, text=(counter+1), fg='red', state="disabled" )
else :
label = tk.Button(self, text=(counter+1), fg='blue', command= self.on_click(i, o.lin_id))
label.grid(row=file, column=0)
# Cell 1
if Order == counter :
label = tk.Label(self, text=o.symbol, font = 'Helvetica 28')
else :
label = tk.Label(self, text=o.symbol, font = 'Helvetica 12')
label.grid(row=file, column=1)
print ('End file = ' + str(file))
print ()
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.grid()
def on_click(self, i, lin_id):
print ('Change db values. OLD initial.lin_choise = ' + str(i.lin_option))
i.lin_option = lin_id
i.update()
print ('Change db values. NEW initial.lin_choise = ' + str(i.lin_option))
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button2 = tk.Button(self, text="Update page 1 and go to the start page",
command=self.on_click)
button1.pack()
button2.pack()
def on_click(self):
self.controller.add_new()
self.controller.show_frame("StartPage")
if __name__ == "__main__":
app = SampleApp()
app.mainloop()