9

I'd like to have a Frame, where the user could add as many textfields as needed by the application.

The application starts with a textfield, and a button below that textfield. When the user presses the button, a new text entry will be added below the first one ( this may be repeated countless times ). In the middle of the window, there will be a Text widget, used to display text :)

However, I noticed this in the documentation:

This widget is used to implement scrolled listboxes, canvases, and text fields.

Is there a way to use the Scrollbar with a Frame?

nbro
  • 15,395
  • 32
  • 113
  • 196
Geo
  • 93,257
  • 117
  • 344
  • 520

2 Answers2

8

If you can use Tix, there is the ScrolledWindow widget which has a window Frame and one or two Scrollbar widgets:

import Tix as tk

r= tk.Tk()
r.title("test scrolled window")
sw= tk.ScrolledWindow(r, scrollbar=tk.Y) # just the vertical scrollbar
sw.pack(fill=tk.BOTH, expand=1)
for i in xrange(10):
    e= tk.Entry(sw.window)
    e.pack()
r.mainloop()

Change the size of the root window. You will want to add code to the focus_get event of the Entry widgets to scroll the ScrolledWindow when tabbing through the keyboard.

Otherwise, you will have to use a Canvas widget (you can add Label, Entry and Text subwidgets) and write a lot more code yourself to implement your required functionality.

tzot
  • 92,761
  • 29
  • 141
  • 204
7

The following is an example of auto hiding scrollbars that only works if you just use the grid geometry manager, taken from the effbot.org documentation:

from tkinter import *


class AutoScrollbar(Scrollbar):
    # A scrollbar that hides itself if it's not needed.
    # Only works if you use the grid geometry manager!
    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()
        Scrollbar.set(self, lo, hi)
    def pack(self, **kw):
        raise TclError("cannot use pack with this widget")
    def place(self, **kw):
        raise TclError("cannot use place with this widget")


# create scrolled canvas

root = Tk()

vscrollbar = AutoScrollbar(root)
vscrollbar.grid(row=0, column=1, sticky=N+S)
hscrollbar = AutoScrollbar(root, orient=HORIZONTAL)
hscrollbar.grid(row=1, column=0, sticky=E+W)

canvas = Canvas(root, yscrollcommand=vscrollbar.set, xscrollcommand=hscrollbar.set)
canvas.grid(row=0, column=0, sticky=N+S+E+W)

vscrollbar.config(command=canvas.yview)
hscrollbar.config(command=canvas.xview)

# make the canvas expandable
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)

# create canvas contents
frame = Frame(canvas)
frame.rowconfigure(1, weight=1)
frame.columnconfigure(1, weight=1)

rows = 5
for i in range(1, rows):
    for j in range(1, 10):
        button = Button(frame, text="%d, %d" % (i,j))
        button.grid(row=i, column=j, sticky='news')

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

root.mainloop()
nbro
  • 15,395
  • 32
  • 113
  • 196
reckoner
  • 2,861
  • 3
  • 33
  • 43
  • I don't think this issue is relevant. I've just downloaded Python 2.6.6 for windows, and it comes with Tix. So, it seems to work just as well as Tkinter. – Denilson Sá Maia Oct 06 '10 at 04:41
  • I tried to refactor the code in this answer into its own reusable `class`, but was unsuccessful. If you have a moment to look at my question over here, I'd really appreciate it: http://stackoverflow.com/questions/30018148/python-tkinter-frame-class-with-autohiding-scroll-bars Also, Rinzler, why did you post this code as an edit instead of as an answer in its own right? The existing comments from 2010 make no sense now, and the rep awarded from me upvoting this code ends up going to reckoner instead, who has nothing to do with the code. You should post a new answer and then rollback your edits. – ArtOfWarfare May 03 '15 at 19:25
  • How can we use the same with place() – Zeryab Hassan Kiani Mar 27 '17 at 10:30