Scrollbar in Tkinter grid [duplicate]

2020-03-26 08:47发布

问题:

This question already has answers here:
Closed 7 years ago.

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()

回答1:

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


回答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 :)