Home > Back-end >  Python tkinter state change creating new window
Python tkinter state change creating new window

Time:09-17

When trying to change the state of TEntry1 which is controlled by the button in the upper right instead of changing the state of TEntry1 it creates a new window that has TEntry1 greyed out and all variable inputs blank.

The GUI was generated by PAGE

PAGE exports to 2 files, I've combined the 2 for this question

The window to the left is the program running as desired, the button will initially say start, then clicking on it will will switch to running mode and changes the text to stop. It is also supposed to grey out the entry widget, but instead creates a new window with the entry widget greyed out

I believe the issue is happening in disableentry(): with how the attribute is called

def disableentry():
    print("disableentry() start")
    root = tk.Tk()
    Toplevel1(root).TEntry1.configure(state='disabled')

Example

import sys
import threading
import tkinter as tk
import tkinter.ttk as ttk

def destroy_Toplevel1():
    thread0.stop()

class Toplevel1:
    def __init__(self, top=None):
        '''This class configures and populates the toplevel window.
           top is the toplevel containing window.'''
        _bgcolor = '#d9d9d9'  # X11 color: 'gray85'
        _fgcolor = '#000000'  # X11 color: 'black'
        _compcolor = '#d9d9d9' # X11 color: 'gray85'
        _ana1color = '#d9d9d9' # X11 color: 'gray85'
        _ana2color = '#ececec' # Closest X11 color: 'gray92'
        self.style = ttk.Style()
        if sys.platform == "win32":
            self.style.theme_use('winnative')
        self.style.configure('.',background=_bgcolor)
        self.style.configure('.',foreground=_fgcolor)
        self.style.configure('.',font="TkDefaultFont")
        self.style.map('.',background=
            [('selected', _compcolor), ('active',_ana2color)])

        top.geometry("460x406 660 210")
        top.minsize(120, 1)
        top.maxsize(3844, 1061)
        top.resizable(0,  0)
        top.title("PAGE GUI")
        top.configure(background="#d9d9d9")
        top.configure(highlightbackground="#d9d9d9")
        top.configure(highlightcolor="black")

        self.TEntry1 = ttk.Entry(top)
        self.TEntry1.place(x=76, y=41, height=21, width=137)
        self.TEntry1.configure(takefocus="")
        self.TEntry1.configure(cursor="ibeam")
        self.TEntry1.configure(textvariable=entry1text)

        self.Label1 = tk.Label(top)
        self.Label1.place(x=21, y=41, height=31, width=38)
        self.Label1.configure(activebackground="#f9f9f9")
        self.Label1.configure(activeforeground="black")
        self.Label1.configure(background="#d9d9d9")
        self.Label1.configure(disabledforeground="#a3a3a3")
        self.Label1.configure(foreground="#000000")
        self.Label1.configure(highlightbackground="#d9d9d9")
        self.Label1.configure(highlightcolor="black")
        self.Label1.configure(text='''IP 1''')

        self.Button1 = tk.Button(top)
        self.Button1.place(x=330, y=41, height=24, width=107)
        self.Button1.configure(activebackground="#ececec")
        self.Button1.configure(activeforeground="#000000")
        self.Button1.configure(background="#d9d9d9")
        self.Button1.configure(disabledforeground="#a3a3a3")
        self.Button1.configure(foreground="#000000")
        self.Button1.configure(highlightbackground="#d9d9d9")
        self.Button1.configure(highlightcolor="black")
        self.Button1.configure(pady="0")
        self.Button1.configure(textvariable=button_text)
        self.Button1.configure(command=guicontrols.start_stop)

class guisetup():
    def set_Tk_var():
        global running_status
        running_status = tk.IntVar()
        running_status.set(0)
        global button_text 
        button_text = tk.StringVar()
        button_text.set('Start')
        global entry1text
        entry1text = tk.StringVar()
        entry1text.set('')

    def vp_start_gui():
        global val, w, root
        root = tk.Tk()
        guisetup.set_Tk_var()
        top = Toplevel1 (root)
        root.mainloop()

class guithread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self

    def run(self):
        guisetup.vp_start_gui()

