0

(Attempt 1): Command in the button executes without showing the button widget. (I would like the user click browse button to select the file) (Attempt 2): If I use lambda then the next chunk of code immediately after the button gets executed throwing error. As the merge_doc = MailMerge(file_name) gets its file_name only after the button command gets executed. Please suggest.

Attempt 1

from tkinter import *
from tkinter import ttk
from mailmerge import MailMerge
import tkinter as tk
import os
from tkinter import filedialog
import tkinter.font as font


root = tk.Tk()
root.geometry("")
root.title("Test")

file_name=""

def main():
    global file_name
    file = filedialog.askopenfile(initialdir="./")
    if file: 
        file_name=file.name
 
browse_button = Button(root, text ='BROWSE',command=main())
browse_button.grid(row=1, column=0, padx=10, ipadx=25,ipady=35)
browse_button.grid_forget()

merge_doc = MailMerge(file_name)

Attempt 2

from tkinter import *
from tkinter import ttk
from mailmerge import MailMerge
import tkinter as tk
import os
from tkinter import filedialog
import tkinter.font as font



root = tk.Tk()
root.geometry("")
root.title("Test")



file_name=""

def main():
    global file_name
    file = filedialog.askopenfile(initialdir="./")
    if file: 
        file_name=file.name
 
browse_button = Button(root, text ='BROWSE',command=lambda:main())
browse_button.grid(row=1, column=0, padx=10, ipadx=25,ipady=35)
browse_button.grid_forget()


merge_doc = MailMerge(file_name)

Error thrown during Attempt 2:

Traceback (most recent call last):
File "C:\Users\Rocky\Desktop\TEST\Testnew.py", line 30, in <module>
merge_doc = MailMerge(file_name)
File "C:\Python38\lib\site-packages\mailmerge.py", line 25, in __init__
self.zip = ZipFile(file)
File "C:\Python38\lib\zipfile.py", line 1251, in __init__
self.fp = io.open(file, filemode)
FileNotFoundError: [Errno 2] No such file or directory: ''

3 Answers 3

1

If you want user to click the BROWSE button to select file, then you can use wait_variable():

import tkinter as tk
from tkinter import filedialog
from mailmerge import MailMerge

root = tk.Tk()

filename = tk.StringVar()

def main():
    file = filedialog.askopenfilename(initialdir='./')
    filename.set(file)

browse_button = tk.Button(root, text='BROWSE', command=main)
browse_button.grid(row=1, column=0, padx=10, ipadx=25, ipady=35)

root.wait_variable(filename) # wait for filename to be updated
browse_button.grid_forget()

# should cater empty filename (user click Cancel in file dialog)
merge_doc = MailMerge(filename.get())
...

Note that you need to cater when user click Cancel button in the file selection dialog.

Sign up to request clarification or add additional context in comments.

Comments

0

According to your 1st attempt, you make a button and grid it as:

browse_button = Button(root, text ='BROWSE',command=main())
browse_button.grid(row=1, column=0, padx=10, ipadx=25,ipady=35)

But then you call grid_forget() function which is vanishing the button from tkinter window.

browse_button.grid_forget()

After all, you have to add root.mainloop() to run the window infinitely. And change

browse_button = Button(root, text ='BROWSE',command=main())

to

browse_button = Button(root, text ='BROWSE',command=main)

2 Comments

When you put command=main(), it immediately calls the main() function. As the main() function returns nothing, so None will be stored in command. So after the first call of main(), you can't call it again by pressing the button. But when you write command=main, then command is taking a callable whose name is main. Then you can call main() every time you click the button.
I have removed the browse_button.grid_forget() for time being and also change the command=main() to command=main. root.mainloop() is placed at the end of the source code. Still getting the same error as shown in "Attempt 2". I think I just need to find a way to wait for the command button gets its value before the code merge_doc = MailMerge(file_name) attempts to run.
0

On second attempt, put the merge_doc = MailMerge(file_name) statement inside if file: block on main().

Because, when python reads the code, initially the file_name variable contains "". So, before pressing any button, it calls merge_doc = MailMerge(file_name) where file_name is "". So, if you want to call the method after choosing the file, put it inside the if block.

1 Comment

Sorry, I can't afford to put that piece of code in the IF block. The problem is there are numerous interdependent codes that goes after merge_doc = Mailmerge(file_name), I meant to say, the core script starts only after merge_doc gets it desired value. There are numerous other widgets too.The source code shown in both attempts is for simple illustration only.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.