tkinter 中带有网格的滚动条 python

scrollbar with grid in tkinter python

这是我的代码(很抱歉,如果它太长)。我想创建 1 个垂直滚动条。因为我有很多行,所以我把它放在滚动条中,这样我就可以滚动查看 GUI 无法显示的行。我尝试使用滚动条,但它只在 1 行中。对不起,我的英语不好。有人可以帮助我吗?

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()

我发现 this solution 最有用。

我根据这个答案以及其他答案创建了一个滚动框架 class,您可以找到 here

这个 class 可以添加到您的 window/frame 包或网格中。它还允许使用 pack 或 frame 添加小部件。

您需要:

  • 在 canvas 中创建一个框架,并将这些标签和组合框放入该框架中
  • 调整框架大小时更新 canvas 的 scrollregion
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()

请注意,我已将 from tkinter import * 更改为 import tkinter as tk,因为不建议使用通配符导入。

非常感谢你 @acw1668. His 为我工作。此外,我想将它与鼠标滚轮一起使用。以下是我的解决方案。希望对遇到同样问题的小伙伴有所帮助

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

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