Home > Mobile >  tkinter: How can I use one vertical scroll bar to scroll two canvases?
tkinter: How can I use one vertical scroll bar to scroll two canvases?

Time:11-06

In my UI I need two canvases, each with their own horizontal scroll bar, but with a single scroll bar controlling the vertical movement of both canvases.

The following code creates two canvases, each with their own horizontal and vertical scrollbars. How can I get rid of one of the vertical scrollbars? Apologies for the length of code, it's as canonical as I could make it.

from tkinter import *
from tkinter import ttk

class MainUI:
    def __init__(self, root):

        mainframe = Frame(root)
        mainframe.grid(column=0, row=0, sticky=(N,W,E,S))

        # set up the first canvas, with large red triangle
        canvas1 = Canvas(mainframe, background="turquoise")
        canvas1.grid(column=1, row=1, sticky=(N,S,W,E))

        canvas1_hscroller = Scrollbar(mainframe, orient="horizontal",command=canvas1.xview)
        canvas1_hscroller.grid(column=1, row=2, sticky=(W,E))
        canvas1.configure(xscrollcommand=canvas1_hscroller.set)

        canvas1_vscroller = Scrollbar(mainframe, orient="vertical",command=canvas1.yview)
        canvas1_vscroller.grid(column=2, row=1, sticky=(N,S))
        canvas1.configure(yscrollcommand=canvas1_vscroller.set)

        points = [0,0,1000,800,800,1000]
        triangle = canvas1.create_polygon(points,fill="red")

        canvas1.configure(scrollregion=canvas1.bbox("all"))

        # set up the second canvas, with large green triangle
        canvas2 = Canvas(mainframe, background="orange")
        canvas2.grid(column=3, row=1, sticky=(N,S,W,E))

        canvas2_hscroller = Scrollbar(mainframe, orient="horizontal",command=canvas2.xview)
        canvas2_hscroller.grid(column=3, row=2, sticky=(W,E))
        canvas2.configure(xscrollcommand=canvas2_hscroller.set)

        canvas2_vscroller = Scrollbar(mainframe, orient="vertical",command=canvas2.yview)
        canvas2_vscroller.grid(column=4, row=1, sticky=(N,S))
        canvas2.configure(yscrollcommand=canvas2_vscroller.set)

        points = [0,0,1000,800,800,1000]
        triangle = canvas2.create_polygon(points,fill="green")

        canvas2.configure(scrollregion=canvas2.bbox("all"))

root = Tk()
ui = MainUI(root)
root.mainloop()

CodePudding user response:

First make the canvases attributes of the instance:

...
self.canvas1 = Canvas(mainframe, background="turquoise")
...
self.canvas2 = Canvas(mainframe, background="orange")

and use the self. prefix everywhere where you reference previously canvas1 and canvas2

Then define a new method

def v_scroll(self, *args):
    self.canvas1.yview(*args)
    self.canvas2.yview(*args)

Then just set the scrollbar command to that method:

canvas_vscroller = Scrollbar(..., command=self.v_scroll)

Additionally, don't use from tkinter import *, it is bad practice to use * when importing modules. Import only what you need. For example in this case

from tkinter import Tk, Frame, Canvas, Scrollbar

Complete example (using import tkinter as tk which is even better):

import tkinter as tk


class MainWindow(tk.Tk):
    def __init__(self):
        super().__init__()

        # set up the first canvas, with large red triangle
        self.canvas1 = tk.Canvas(self, background="turquoise")
        self.canvas1.grid(column=0, row=0, sticky='news')

        self.canvas1_hscroller = tk.Scrollbar(self, orient="horizontal", command=self.canvas1.xview)
        self.canvas1_hscroller.grid(column=0, row=1, sticky='we')
        self.canvas1.configure(xscrollcommand=self.canvas1_hscroller.set)

        points = [0, 0, 1000, 800, 800, 1000]
        self.canvas1.create_polygon(points, fill="red")

        self.canvas1.configure(scrollregion=self.canvas1.bbox("all"))

        # set up the second canvas, with large green triangle
        self.canvas2 = tk.Canvas(self, background="orange")
        self.canvas2.grid(column=1, row=0, sticky='news')

        self.canvas2_hscroller = tk.Scrollbar(self, orient="horizontal", command=self.canvas2.xview)
        self.canvas2_hscroller.grid(column=1, row=1, sticky='we')
        self.canvas2.configure(xscrollcommand=self.canvas2_hscroller.set)

        points = [0, 0, 1000, 800, 800, 1000]
        self.canvas2.create_polygon(points, fill="green")

        self.canvas2.configure(scrollregion=self.canvas2.bbox("all"))

        self.v_scroller = tk.Scrollbar(self, orient='vertical', command=self.v_scroll)
        self.v_scroller.grid(column=2, row=0, sticky='ns')
        self.canvas1.config(yscrollcommand=self.v_scroller.set)

    def v_scroll(self, *args):
        self.canvas1.yview(*args)
        self.canvas2.yview(*args)


root = MainWindow()
root.mainloop()

And btw, rows and columns start from 0, so first row and column would be row=0, column=0 accordingly

  • Related