Tkinter filedialog to variable, but can't get the variable into Entry widget

Hi, Very new to tkinter …
simple Frame with an Entry box

import sys
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *

import iptoname_support


class IPToName:
    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.map('.',background=
            [('selected', _compcolor), ('active',_ana2color)])

        top.geometry("774x701+557+57")
        top.minsize(120, 1)
        top.maxsize(3844, 2141)
        top.resizable(1,  1)
        top.title("IP To Name")
        top.configure(background="#d9d9d9")
        top.configure(highlightbackground="#d9d9d9")
        top.configure(highlightcolor="black")

        self.top = top
        self.ip2nimport_path = tk.StringVar()

self.ip2nimportfield = tk.Entry(self.top)
        self.ip2nimportfield.place(relx=0.297, rely=0.029, height=20
                , relwidth=0.677)
        self.ip2nimportfield.configure(background="white")
        self.ip2nimportfield.configure(disabledforeground="#a3a3a3")
        self.ip2nimportfield.configure(font="TkFixedFont")
        self.ip2nimportfield.configure(foreground="#000000")
        self.ip2nimportfield.configure(insertbackground="black")
        self.ip2nimportfield.configure(textvariable=self.ip2nimport_path)

Got my functions defined in an _support.py file, I can get the filedialog box to pop and save the selection to a varaible, but I can’t seem to get the variable to pack back to the _main.py tk.Entry field no matter what I try?

import sys
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *
from tkinter.ttk import Entry

import iptoname


def main(*args):
    '''Main entry point for the application.'''
    global root
    root = tk.Tk()
    root.protocol('WM_DELETE_WINDOW', root.destroy)
    # Creates a toplevel widget.
    global _top1, _w1
    _top1 = root
    _w1 = iptoname.IPToName(_top1)
    root.mainloop()

def ip2n_getimport(*args):
    global ip2nimport_path
    import tkinter
    from tkinter import filedialog
    tkinter.Tk().withdraw()  # prevents an empty tkinter window from appearing
    ip2nimport_path = filedialog.askopenfilename(title="Select File")
    print(ip2nimport_path)


    sys.stdout.flush()

python 3.10 …

I’ve tried so many combinations of gluing the variable to the function.Entry path I’m all mixed up.

Any pointers are appreciated , downloading grayson’s book on Tkinter to start reading …

Thanks

Your problem is not as much Tkinter as Python itself.

You write:

This does not define a variable root at the global level. the global root tells Python to make the root variable point at the same variable as the global root variable. The latter does not exist, so the variable remains local. The same for the ip2nimport_path, _top1 and _w1 variables.

To put them at the global level, remove the main() function and place the code to create the root window at the module level. Don’t us a global for _w1, but create an attribute for the root:

root.ip_to_name = iptoname.IPToName(root)

Look at:

  1. Imports are usually placed at the top of your module. Your imports of tkinter and filedialog are out of place.
  2. After you import tkinter all exported variables are usable. So using tkinter.filedialog will have the same effect as what you do now. You can also choose the style of importing explicitly what you want to do as you do in the next line.
  3. The tkinter.Tk().withdraw() as you write is necessary because tkinter has lost the connection to your root variable. It is not necessary when you keep your root around.
  4. Why you create another reference (_top1) for the root? Just pass the original variable:
    iptoname.IPToName(root)

Hi Menno,

You misquoted Michael’s quote. Michael’s code said:

def main(*args):
    '''Main entry point for the application.'''
    global root
    root = tk.Tk()

but when you quoted him, you removed the global root line. You then said “This does not define a variable root at the global level” but that is incorrect, it does create root at the global level.

It does not need to already exist as a global, if it doesn’t exist, the assignment will create it.

It is never the case that a variable declared as global “remains local” because it doesn’t already exist.

# Self-contained example you can run in the interactive interpreter.
def demo():
    global x
    try:
        x
    except NameError:
        print("no global variable x")
    else:
        print("global x already exists:", x)
    x = 1

demo()

If you run that, either in the interactive interpreter or in a script, regardless of the initial state of global x, after calling the demo() function global x will have the value 1.

Hi Michael,

It is not clear what your two chunks of code are. I guess that the first one, containing class IPToName, is the module iptoname.py. Is that correct?

But the second code chunk, containing your def main function, I can’t guess what it is, nor can I tell whether the iptoname_support.py module is a third (unseen) support file, or possibly the main application containing the main function.

And then there is a third (or maybe a fourth) file, _support.py with a leading underscore. And a fourth (or is it fifth ???) file _main.py also with a leading underscore.

So there is a lot of code we cannot see, and cannot guess.

You should try to produce a Minimal Reproducible Example, one which is self-contained so we can run it:

But allow me to brave proceed with some suggestions anyway.

Your first module, iptoname, tries to import iptoname_support, which I will assume is the file containing the main() function.

