0

The following MWE is for a window with horizontal and vertical scrollbars. The window contains an entry box in which the current working directory is displayed. However, the text in the entry box cannot all be seen as the box is too small. I would like to be able to display more of this text as the user enlarges the window. How can I adapt the following example so that the Entry box (defined in UserFileInput) resizes with the window? I have tried using window.grid_columnconfigure (see below), however this doesn't have any effect. It seems to be a problem with using the canvas, as previously I was able to get the Entry boxes to resize, however I need the canvas in order to place the horizontal and vertical scrollbars on the window.

window.grid(row=0, column=0, sticky='ew')
window.grid_columnconfigure(0, weight=1)

(and also with column = 1) but this doesn't have an effect.

import Tkinter as tk
import tkFileDialog
import os

class AutoScrollbar(tk.Scrollbar):
    def set(self, lo, hi):
        if float(lo) <= 0.0 and float(hi) >= 1.0:
            # grid_remove is currently missing from Tkinter!
            self.tk.call("grid", "remove", self)
        else:
            self.grid()
        tk.Scrollbar.set(self, lo, hi)

class Window(tk.Frame):

    def UserFileInput(self,status,name):
        row = self.row
        optionLabel = tk.Label(self)
        optionLabel.grid(row=row, column=0, sticky='w')
        optionLabel["text"] = name
        text = status#str(dirname) if dirname else status
        var = tk.StringVar(root)
        var.set(text)
        w = tk.Entry(self, textvariable= var)
        w.grid(row=row, column=1, sticky='ew')
        w.grid_columnconfigure(1,weight=1)
        self.row += 1
        return w, var

    def __init__(self,parent):
        tk.Frame.__init__(self,parent)

        self.row = 0
        currentDirectory = os.getcwd()
        directory,var = self.UserFileInput(currentDirectory, "Directory")


if __name__ == "__main__":
    root = tk.Tk()
    root.grid_columnconfigure(0, weight=1)
    root.grid_rowconfigure(0,weight=1)

    vscrollbar = AutoScrollbar(root,orient=tk.VERTICAL)
    vscrollbar.grid(row=0, column=1, sticky='ns')
    hscrollbar = AutoScrollbar(root, orient=tk.HORIZONTAL)
    hscrollbar.grid(row=1, column=0, sticky='ew')

    canvas=tk.Canvas(root,yscrollcommand=vscrollbar.set,xscrollcommand=hscrollbar.set)
    canvas.grid(row=0, column=0, sticky='nsew')
    vscrollbar.config(command=canvas.yview)
    hscrollbar.config(command=canvas.xview)


    window = Window(canvas)
    canvas.create_window(0, 0, anchor=tk.NW, window=window)
    window.update_idletasks()
    canvas.config(scrollregion=canvas.bbox("all"))

    root.mainloop()
arunanshub
  • 581
  • 5
  • 15
218
  • 1,754
  • 7
  • 27
  • 38

1 Answers1

1

You have several problems in your code that are getting in your way. The biggest obstacle is that you're putting a frame inside a canvas. That's rarely necessary, and it makes your code more complex than it needs to be? Is there a reason you're using a canvas, and is there a reason you're using classes for part of your code but not for everything?

Regardless, you have two problems:

  1. the frame isn't growing when the window grows, so the contents inside the window can't grow
  2. the label won't grow because you're using grid_columnconfigure incorrectly.

Hints for visualizing the problem

When trying to solve layout problems, a really helpful technique is to temporarily give each containing widget a unique color so you can see where each widget is. For example, coloring the canvas pink and the Window frame blue will make it clear that the Window frame is also not resizing.

Resizing the frame

Because you're choosing to embed your widget in a canvas, you are going to have to manually adjust the width of the frame when the containing canvas changes size. You can do that by setting a binding on the canvas to call a function whenever it resizes. The event you use for this is <Configure>. Note: the configure binding fires for more than just size changes, but you can safely ignore that fact.

The function needs to compute the width of the canvas, and thus the desired width of the frame (minus any padding you want). You'll then need to configure the frame to have that width. To facilitate that, you'll need to either keep a reference to the canvas id of the frame, or give the frame a unique tag.

Here is a function that assumes the frame has the tag "frame":

def on_canvas_resize(event):
    padding = 8
    width = canvas.winfo_width() - padding
    canvas.itemconfigure("frame", width=width)

You'll need to adjust how you create the canvas item to include the tag:

canvas.create_window(..., tags=["frame"])

Finally, set a binding to fire when the widget changes size:

canvas.bind("<Configure>", on_canvas_resize)

Using grid_columnconfigure to get the label to resize

You need to use grid_columnconfigure on the containing widget. You want the columns inside the frame to grow and shrink, not the columns inside the label.

You need to change this line:

w.grid_columnconfigure(...)

to this:

self.grid_columnconfigure(...)
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Originally I wasn't using a canvas, just a frame. However, my window was larger than my screen and I was losing text off the bottom of the window, hence I wanted to add a scrollbar so all the text could be viewed. Reading around it seemed this was only possible with a canvas, and I used this example http://effbot.org/zone/tkinter-autoscrollbar.htm . If there's a simpler way, I would happily use this. I'm not sure what you mean about classes. I wasn't aware there was anything else I could put in a class. – 218 Aug 14 '14 at 17:29
  • @Mark: you have 15 lines of code at the end of the program that is not a class. See here for an example of how to use a class for the application: http://stackoverflow.com/a/17470842/7432 – Bryan Oakley Aug 14 '14 at 18:00
  • In theory I understand your answer, but in practice I can't get this to work. I'm very new to tkinter so there's a lot I'm still not understanding. I've posted my new code as another question - http://stackoverflow.com/questions/25317208/resize-widget-in-canvas . Maybe you can show me where I'm going wrong now. – 218 Aug 14 '14 at 20:41