[Tkinter-discuss] Getting an Entry field to stretch

Bryan Oakley bryan.oakley at gmail.com
Tue Jul 2 23:41:49 CEST 2013


This problem requires that you do two things:

a) cause the width of the inner frame to resize when the canvas resizes
b) make sure the widgets inside the inner frame resize when the inner
frame resizes.

For a), you need to do a binding on the <Configure> event of the
canvas. In the callback for that binding, use the canvas's
'itemconfigure' method to change the width of the inner frame.

For b), the easiest is to use the grid geometry manager and do away
with all of the inner frames. Then all you need to do is configure the
inner frame such that the appropriate column grows and shrinks. Of
course, you can use the inner frames if you really want to. In that
case you wouldn't use grid, you could use pack, and as long as the
inner frames were all packed identically with one entry being told to
expand, it will all work just fine.

It's hard to retrofit some of that into the code you posted. I'll post
some code to illustrate how I would do it. I switched up the style of
the app as a whole to something more object-oriented, and I did away
with the global imports. I think these two changes make for a better
way to write Tkinter apps.

import Tkinter as tk

class Example(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)

        self.activeVar = tk.StringVar()
        self.activeVar.set(1)

        self.canvas = tk.Canvas(self,
                                background="red",
                                borderwidth=0,
                                highlightthickness=0)
        self.vsb = tk.Scrollbar(self, orient="vertical",
command=self.canvas.yview)
        self.canvas.config(yscrollcommand=self.vsb.set)
        self.vsb.pack(side="right", fill="y", expand=False)
        self.canvas.pack(side="left", fill="both", expand=True)

        self.inner_frame = tk.Frame(self, background="blue")
        self.canvas.create_window(0,0,
                                  anchor="nw",
                                  window=self.inner_frame,
                                  tags=("frame",))
        self.canvas.bind("<Configure>", self._on_canvas_resize)
        self._add_widgets(20)

    def _on_canvas_resize(self, event=None):
        width = self.canvas.winfo_width()
        self.canvas.itemconfigure("frame", width=width)
        self.canvas.config(scrollregion=self.canvas.bbox("all"))

    def _add_widgets(self, count):
        bg = self.inner_frame.cget('background')
        self.inner_frame.grid_columnconfigure(2, weight=1)

        for row in xrange(1, count):
            lrb = tk.Radiobutton(self.inner_frame, text="",
                                 variable = self.activeVar,
                                 value=str(row),
                                 background=bg)
            lent1 = tk.Entry(self.inner_frame,  bg = "white")
            lent2 = tk.Entry(self.inner_frame,  bg = "white")
            lent3 = tk.Entry(self.inner_frame,  bg = "white")

            lrb.grid(row=row, column=0, pady=2)
            lent1.grid(row=row, column=1, sticky='ew', pady=2)
            lent2.grid(row=row, column=2, sticky='ew', pady=2)
            lent3.grid(row=row, column=3, sticky='ew', pady=2)


if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

On Tue, Jul 2, 2013 at 3:59 PM, Bob Greschke <bob at passcal.nmt.edu> wrote:
> This is what I want to do...almost:
>
> -----
> #! /usr/bin/env python
>
> from Tkinter import *
>
> Root = Tk()
>
> RowActiveVar = StringVar()
>
> LastWidth = 0
> Count = 0
> def iChanged(e = None):
>     global LastWidth
>     global Count
>     Count += 1
>     Geom = Root.geometry()
>     Width = int(Geom[:Geom.index("x")])
>     if Width == LastWidth:
>         return
> #    Root.geometry("%d%s"%((Width+ScrollWidth+2), Geom[Geom.index("x"):]))
>     LastWidth = Width+ScrollWidth+2
>     return
>
> RowSub = Frame(Root, bg = "blue")
> RowCan = Canvas(RowSub, bg = "red")
> RowCan.pack(side = LEFT, expand = YES, fill = BOTH)
> Scroll = Scrollbar(RowSub, orient = VERTICAL, command = RowCan.yview, \
>         width = 15)
> Scroll.pack(side = RIGHT, fill = Y)
> ScrollWidth = int(Scroll.cget("width"))+int(Scroll.cget("bd"))*2+ \
>         int(Scroll.cget("highlightthickness"))*2
> RowCan.configure(yscrollcommand = Scroll.set)
> RowSub.pack(side = TOP, expand = YES, fill = BOTH)
>
> Y = 0
> for I in xrange(1, 20):
>     SSub = Frame()
>     LRb = Radiobutton(SSub, text = "", variable = RowActiveVar, \
>             value = str(I), bg = Frame().cget("bg"))
>     LRb.pack(side = LEFT)
>     LEnt = Entry(SSub, width = 15, bg = "white")
>     LEnt.pack(side = LEFT)
> # This one...
>     LEnt = Entry(SSub, width = 40, bg = "white")
>     LEnt.pack(side = LEFT, expand = YES, fill = X)
>     LEnt = Entry(SSub, width = 10, bg = "white")
>     LEnt.pack(side = LEFT)
>     SSub.pack(expand = YES, fill = X)
>     RowCan.create_window(0, Y, anchor = "nw", window = SSub)
>     RowCan.update()
>     L,T,R,B = RowCan.bbox(ALL)
>     Y = B
> RowCan.configure(scrollregion = (0, 0, R, B))
> Geom = Root.geometry()
> LastWidth = R+ScrollWidth+2
> Root.geometry("%d%s"%(LastWidth, Geom[Geom.index("x"):]))
> Root.bind("<Configure>", iChanged)
>
> Root.mainloop()
> -----
>
> I'd like the center column of Entry fields to get longer as the window width is changed.  I have a static non-scrollbar version of this that works fine (Entry fields in a Frame that is packed TOP into another Frame -- everyone set to expand and fill as needed), but throwing the Canvas and the scrolling in there seems to be a problem.  I have another version that uses a Text() to hold all of the rows, but I can't get that to work either.  The iChanged() stuff really doesn't do anything at this point.  I was thinking that might be where a solution goes.  Can it be done?
>
> Thanks!
>
> Bob
>
> _______________________________________________
> Tkinter-discuss mailing list
> Tkinter-discuss at python.org
> http://mail.python.org/mailman/listinfo/tkinter-discuss


More information about the Tkinter-discuss mailing list