简体   繁体   中英

Python Tkinter AutoResizing scrolling Canvas in window

I create a simple application interface in python with tkinter.

[you can run the code]

It has 2 frames inside [self.CON] frame. Frame one is for header [self.HeaderFrame] and second frame [self.CFrame] is a dynamically populated list inside scrolling canvas [self.Content]. Since the number of items in scrolling canvas [self.Content] will change, I need to resize the canvas each time list was populated or window resized.

from tkinter import *
import tkinter.font as font
from PIL import Image, ImageTk

class wmGUI (object):    
    def __init__ (self,tittle,itemnum):
        self.tittle=tittle

        self.GUI = wmWINDOW(self.tittle,itemnum)


class wmWINDOW(Tk):    
    windowwidth,windowheight,sliderresizer = 250,600,100

    def __init__ (self,tittle,itemnum):
        super().__init__()    
        WW = self.winfo_screenwidth()
        WH = self.winfo_screenheight()
        print('WW : %d & WH : %d' % (WW,WH))
        geometry = '{width}x{height}+{pos_x}+{pos_y}'.format(height=WH, width=self.windowwidth, pos_y=0, pos_x=WW-self.windowwidth-20)
        self.geometry(geometry)
        self.configure(background='grey')
        self.title("GUI")
        self.itemnum=itemnum
        self.resizable(width=False, height=True)
        self.attributes('-topmost',True)
        self.CreateMenus()
        self.Myfont= font.Font(family="Arial", size=8, weight=font.NORMAL)
        self.Myfont2 = font.Font(family="Helvetica", size=9, weight=font.BOLD)
        self.Myfont3 = font.Font(family="Helvetica", size=7, weight=font.BOLD)
        self.CON=Frame(self,width=self.windowwidth,height=WH)
        self.MakeHeader()
        self.MakeContent()
        self.CON.pack(fill=BOTH, expand=YES)
        self.RUN()

    def MakeHeader (self):

        self.HeaderFrame= Frame(self.CON, width=self.windowwidth,height=60, background='Blue',borderwidth=0 )
        self.HeaderFrame.propagate(1)
        hImage = Image.open("images/header.jpg")
        headerImage=ImageTk.PhotoImage(hImage, width= self.windowwidth, height=60)
        self.headerLabel=Label(self.HeaderFrame,image=headerImage, width= self.windowwidth, height=60, borderwidth=0, highlightthickness=0)
        self.headerLabel.image=headerImage
        self.headerLabel.pack( )
        self.HeaderFrame.pack( padx=0,pady=0,ipadx=0,ipady=0)

    def MakeContent (self):

        self.CFrame = Frame(self.CON, width=self.windowwidth,bg="cyan")
        self.Content = Canvas(self.CFrame, width=self.windowwidth-15, bg="green",borderwidth=0, highlightthickness=0)
        self.ContentFrame = Frame(self.Content, bg="#EBEBEB",height=100)
        self.Content.create_window(0, 0, window=self.ContentFrame, anchor='nw')
        self.ContentFrame.bind("<Configure>", self.on_change)
        self.Items()
        self.CScrollbar = Scrollbar(self.CFrame, orient=VERTICAL , width=15)
        self.CScrollbar.config(command=self.Content.yview)
        self.Content.config(yscrollcommand=self.CScrollbar.set)
        self.CScrollbar.grid(row=0, column=1, sticky="ns")
        self.Content.grid(row=0, column=0, sticky="nsew")
        self.CFrame.pack(fill=BOTH, expand=YES)
        self.Content.configure(height=self.CON.winfo_reqheight() - 60)

    def on_change(self,event):
        self.Content.configure(scrollregion=self.Content.bbox("all"))

    def Items(self):
        for n in range(self.itemnum):
                LabelFrame(self.ContentFrame, text='Example Item {}'.format(n) , font=self.Myfont3, bg="yellow", fg="black",width=self.windowwidth,height=40).grid()

    def RUN (self):
        self.mainloop()

    def CreateMenus(self):
        #MAIN MENUBAR
        MenuBar = Menu(self) #Creates Menu bar
        self.config(menu=MenuBar)

        # FILE MENU
        FileMenu=Menu(MenuBar,tearoff=0)
        FileMenu.add_command(label="Open",command=None) #command=bewritten
        FileMenu.add_command(label="Close",command=None)  
        FileMenu.add_separator()  
        FileMenu.add_command(label="Reset",  accelerator="Ctrl + Shift + r")  
        FileMenu.add_separator()
        FileMenu.add_command(label="Quit", command= None,accelerator="Ctrl q") 
        MenuBar.add_cascade(label="File",menu=FileMenu)

WMGUI=wmGUI('My Window',50)

I assume to resize the canvas [self.Content] I should retrieve the window inner height. But I can not find a method for it. How can i do this ?

I found the solution . The example here really helps.. LINK

The format of frames in the window was like following

[Frame CON] -[Frame Header] -[Frame Content] -[Content Canvas] > [/Frame CON]

I binded on_change function to self.CON ; container frame since the container frame will change each time CON content changed.

self.CON.bind("<Configure>", self.on_change)

I changed on_change function to :

def on_change(self,event):
    self.Content.configure(scrollregion=self.Content.bbox("all"))
    self.Content.configure(height=self.CON.winfo_height()-60)

So on an event, on_change event gets the height of CON container frame and applies height-60 to canvas each time CON changed.

This really worked for the scrollbar to be resize when content created...

Also added an event handler to the root window ..This will resize the scrollbar when the window size changes.

self.bind('<Configure>', self.on_change)

Seems like everything works fine now ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM