Oliver Potts
Oliver Potts

Reputation: 11

Why are my tkinter widgets packing into the wrong window?

I have a game I'm working on, using text to inform the user what's going on in the game. However, I'm using a Tkinter window to enable input with buttons, for a more professional feel. I also included a few labels, but they're all packing into a new window rather than the one I already made. Don't ask about variable names, but this is the code:

def scan():
    action=str('scan')
    TSGcontrols.destroy()
    return action
def lookaround():
    action=str('look around')
    TSGcontrols.destroy()
    return action
def visoron():
    action=str('engage visor')
    global firstvisor
    if firstvisor==1:
        firstvisor=int(0)
        print ('The visor has a colour code.')
        print ('It displays a wire frame over black, based on sensor data -\nallowing you to see through walls (to a degree).')
        print ('\nColours:')
        print ('Green = inert object')
        print ('Blue = electrical signature')
        print ('Red = weapon signature')
        print ('Yellow = radiation (the darker the yellow, the deadlier exposure would be)')
        print ('White = life (the more grey, the weaker the lifesigns. Dark grey is dead.)')
        print ('Purple = unidentified\n')
    TSGcontrols.destroy()
    return action
def visoroff():
    action=str('disengage visor')
    TSGcontrols.destroy()
    return action
def personbasecreate():
    global TSGcontrols
    TSGcontrols=tkinter.Tk(screenName='/TSGcontrols',baseName='/TSGcontrols',className='/TSGcontrols')
    warning=Label(text='This is only the control panel for TSG.\nThe game\'s responses are output in the Python window.',bg='red')
    global location
    locationw=Label(text='Location: {0}'.format(location))
    controlling=Label(text='You are controlling only yourself.',bg='blue',fg='white')
    lookaround=Button(text='Look around',command=lookaround)
    visoron=Button(text='Turn visor on',command=visoron)
    visoroff=Button(text='Turn visor off',command=visoroff)
    scan=Button(text='Scan',command=scan)
    warning.pack(parent=TSGcontrols,side='top')
    locationw.pack(parent=TSGcontrols,side='top')
    controlling.pack(parent=TSGcontrols,side='top')
    lookaround.pack(side='left')
    scan.pack(side='left')
    if visor=='on':
        visoroff.pack(parent=TSGcontrols,side='right')
    else:
        visoron.pack(parent=TSGcontrols,side='right')
   groupw.pack(parent=TSGcontrols,side='bottom')

Then later on:

addbutton1 = str('no')

while repeat==str('yes'):
    time.sleep(3)
    print ('\nChoose your action.')
    # Creating the basic window:
    personbasecreate()
    if addbutton1=='yes':
        # Adding the additional function:
        leavequarters.pack(in_=personGUI,side='left')
    action=str(personGUI.mainloop())

But instead of the widgets appearing in the window called 'TSG Controls', they appear in a new one called 'tk' - so when the window is destroyed to allow the variable 'action' to be processed, it's destroying an empty window and the game crashes because the functions are trying to destroy a window that isn't there, throwing the error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "D:\Python\lib\tkinter\__init__.py", line 1489, in __call__
    return self.func(*args)
  File "D:\Python\TSG.py", line 881, in lookaround
    personGUI.destroy()
  File "D:\Python\lib\tkinter\__init__.py", line 1849, in destroy
    self.tk.call('destroy', self._w)
_tkinter.TclError: can't invoke "destroy" command:  application has been destroyed

When the button 'Look around' is clicked twice.

Is there any way to fix this code, or a simpler way to do what I'm trying to accomplish here?

Upvotes: 0

Views: 1536

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 386240

Part of the problem is probably this:

personGUI=tkinter.Tk(className='/TSG Controls')
warning=Label(text='This is only the control panel for TSG.\nThe game\'s responses are output in the Python window.',bg='red')

Notice that you are creating a new root window, but then you create a label without specifying a parent. You should always specify a parent for a widget, and you should always only ever create a single instance of Tk for your entire application. If you need to create more than one window, create your root window once, and then for other windows you need to create instances of tkinter.Toplevel.

Upvotes: 2

Related Questions