pythontkinter-label

Creating tkinter labels with links using a for loop results in all links pointing to the same URL. Why?


I need to create a lot of labels with links (binds) in tkinter. I am using a for loop to go through a dataset to create the labels. But in the result all labes link to the same URL (the last).

This is my code:

from tkinter import *
import os

root = Tk()

dataset =[['Google', 'http://www.google.com'], ['Ecosia', 'http://www.ecosia.org'], ['IBM', 'http://www.ibm.com']]

def create_links(dataset):
    docs = []
    for i, data in enumerate(dataset):
        docs.append(Label(root, text=data[0], fg="blue", cursor="hand2"))
        docs[i].bind('<Button-1>', lambda e: os.system(f'start {data[1]}'))
        docs[i].pack()


create_links(dataset)
root.mainloop()

If running the for loop directly (not in function) ist works fine. Why is that?

In my real application I need to run the for loop in a function. Help would be highly appreciated.


Solution

  • As was noted in the comments, your issue arises from the fact that (as is noted here), your data variable is not local to the lambdas, but is defined in the outer scope, and is evaluated when the lambda is called not when it is defined!

    The workaround is to define a local variable in your lambdas, which is evaluated when the lambda is defined.

    In code:

    def create_links(dataset):
        docs = []
        for i, data in enumerate(dataset):
            docs.append(Label(root, text=data[0], fg="blue", cursor="hand2"))
            docs[i].bind('<Button-1>', lambda e, l=data[1]: os.system(f'start {l}'))
            docs[i].pack()