Python Forum
[Tkinter] HOW TO: Use Globals In Module ???
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] HOW TO: Use Globals In Module ???
#1
Esteemed Forum Participants and Lurkers:
Platform: Linux Mint 18.3 Mate 64-bit, Python 3.5.2 & Idle3
I am working on a Python 3 program using TKinter which is essentially a keystroke driven state machine. I want to segregate the different states in 'modules'. The 'root' TKinter window is global to the whole program, but I can't seem to make it visible to a module, EXCEPT I CAN pass it to a function in a module as a parameter.
How do I make it available to the function as a global object which is what I REALLY want to learn how to do?

Main Program:
# Module Test for Globals and Modules
import tkinter as tk

Groot = tk.Tk()  # Create the GLOBAL root window
Glabel1 = []     # Global Label identifier
GCOUNT = 0       # Global Keystroke counter

# Pull in the "setup" module
import setup
# Create and load the display label
setup.setup()

# #########  Keyboard 'Keypress' event handler  #########
def key(event):
    global GCOUNT
    GCOUNT += 1
    msg = '%d %r %d %d' %(GCOUNT,event.keysym,event.keysym_num,event.state)
    print(msg)
# #######################################################

# Bind the Keypress event to the 'key' event handler
Groot.bind_all('<Key>', key)
# Exit to the running event-driven app
Groot.mainloop()
Test Module:
# MODULE "setup.py" in moduletest
import tkinter as tk

# GLOBALS:
global Groot
global Glabel1

def setup():
    # Create and load the display label into the window
    prompt = '        Press any key        '
    Glabel1 = tk.Label(Groot, text=prompt, width=len(prompt), bg='yellow')
    Glabel1.pack()
    return()
Here is the error message:
Traceback (most recent call last):
File "/media/mint/python/keystroke.py", line 19, in <module>
setup.setup()
File "/media/mint/python/setup.py", line 18, in setup
Glabel1 = tk.Label(Groot, text=prompt, width=len(prompt), bg='yellow')
NameError: name 'Groot' is not defined


As I mentioned, I can get this to work by passing 'Groot' as a parameter to setup.setup(), but how can I use 'Groot' as a global WITHOUT having to pass it as a parameter?

Thank you for any and all comments, suggestions, and assistance in this effort.

Blessings in abundance, all the best, & ENJOY!
Art in Carlisle, PA USA
Reply
#2
Without passing as a parameter... i would say to create your Groot within setup directly and pass that back to the main program then. Often you will have a settings file with static data that you import to many modules. You should be cautious to use globals so often.

setup.py
# MODULE "setup.py" in moduletest
import tkinter as tk

Groot = tk.Tk()
 
def setup():
    # Create and load the display label into the window
    prompt = '        Press any key        '
    Glabel1 = tk.Label(Groot, text=prompt, width=len(prompt), bg='yellow')
    Glabel1.pack()
    return Groot
main program
import setup #<- imports go at top
...
#Groot = tk.Tk()  # Create the GLOBAL root window
Glabel1 = []     # Global Label identifier
GCOUNT = 0       # Global Keystroke counter
 

# Create and load the display label
Groot = setup.setup()
...
Recommended Tutorials:
Reply
#3
Thanks metulburr!
Your suggestion looks reasonable and your advice is sound. I did a LOT of searching, and did find MANY caveats regarding Globals. However, I did also find the following ELEGANT and sanctioned solution, which works great for my program:

Python Software Foundation
Programming FAQ: How do I share global variables across modules?

It is very brief and is well worth looking at. Basically, you just put all the Globals in a "config.py" file. That puts them all in a single file in their own namespace ... I use "import config as G", so each Global is "G.name". Without this I would be passing TONS of stuff ... 3 arrays of 65 widgets each, a dictionary of complex dynamic widget formats, and many other variables. Each of the FIVE steps of the State Machine manipulates them differently.

# Module config.py
Root = []       # Global Window identifier
Label1 = []     # Global Label identifier
Count = 0       # Global Keystroke counter
# Module Test for Globals and Modules
import tkinter as tk
import config as G
import setup
 
G.Root = tk.Tk()  # Create the GLOBAL root window

# Create and load the display label
setup.setup()
 
# #########  Keyboard 'Keypress' event handler  #########
def key(event):
    G.COUNT += 1
    msg = '%d %r %d %d' %(G.COUNT,event.keysym,event.keysym_num,event.state)
    print(msg)
# #######################################################
 
# Bind the Keypress event to the 'key' event handler
G.Root.bind_all('<Key>', key)
# Exit to the running event-driven app
G.Root.mainloop()
# MODULE "setup.py" in moduletest
import tkinter as tk
import config as G
 
def setup():
    # Create and load the display label into the window
    prompt = '        Press any key        '
    G.Label1 = tk.Label(G.Root, text=prompt, width=len(prompt), bg='yellow')
    G.Label1.pack()   #  <-- pack/grid MUST be on separate line !!!
    return
Blessings in abundance, all the best, & ENJOY!
Art in Carlisle, PA USA
Reply
#4
(May-10-2019, 04:28 AM)Webtest Wrote: I did also find the following ELEGANT and sanctioned solution, which works great for my program:
It may work,buy is far from great Wink
There is a reason why classes is almost always used and preferred in GUI programming.
Then there is no use of Globals Sick ,self act like magic transporter of values.
So a basic example with a class from doc,if i put in counter as you have it then it look like this.
See that there is no Global used to make this counter.
import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.button_clicks = 0
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Click me"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack(side="top")
        self.quit = tk.Button(self, text="QUIT",fg="blue",command=self.master.destroy)
        self.quit.pack(side="bottom")

    def say_hi(self):
        self.button_clicks += 1
        print(f"hi there,you have clicked {self.button_clicks} times now")

root = tk.Tk()
app = Application(master=root)
app.mainloop()
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020