修复包含可滚动图形 Canvas 的 Canvas 的大小 CanvasTkAgg

Fix size of the Canvas who contains a Scrollable FigureCanvasTkAgg

我想问你有没有人可以修复ScrollableTkAggX,

问题是网格位置的tk.Canvas()tk.Tk()总是需要设置gridrowconfigurecolumnconfigure, 要使小部件展开和调整大小,在正常情况下我们可以为小部件设置 widthheight 以获得预定义的 window ,但在这种情况下,我不能这样做是因为 ScrollableTkAggX(tk.Canvas) 它会自动调整大小。

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib.colors import to_hex


class ScrollableTkAggX(tk.Canvas):
    def __init__(self, figure, master, **kw):
        # --- create canvas with scrollbar ---
        facecolor = str(to_hex(figure.get_facecolor()))
        super(ScrollableTkAggX, self).__init__(master, **kw) # , background=facecolor
        self.grid(row=0, column=0, sticky=tk.NSEW)
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)

        self.fig_wrapper = tk.Frame(self) # , background=facecolor
        self.fig_wrapper.grid(row=0, column=0, sticky=tk.NSEW)
        self.fig_wrapper.rowconfigure(0, weight=1)
        self.fig_wrapper.columnconfigure(0, weight=1)

        self.TkAgg = FigureCanvasTkAgg(figure, master=self.fig_wrapper)
        self.TkAggWidget = self.TkAgg.get_tk_widget()
        self.TkAggWidget.configure(background=facecolor)
        self.TkAggWidget.grid(row=0, column=0, sticky=tk.NSEW)

        self.hbar = tk.Scrollbar(self, orient=tk.HORIZONTAL, command=self.xview)
        self.hbar.grid(row=1, column=0, sticky=tk.EW)

        self.configure(xscrollcommand=self.hbar.set, scrollregion=self.bbox(tk.ALL))

        # when all widgets are in canvas
        self.bind('<Configure>', self.on_configure_y)
        # --- put frame in canvas ---
        self.canvas_frame = self.create_window((0, 0), window=self.fig_wrapper, anchor=tk.NW)

    # expand canvas_frame when canvas changes its size
    def on_configure_y(self, event):
        # when all widgets are in canvas
        canvas_height = event.height
        self.itemconfigure(self.canvas_frame, height=canvas_height)
        # update scrollregion after starting 'mainloop' - 20
        self.configure(scrollregion=self.bbox(tk.ALL))

    def on_configure_x(self, width):
        # when all widgets are in canvas
        self.itemconfigure(self.canvas_frame, width=width)
        # update scrollregion after starting 'mainloop'
        self.configure(scrollregion=self.bbox(tk.ALL))

    def Draw(self, width):
        self.on_configure_x(width)
        self.TkAgg.draw()
        self.xview_moveto(0)


if __name__ == '__main__':
    win = tk.Tk()

    fig = Figure(figsize=(2, 2), dpi=120, facecolor='#212121')

    mpl_white_rgb = ((255. / 255.), (255. / 255.), (255. / 255.))
    fig.text(0, 0.5, 'test', fontsize=72, color=mpl_white_rgb)

    tkagg = ScrollableTkAggX(fig, win)

    # try like that and disable them to understand what the problem
    win.rowconfigure(0, weight=1)
    win.columnconfigure(0, weight=1)

    # like that 
    # win.rowconfigure(0, weight=1)
    # win.columnconfigure(0, weight=1)

    win.mainloop()

或与其他 tk.Canvas()

if __name__ == '__main__':
    win = tk.Tk()

    cnv = tk.Canvas(win, width=200, height=200)
    cnv.grid(row=0, column=0, sticky=tk.NSEW)

    # try like that and disable them to understand what the problem
    cnv.rowconfigure(0, weight=1)
    cnv.columnconfigure(0, weight=1)

    # like that
    # cnv.rowconfigure(0, weight=1)
    # cnv.columnconfigure(0, weight=1)

    fig = Figure(figsize=(2, 2), dpi=120, facecolor='#212121')

    mpl_white_rgb = ((255. / 255.), (255. / 255.), (255. / 255.))
    fig.text(0, 0.5, 'test', fontsize=72, color=mpl_white_rgb)

    tkagg = ScrollableTkAggX(fig, cnv)

    # try like that and disable them to understand what the problem
    win.rowconfigure(0, weight=1)
    win.columnconfigure(0, weight=1)


    win.mainloop()

这是一个非常奇怪的解决方案

步骤:

delete self.on_configure_y

add height in call class and set it initial in self.create_window

finaly call and set first tk.Canvas(win), call and set second ScrollableTkAggX(win) in same position grid one under other.

import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib.colors import to_hex


class ScrollableTkAggX(tk.Canvas):
    def __init__(self, figure, height, master, **kw):
        self.height = height
        facecolor = str(to_hex(figure.get_facecolor()))
        # --- create canvas with scrollbar ---
        super(ScrollableTkAggX, self).__init__(master, height=self.height, background=facecolor, **kw)
        self.grid(row=0, column=0, sticky=tk.NSEW)
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)

        self.fig_wrapper = tk.Frame(self, background=facecolor)
        self.fig_wrapper.grid(row=0, column=0, sticky=tk.NSEW)
        self.fig_wrapper.rowconfigure(0, weight=1)
        self.fig_wrapper.columnconfigure(0, weight=1)

        self.TkAgg = FigureCanvasTkAgg(figure, master=self.fig_wrapper)
        self.TkAggWidget = self.TkAgg.get_tk_widget()
        self.TkAggWidget.configure(background=facecolor)
        self.TkAggWidget.grid(row=0, column=0, sticky=tk.NSEW)

        self.hbar = tk.Scrollbar(self, orient=tk.HORIZONTAL, command=self.xview)
        self.hbar.grid(row=1, column=0, sticky=tk.EW)

        # --- put frame in canvas ---
        self.canvas_frame = self.create_window((0, 0), window=self.fig_wrapper, height=self.height, anchor=tk.NW)
        self.configure(xscrollcommand=self.hbar.set, scrollregion=self.bbox(tk.ALL))

    # expand canvas_frame when canvas changes its size
    def on_configure_x(self, width):
        # when all widgets are in canvas
        self.itemconfigure(self.canvas_frame, width=width)
        # update scrollregion after starting 'mainloop'
        self.configure(scrollregion=self.bbox(tk.ALL))

    def Draw(self, width):
        self.on_configure_x(width)
        self.TkAgg.draw()
        self.xview_moveto(0)

if __name__ == '__main__':
    win = tk.Tk()

    cnv = tk.Canvas(win, width=200, height=200)
    cnv.grid(row=0, column=0, sticky=tk.NSEW)

    fig = Figure(figsize=(2, 2), dpi=120, facecolor='#212121')

    mpl_white_rgb = ((255. / 255.), (255. / 255.), (255. / 255.))
    fig.text(0, 0.5, 'test', fontsize=72, color=mpl_white_rgb)

    tkagg = ScrollableTkAggX(figure=fig,  master=win, height=200)
    tkagg.grid(row=0, column=0, sticky=tk.NSEW)


    win.mainloop()