0

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()
ogeretal
  • 509
  • 4
  • 12
  • Thank you. My fault. I did not see it. Thanks. – ogeretal Nov 01 '17 at 08:17
  • I solved the issue thanks to Bryan's comment. This was my solution: def on_click(self, i, lin_id): def inner (): 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)) self.controller.remake_PageOne() return inner – ogeretal Nov 02 '17 at 06:13

0 Answers0