Eric
Eric

Reputation: 205

Reference a global object within python tkinter application

I'm trying to update a label in a python tkinter application when another widget is selected.

I created a small tool, that demonstrates the issue. The tool will create a small GUI with a label on top. This label should show the number of the box that was selected.

Image of tool

Problem is that when a box number is selected by a mouse click, the number is not shown in the top label. Clicking the box number should call setSelected, which should call app.setLabel(string). However, I get the error "global name 'app' is not defined"

How do I make the object 'app' global?

#!/usr/bin/env python
import Tkinter

def setSelected(string):
    app.setLabel(string)

class Gui():
    Boxes = []

    def __init__(self):
        self._root = Tkinter.Tk()
        self._root.protocol("WM_DELETE_WINDOW", self._applicationExit)
        self._string = Tkinter.StringVar()
        self.setLabel('None')
        self._label = Tkinter.Label(self._root, textvariable = self._string,
            width = 10)
        self._label.grid(row = 0, column = 0, padx = 5, pady = 5)
        self._createBoxOverview()
        self._root.mainloop()

    def _applicationExit(self, event = None):
        self._root.destroy()

    def _createBoxOverview(self):
        _frame = Tkinter.LabelFrame(self._root, text = 'Boxes')
        for _id in range(4):
            self.Boxes.append(Box(_frame, _id))
            self.Boxes[_id].grid(row = 0, column = _id)
        _frame.grid(row = 1, column = 0, padx = 5, pady = 5)

    def setLabel(self, string):
        self._string.set(string)

class Box(Tkinter.Label):
    def __init__(self, master, id):
        Tkinter.Label.__init__(self, master)
        self._id = str(id)
        self._text = Tkinter.StringVar()
        self._text.set(self._id)
        self.config(textvariable = self._text, width = 3)
        self.bind("<Button-1>", self._onSelect)

    def _onSelect(self, event):
        setSelected(self._id)

if __name__ == '__main__':
    app = Gui()

Upvotes: 1

Views: 638

Answers (1)

Anand S Kumar
Anand S Kumar

Reputation: 90889

The issue is that you are creating root (Tk() App) and calling root.mainloop() , inside __init__() itself, so app does not completely get created, since it would only get created if you return from __init__() , but you do not do that until you close the app.

The easiest solution for your case would be to move the root object outisde Gui() class. Example -

import Tkinter

def setSelected(string):
    app.setLabel(string)

class Gui():
    Boxes = []

    def __init__(self, root):
        self._root = root
        self._root.protocol("WM_DELETE_WINDOW", self._applicationExit)
        self._string = Tkinter.StringVar()
        self.setLabel('None')
        self._label = Tkinter.Label(self._root, textvariable = self._string,
            width = 10)
        self._label.grid(row = 0, column = 0, padx = 5, pady = 5)
        self._createBoxOverview()

    def _applicationExit(self, event = None):
        self._root.destroy()

    def _createBoxOverview(self):
        _frame = Tkinter.LabelFrame(self._root, text = 'Boxes')
        for _id in range(4):
            self.Boxes.append(Box(_frame, _id))
            self.Boxes[_id].grid(row = 0, column = _id)
        _frame.grid(row = 1, column = 0, padx = 5, pady = 5)

    def setLabel(self, string):
        self._string.set(string)

class Box(Tkinter.Label):
    def __init__(self, master, id):
        Tkinter.Label.__init__(self, master)
        self._id = str(id)
        self._text = Tkinter.StringVar()
        self._text.set(self._id)
        self.config(textvariable = self._text, width = 3)
        self.bind("<Button-1>", self._onSelect)

    def _onSelect(self, event):
        setSelected(self._id)

if __name__ == '__main__':
    root = Tkinter.Tk()
    app = Gui(root)
    root.mainloop()

Upvotes: 1

Related Questions