3

Possible Duplicate:
Adding a scrollbar to a grid of widgets in Tkinter

On my project, i want do display my results in a window, using Tkinter as GUI. I place them in a kind of table, using the grid widget, and the window is separated in two different parts (for different results). But after longer runs, the number of results displayed exceed the height of my screen, so i want to add a scrollbar to my program. I already looked into several questions here on stackoverflow, and the answer that has come closest was this:

Adding a scrollbar to a group of widgets in Tkinter (just to let You know what I am axactly looking for!)

I am not able to apply that to my program though, maybe because I am rather new to Python and sometimes think i am a Dr. Frankenstein with tutorial-examples.

I tried a lot now, but i cant get the tables to be displayed in the canvas, possibly just some little thing i am missing.

I created an abstract example of my program (without scrollbar) so You know what I am working with, maybe someone of You can help my getting that scrollbar where it belongs!

Thank You very much!

example code: (runs)

import Tkinter as tk
toprow=1
botrow=1
class ProgramWindow(tk.Frame): 

    def __init__(self,name): 
        self.name = name
        tk.Frame.__init__(self,root)
        self.pack()

        if name=="BotWin":
            tk.Label(self,text="FirstColBot",width=30).grid(row=0,column=0)            
            tk.Label(self,text="SecndColBot",width=20).grid(row=0,column=1)

        elif name=="TopWin":
            tk.Label(self,text="FirstColTop",width=30).grid(row=0,column=0)         
            tk.Label(self,text="SecndColTop",width=20).grid(row=0,column=1)

    def addrowTop(self,stuff,otherstuff):
        global toprow

        textfield = tk.Text(self,width=30,height=1)
        textfield.grid(row=toprow,column=0)
        textfield.insert('0.0',stuff)

        textfield = tk.Text(self,width=20,height=1)
        textfield.grid(row=toprow,column=1)
        textfield.insert('0.0',otherstuff)

        toprow+=1

    def addrowBot(self,stuff,otherstuff):
        global botrow

        textfield = tk.Text(self,width=30,height=1)
        textfield.grid(row=botrow,column=0)
        textfield.insert('0.0',stuff)

        textfield = tk.Text(self,width=20,height=1)
        textfield.grid(row=botrow,column=1)
        textfield.insert('0.0',otherstuff)

        botrow+=1

def SomeProg():
    for i in range(20):
        if i%2==0:
            stuff = "Stuff is "+str(i)
            otherstuff=i*3
            Wins[0].addrowTop(stuff,otherstuff)
        elif i%2==1:
            stuff = "Stuff is "+str(i)
            otherstuff=i*4
            Wins[1].addrowBot(stuff,otherstuff)


root = tk.Tk()
root.title("Stuff")

Wins = [ ProgramWindow("TopWin"),ProgramWindow("BotWin")]
SomeProg()

root.mainloop()

additional code with my tries to add the scrollbar (based on example shown in link above). if the scrollbar is only shown in the lower part, that would be okay since thats the part with the many results.)

import Tkinter as tk
toprow=1
botrow=1
class ProgramWindow(tk.Frame): 

    def __init__(self,name): 
        self.name = name
        self.frame=tk.Frame.__init__(self,root)


        if name=="BotWin":
            tk.Label(self,text="FirstColBot",width=30).grid(row=0,column=0)            
            tk.Label(self,text="SecndColBot",width=20).grid(row=0,column=1)

            self.canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
            self.vsb = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
            self.canvas.configure(yscrollcommand=self.vsb.set)

            self.vsb.pack(side="right", fill="y")
            self.canvas.pack(side="left", fill="both", expand=True)
            self.canvas.create_window((4,4), window=self.frame)

            self.bind("<Configure>", self.OnFrameConfigure)

        elif name=="TopWin":
            self.pack()
            tk.Label(self,text="FirstColTop",width=30).grid(row=0,column=0)         
            tk.Label(self,text="SecndColTop",width=20).grid(row=0,column=1)

    def addrowTop(self,stuff,otherstuff):
        global toprow

        textfield = tk.Text(self,width=30,height=1)
        textfield.grid(row=toprow,column=0)
        textfield.insert('0.0',stuff)

        textfield = tk.Text(self,width=20,height=1)
        textfield.grid(row=toprow,column=1)
        textfield.insert('0.0',otherstuff)

        toprow+=1

    def OnFrameConfigure(self, event):
        self.canvas.configure(scrollregion=self.frame.bbox("all"))

    def addrowBot(self,stuff,otherstuff):
        global botrow

        textfield = tk.Text(self,width=30,height=1)
        textfield.grid(row=botrow,column=0)
        textfield.insert('0.0',stuff)

        textfield = tk.Text(self,width=20,height=1)
        textfield.grid(row=botrow,column=1)
        textfield.insert('0.0',otherstuff)

        botrow+=1

def SomeProg():
    for i in range(20):
        if i%2==0:
            stuff = "Stuff is "+str(i)
            otherstuff=i*3
            Wins[0].addrowTop(stuff,otherstuff)
        elif i%2==1:
            stuff = "Stuff is "+str(i)
            otherstuff=i*4
            Wins[1].addrowBot(stuff,otherstuff)


root = tk.Tk()
root.title("Stuff")

