менеджер сетки не размещает фрейм в левом верхнем углу - PullRequest
0 голосов
/ 30 апреля 2020

Я отлаживаю прокручиваемый фрейм, чтобы удерживать фрейм, который увеличивается до большего размера, а затем уменьшается (содержащиеся виджеты уничтожаются, а меньшее количество помещается обратно). фрейм: frame.grid (column = 0, row = 0, sticky = 'nw'). Тем не менее, меньший кадр помещается в середине холста. Если вы запустите этот пример, вы сначала получите список из 9 кнопок и записей. Если вы нажмете кнопку «Показать больше», вы увидите все 30 кнопок / записей. Затем, нажав кнопку «Показать меньше», вы увидите исходную рамку, за исключением того, что она не будет находиться в северо-западном углу холста.

import tkinter as tk
from tkinter import ttk
import os
import inspect
import functools
import sys

class ScrollableFrame:
    # https://blog.tecladocode.com/tkinter-scrollable-frame
    def __init__(self,container):
        self.container = container
        self.top_frame = tk.Frame(container,height=2)
        self.top_frame.configure(bg='gray15')

    # create a frame to hold the Canvas andscrollbars

        self.canvas = tk.Canvas(container,borderwidth=5)
        self.canvas.configure(bg = 'orange')

    #self.canvas.pack_propagate(False)

        self.content_frame = tk.Frame(self.canvas, bg = 'yellow')    
    #self.content_frame.grid_propagate(True)
    # create a vertical scrollbar linked to the canvas 
        self.scrollbar = ttk.Scrollbar(self.canvas, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.scrollbar.set) # again scrollbar.set is a provided function
        self.scrollbar.config(command=self.canvas.yview)

        self.xscrollbar = ttk.Scrollbar(self.canvas, orient = 'horizontal', command=self.canvas.xview)
        self.canvas.configure(xscrollcommand=self.xscrollbar.set) 
        self.xscrollbar.config(command=self.canvas.xview)


    # before we are done we need to put buttons into ScrollableFame, row 0
    # and populate the content_frame with widgets
    # after this has been done, the bounding box must be created 


        container.bind(
            "<Configure>",
            lambda e: self.canvas.configure(
            scrollregion=self.canvas.bbox("all")
            )
        )

    def finish(self):
        self.container.config(bg = 'lightgreen')
        self.top_frame.pack(side=tk.TOP,fill=tk.BOTH,expand=False)
    #self.content_frame.pack(side=tk.TOP,fill = tk.BOTH,expand=False)
        self.content_frame.grid(column=0,row=0,sticky='nw',ipadx = 5,ipady=5)
        self.canvas.create_window((0,0), window=self.content_frame) 

        self.canvas.pack(side=tk.TOP,fill=tk.BOTH,expand=True,ipady=10)
        self.canvas.configure(scrollregion=self.canvas.bbox('all'))

        self.canvas.pack_propagate(False)

        self.scrollbar.pack(fill='both',side='right',expand='false')
        self.xscrollbar.pack(fill='both',side='bottom',expand='false')
    #self.container.grid(column=0,row=0,sticky='nsew')
    #self.container.rowconfigure(0,weight=1)
    #self.container.columnconfigure(0,weight=1)
        self.canvas.update_idletasks()
        self.canvas.yview_moveto(0)
        self.canvas.xview_moveto(0)

