1

I am trying to make a custom scrollbar widget for tkinter in Python3. I'm using classes and functions to organise my code. I have a boolean variable that needs to be accessed by the rest of the program to determine whether the scrollbar is active so that it can be updated visually to move with the user's mouse. Changing this variable is done within two functions however when I observe the variable outside the function it has nto updated which has made me believe that I'm doing something wrong with how I am handling self, or just how global and local variables work inside functions and classes. I tried a number of things however I could not get it to work.

Here are the two functions that change the variable:

def scrollOn(self):
    self.scrolling = True
def scrollOff(self):
    self.scrolling = False

Both of these functions are triggered by tkinter bind events from a tkinter.Button:

scrollBar = tk.Button(window, bg = "#000000")
scrollBar.place(x = 390, y = 30, width = 20, height = 40)
scrollBar.bind("<Button-1>", lambda s = self : scrollOn(s))
scrollBar.bind("<ButtonRelease-1>", lambda s = self : scrollOff(s))

This is all of the code:

import tkinter as tk

class scrollbar:

    scrolling = False   

    def __init__(self, window):

        scrollFrame = tk.Frame(window, bg = "#666666")
        scrollFrame.place(x = 10, y = 10, width = 400, height = 400)

        scrollBounds = tk.Frame(window, bg = "#444444")
        scrollBounds.place(x = 390, y = 30, width = 20, height = 360)

        upButton = tk.Button(window, text = "")
        upButton.place(x = 390, y = 10, width = 20, height = 20)

        downButton = tk.Button(window, text = "")
        downButton.place(x = 390, y = 390, width = 20, height = 20)

        def scrollOn(self):
            self.scrolling = True
        def scrollOff(self):
            self.scrolling = False
            
        scrollBar = tk.Button(window, bg = "#000000")
        scrollBar.place(x = 390, y = 30, width = 20, height = 40)
        scrollBar.bind("<Button-1>", lambda s = self : scrollOn(s))
        scrollBar.bind("<ButtonRelease-1>", lambda s = self : scrollOff(s))

        def updateScrollbar(self):
            if self.scrolling == True:
                print("SCROLLING")
            window.after(1, lambda s = self : updateScrollbar(s))
            
        window.after(1, lambda s = self : updateScrollbar(s))

I tried a few different configurations that came to mind when trying to solve this problem however I couldn't solve it. Observing the variable inside the two functions returns the correct result. Any help and guidance would be much appreciated, constructive criticism on how I've wrote my code is appreciated too

  • 1
    But why would you make a button into a scrollbar..? Also `updateScrollbar` is not being called. You probably need to call the function within another event callback like: `scrollBar.bind("", lambda e, s = self : updateScrollbar(s))`, notice the `e` being passed on, it is important, so you might as well make it into a method rather than nested function. – Delrius Euphoria May 21 '23 at 13:45
  • 1
    If all three function inside `__init__.` It will not work. – toyota Supra May 21 '23 at 14:27
  • It will work if all three functions outside of __init__. – toyota Supra May 21 '23 at 14:29
  • I'm making a button into a scrollbar because I like the visuals it has when clicked. updateScrollbar is being called where I use window.after(). – Darrian Penman May 21 '23 at 15:11
  • @DarrianPenman `updateScrollbar` requires to be executed first so that the `after` calls can be scheduled, you example does not show that – Delrius Euphoria May 21 '23 at 19:04
  • It doesn't need to be like that and works completely fine. – Darrian Penman May 22 '23 at 19:12

1 Answers1

2

self scrollOn and in scrollOff is not scrollbar, it's a ButtonPress event. Remove the parameter or change it to something else

def scrollOn():
    self.scrolling = True

def scrollOff():
    self.scrolling = False

scrollBar = tk.Button(window, bg="#000000")
scrollBar.place(x=390, y=30, width=20, height=40)
scrollBar.bind("<Button-1>", lambda s=self: scrollOn())
scrollBar.bind("<ButtonRelease-1>", lambda s=self: scrollOff())
Guy
  • 46,488
  • 10
  • 44
  • 88