Nguyen Son
Nguyen Son

Reputation: 15

scrollbar with grid in tkinter python

Here is my code (so sorry if it's too long). And I want to create 1 vertical scroll bar. Because I have a lot of lines and I put it in a scrollbar so I can scroll to see the lines that the GUI can't show. I tried with Scrollbar but it is only in 1 row. Sorry my english is not good. Can someone help me?

from tkinter import *
from tkinter import ttk


class LabelAndCombobox:
    def __init__(self, tk_root, row, text_label, value_combobox):
        # self.row = row
        self.text_label = text_label
        self.value_combobox = value_combobox
        self.textvariable = StringVar()
        # label text for combobox
        self.label = ttk.Label(tk_root, text=self.text_label+" ", font=("Times New Roman", 10), relief=RAISED).grid(column=0, row=row, padx=10, pady=5, sticky=W)

        # combobox
        self.combobox = ttk.Combobox(tk_root, width=50, textvariable=self.textvariable, values=self.value_combobox, state='readonly')
        self.combobox.current(None)
        self.combobox.unbind_class("TCombobox", "<MouseWheel>")
        self.combobox.bind('<<ComboboxSelected>>', lambda event: self.changed(event))
        self.combobox.grid(column=1, row=row, sticky=W)

    def changed(self, event):
        print(self.combobox.get())


if __name__ == '__main__':
    a = ["Ăn uống", "Ăn uống > Ẩm thực", "Ăn uống > Ẩm thực > Ẩm thực Hàn Quốc", "Ăn uống > Ẩm thực > Ẩm thực Việt",
         "Ăn uống > Cafe/Nước giải khát", "Ăn uống > Cafe/Nước giải khát > Nước hoa quả", " sinh tố",
         "Ăn uống > Cafe/Nước giải khát > Trà sữa", "Ăn uống > Đồ uống", "Ăn uống > Đồ uống có cồn",
         "Ăn uống > Đồ uống có cồn > Bia", "Ăn uống > Đồ uống có cồn > Rượu", "Ăn uống > Món ăn > Ăn vặt",
         "Ăn uống > Món ăn > Bánh > Bánh Âu", "Ăn uống > Món ăn > Đặc sản", "Ăn uống > Món ăn > Pizza",
         "Ăn uống > Nhà hàng", "Ăn uống > Nhà hàng > Quán nhậu", "Công việc", "Công việc > Dịch vụ chăm sóc cá nhân",
         "Công việc > Dịch vụ chăm sóc cá nhân > Nhân viên thẩm mỹ viện", " spa", "Công việc > Giáo dục",
         "Công việc > Giáo dục > Giáo dục tiểu học", "Công việc > Khoa học > Khoa học kỹ thuật",
         "Công việc > Khoa học > Khoa học kỹ thuật > Trắc địa", "Công việc > Khoa học > Khoa học kỹ thuật > Xây dựng",
         "Công việc > Khoa học > Khoa học kỹ thuật > Xây dựng > Kiến trúc dân dụng",
         "Công việc > Khoa học > Khoa học kỹ thuật > Xây dựng > Kỹ sư xây dựng", "Công việc > Nghệ thuật biểu diễn"]

    b = ["Ăn uống", "Ăn uống > Ẩm thực", "Ăn uống > Ẩm thực > Ẩm thực Hàn Quốc", "Ăn uống > Ẩm thực > Ẩm thực Việt",
     "Ăn uống > Cafe/Nước giải khát", "Ăn uống > Cafe/Nước giải khát > Nước hoa quả, sinh tố"]        

    root = Tk()
    root.geometry("600x700")
    canvas = Canvas(root, height=700, width=600)

    ybar = Scrollbar(root, orient=VERTICAL, command=canvas.yview)
    ybar.grid()
    canvas.config(yscrollcommand=ybar.set)

    count = 1
    for i in a:
        # LabelAndCombobox(root, count, "check  "+str(count), b)
        LabelAndCombobox(root, count, i, b)
        count += 1

    canvas.grid(rowspan=len(a), columnspan=2)
    root.mainloop()

Upvotes: 0

Views: 999

Answers (3)

Nguyen Son
Nguyen Son

Reputation: 15

thank you very much @acw1668. His solution worked for me. Besides i want to use it with mouse wheel. Below is my solution. Hope it's helpful for those who have the same problem

def on_mousewheel(event):
    canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

canvas.bind_all("<MouseWheel>", on_mousewheel)

Upvotes: 0

acw1668
acw1668

Reputation: 46678

You need to:

  • create a frame inside the canvas and put those labels and comboboxes into this frame
  • update scrollregion of canvas when the frame is resized
import tkinter as tk
from tkinter import ttk


class LabelAndCombobox:
    def __init__(self, tk_root, row, text_label, value_combobox):
        # self.row = row
        self.text_label = text_label
        self.value_combobox = value_combobox
        self.textvariable = tk.StringVar()
        # label text for combobox
        self.label = ttk.Label(tk_root, text=self.text_label+" ", font=("Times New Roman", 10), relief=tk.RAISED)
        self.label.grid(column=0, row=row, padx=10, pady=5, sticky=tk.W)

        # combobox
        self.combobox = ttk.Combobox(tk_root, width=50, textvariable=self.textvariable, values=self.value_combobox, state='readonly')
        self.combobox.current(None)
        self.combobox.unbind_class("TCombobox", "<MouseWheel>")
        self.combobox.bind('<<ComboboxSelected>>', lambda event: self.changed(event))
        self.combobox.grid(column=1, row=row, sticky=tk.W)

    def changed(self, event):
        print(self.combobox.get())


if __name__ == '__main__':
    a = ["Ăn uống", "Ăn uống > Ẩm thực", "Ăn uống > Ẩm thực > Ẩm thực Hàn Quốc", "Ăn uống > Ẩm thực > Ẩm thực Việt",
         "Ăn uống > Cafe/Nước giải khát", "Ăn uống > Cafe/Nước giải khát > Nước hoa quả", " sinh tố",
         "Ăn uống > Cafe/Nước giải khát > Trà sữa", "Ăn uống > Đồ uống", "Ăn uống > Đồ uống có cồn",
         "Ăn uống > Đồ uống có cồn > Bia", "Ăn uống > Đồ uống có cồn > Rượu", "Ăn uống > Món ăn > Ăn vặt",
         "Ăn uống > Món ăn > Bánh > Bánh Âu", "Ăn uống > Món ăn > Đặc sản", "Ăn uống > Món ăn > Pizza",
         "Ăn uống > Nhà hàng", "Ăn uống > Nhà hàng > Quán nhậu", "Công việc", "Công việc > Dịch vụ chăm sóc cá nhân",
         "Công việc > Dịch vụ chăm sóc cá nhân > Nhân viên thẩm mỹ viện", " spa", "Công việc > Giáo dục",
         "Công việc > Giáo dục > Giáo dục tiểu học", "Công việc > Khoa học > Khoa học kỹ thuật",
         "Công việc > Khoa học > Khoa học kỹ thuật > Trắc địa", "Công việc > Khoa học > Khoa học kỹ thuật > Xây dựng",
         "Công việc > Khoa học > Khoa học kỹ thuật > Xây dựng > Kiến trúc dân dụng",
         "Công việc > Khoa học > Khoa học kỹ thuật > Xây dựng > Kỹ sư xây dựng", "Công việc > Nghệ thuật biểu diễn"]

    b = ["Ăn uống", "Ăn uống > Ẩm thực", "Ăn uống > Ẩm thực > Ẩm thực Hàn Quốc", "Ăn uống > Ẩm thực > Ẩm thực Việt",
     "Ăn uống > Cafe/Nước giải khát", "Ăn uống > Cafe/Nước giải khát > Nước hoa quả, sinh tố"]        

    root = tk.Tk()
    #root.geometry("600x700")

    canvas = tk.Canvas(root, height=700, width=600)

    ybar = tk.Scrollbar(root, orient=tk.VERTICAL, command=canvas.yview)
    ybar.pack(side=tk.RIGHT, fill=tk.Y)
    canvas.config(yscrollcommand=ybar.set)

    # create a frame inside canvas for those labels and comboboxes
    frame = tk.Frame(canvas)
    canvas.create_window(0, 0, window=frame, anchor='nw')

    # update scrollregion of canvas when the frame is resized
    frame.bind('<Configure>', lambda e:canvas.config(scrollregion=canvas.bbox('all')))

    count = 1
    for i in a:
        # changed root to frame
        LabelAndCombobox(frame, count, i, b)
        count += 1

    canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)

    root.bind('<MouseWheel>', lambda e: canvas.yview_scroll(e.delta//-120, 'units'))

    root.mainloop()

Note that I have changed from tkinter import * to import tkinter as tk because wildcard import is not recommended.

Upvotes: 1

nikost
nikost

Reputation: 858

I found this solution to be most useful.

I have created a scrolled frame class based on this answer, as well as others, which you can find here.

This class can be added to your window/frame with pack or grid. It also allows widgets to be added using pack or frame.

Upvotes: 1

Related Questions