0

I am creating button which will call a function to import a file into my python program. I am using a for loop combined with os.listdir() to iterate over the files in a given directory. For each file I am creating a button that has the file's name. When the button is pressed a function is called that then imports the file, this function requires 3 parameters, the quiz (a list to append the new data to), a name (the name of the file to get data from), a master (a frame to display a label that shows when the data is imported). Since I am using a for loop to get the names of the files, I am giving that name variable as an argument for the functions name parameter. The problem is that the function is called only when one of the buttons is pressed and this is after the for loop has finished so the program resorts to using the last value for the name variable. For example, if I have 3 files called, file1.txt, file2.txt, and file3.txt, when the button is pressed only file3.txt is given as an argument. This means that I can only import file3.txt and none of the other files.

I am thinking of creating a new frame for each file, and the user will than have to press next to view the next possible file, but this is a less than ideal solution.

from tkinter import *
import os

# classes and functions
class Question():
    def __init__(self, q, a, b, c, ans):
        self.q = q
        self.a = a
        self.b = b
        self.c = c
        self.ans = ans
        self.print = self.q + self.a + self.b + self.c + self.ans


def import_the_save(quiz, name, master):
    frame = Frame(master)
    frame.place(relx=0, rely=0, relwidth=1, relheight=1)
    open_file = open(os.getcwd()+'/saves/' + name, 'r')
    for line in open_file.readlines():
        if line != '\n':
            fields = line.split(' | ')
            print(fields)
            quiz.append(Question(fields[0], fields[1], fields[2], fields[3], fields[4]))
    Label(frame, text='File Imported').pack()
    for item in quiz:
        print(item.print)


def myfunction(event):
    global canvas
    canvas.configure(scrollregion=canvas.bbox("all"))

# This is what actually runs    
root = Tk()

quiz = []

canvas = Canvas(root)
g_frame = Frame(canvas)
myscrollbar = Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=myscrollbar.set)

myscrollbar.pack(side="right", fill="y")
canvas.pack(side="left")
canvas.create_window((0, 0), window=g_frame, anchor='nw')
g_frame.bind("<Configure>", myfunction)

for filename in os.listdir(os.getcwd()+'/saves'):
    if filename.endswith(".txt"):
        file = Button(g_frame, text=filename, command=lambda: import_the_save(quiz, filename, root))
        file.pack()

root.mainloop()

The above code creates a tkinter window, then checks a folder for txt files and returns the file name if they are found. To replicate the problem, you will need a folder called saves inside of the folder where this script is placed. Inside of the saves folder you will need some txt files in which each line looks something like this:

something | something | something | something | something

Basically each line needs to have 5 strings separated by ' | '

As a test I gave the above code 3 different files, with different contents, but no matter which button I press it only imports the 3rd file.

I am a complete beginner, so please give me tips on how I can do this better, and please explain the solutions you pose, in the event that I do not understand.

Thank you for your time.

Kam S
  • 38
  • 1
  • 4
  • Read [Python and Tkinter lambda function](https://stackoverflow.com/a/11005426/7414759) – stovfl Oct 15 '19 at 23:15
  • Possible duplicate of [Working on a way to return the text of a button after the button is clicked in tkinter](https://stackoverflow.com/questions/6195702/working-on-a-way-to-return-the-text-of-a-button-after-the-button-is-clicked-in-t) – stovfl Oct 15 '19 at 23:16
  • Use `lambda q=quiz, f=filename, r=root: import_the_save(q, f, r)`. – acw1668 Oct 15 '19 at 23:17

0 Answers0