1

I am making a custom button using the tk.Label and my own class so i can import use this in a separate module of a project i don't know how i can replicate the command= function of the button object, is this a implementation of the callback function or if not where should i look for information on how to acomplish this

import tkinter as tk

class Main(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.geometry(self, "800x400")
        tk.Tk.config(self, bg="black")
        container = tk.Frame(self)
        container.config(bg="black")
        container.pack(side="top", fill="both", expand="true", pady=30)
        this = Nav(container, text="Button 1")
        this.bind("<Button>", lambda event: print("HELLO"))
        this.pack()
        Nav(container, text="Button 2")

class Nav(tk.Label):
    def __init__(self, *args, **kwargs):
        btn = tk.Label.__init__(self, *args, **kwargs, bg="green")

    def on_enter(event, ref):
        ref.config(text="enter", bg="#990000")
    def on_leave(event, ref):
        ref.config(text="leave", bg="black")
    def left_click(event, ref):
        ref.config(text="left click")
        return True;
    def release(event, ref):
        ref.config(text="release")


app = Main()
app.mainloop()
2
  • Do you want to add a property called command to your custom button, which mimics the property that exists for standard buttons, or do you simply need a callback function activated when left clicking the button? Commented Dec 28, 2019 at 18:23
  • @sciroccorics if its possible a parameter which mimics the standard button. Commented Dec 28, 2019 at 18:58

2 Answers 2

1

You need to do four things:

  • have the caller pass in a command parameter, like you do with a Button,
  • have your new class save this command in a variable
  • implement a binding within Nav to call an internal function
  • have that internal function call the saved command

For example, start by adding a command to Main, and passing that command to Nav just like you would do with a Button:

class Main(tk.Tk):
    def __init__(self, *args, **kwargs):
        ...
        this = Nav(container, text="Button 1", command=self.do_something)
        ...

    def do_something(self):
        print("do_something was called")

Next, define Nav to accept this parameter.

Note: you're mistakingly using both inheritance and composition (inheriting from Label and also creating a second Label) which is unnecessary, so I'm going to remove the second label in the following example.

Since a Label doesn't support the command keyword arg, we need to pull that out of kwargs and save it to a variable before passing the remaining arguments to the __init__ of Label,

class Nav(tk.Label):
    def __init__(self, *args, **kwargs):
        self.command = kwargs.pop("command", None)
        super().__init__(*args, **kwargs, bg="green")

Your original code has a call to bind in Main, but if you're trying to mimic a widget then the bindings need to be inside the widget. With that, this new widget will work just like a button, by specifying a command rather than bindings.

This is how you would define the <Enter>, <Leave>, <ButtonPress> and <ButtonRelease> events. I've renamed the functions from your original code to be more consistent with each other.

class Nav(tk.Label):
    def __init__(self, *args, **kwargs):
        ...

        self.bind("<Enter>", self.on_enter)
        self.bind("<Leave>", self.on_leave)
        self.bind("<ButtonPress>", self.on_press)
        self.bind("<ButtonRelease>", self.on_release)

And finally, you need to define these methods. Here's the one you're specifically asking about which implements the command functionality:

class Nav(tk.label):
    ...
    def on_release(self, event):
        if self.command is not None:
            self.command()

Here are the other methods, replacing ref with self, and putting the arguments in the correct order:

def on_enter(self, event):
    self.config(text="enter", bg="#990000")

def on_leave(self, event):
    self.config(text="leave", bg="black")

def left_click(self, event):
    self.config(text="left click")
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for such an informative answer, i was surprised at how easy this was to implement hope others find a link here should they require. +1 for the tips about the inheritance.
1

Question: how i can implement the command= named argument of my own Button object.

To get he same usage as command= and the callback like def callback(), you have to bind to self.on_left_click which calls the callback.


Reference:

  • Events and Bindings

    Use the bind method of the Label widget to bind a callback function to an event called "<Button-1>".


class Nav(tk.Label):
    def __init__(self, parent, **kwargs):
        self.command = kwargs.pop('command', None)

        # Defaults
        kwargs['bg'] = kwargs.get('bg', "green")
        kwargs['fg'] = kwargs.get('fg', "white")

        super().__init__(parent, **kwargs)

        self.bind("<Button-1>", self.on_left_click)
   
    def on_left_click(self, event):
        self.command()

Usage:

nav_button = Nav(container, text="Button 1", command=lambda: print("HELLO"))
nav_button .pack()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.