0
votes

I am having issues with a Tkinter GUI. I need to create a large application. I need to use classes for that to manage all modules together. For a unit check and getting help here, I have tried to provide a sample which is close to exact problem ( with a small example) here:

I am creating a 1st window with a Button labelled as "Test". What I want is that when I click the button "Test", a new second window will pop up with a text "Enter Value" and entry space, where I can enter the value. I have provided the code below. What is happening is that, I am able to get the new window, but the text "Enter Value" and entry Space is generated in the first window instead of the second and the second window remains blank. I am not understanding where I am making the wrong logic call. Help will be very much appreciated.

I know we do not need classes for GUI applications, however to manage my large application ( not shown here), I need to have classes and I will very much appreciate, if some Tkinter Guru can help me with the bug in my code.

gui view File (gui_view.py)

import tkinter as tk

from tkinter import Tk

class MyMainGUI(tk.Frame):

       def __init__(self, controller):

        tk.Frame.__init__(self)
        self.pack()
        self.controller = controller

        self.Button1=tk.Button(self)
        self.Button1["text"]= "Test"
        self.Button1["command"]=self.controller.buttonPressed1
        self.Button1.grid(row=2,column=0,rowspan=2)


class MySecondGUI(tk.Frame):

       def __init__(self, controller):

        tk.Frame.__init__(self)
        self.pack()
        self.controller = controller

        self.outputLabel2 = tk.Label(self)
        self.outputLabel2["text"] = ("Enter Value")
        self.outputLabel2.grid(row=1,rowspan=2)

         #Entry Space
        self.entrySpace2 = tk.Entry(self)
        self.entrySpace2.grid(row=2,column=0,rowspan=2)


### gui Controller File (gui_controller.py)

import tkinter as tk 

import gui_view # the VIEW file


class MainControl:

    def __init__(self):    
        self.root = tk.Tk()
        self.root.geometry('550x200')
        self.view = gui_view.MyMainGUI(self)
        self.view.mainloop()

    def newWindow(self):

        self.newWin = tk.Toplevel(self.root)
        self.newWin.geometry('300x400')
        self.newDisplay = tk.Label(self.newWin, text='Test Mode')
        self.viewNew = gui_view.MySecondGUI(self.newWin)
        self.viewNew.mainloop()
        self.newDisplay.pack()

    def buttonPressed1(self):

         self.newWindow()

if __name__ == "__main__":

    c = MainControl()
#

ADDING A MODIFIED CODE WITH NEW PROBLEM.

I have now been able to generate a code which pops up a new window with entries, when I click the button "Test" in the first Window. However, I am having problems creating buttons in the scond window. The way I have it now, it pops an error to me saying "'MySecondGUI' object has no attribute 'buttonPressed2"

Help will be very much appreciated.

I have pasted my updated code below:

GUI_VIEW FILE ( gui_view.py)

import tkinter as tk

from tkinter import Tk

class MyMainGUI(tk.Frame):

def __init__(self, controller):

   tk.Frame.__init__(self)
   self.pack()
   self.controller = controller

   self.Button1=tk.Button(self)
   self.Button1["text"]= "Test"
   self.Button1["command"]=self.controller.buttonPressed1
   self.Button1.grid(row=2,column=0,rowspan=2)

class MySecondGUI(tk.Toplevel):

   def __init__(self):

    tk.Toplevel.__init__(self)


    self.outputLabel2 = tk.Label(self)
    self.outputLabel2["text"] = ("Enter Value")
    self.outputLabel2.grid(row=5,rowspan=2)

    self.entrySpace2 = tk.Entry(self)
    self.entrySpace2.grid(row=8,column=0,rowspan=2)

    self.Button2=tk.Button(self)
    self.Button2["text"]= "Try Me"
    self.Button2["command"] = self.buttonPressed2
    self.Button2.grid(row=14,column=0,rowspan=2)enter code here

GUI MAIN CONTROLLER FILE

import tkinter as tk

import gui_view # the VIEW file

class MainControl:

def __init__(self):   
  self.root = tk.Tk()
  self.root.geometry('550x200')
  self.view = gui_view_temp.MyMainGUI(self)
  self.view.mainloop()

def newWindow(self):

  self.viewNew = gui_view.MySecondGUI()
  self.viewNew.geometry('300x400')
  self.newDisplay = tk.Label(self.newWin, text='Test Mode')
  self.viewNew.mainloop()
  self.newDisplay.pack()

def buttonPressed1(self):

     self.newWindow()

def buttonPressed2(self):

     pass

if name == "main":

c = MainControl()
1
Here is a thread where the answers go over drawing elements to two windows and the construction of programs using tkinter: stackoverflow.com/questions/16115378/… Also, check out this answer by Bryan Oakley about the proper way to structure a tkinter application, it contains an answer as to why class based tkinter GUIs underperform in large applications specifically: stackoverflow.com/a/17470842/7062209Lucas Leodler
Thanks Lucas. I will try and let you know.Stan
I updated with some additions of the code and new problem.Stan
Thank you for the update. As soon as I get back from work/class I will see if a solution is still needed and if I can come up with one!Lucas Leodler

1 Answers

1
votes

in MySecondGUI(tk.Frame):

def __init__(self, controller):
    #Attach your frame to "secondGUI" (which is your second window)
    tk.Frame.__init__(self, controller) 

in class MainControl:

#I assume you're passing your parent window/frame as "controller"?
self.viewNew = MySecondGUI(self.newWin)

according to Python Tkinter Docs

https://docs.python.org/3.5/library/tkinter.html#mapping-basic-tk-into-tkinter

You should specify your parent window if you're not attach your widget to main window.

#Main window
root = tk.Tk()
#Second Window
newWin = tk.Toplevel(root)

#Attach to main window
tk.Label(text="This label attached to root").pack()
tk.Button(text="This button attached to root").pack()

#Second Window
tk.Label(newWin, text="This label attached to second window").pack()
tk.Button(newWin, text="This button attached to second window").pack()

also,

self.viewNew.mainloop()
#This will fail because you have to set everything up before mainloop()
#_tkinter.TclError: can't invoke "pack" command: application has been destroyed
self.newDisplay.pack()

Edit for update

You should put your

def buttonPressed2(self):

in class MySecondGUI, not in class MainControl.

class MySecondGUI(tk.Toplevel):

    def __init__(self):

        tk.Toplevel.__init__(self)

        self.outputLabel2 = tk.Label(self)
        self.outputLabel2["text"] = ("Enter Value")
        self.outputLabel2.grid(row=5,rowspan=2)

        self.entrySpace2 = tk.Entry(self)
        self.entrySpace2.grid(row=8,column=0,rowspan=2)

        self.Button2=tk.Button(self)
        self.Button2["text"]= "Try Me"
        #self means "MySecondGUI" not "MainControl" here
        self.Button2["command"] = self.buttonPressed2
        self.Button2.grid(row=14,column=0,rowspan=2)

      def buttonPressed2(self):
          pass