class DisplayKeys(tk.Frame):
    def __init__(self,parent,*args,**kwargs) :
        tk.Frame.__init__(self,parent,*args,**kwargs)
        self.keys_ = [f'display{i}' for i in range(30)]
        self._showless = False
        self._checkbuttons_initialized = None
        self.scrollable_frame = ScrollableFrame(parent)
        self._label = tk.Label(self.scrollable_frame.top_frame,
                           text = "Key List",font = LARGE_FONT)
        self._label.grid(column=0,row=0)

        self._sequence = [1,2,3,29,5,7,21,15,6]
        self._showbutton = tk.Button(self.scrollable_frame.top_frame, 
                       text='Show More',
                       command=lambda: 
                       self._showbutton_action())

        self._showbutton.grid(column=2,row=0,padx=10,sticky=tk.N)
        self._update_checkbuttons(
                  self.scrollable_frame.content_frame,self._sequence )
    #self.scrollable_frame.finish()


    def _update_checkbuttons(self,frame,seq):
    #print(*seq)
        if self._checkbuttons_initialized != None :
            for widget in self.scrollable_frame.content_frame.winfo_children() :
                widget.destroy()
        self._checkbuttons_initialized = True     
        self.checkVars = []
        self.txtVars = []
        searchVar = "Search"
        self._checkbuttons = []

        for i,place in enumerate(seq) :
            bv = tk.BooleanVar()
            tvar = tk.StringVar()
            dn = self.keys_[place]
            ck = tk.Checkbutton(frame,text=dn,variable=bv)
            ck.grid(column=0,row=i,sticky='nw')
            self._checkbuttons.append(ck)
            self.checkVars.append(bv)
            txt = tk.Entry(frame,width = 30, textvariable = tvar)
            txt.bind('<Return>',self._cmgo)
            txt.grid(column = 1,row = i,sticky="nw")
        #txt.rowconfigure(0,minsize=400,weight = 1)
        #txt.columnconfigure(0,weight=1)
            self.txtVars.append(tvar)
        self.scrollable_frame.finish()
    #self.scrollable_frame.canvas.pack()
    #tk.Label(frame,height=1,bg = 'skyblue').grid(column=0,row=len(seq)+1)
    #self.scrollable_frame.canvas.configure(scrollregion=self.scrollable_frame.canvas.bbox("all") ) 

    def _cmgo(self):
        pass

    def _showbutton_action(self):

        if not self._showless :
            self._sequence = range(len(self.keys_))           
            self._showbutton.configure( text = "Show Less")
        #self._showbutton.grid(column=2,row=0,sticky=tk.W)
            self._showless = True

        else :            
            self._showbutton.configure(text = "Show More")
        #self._showbutton.grid(column=2,row=0,sticky=tk.W)
            self._showless = False
            self._sequence = [1,2,3,29,5,7,21,15,6]


        self._update_checkbuttons(
               self.scrollable_frame.content_frame,self._sequence) 

if __name__=="__main__" :
    LARGE_FONT= ("Verdana", 12)
    DISPLAY_KEYS_GEOMETRY='350x450'
    root = tk.Tk()
    show = DisplayKeys(root)
    show.pack()
    root.mainloop()

1 Ответ

0 голосов
/ 03 мая 2020

Я действительно понимаю, что мой пример слишком велик. У меня есть обходной путь, который я покажу. Единственное достоинство состоит в том, что он показывает ценность определения класса, облегчая уничтожение и замену прокручиваемого фрейма. Решение состоит в том, чтобы уничтожить весь прокручиваемый фрейм и восстановить его. Я не понимаю, почему: self.content_frame.grid (column = 0, row = 0, sticky = 'nw', ipadx = 5, ipady = 5) в строке 53 не работает, но этот обходной путь позволит мне переместиться вперед. Я прошу прощения, если кто-то потратил время на этот вопрос.

import tkinter as tk
from tkinter import ttk
import os
import inspect
import functools
import sys

class ScrollableFrame:
    # https://blog.tecladocode.com/tkinter-scrollable-frame
    def __init__(self,container):
        self.container = container
        self.top_frame = tk.Frame(container,height=2)
        self.top_frame.configure(bg='gray15')

        # create a frame to hold the Canvas andscrollbars

        self.canvas = tk.Canvas(container,borderwidth=5)
        self.canvas.configure(bg = 'orange')

        self.content_frame = tk.Frame(self.canvas, bg = 'yellow')    
        #self.content_frame.grid_propagate(True)
        # create a vertical scrollbar linked to the canvas 
        self.scrollbar = ttk.Scrollbar(self.canvas, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.scrollbar.set) # again scrollbar.set is a provided function
        self.scrollbar.config(command=self.canvas.yview)

        self.xscrollbar = ttk.Scrollbar(self.canvas, orient = 'horizontal', command=self.canvas.xview)
        self.canvas.configure(xscrollcommand=self.xscrollbar.set) 
        self.xscrollbar.config(command=self.canvas.xview)


        # before we are done we need to put buttons into ScrollableFame, row 0
        # and populate the content_frame with widgets
        # after this has been done, the bounding box must be created 


        container.bind(
            "<Configure>",
            lambda e: self.canvas.configure(
                scrollregion=self.canvas.bbox("all")
            )
        )

    def destroy(self):
        self.top_frame.destroy()
        self.canvas.destroy()

    def finish(self):
        self.container.config(bg = 'lightgreen')
        self.top_frame.pack(side=tk.TOP,fill=tk.BOTH,expand=False)
        #self.content_frame.pack(side=tk.TOP,fill = tk.BOTH,expand=False)
        self.content_frame.grid_rowconfigure(0,weight=1)
        self.content_frame.grid(column=0,row=0,sticky='nw',ipadx = 5,ipady=5)
        self.canvas.create_window((0,0), window=self.content_frame) 
        self.canvas.pack(side=tk.TOP,fill=tk.BOTH,expand=False,ipady=10)
        self.scrollbar.pack(fill='both',side='right',expand='false')
        self.xscrollbar.pack(fill='both',side='bottom',expand='false')
        self.canvas.update_idletasks()
        self.canvas.yview_moveto(0)
        self.canvas.xview_moveto(0)