class guicontrols():
    def disableentry():
        print("disableentry() start")
        root = tk.Tk()
        Toplevel1(root).TEntry1.configure(state='disabled')

    def start_stop():
        print('PLA_support.start_stop')
        if (running_status.get() == 1):
            button_text.set("Stop")
            running_status.set(0)
            guicontrols.disableentry()
        else:
            button_text.set("Start")
            running_status.set(1)
        sys.stdout.flush()

if __name__ == '__main__':
    thread0 = guithread()
    thread0.start()

CodePudding user response:

Here is a cleaned-up version of your code. I put everything to do with the window into one class: App, so that all the variables can be accessed properly.

import sys
import threading
import tkinter as tk
import tkinter.ttk as ttk

class App(tk.Tk):
    """The main window."""

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

        # Set the theme
        _bgcolor = '#d9d9d9'  # X11 color: 'gray85'
        _fgcolor = '#000000'  # X11 color: 'black'
        _compcolor = '#d9d9d9' # X11 color: 'gray85'
        _ana1color = '#d9d9d9' # X11 color: 'gray85'
        _ana2color = '#ececec' # Closest X11 color: 'gray92'

        self.style = ttk.Style()

        if sys.platform == "win32":
            self.style.theme_use('winnative')
        self.style.configure('.', background=_bgcolor)
        self.style.configure('.', foreground=_fgcolor)
        self.style.configure('.', font="TkDefaultFont")
        self.style.map(
            '.',
            background=[('selected', _compcolor), ('active',_ana2color)]
        )

        self.geometry("460x406 660 210")
        self.minsize(120, 1)
        self.maxsize(3844, 1061)
        self.resizable(0,  0)
        self.title("PAGE GUI")
        self.configure(background="#d9d9d9")
        self.configure(highlightbackground="#d9d9d9")
        self.configure(highlightcolor="black")

        # Running status
        self.running_status = tk.IntVar()
        self.running_status.set(1)

        # Create the widgets
        self.create_widgets()

    def create_widgets(self):
        """Create the widgets and add them to the window."""

        self.entry1text = tk.StringVar()
        self.entry1text.set("")
        self.TEntry1 = ttk.Entry(
            self,
            takefocus="",
            cursor="xterm",
            textvariable=self.entry1text
        )
        self.TEntry1.place(x=76, y=41, height=21, width=137)

        # The label-
        self.Label1 = tk.Label(
            self,
            activebackground="#f9f9f9",
            activeforeground="black",
            background="#d9d9d9",
            disabledforeground="#a3a3a3",
            foreground="#000000",
            highlightbackground="#d9d9d9",
            highlightcolor="black",
            text="IP 1"
        )
        self.Label1.place(x=21, y=41, height=31, width=38)

        # The button
        self.button_text = tk.StringVar()
        self.button_text.set('Start')
        self.Button1 = tk.Button(
            self,
            activebackground="#ececec",
            activeforeground="#000000",
            background="#d9d9d9",
            disabledforeground="#a3a3a3",
            foreground="#000000",
            highlightbackground="#d9d9d9",
            highlightcolor="black",
            pady="0",
            textvariable=self.button_text,
            command=self.start_stop
        )
        self.Button1.place(x=330, y=41, height=24, width=107)

    def disable_entry(self):
        self.TEntry1.config(state="disabled")

    def enable_entry(self):
        self.TEntry1.config(state="enabled")

    def start_stop(self):
        print('PLA_support.start_stop')
        if (self.running_status.get() == 1):
            self.button_text.set("Stop")
            self.running_status.set(0)
            self.disable_entry()
        else:
            self.button_text.set("Start")
            self.running_status.set(1)
            self.enable_entry()



class guithread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.app = App()

    def run(self):
        self.app.mainloop()

if __name__ == '__main__':
    thread0 = guithread()
    thread0.run()

I also put the widget arguments that were originally in tons of config() functions as arguments for the widget classes themselves; it's better syntax.

I kept the threading and added a function that re-enables the entry when the user clicks the button. I also changed the line self.running_status.set(0) after self.running_status = tkinter.IntVar() to self.running_status.set(1). This fixes an error where, when the program first starts, you have to click the button twice before anything happens.

If something wasn't what you wanted, or if you have any questions or run into any problems, I'll be glad to help!

  • Related