Next / Previous / Contents / Shipman's homepage

5.6. ScrolledList.__createWidgets(): Lay out internal widgets

This method creates and grids all our internal widgets.
    def __createWidgets(self):
        """Lay out internal widgets.

Here is the grid plan for our internal widgets:


First, we create the vertical scrollbar, if there is one. The sticky=tk.N+tk.S attribute makes the scrollbar stretch to the full height of grid row 0.
        #-- 1
        # [ if self.vscroll ->
        #     self  :=  self with a vertical Scrollbar widget added
        #     self.vScrollbar  :=  that widget ]
        #   else -> I ]
        if  self.vscroll:
            self.vScrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
            self.vScrollbar.grid(row=0, column=1, sticky=tk.N+tk.S)

Next, we create the horizontal scrollbar, if there is one. The sticky=tk.E+tk.W attribute makes it stretch to the width of grid column 0.
        #-- 2
        # [ if self.hscroll ->
        #     self  :=  self with a horizontal Scrollbar widget added
        #     self.hScrollbar  :=  that widget
        #   else -> I ]
        if  self.hscroll:
            self.hScrollbar = tk.Scrollbar(self, orient=tk.HORIZONTAL)
            self.hScrollbar.grid(row=1, column=0, sticky=tk.E+tk.W)

Now we create the Listbox widget. The relief=SUNKEN attribute makes the listbox's contents look like they are recessed into the window. The borderwidth=2 attribute puts a 2-pixel border around the listbox.
        #-- 3
        # [ self  :=  self with a Listbox widget added
        #   self.listbox  :=  that widget ]
        self.listbox = tk.Listbox(self, relief=tk.SUNKEN,
            width=self.width, height=self.height,
        self.listbox.grid(row=0, column=0)

The next step is to create the linkages between the scrollbars and the Listbox. The command attribute of a vertical Scrollbar widget is a method that is called whenever the scrollbar is scrolled by the user; the yview method of a Listbox widget causes its contents to be repositioned. This linkage allows the scrollbar to move the listbox.

However, the linkage is bidirectional. There are operations on the Listbox widget that change its contents' position, and when that happens, the scrollbar's position should also be adjusted. This linkage sets the yscrollcommand attribute of the Listbox to the .set() method of the scrollbar.

The linkages are similar for a horizontal scrollbar.
        #-- 4
        # [ if self.vscroll ->
        #     self.listbox  :=  self.listbox linked so that
        #         self.vScrollbar can reposition it ]
        #     self.vScrollbar  :=  self.vScrollbar linked so that
        #         self.listbox can reposition it
        #   else -> I ]
        if  self.vscroll:
            self.listbox["yscrollcommand"] = self.vScrollbar.set
            self.vScrollbar["command"] = self.listbox.yview

        #-- 5
        # [ if self.hscroll ->
        #     self.listbox  :=  self.listbox linked so that
        #         self.hScrollbar can reposition it ]
        #     self.hScrollbar  :=  self.hScrollbar linked so that
        #         self.listbox can reposition it
        #   else -> I ]
        if  self.hscroll:
            self.listbox["xscrollcommand"] = self.hScrollbar.set
            self.hScrollbar["command"] = self.listbox.xview

So that our widget will respond to the user clicking on a line in the listbox, we use the .bind() method to set up an event binding that will call our .__clickHandler method when that happens.
        #-- 6
        # [ self.listbox  :=  self.listbox with an event handler
        #       for button-1 clicks that causes self.callback
        #       to be called if there is one ]
        self.listbox.bind("<Button-1>", self.__clickHandler)