But that file in turn tries to import iptoname_support, which gives you
a circular import. Circular imports occur when Python is asked to do
this:

# inside module a.py
import b

# inside module b.py
import a

The problem is that at the point that b.py tries to import a.py, the a module isn’t finished initialising yet! So odd errors that are hard to diagnose can occur.

There are ways to manage circular imports correctly that avoid those
errors, but the easiest way to solve the errors is to avoid the circular
import at all!

  1. Python is not Java, and if anyone has taught you to put every class into its own separate file, unlearn that bad advice immediately. It is okay to put all your code into one file.

  2. If you don’t want to move all your code into one .py file, arrange the code so that the main application, the file containing the main() function, imports the other modules, but those modules never import the main application.

Another problem: in your iptoname block of code, at least one line has
the indentation badly messed up:

self.ip2nimportfield = tk.Entry(self.top)

is not indented at all, it is flush with the left, but then followed by indented code. So trying to run that code will give you a SyntaxError.

If you are not seeing that SyntaxError, but some other error, that means that the code you are running is different from the code you have shown us. That makes it hard for us to diagnose bugs in your code if we can’t see it or run it.

Thanks all for the direction and comments and yes all valid especially me being a noob in this area, I’m use to packets and sniffers, not programming, so just starting this journey.

The “self.ip2nimportfield” indent was a copy paste error into the discussion page on my part, it is correctly indented in code.

OK, better picture and using the “Minimum Code” rule (thanks, good guide pointer)

Python 3.10
Using PyCharm IDE
Using Page (tcl based Tkinter UI builder)
Page builds a main testentry.py file for UI elements and a support_testentry.py file for DEF functions called in the main via the UI elements “command” variable, you put a command variable in a UI element and Page adds a def (function) to the support file for you code.

Cut down the example to bear bones

main (testentry.py)

import sys
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *

import testentry_support

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'

        top.geometry("600x450+660+210")
        top.minsize(120, 1)
        top.maxsize(3844, 2141)
        top.resizable(1,  1)
        top.title("Toplevel 0")
        top.configure(background="#d9d9d9")

        self.top = top
        self.importentry_path = tk.StringVar()

        self.importentry = tk.Entry(self.top)
        self.importentry.place(relx=0.283, rely=0.044, height=20, relwidth=0.557)

        self.importentry.configure(background="white")
        self.importentry.configure(disabledforeground="#a3a3a3")
        self.importentry.configure(font="TkFixedFont")
        self.importentry.configure(foreground="#000000")
        self.importentry.configure(insertbackground="black")
        self.importentry.configure(textvariable=self.importentry_path)

        self.EntryButton1 = tk.Button(self.top)
        self.EntryButton1.place(relx=0.117, rely=0.044, height=24, width=47)
        self.EntryButton1.configure(activebackground="#ececec")
        self.EntryButton1.configure(activeforeground="#000000")
        self.EntryButton1.configure(background="#d9d9d9")
        self.EntryButton1.configure(command=testentry_support.importpath_cmd)
        self.EntryButton1.configure(compound='left')
        self.EntryButton1.configure(disabledforeground="#a3a3a3")
        self.EntryButton1.configure(foreground="#000000")
        self.EntryButton1.configure(highlightbackground="#d9d9d9")
        self.EntryButton1.configure(highlightcolor="black")
        self.EntryButton1.configure(pady="0")
        self.EntryButton1.configure(text='''Get File''')

def start_up():
    testentry_support.main()

if __name__ == '__main__':
    testentry_support.main()

and support (testentry_support.py)

import sys
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *

import testentry

def main(*args):
    '''Main entry point for the application.'''
    global root
    root = tk.Tk()
    root.protocol( 'WM_DELETE_WINDOW' , root.destroy)
    # Creates a toplevel widget.
    global _top1, _w1
    _top1 = root
    _w1 = testentry.Toplevel1(_top1)
    root.mainloop()

def importpath_cmd(*args):
    global importentry_path
    import tkinter
    from tkinter import filedialog
    tkinter.Tk().withdraw()  # prevents an empty tkinter window from appearing
    importentry_path = filedialog.askopenfilename(title="Select File")
    print(importentry_path)
    #testentry.Toplevel1()

if __name__ == '__main__':
    testentry.start_up()

As I read more I also realize that this is a General Python forum, not really a GUI specific or Tkinter , so after this I’ll move my posts to more 'Library specific" forums. Read and learn … but thanks for the help.

Still puzzling over this, it sets the variable via the supportfile in “def importpath_cmd” , I just thought I’d have to call testentry.importentry.pack() to get the UI to refresh the importentry tk.Entry field , but so far nothing and no exceptions thrown.

Again, thanks

Thank you for putting that right.

@MikeP : Excuse me for misleading you.