「使用grid管理方法添加小部件后的可滚动tkinter画布」

2024-10-04 03:24:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试创建一个画布小部件,其中嵌入了许多小部件。因为在画布上经常会有很多垂直滚动的空间。

import tkinter as tk                # for general gui
import tkinter.ttk as ttk           # for notebook (tabs)

class instructionGeneratorApp():

    def __init__(self, master):

        # create a frame for the canvas and scrollbar
        domainFrame = tk.LabelFrame(master)
        domainFrame.pack(fill=tk.BOTH, expand=1)

        # make the canvas expand before the scrollbar
        domainFrame.rowconfigure(0,weight=1)
        domainFrame.columnconfigure(0,weight=1)

        vertBar = ttk.Scrollbar(domainFrame)
        vertBar.grid(row=0, column=1, sticky=tk.N + tk.S)

        configGridCanvas = tk.Canvas(domainFrame,
                                    bd=0,
                                    yscrollcommand=vertBar.set)
        configGridCanvas.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W)

        vertBar.config(command=configGridCanvas.yview)

        # add widgets to canvas

        l = tk.Label(configGridCanvas, text='Products')
        l.grid(row=1, column=0)

        r = 2
        for product in ['Product1','Product2','Product3','Product4','Product5','Product6','Product7','Product8','Product9','Product10','Product11','Product12','Product13','Product14','Product15','Product16','Product17','Product18','Product19','Product20']:
            l = tk.Label(configGridCanvas, text=product)
            l.grid(row=r, column=0)
            c = tk.Checkbutton(configGridCanvas)
            c.grid(row=r, column=1)
            r += 1

        ButtonFrame = tk.Frame(domainFrame)
        ButtonFrame.grid(row=r, column=0)

        removeServerButton = tk.Button(ButtonFrame, text='Remove server')
        removeServerButton.grid(row=0, column=0)

        # set scroll region to bounding box?
        configGridCanvas.config(scrollregion=configGridCanvas.bbox(tk.ALL))


root = tk.Tk()
mainApp = instructionGeneratorApp(root)

root.mainloop()

据我所知,我遵循的是effbot pattern for canvas scrollbars,但最终要么是一个未绑定到画布的滚动条,要么是一个超出主框架边缘的画布:

screenshot of applicationsmaller screenshot of application

我已经尝试过这些问题的解决方案,但仍有一些东西我没有做到:

resizeable scrollable canvas with tkinter

Tkinter, canvas unable to scroll

你知道我做错什么了吗?


Tags: thetotextfortkinter画布columntk
1条回答
网友
1楼 · 发布于 2024-10-04 03:24:03

据我所知,你正在寻找这样的东西。。在

from tkinter import *


class ProductItem(Frame):
    def __init__(self, master, message, **kwds):
        Frame.__init__(self, master, **kwds)
        self.grid_rowconfigure(1, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.text = Label(self, text=message, anchor='w')
        self.text.grid(row=0, column=0, sticky='nsew')
        self.check = Checkbutton(self, anchor='w')
        self.check.grid(row=0, column=1)


class ScrollableContainer(Frame):
    def __init__(self, master, **kwargs):
        Frame.__init__(self, master, **kwargs)  # holds canvas & scrollbars
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        self.canvas = Canvas(self, bd=0, highlightthickness=0)
        self.hScroll = Scrollbar(self, orient='horizontal',
                                 command=self.canvas.xview)
        self.hScroll.grid(row=1, column=0, sticky='we')
        self.vScroll = Scrollbar(self, orient='vertical',
                                 command=self.canvas.yview)
        self.vScroll.grid(row=0, column=1, sticky='ns')
        self.canvas.grid(row=0, column=0, sticky='nsew')
        self.canvas.configure(xscrollcommand=self.hScroll.set,
                              yscrollcommand=self.vScroll.set)

        self.frame = Frame(self.canvas, bd=2)
        self.frame.grid_columnconfigure(0, weight=1)

        self.canvas.create_window(0, 0, window=self.frame, anchor='nw', tags='inner')

        self.product_label = Label(self.frame, text='Products')
        self.product_label.grid(row=0, column=0, sticky='nsew', padx=2, pady=2)
        self.products = []
        for i in range(1, 21):
            item = ProductItem(self.frame, ('Product' + str(i)), bd=2)
            item.grid(row=i, column=0, sticky='nsew', padx=2, pady=2)
            self.products.append(item)

        self.button_frame = Frame(self.frame)
        self.button_frame.grid(row=21, column=0)

        self.remove_server_button = Button(self.button_frame, text='Remove server')
        self.remove_server_button.grid(row=0, column=0)

        self.update_layout()
        self.canvas.bind('<Configure>', self.on_configure)

    def update_layout(self):
        self.frame.update_idletasks()
        self.canvas.configure(scrollregion=self.canvas.bbox('all'))
        self.canvas.yview('moveto', '1.0')
        self.size = self.frame.grid_size()

    def on_configure(self, event):
        w, h = event.width, event.height
        natural = self.frame.winfo_reqwidth()
        self.canvas.itemconfigure('inner', width=w if w > natural else natural)
        self.canvas.configure(scrollregion=self.canvas.bbox('all'))


if __name__ == "__main__":
    root = Tk()
    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)
    sc = ScrollableContainer(root, bd=2)
    sc.grid(row=0, column=0, sticky='nsew')

    root.mainloop()

相关问题 更多 >