Lect
Lect

Reputation: 93

scrollable listbox within a grid using tkinter

I'm new to this place and tkinter. I am stuck at making a scrollable listbox or canvas. I have tried both widgets. Within this listbox or canvas, I have several entry and label widgets. The origin point is R0,C0. I used row/columnconfigure to stretch the listbox or canvas.

In the main window, I had 4 buttons on row four to column four (0,4->4,4). I placed the scrollbar on column 5. I attempted to use the grid method. The issue I am having is making the scrollbar functional.

Note: Turning the mainframe into a class is only one of the ways I have tried. Packing the scrollbar on the right has worked, with the listbox/canvas packed on the left. However, the listbox/canvas widget that the scrollbar is commanded to does not scroll the listbox/canvas. Also, adding many entry boxes does not cause the listbox/canvas to scroll. Help please.

from tkinter import *
from tkinter.ttk import *

Style().configure("B.TFrame", relief="flat",
background="blue")
Style().configure("R.TFrame", relief="flat",
background="red")
Style().configure("R.TLabel", background="red")

class Application(Frame): 
    def __init__(self, master=None):
        Frame.__init__(self, master, style="B.TFrame") 
        self.grid(sticky=N+S+E+W) 
        self.mainframe()

    def mainframe(self):
        top=self.winfo_toplevel()
        self.menuBar = Menu(top)
        top["menu"] = self.menuBar
        self.subMenu = Menu(self.menuBar, tearoff=0)
        self.subMenu2 = Menu(self.menuBar, tearoff=0)
        self.menuBar.add_cascade(label="File", menu=self.subMenu)
        self.menuBar.add_cascade(label="About", menu=self.subMenu2)
        self.subMenu.add_command(label="Open")
        self.subMenu.add_command(label="Save")
        self.subMenu.add_command(label="Exit")
        self.subMenu2.add_command(label="About")
        self.subMenu2.add_command(label="Help")



        self.data = Listbox (self, bg='red')
        scrollbar = Scrollbar(self.data, orient=VERTICAL)

        self.add = Button(self, text="")
        self.remove = Button(self, text="")
        self.run = Button(self, text="")
        self.stop = Button(self, text="")

        self.data.grid (row=0, column=0, rowspan=4, columnspan=4, sticky=N+E+S+W)
        self.data.columnconfigure(1, weight=1)
        self.data.columnconfigure(3, weight=1)

        self.add.grid(row=4,column=0,sticky=EW)       
        self.remove.grid(row=4,column=1,sticky=EW)
        self.run.grid(row=4,column=2,sticky=EW)
        self.stop.grid(row=4,column=3,sticky=EW)
        scrollbar.grid(column=5, sticky=N+S)

Upvotes: 9

Views: 30262

Answers (3)

Junuxx
Junuxx

Reputation: 14251

Without any content in the listbox, there's nothing to scroll...

This seems to work though (shortened the example a bit). See also the example at the scrollbar documentation.

class Application(Frame):   
    def __init__(self,  master=None):
        Frame.__init__(self, master)    
        self.grid(sticky=N+S+E+W)   
        self.mainframe()

    def mainframe(self):                
        self.data = Listbox(self, bg='red')
        self.scrollbar = Scrollbar(self.data, orient=VERTICAL)
        self.data.config(yscrollcommand=self.scrollbar.set)
        self.scrollbar.config(command=self.data.yview)

        for i in range(1000):
            self.data.insert(END, str(i))

        self.run = Button(self, text="run")
        self.stop = Button(self, text="stop")

        self.data.grid(row=0, column=0, rowspan=4,
                   columnspan=2, sticky=N+E+S+W)
        self.data.columnconfigure(0, weight=1)

        self.run.grid(row=4,column=0,sticky=EW)
        self.stop.grid(row=4,column=1,sticky=EW)

        self.scrollbar.grid(column=2, sticky=N+S)

a = Application()
a.mainframe()
a.mainloop()

Upvotes: 9

JEL
JEL

Reputation: 11

This thread is old but in case somebody else falls across it as I did, it needs a few precisions.

Junuxx's answer doesnt work as is, not only because there is an indentation problem due to difficulties in seizing code here (from "self.run" which is part of the "mainframe" function) but because it seems necessary to put the listbox and the scrollbar in their own frame.

Here is a working code for Python 2 and 3 :

#!/usr/bin/env python2

try:
   # for Python2
   from Tkinter import *
except ImportError:
   # for Python3
   from tkinter import *

class   Application(Frame):
    def __init__(self,  master=None):
        Frame.__init__(self, master)
        self.grid(sticky=N+S+E+W)
        self.mainframe()

    def mainframe(self):
       frame = Frame(self)
       scrollbar = Scrollbar(frame, orient=VERTICAL)
       data = Listbox(frame, yscrollcommand=scrollbar.set,
              bg='red')
       scrollbar.config(command=data.yview)
       scrollbar.pack(side=RIGHT, fill=Y)
       data.pack(side=LEFT, fill=BOTH, expand=1)

       for i in range(1000):
          data.insert(END, str(i))

       self.run = Button(self, text="run")
       self.stop = Button(self, text="stop")

       frame.grid(row=0, column=0, rowspan=4,
                   columnspan=2, sticky=N+E+S+W)
       frame.columnconfigure(0, weight=1)

       self.run.grid(row=4,column=0,sticky=EW)
       self.stop.grid(row=4,column=1,sticky=EW)

a = Application()
a.mainframe()
a.mainloop()

You may find further information here : https://www.effbot.org/tkinterbook/listbox.htm. Hope this helps.

Upvotes: 1

Bryan Oakley
Bryan Oakley

Reputation: 385870

You must define the command attribute to the scrollbar, and you must supply the yscrollcommand attribute to the listbox. These two attributes work together to make something scrollable.

The yscrollcommand option tells the listbox "when you are scrolled in the Y direction, call this command. This is usually the set method of a scrollbar, so that when the user scrolls via arrow keys, the scrollbar gets updated.

The command attribute of a scorllbar says "when the user moves you, call this command". This is usually the yview or xview method of a widget, which causes the widget to change its view parameters in the Y or X direction.

In your case, after creating the widgets you would do this:

self.data.config(yscrollcommand=self.scrollbar.set)
scrollbar.config(command=self.data.yview)

Upvotes: 3

Related Questions