4

I am using Tix to automatically create a scroll bar as the content changes. I want to keep a button or two in the user's view while they scroll through the contents of the application. I haven't seen this question for Tkinter/Tix yet so I thought I'd ask.

The following code will create a sample of the problem where the button is at a fixed point in the window, and is subject to being scrolled.

from Tkinter import *
import Tix
class some_GUI:
    def __init__(self, root):
        sw= Tix.ScrolledWindow(root, scrollbar=Tix.AUTO)
        sw.pack(fill=Tix.BOTH, expand=1)
        frame1 = Frame(sw.window) 
        frame1.grid(row = 0, column = 1)
        frame2 = Frame(sw.window) 
        frame2.grid(row = 0, column = 2)
        def quit():
            root.quit()
        for i in range(0,300):
            label1 = Label(frame1, text = "foo")
            label1.grid(row = i, column = 0)
        button = Button(frame2, text  = "Quit", command = quit)
        button.pack()

root = Tix.Tk()
display = some_GUI(root)
root.mainloop()

I want the button(s) to be in "frame2" and centered vertically relative to the application's window. I tried using winfo_height/winfo_width to find the frame's height/ width to work with update, but these values didn't change with the addition of the labels and button.

Attempted/possible solutions:

  • I put frame2 in sw.subwidgets_all[1] by doing the following:

    frame1.pack(side = LEFT)
    frame2 = Frame(sw.subwidgets_all()[1]) 
    frame2.pack(side = RIGHT)
    button = Button(frame2, text  = "Quit", command = quit)
    button.pack(side = RIGHT)
    

    This allows the fixed position relative to the application, but the window resizes relative to the button's parent instead of frame1. Another drawback is that the horizontal scrollbar is only relative to frame1.

  • Find the midpoint of the scrollbar and update the position of the buttons relative to those coordinates using place(maybe?) not sure how to accomplish this, and seeing SO solutions in general I think this might be an inefficient way of doing this.

EDIT: Although this isn't exactly what I had in mind, the following code works as per falsetru's suggestion in the comments:

from Tkinter import *
import Tix
class some_GUI:
    def __init__(self, root):
        def quit():
            root.quit()
        frame2 = Frame(root) 
        frame2.pack(side = RIGHT)
        button = Button(frame2, text  = "Quit", command = quit)
        button.pack()
        frame1 = Frame(root) 
        frame1.pack(side = LEFT)
        sw= Tix.ScrolledWindow(frame1, scrollbar=Tix.AUTO)
        sw.pack(fill=Tix.BOTH, expand=1)
        for widget in sw.subwidgets_all():
            print widget
        for i in range(0,300):
            label1 = Label(sw.window, text = "foo")
            label1.grid(row = i, column = i)
        print root.winfo_toplevel()
        for widget in sw.subwidgets_all():
            print widget



root = Tix.Tk()
display = some_GUI(root)
root.mainloop()
R. Joseph
  • 127
  • 1
  • 8
  • 1
    How about put the button out of the ScrolledWindow? – falsetru Mar 22 '16 at 12:26
  • @falsetru I'm always astounded by how simple the solution is once you know it. Did you want to make an official answer so I can accept it? I'll edit working code in the question or something. I avoided that route after solution 1 didn't pan out. Thank you! – R. Joseph Mar 22 '16 at 17:06

2 Answers2

1

The second option you mentioned could be the one that satisfies your situation, however that is computationally expensive as you will need to delete the button(s) and redraw them over and over relatively to the scrollbar up/down motion. Not only this is ugly by design but it can be an obstacle for any further scalability of your application or even lead to unexpected bugs if your application runs some serious operations.

The only realistic solution I see for your problem is to fix the button(s) on (for example the bottom of) the upper canvas (or whatever region you want to set) and outside the scrollable region as @falsetru commented you.

Billal Begueradj
  • 20,717
  • 43
  • 112
  • 130
  • It is still aesthetically not as pleasing as scrolling and seeing something fixed in place, within the window, but it definitely does the job. I'll wait for falsetru to post an answer. – R. Joseph Mar 22 '16 at 17:09
1

You can put the button out of ScrollWindows:

import Tix
from Tkinter import *


def build_ui(root):
    sw = Tix.ScrolledWindow(root, scrollbar=Tix.AUTO)
    sw.pack(side=LEFT, fill=Tix.BOTH, expand=1)
    for i in range(300):
        label1 = Label(sw.window, text="foo")
        label1.grid(row=i, column=0)
    button = Button(root, text="Quit", command=root.quit)
    button.pack(side=RIGHT)


root = Tix.Tk()
build_ui(root)
root.mainloop()
falsetru
  • 357,413
  • 63
  • 732
  • 636