class DisplayKeys(tk.Frame):
    def __init__(self,parent,*args,**kwargs) :
        tk.Frame.__init__(self,parent,*args,**kwargs)
        self.keys_ = [f'display{i}' for i in range(30)]
        self.parent = parent
        self._showless = False
        #self._checkbuttons_initialized = None
        self.scrollable_frame = ScrollableFrame(parent)
        self._label = tk.Label(self.scrollable_frame.top_frame,
                               text = "Key List",font = LARGE_FONT)
        self._label.grid(column=0,row=0)

        self._sequence = [1,2,3,29,5,7,21,15,6]
        self._showbutton = tk.Button(self.scrollable_frame.top_frame, 
                           text='Show More',
                           command=lambda: 
                           self._showbutton_action())

        self._showbutton.grid(column=2,row=0,padx=10,sticky=tk.N)
        self._update_checkbuttons(self.scrollable_frame.content_frame,self._sequence )

    def _update_checkbuttons(self,frame,seq):
        #print(*seq)
    #    self._checkbuttons_initialized = True     
        self.checkVars = []
        self.txtVars = []
        searchVar = "Search"
        self._checkbuttons = []

        for i,place in enumerate(seq) :
            bv = tk.BooleanVar()
            tvar = tk.StringVar()
            dn = self.keys_[place]
            ck = tk.Checkbutton(frame,text=dn,variable=bv)
            ck.grid(column=0,row=i,sticky='w')
            ck.grid_rowconfigure(0,weight = 1)
            self._checkbuttons.append(ck)
            self.checkVars.append(bv)
            txt = tk.Entry(frame,width = 30, textvariable = tvar)
            txt.bind('<Return>',self._cmgo)
            txt.grid(column = 1,row = i,sticky="nw")
            txt.grid_rowconfigure(1,weight=2)
            #txt.grid_rowconfigure(0,minsize=400,weight = 1)
            #txt.grid_columnconfigure(0,weight=1)
            self.txtVars.append(tvar)

        self.scrollable_frame.finish()

    def _cmgo(self):
        pass

    def _showbutton_action(self):

        if not self._showless :
            self._sequence = range(len(self.keys_))           
            button_text = "Show Less"
            #self._showbutton.grid(column=2,row=0,sticky=tk.W)
            self._showless = True

        else :            
            button_text = "Show More"
            #self._showbutton.grid(column=2,row=0,sticky=tk.W)
            self._showless = False
            self._sequence = [1,2,3,29,5,7,21,15,6]

        self.scrollable_frame.destroy()
        self.scrollable_frame = ScrollableFrame(self.parent)
        self._label = tk.Label(self.scrollable_frame.top_frame,
                               text = "Key List",font = LARGE_FONT)
        self._label.grid(column=0,row=0)

        self._showbutton = tk.Button(self.scrollable_frame.top_frame, 
                           text=button_text,
                           command=lambda: 
                           self._showbutton_action())

        self._showbutton.grid(column=2,row=0,padx=10,sticky=tk.N)

        self._update_checkbuttons(self.scrollable_frame.content_frame,self._sequence) 

if __name__=="__main__" :
    LARGE_FONT= ("Verdana", 12)
    DISPLAY_KEYS_GEOMETRY='350x450'
    root = tk.Tk()
    show = DisplayKeys(root)
    show.pack()
    root.mainloop()
...