2

I'm building an application that provides viewports for an internal data file. The files are somewhat complex, so I've created three sub-windows that handle different aspects of the file. The upper left provides an outline of the different sections, the upper right provides a series of text widgets containing errors found in the data file, and the lower provides a view of the datafile itself. To facilitate all of this, I wrote a small class that serves as a frame for each of these sections and can be populated with labels, textboxes, etc. (Code below.)

The problem I'm running into is that the text widgets in the upper right and lower sections do not expand with their containing frame. Based on various searches of effbot.org, Stackoverflow, and others, I think I have the settings correct, but obviously something is wrong. If I enlarge the main window, each section adapts as it should, but the text widgets don't expand left to right to fill the new subwindow dimensions.

Any tips are greatly appreciated.

Here's the class that provides functionality for the subwindows:

     import Tkinter as tk

     class ScrollingChildFrame(tk.Frame):
        '''
        A Tkinter class creating a scrollable window that can be used
        in a docked multiple document interface form.  The window created here 
        allows addition of widgets to create scrolling tables (spreadsheet like),
        groups of text fields, etc.
        '''

        def __init__(self, root):

           self.count = 0

           tk.Frame.__init__(self)

           self.root = root
           self.canvas = tk.Canvas(self, height=self.winfo_height(), width=self.winfo_width() )
           self.canvas.grid(row=0, column=0, sticky='nsew')

           self.vsb = tk.Scrollbar(self, orient='vertical', command=self.canvas.yview)
           self.vsb.grid(row=0,column=1,sticky='ns')
           self.hsb = tk.Scrollbar(self, orient='horizontal', command=self.canvas.xview)
           self.hsb.grid(row=1,column=0,sticky='ew')

           self.intframe = tk.Frame(self.canvas)
           self.intframe.config(height=self.winfo_height(), width=self.winfo_width())

           self.canvas.configure(yscrollcommand=self.vsb.set, xscrollcommand=self.hsb.set)
           self.canvas.create_window(0, 0, window=self.intframe, anchor='nw')

           #set event bindings
           self.bind('<Configure>', self.OnFrameConfigure)
           self.intframe.bind('<Configure>', self.OnIntFrameConfigure)

        def OnFrameConfigure(self, event=None):
           '''
           adjust canvas when main frame adjusts
           '''
           self.canvas.configure(width=event.width - self.vsb.winfo_width()-2,
                                height=event.height - self.hsb.winfo_height()-2)

        def OnIntFrameConfigure(self, event=None):
           '''
           adjust the scrolling window when the internal frame is adjusted
           '''
           self.canvas.configure(scrollregion=self.canvas.bbox(tk.ALL))

Here's an example of how I'm using it with textboxes that don't expand:

     import Tkinter as tk
     from scrollingchildframe import *

     class Vis_GUI:
        '''
        The main GUI class 
        '''

        def __init__(self):

           #tkinter stuff
           self.root = tk.Tk()
           self.root.geometry('500x500')

           self.create_frames()

           self.root.mainloop()


        def create_frames(self):
           '''
           Build the GUI frames
           '''      

           self.root.columnconfigure(0,weight=1)
           self.root.columnconfigure(1,weight=3)
           self.root.rowconfigure(0,weight=1)
           self.root.rowconfigure(1,weight=3)

           #data blocks
           self.block_frame = ScrollingChildFrame(self.root)
           self.block_frame.config(height=200, width=200)

           ##error list
           self.error_frame = ScrollingChildFrame(self.root)
           self.error_frame.config(height=200, width=300)

           ##data
           self.data_frame = ScrollingChildFrame(self.root)
           self.data_frame.config(height=300, width=500)

           ##populate with empty cells
           self.PopulateEmpty()

           ##place them on the grid
           self.block_frame.grid(row=0, column=0, padx=2, pady=2, sticky='nsew')
           self.error_frame.grid(row=0,column=1, padx=2, pady=2, sticky='nsew')
           self.data_frame.grid(row=1, column=0, columnspan=2, padx=2,pady=2, sticky='nsew')


        def PopulateEmpty(self):
           '''
           Populate the frames with empty contents so it doesn't look quite so empty.
           '''

           z = tk.Text(self.data_frame.intframe)
           z.insert(tk.INSERT, 'blah\nblah\nblah')
           height = float(z.index(tk.END))
           z.config( height=height, state=tk.DISABLED, wrap=tk.NONE)
           z.pack(anchor='nw', expand=1, fill=tk.X)

           z = tk.Text(self.error_frame.intframe, height=1)
           z.pack(anchor='w', expand = 1, fill=tk.X)

           z = tk.Label(self.block_frame.intframe, text = 'No file open')
           z.pack(anchor='w')

     if (__name__=="__main__"):
        wv = Vis_GUI()
KirkD-CO
  • 1,603
  • 1
  • 22
  • 35
  • "textbox" isn't a term common to Tkinter. Your description would be easier to understand if you used either "text widget" or "entry widget" rather than "textbox". – Bryan Oakley Nov 12 '14 at 21:24
  • Please read https://stackoverflow.com/help/mcve about posting minimal examples. – Terry Jan Reedy Nov 12 '14 at 21:45
  • Textboxes and text boxes are not changed to text widgets. As for minimal examples, I tried to reduce this as much as I could to get the problem across. I have a feeling if I reduced it further it wouldn't make sense and I would be criticized for not supplying enough example code. – KirkD-CO Nov 12 '14 at 22:25

1 Answers1

2

The Frame also has to have expand and fill options set (and you will have to check on what ScrollingChildFrame does-and this is not a complaint about incomplete code, just pointing out the next step). Using just pack() for the Frame in the following code will not allow it to expand. You can uncomment it and comment the other pack if you want to see the difference.

try:
    import Tkinter as tk     ## Python 2.x
except ImportError:
    import tkinter as tk     ## Python 3.x

top=tk.Tk()
## use separate frame instead of top
fr=tk.Frame(top)
##fr.pack()                ## does not expand
fr.pack(anchor='nw', expand=1, fill=tk.X)
z = tk.Text(fr)
insert_text="%s" % ("blah"*25) + 'blah\nblah\nblah'
z.insert(tk.INSERT, insert_text)
height = float(z.index(tk.END))
z.config( height=height, state=tk.DISABLED, wrap=tk.NONE)
z.pack(anchor='nw', expand=1, fill=tk.X)

top.mainloop()
  • Ah ha! This makes sense. Thank you! I'm working on getting in implemented in my code now. Once I have it working on my side, I'll vote this one as an answer. – KirkD-CO Nov 13 '14 at 17:12