0

I am a Python beginner (started from scratch about 2 months ago) and don't know what I am doing wrong so any guidance is appreciated.

I'm currently trying to create a simple TKinter app to display search results using a basic API call.

All widgets are displaying fine but the problem is that the event to open the hyperlink is always set to the very last value in the for loop. In other words, after running the program, whenever I click on the link k.bind("<Button-1>", lambda x: callback(blah_list[i])) the link with the very last value of [i] opens. So, doesn't matter which of the label Widgets I click on, I always end up opening the the last results URL.

Hope I've explained the problem clearly?

I think I know what the problem is but don't know how to fix it. After doing some searching, I found that it may be a good idea to store the widgets in a list, which is what I have tried to do as can be seen in the code below, but it doesn't seem to make any difference.

from requests.auth import HTTPBasicAuth
from tkinter import *


root = Tk()
def callback(url):
    webbrowser.open_new(url)
    
def search_website():

    search_button.config(state="disabled")
    auth =  HTTPBasicAuth('my_API_key', '')
    sq = search_query.get()
    payload={'q':sq}
    r = requests.get(url='my_search_URL', params= payload, auth=auth)
    d = r.json()
    results = d['results']
    
    title_list = []
    blah_list = []
    tags_list = []

    if not results:
        j = Label(root, text="No search results found\n", wraplength=200, justify="left")
        j.grid(row=3, columnspan= 3, sticky=W, padx=5, pady=5)
    else:
        j = Label(root, text="Title", wraplength=400, justify="left")
        j.grid(row=3, column=0, sticky=W, padx=5, pady=5)
        k = Label(root, text="Link", font="Calibri 15", wraplength=350, justify="left")
        k.grid(row=3, column=1, sticky=W, padx=5, pady=5)
        l = Label(root, text="Tags")
        l.grid(row=3, column=2, sticky=E, padx=5, pady=5)
        for i in range(len(results)):
            title_list.append(results[i]['title']) #Storing results in list
            blah_list.append(results[i]['itemUrl'])
            tags_list.append(results[i]['tags'])
            
        for i in range(len(results)):
            j = Label(root, text=title_list[i], wraplength=400, justify="left")
            j.grid(row=i+4, column=0, sticky=W, padx=5, pady=5)
            blah = StringVar()
            blah.set(blah_list[i])
            k = Entry(root, textvariable= blah, width=110, justify="left", fg='#0000EE', font="Calibri 15 underline", cursor="hand2")
            k.bind("<Button-1>", lambda x: callback(blah_list[i]))
            k.grid(row=i+4, column=1, sticky=W, padx=5, pady=5)
            l = Label(root, text=tags_list[i])
            l.grid(row=i+4, column=2, sticky=E, padx=5, pady=5)
            
            
    
name_s = Label(root, text="Enter search term")
name_s.grid(row=0, columnspan=2)

search_query = Entry(root)
search_query.grid(row= 1, columnspan=2)

search_button = Button(root, text="Search something", relief=GROOVE, command=search_website)
search_button.grid(row=2, columnspan=3)
root.mainloop()

I'm sure the code contains lots of things that are probably not considered best practice and Python veterans might be unhappy looking at the code, so, feel free to provide feedback so I can improve!

  • It looks like it should, but I am not able to quite able to adapt it to fit my code. I am guessing, I should change this line ``` k.bind("", lambda x: callback(blah_list[i]))``` Would you be so kind to suggest what should I change it to? – user14752375 Feb 19 '21 at 09:06
  • Try `k.bind("", lambda e, i=i: callback(blah_list[i]))`. – acw1668 Feb 19 '21 at 09:11
  • OK, yes, that worked! Would you be able to explain why (or How) this works to a beginner? – user14752375 Feb 19 '21 at 09:13
  • The link provided has explanation. – acw1668 Feb 19 '21 at 09:28
  • Thanks for your help. I went to that link again and then to another link which linked me to https://docs.python.org/3/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result and this explanation now makes sense. – user14752375 Feb 19 '21 at 10:36

0 Answers0