eat-sleep-code
eat-sleep-code

Reputation: 4855

TKinter/TTK: Multiple elements in a clickable area

I was curious if it is possible to create an clickable element that contains multiple elements?

ttk.Button appears to take text or an image.

I would like to have a clickable element that will have 8 text items and 2 images inside it. Clicking anywhere in that element will trigger the same backend method.

Any code examples would be helpful as still wading through TKinter -- only my second project to use it.

Upvotes: 1

Views: 708

Answers (2)

user15801675
user15801675

Reputation:

What you can do is get the children of the tk.Frame and bind them to a function.

from tkinter import *
from tkinter import messagebox
class ClickFrame:
    def __init__(self,root):
        self.root = root
        self.root.geometry("700x500")
        Label(self.root,text="Clickable Frame!",font=("arial",15)).pack(fill=X,side=TOP)
        self.Frame1 = Frame(self.root,bg="light grey")
        self.Frame1.pack(fill=BOTH,expand=1,padx=100,pady=100)
        for  i in range(8):
            Label(self.Frame1,text=f"This is Label {i}").pack(pady=5,anchor="w",padx=5)
        self.Frame1.bind("<Button-1>",self.detect_click)
        for wid in self.Frame1.winfo_children():
            wid.bind("<Button-1>",self.detect_click)
    def detect_click(self,event,*args):
        
        messagebox.showerror("Clicked",f"Clicked  the widget {event.widget}")
        print(event.widget,type(event.widget))
        
        
root=Tk()
ob=ClickFrame(root)
root.mainloop()

You also can use bind_all() to bind . However, this will bind everything in the window.

from tkinter import *
from tkinter import messagebox
class ClickFrame:
    def __init__(self,root):
        self.root = root
        self.root.geometry("700x500")
        Label(self.root,text="Clickable Frame!",font=("arial",15)).pack(fill=X,side=TOP)
        self.Frame1 = Frame(self.root,bg="light grey")
        self.Frame1.pack(fill=BOTH,expand=1,padx=100,pady=100)
        for  i in range(8):
            Label(self.Frame1,text=f"This is Labe {i}").pack(pady=5,anchor="w",padx=5)
        self.Frame1.bind_all("<Button-1>",self.detect_click)
    def detect_click(self,event,*args):
        messagebox.showerror("Clicked",f"Clicked  the widget {event.widget}")
        
root=Tk()
ob=ClickFrame(root)
root.mainloop()

Upvotes: 0

Art
Art

Reputation: 3089

Use bindtags and give the same tag for all widgets that you want to be clickable, then use bind_class to bind all the widgets.

Here's an example

import tkinter as tk

def clicked(event):
    print("Clicked !")


class ClickableElement(tk.Frame):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        self.bindtags('Click')  # or pass a list if you want to have multiple tag names

        for x in range(8):
            lbl = tk.Label(self, text=f"Text {x}")
            lbl.bindtags('Click')
            lbl.pack()
        

root = tk.Tk()
root.geometry("200x200")


frame = ClickableElement(root) # or tk.Frame(root, class_='Click')
frame.pack(fill='both', expand=True)


frame2 = tk.Frame(root, bg='red')
frame2.pack(expand=True, fill='both')


root.bind_class('Click', "<Button-1>", clicked)
root.mainloop()

The above example will make both text and Frame clickable. You can expand on this to include images. Alternatively, You can use bind on each widget inside the frame.

Upvotes: 2

Related Questions