Wins = [ ProgramWindow("TopWin"),ProgramWindow("BotWin")]
SomeProg()

root.mainloop()
Community
  • 1
  • 1
user1451340
  • 387
  • 1
  • 4
  • 12
  • 1
    Nothing to add to the wonderful answer and example provided in the question you linked. Take Brian Oakley's code and create your items in the so called `populate` method (or set the parent of your ProgramWindows to the embeded frame). You might have better feedback if you show us where you stuck / what have failed than what works... – FabienAndre Nov 08 '12 at 15:25
  • i will edit/add the code with scrollbar, but it does not show what i wanted it to – user1451340 Nov 08 '12 at 15:36
  • i referred to it, applied it and it does not work for me, i can not figure out why. – user1451340 Nov 08 '12 at 16:06
  • 1
    difference I can see between Brian Oakley example and your's are: your ProgramWindow frame does not have the canvas as parent and `OnFrameConfigure` use `self.frame` scroll region and not `self.canvas` – FabienAndre Nov 08 '12 at 16:13
  • i would like to have the the bottom-part in the canvas, the upper part can be the normal part. when you run the second code, you see that in the lower part there is a canvas window, i think i just mess up the part when i have to assing the frame to the canvas (thats why its white), and the scrollregion (thats why the scrollbar is unscrollable). i have trouble changing that :/ – user1451340 Nov 08 '12 at 16:21

2 Answers2

4

To adapt Bryan Oakley's answer to your specific problem:

  • create your frame with the canvas as parent
  • use the canvas as the parameter of scrollregion

Note: when subclassing in python, you do not need to store the result of parent __init__ since it operate on self.

Here is the patch:

     def __init__(self,name): 
         self.name = name
-        self.frame=tk.Frame.__init__(self,root)

         if name=="BotWin":
+            self.canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
+            tk.Frame.__init__(self,self.canvas)
             tk.Label(self,text="FirstColBot",width=30).grid(row=0,column=0)            
             tk.Label(self,text="SecndColBot",width=20).grid(row=0,column=1)
-            self.canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
             self.vsb = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
             self.canvas.configure(yscrollcommand=self.vsb.set)

             self.vsb.pack(side="right", fill="y")
             self.canvas.pack(side="left", fill="both", expand=True)
-            self.canvas.create_window((4,4), window=self.frame)
+            self.canvas.create_window((4,4), window=self)
             self.bind("<Configure>", self.OnFrameConfigure)

         elif name=="TopWin":
+            self.frame=tk.Frame.__init__(self,root)
             self.pack()
             tk.Label(self,text="FirstColTop",width=30).grid(row=0,column=0)         
             tk.Label(self,text="SecndColTop",width=20).grid(row=0,column=1)
@@ -41,7 +40,7 @@
         toprow+=1

     def OnFrameConfigure(self, event):
-        self.canvas.configure(scrollregion=self.frame.bbox("all"))
+        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

     def addrowBot(self,stuff,otherstuff):
         global botrow
Community
  • 1
  • 1
FabienAndre
  • 4,514
  • 25
  • 38
  • Thank you very much! i was trying around the time and my last result looked quite similar to yours, but i did not think of exchanging the 'frame' with 'canvas' in the OnFrameConfigure() that, and the create_window line were the only reasons i tried to store it, else i would have no self.frame (which i deperately tried to build in somehow) Thank you for the fix! – user1451340 Nov 08 '12 at 16:54
2

From your question I'm pretty sure I can help you, I had a similar problem a few months ago, and I tried so many different solutions, in the end I found out about the ttk treeview widget, from the ttk module, which comes standard with python 2.7

here is a small example to help you see what I mean

from Tkinter import *
import ttk
root = Tk()
treedata = [('column 1', 'column 2'), ('column 1', 'column 2')]
column_names = ("heading1", "heading2")
tree = ttk.Treeview(root, columns = column_names, yscrollcommand = scrollbar.set)
scrollbar = ttk.Scrollbar(root)
scrollbar.pack(side = 'right', fill= Y)
for x in treedata:
    tree.insert('', 'end', values =x)
for col in column_names: 
    tree.heading(col, text = col.Title())
scrollbar.config(command=tree.yview)
tree.pack()

hope this helps there isn't a lot of docs on this, but google will help, one very helpful link: http://www.tkdocs.com/tutorial/tree.html

good luck :)

jbaldwin
  • 924
  • 1
  • 7
  • 21
  • Thats an interesting alternative, but unfortunately that does not fit my problem, since i just have two "groups" (i dont know a probper word, i am not that good at english), with one of tham containing too many "subentrys", and splitting them up is no alternative for me. I was considering to split them in several sections (once 20 lines were exceeded), but that did not turn out good for me. but thanks for that suggestion, that would be a good alternative for tabs! – user1451340 Nov 08 '12 at 15:54
  • surely you could use a while loop to check if its less than 20 rows, then if over 20 run a function to create a new treeview? If your'e only putting 20 in each, why do you need to scroll? are you trying to scroll individually or separately? – jbaldwin Nov 08 '12 at 16:11
  • i would not need to scroll with treeview, but splitting the results after X rows is no option for me. if it was, treeview would be the way to go ;) – user1451340 Nov 08 '12 at 16:18