-1

I use a multiple frame window from Steven M. Vascellaro example Switch between two frames in tkinter. And I don't understand is it possible to use global variable, because each frame is destroyed every time it is changed. 1st (of 2 buttons) button at StartPage is deactivated, if I click on 2nd button and go to PageOne and do something there and return to StartPage 1st button must be activated.

If I declare global in StartPage class

_tkinter.TclError: invalid command name ".!startpage.!button2"

If I declare it in PageOne class

NameError: name 'install_svc' is not defined

Not good idea, but I think about 3rd frame where I define buttons again.

EDIT1:

class MyGUI(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self._frame = None
        self.switch_frame(StartPage)
        self.geometry("400x300")

    def switch_frame(self, frame_class):
        """Destroys current frame and replaces it with a new one."""
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.pack()

    def quit_app(self):
        self._frame.destroy()
        self.destroy()

class StartPage(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        global install_svc

class PageOne(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
    def entry_check(self,parent):
        global install_svc
JoshuaCS
  • 2,524
  • 1
  • 13
  • 16
Rostislav Aleev
  • 351
  • 5
  • 19
  • 1
    Where exactly is the `global` statement and when/where does this error occur? – martineau Jan 10 '19 at 12:38
  • @martineau `class StartPage(tk.Frame): def __init__(self, parent) global install_svc` and in `PageOne` method after some routine `def entry_check(self,parent):global install_svc`. As I thought with 3rd I can achieve what I want. – Rostislav Aleev Jan 10 '19 at 12:44
  • 2
    Please refer to changes in terms of changes since you haven't posted any code of your own. To help you we need to be able to reproduce the problem. You also need to show the entire error message include traceback indicating where it occurs. Just sticking in some `global` statement couldn't cause the `NameError` by itself. – martineau Jan 10 '19 at 12:51
  • I don't get any errors running the code you have added to your question. – martineau Jan 10 '19 at 13:47
  • 2
    @martineau the OP is not using `install_svc` anywhere, just doing `global install_svc` and that, alone, wont throw any error. He needs to post the error and a more complete and verifiable example. – JoshuaCS Jan 10 '19 at 13:51

1 Answers1

1

Declare and initialize install_svc at the root level (global scope). The statement global install_svc wont auto-magically create, by itself, the variable in the global scope: it will just do a lookup for a global variable with such name but, if you try to use that variable without first assigning something to it, a NameError will be thrown.

Code

install_svc = None # Or some other initial value

class MyGUI(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self._frame = None
        self.switch_frame(StartPage)
        self.geometry("400x300")

    def switch_frame(self, frame_class):
        """Destroys current frame and replaces it with a new one."""
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.pack()

    def quit_app(self):
        self._frame.destroy()
        self.destroy()

class StartPage(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        global install_svc

        # You can use install_svc safely
        print(install_svc)

class PageOne(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
    def entry_check(self,parent):
        global install_svc

        # You can use install_svc safely
        print(install_svc)

You could also check if the variable exists, doing a try..except, but that will be really ugly (at least for me) and you will need to do such check everywhere:

class MyGUI(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self._frame = None
        self.switch_frame(StartPage)
        self.geometry("400x300")

    def switch_frame(self, frame_class):
        """Destroys current frame and replaces it with a new one."""
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.pack()

    def quit_app(self):
        self._frame.destroy()
        self.destroy()

class StartPage(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        global install_svc

        try:
            install_svc
        except NameError:
            install_svc = None # Or some initial value

class PageOne(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
    def entry_check(self,parent):
        global install_svc

        try:
            install_svc
        except NameError:
            install_svc = None # Or some initial value
JoshuaCS
  • 2,524
  • 1
  • 13
  • 16
  • I think my problem, is that I call variable from `PageOne` method . In `PageOne` I check connection to SQL DB and if everything satisifes conditions then button at `StartPage` is active – Rostislav Aleev Jan 11 '19 at 07:34
  • @RostislavAleev did my answer work for you? If so, please, mark it as **accepted** (green checkmark), otherwise, let me know what went wrong. Thnx in advance! – JoshuaCS Jan 14 '19 at 13:50
  • It works. But I don't think outer global variable is a good idea. I prefered 3rd frame (class). Accepted. Sorry, forgot to answer. – Rostislav Aleev Jan 14 '19 at 14:33