0

I'm trying to make some simple program to open url if the condition fits.

Here's the minimal reproducible example.

from tkinter import *
import requests
from bs4 import BeautifulSoup
import webbrowser
import time

def call_back(event):
    input_id.delete(0,END)
    return None

def open_browse(url):
    webbrowser.open_new(url)



win = Tk()
win.geometry("150x150")
win.title("Example")

search_btn = Button(win)
search_btn.config(text="search")
search_btn.config(width=5,height=1)
search_btn.grid(column = 2, row = 2)


def search_chr():
    
    chr_list = ["test1","test2"]
    result = [(0,"test_r_1"),(0,"test_r_2")]
    var_dict = {}
    num = -1
    for ch in chr_list:
        num += 1
        var_dict["output%s" %num] = Entry(win, width = 10)
        
        
        if result[0] == 0:
            pass
        else:
            link_url = result[num][1]
            print(link_url)
            var_dict["o-button%s" %num] = Button(win, command=lambda aurl=link_url:open_browse(link_url))
            var_dict["output"+str(num)].insert(0, "Text")
            var_dict["output"+str(num)].grid(column = 0, row = 0+num, columnspan = 4, sticky=W, padx=5, pady=5)
            var_dict["o-button"+str(num)].config(text="URL")
            
            var_dict["o-button"+str(num)].grid(column = 4, row = 0+num, sticky=E, padx=5, pady=5)
            var_dict["output"+str(num)].config(state="disabled")

search_btn.config(command = search_chr)


win.mainloop()

So, if you run the code, there would be a button. And if you click it, There will be two sets of Label with "Text" in it and Button with "URL" in it. When you press the URL button, it should open a browse with a given url.

As you see the printed text in your terminal, the url is supposed to be "test_r_1" and "test_r_2" But, if you press each button, all buttons are directed to "test_r_2". It seems that it somehow overwrote the previous "test_r_1" as well.

If anyone can explain how to make each button to link to each url, it would be perfect. Thanks for stopping by, and I hope you can help me with this.

Jeong In Kim
  • 373
  • 2
  • 12
  • 1
    Voting to close as a typo. The point of `lambda aurl=link_url` is that the name `aurl` is bound immediately, to avoid the problem of `link_url` using late binding. So clearly, `open_browse(link_url)` needs to be `open_browse(aurl)` instead. I judge this as a typo because someone who didn't understand the problem would not think to use the trick in the first place. – Karl Knechtel Aug 18 '22 at 04:05

1 Answers1

0

Okay, I tracked down that I didn't fully understand that how lambda works.

So I changed my search keyword and found this beautiful question and answer.

Tkinter assign button command in loop with lambda

I changed

var_dict["o-button%s" %num] = Button(win, command=lambda aurl=link_url:open_browse(link_url))
        

into

var_dict["o-button%s" %num] = Button(win, command=lambda link_url=link_url:open_browse(link_url))

and it worked.

Thanks all!

Jeong In Kim
  • 373
  • 2
  • 12
  • I haven't found any difference by changing this also, both question code and changed code is working fine for me? Nither I understood your question nor this answer! – imxitiz Aug 09 '21 at 05:20
  • Well, I tested again but the first code still sends wrong url. if you click first button in first code, it will open "test_r_2" instead of "test_r_1". and if you try the same button in the fixed code, it will give you "test_r_1" – Jeong In Kim Aug 09 '21 at 05:23
  • You really didn't have to change it that way necessarily, you simply should have used `command=lambda aurl=link_url:open_browse(aurl)` also that is how the other functions work too – Matiiss Aug 09 '21 at 07:12
  • @Matiiss Thanks! That's what I learnt. I didn't know how lambda assign variables in loops. I thought that the first one would work, but it turns out, I needed to match those two aurl in your suggested code. Thanks a lot Matiiss! – Jeong In Kim Aug 10 '21 at 02:10