0

I have read Why is the command bound to a Button or event executed when declared?, and the solution provided by Bryan Oakley looks useful, but in my case I need something different (or maybe I'm wrong). Since I need to pass parameters in the class MainFrame.

My code:

views/login.py

import tkinter as tk

from AgileBooks.controllers.login import submit_login

global_font = 'Helvetica'
global_bg = 'gray25'
global_fg = 'lawn green'


class MainFrame():
    # Frame:
    frm_login = tk.Tk()
    frm_login.title('Login | AgileBooks - Copyright Gonzalo Dambra')
    frm_login.geometry('400x300')
    frm_login.configure(background=global_bg)
    # Labels:
    lbl_username = tk.Label(frm_login, text='Username', bg=global_bg, fg=global_fg, font=(global_font, 16))
    lbl_username.place(x=150, y=50)
    lbl_password = tk.Label(frm_login, text='Password', bg=global_bg, fg=global_fg, font=(global_font, 16))
    lbl_password.place(x=150, y=125)
    # Inputtexts:
    txt_username = tk.Entry(frm_login, font=(global_font, 14))
    txt_username.focus()
    txt_username.place(x=100, y=80, height=25, width=200)
    txt_password = tk.Entry(frm_login, show='*',font=(global_font, 14))
    txt_password.place(x=100, y=155, height=25, width=200)
    # Button:
    btn_login = tk.Button(frm_login, text='Login', font=(global_font, 16), bg=global_bg, fg=global_fg,
                          command=submit_login(txt_username.get(), txt_password.get()))
    btn_login.place(x=165, y=200, height=25)


def main():
    frame = MainFrame()
    frame.frm_login.mainloop()


if __name__ == '__main__':
    main()

controllers/login.py:

def submit_login(username, password):
    if len(username) > 0 and len(password) > 0:
        print('Username: ', username, ' | Password: ', password)
    else:
        print('One of the fields is not filled.')

My problem is that the method submit_login is being called without any click event, it is called just on the run of the code. What am I doing wrong?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Gonzalo Dambra
  • 891
  • 2
  • 19
  • 34
  • I don't see how this question is any different than the one you link to. That other question gives you all the information you need to solve this problem. – Bryan Oakley May 21 '19 at 14:33

1 Answers1

1

You're calling submit_login when you bind it to the button:

command=submit_login(txt_username.get(), txt_password.get())

Instead, in Tkinter you can bind the command to a lambda:

command=lambda username=txt_username.get(), password=txt_password.get(): submit_login(username, password)

You'll probably also want to move your call to .get() so that it happens at the time of the click:

btn_login = tk.Button(frm_login, text='Login', font=(global_font, 16), bg=global_bg, fg=global_fg,    
                      command=lambda username=txt_username, password=txt_password: submit_login(username, password)


def submit_login(username, password):
    username = username.get()
    password = password.get()
    if len(username) > 0 and len(password) > 0:
        print('Username: ', username, ' | Password: ', password)
    else:
        print('One of the fields is not filled.')
MrAlexBailey
  • 5,219
  • 19
  • 30
  • 1
    It worked, thank you. And you were right about the use of .get(). – Gonzalo Dambra May 21 '19 at 11:29
  • @GonzaloDambra There's a lot of good reading on the question you linked as well, and while this question should probably have been closed for being a duplicate, sometimes it's helpful to see a direct answer to your exact scenario. I'd suggest reading through Bryan's answer and the links he provides. He's extremely knowledgeable and I'd consider anything from him to be very useful. This is a very common pain point for folks learning Tkinter. – MrAlexBailey May 21 '19 at 11:36
  • 1
    Even better would be to add a method in the class itself so that you can do `... command=self.login`, and then the login method can fetch the data instead of having it passed to it. – Bryan Oakley May 21 '19 at 14:31