0

Im running into this problem with tkinter, where I want to set the source of a document so my code can work with the file in python using a search button and askopenfilename.

here is the snipped of my code.

...
from tkinter import *
from tkinter import filedialog

root = Tk()
root.title("Alpha")
root.iconbitmap('images\alpha.ico')


def search():
    global location
    root.filename = filedialog.askopenfilename(initialdir="/", title="Select A File",
                                               filetypes=(("txt files", "*.txt"), ("All Files", "*.*")))
    location = root.filename

open_button = Button(root, text="Open File", command=search).pack()


input_txt = open(location, "r", encoding="utf8")
...
root.mainloop()

Problem: As I am running the program, the window opens for a brief moment and I am instantly getting the error that location in the input_txt variable is not defined, which I totally understand. I guess my python code is not waiting for me to press the button in the program window and search for my file so location can be defined. How can I make python wait for open() to return a value for location before trying to define input_txt?

I have tried with

import time
...
location = ''
open_button = Button(root, text="Open File", command=open).pack()
while not location:
    time.sleep(0.1)

this however causes the program to freeze and I know sleep is not the not the best option here. Any suggestions?

  • I don't entirely get what you are trying to achieve here. I get that you want to open a file based on a GUI input from an user, but in your first code snippet I don't get why you define a global variable. You might as well do the manipulation of the input file inside your function. – boomkin Mar 19 '20 at 23:19
  • 1
    I don't think you understand GUI event processing & programming. See @Bryan Oakley's answer to [Tkinter — executing functions over time](https://stackoverflow.com/questions/9342757/tkinter-executing-functions-over-time). – martineau Mar 20 '20 at 00:01

1 Answers1

1

Regarding your question

Like boomkin suggests, I'd advise moving the input_txt = open(location, ...) line into your search function. That way, the program will only try to open from location once you've pressed the button and defined location.

If there's other stuff going on, you could make another function and call that:

def file_handling(location):
    input_txt = open(location, "r", encoding="utf8")
    ... #anything using input_txt

def search():
    root.filename = filedialog.askopenfilename(initialdir="/", title="Select A File",
                                               filetypes=(("txt files", "*.txt"), ("All Files", "*.*")))
    file_handling(root.filename)

open_button = Button(root, text="Open File", command=search)
open_button.pack()
...
root.mainloop()

The issue is that Tkinter objects don't do anything until you reach the mainloop--but once you're in the mainloop, you can't go back and fill anything in. So everything you want to do has to be tied to some sort of input: like a button press (or a keystroke, or a mouseover).

In this case, you want to set location, but you have to wait until you call mainloop and the button starts taking input. But by that time, you've passed the line that needs location and can't go back. That's why I suggest calling the input_txt line from the search function--because it won't get called until you've already gotten the location.

That's a little long-winded, but I hope it illuminated the issue.

As a sidenote

I'd also recommend you declare and pack your widgets separately. That is, change this:

open_button = Button(root, text="Open File", command=search).pack()

to this:

open_button = Button(root, text="Open File", command=search)
open_button.pack()

Otherwise, you end up storing the value of pack() (which is None) instead of storing your widgets (the Button object).

Shadorian
  • 182
  • 1
  • 9
  • Tkinter objects are not idle before the mainloop, mainloop is the infinite loop that gets them shown/drawn and stay on the screen, till termination. – Samuel Kazeem Mar 20 '20 at 05:52