How to add 2 scrollbars with tkinter in python 3.4?

女生的网名这么多〃 提交于 2021-02-08 10:33:02

问题


I have the following code:

from win32com.client import Dispatch
from tkinter import *
from tkinter import ttk
import tkinter

class applicazione:

def __init__(self, root):
    self.root = root
    self.root.title('Controllo dati per fatturazione elettronica - Manticle - Smith & Nephew Italia')
    ttk.Frame(self.root, width=300, height=250).pack()






    #### label list
    self.titoli = list()
    self.titoli_BFT = ["Num_Doc", "Cod_Art", "Unita Misura", "Tot_Prod", "Quant_Prod", "Perc_IVA_Prod", "Tot_IVA_Prod",
                       "Linea_Prod", "Sconto", "Perc_Sconto", "Tipo_Sconto", "Cod_Art2", "Desc_Art"]
    self.titoli_HFT = ["Dest_Cod_FIS_P_Iva", "Cod_Cli", "Dest_RagSoc1", "Dest_RagSoc2",
                       "Dest_Indirizzo", "Dest_CAP", "Dest_Localita", "Dest_Provincia", "Cli_Cod_Fis_P_Iva",
                        "Cod_Dest", "Cli_RagSoc1", "Cli_RagSoc2", "Cli_Indirizzo", "Cli_CAP",
                       "Cli_Localita", "Cli_Provincia", "Tipo_Doc", "pre_Num_Doc", "Num_Doc",
                        "Data_Doc", "Vs_Rif", "Data_Rif", "Blank", "Blank2", "CPT", "Scad_Pagamento",
                       "Descr", "Num_Ord", "Tot_Imp", "Tot_IVA", "Tot_Doc", "Nazione", "IPA", "Reg_Fiscale"]

    self.titoli_IVA = ["Num_Doc_TMP", "Num_Doc", "Imponibile", "IVA, Tot", "Perc_IVA"]

    self.titoli_RIF_DOC = [ "Num_Doc_TMP", "Num_Doc", "Rif_Doc" ]

    self.titoli_RIF_DOC_BFT = ["Num_Doc_TMP", "Num_Doc", "Cod_Art", "NOTE" ]

    self.titoli_anomalieBFT = ["ordine", "anomalia"]

    self.titoli_anomalieHFT = ["ordine", "anomalia"]

    self.inizializza_widgets()
    self.lettura()



def inizializza_widgets(self):
    #label 

    self.lblins=tkinter.Label(self.root, text="Controllo dati per fatturazione elettronica", font=("Helvetica", 12))
    self.lblins.place(x=10, y=10



    for i in range (0,len(self.titoli_HFT)):
        j = 80*i
        self.lblnome=tkinter.Label(self.root, text= self.titoli_HFT[i], font=("Helvetica", 8))
        self.lblnome.place(x=85+j, y=50)


    #buttons

    ttk.Button(self.root, , text='Inserisci', width='10').place(x=645, y=590)
    #pulsante lettura
    ttk.Button(self.root, text='Modifica', width='10').place(x=725, y=590)

    ttk.Button(self.root, text='Indietro', width='10').place(x=805, y=590)

    ttk.Button(self.root, text='Avanti', width='10').place(x=885, y=590)


def onFrameConfigure(self, event):
    '''Reset the scroll region to encompass the inner frame'''
    self.canvas.configure(scrollregion=self.canvas.bbox("all"))

def lettura(self):
        xl= Dispatch("Excel.Application")
        xl.Visible = True


        self.checkb_intvar = list()   #contiene una lista di 1 o 0 associati alle checkbox nella lista quadratini
        self.quadratiniB = l = [None] * (13 * len(self.titoli_BFT) )
        self.quadratiniH = l = [None] * (13 * len(self.titoli_HFT) )


        wbH = xl.Workbooks.Open(r'C:\Users\\Marco\\LAVORO\\Smith&Nephew\\appRonca\\fonte\\HFT_SAP_2.csv')
        print("wbH")

        wsH=wbH.WorkSheets(1) # get a reference to the first sheet


        cont = 0

        MAX = 3  #13 lunghezza visibile senza barra navigatrice del numero di righe nella finestra 13
        cont = 0
        for i in range(0, MAX):
            for j in range(0,len(self.titoli_HFT)):
                print("for for")
                cont = cont + 1
                print("i")
                print(i)
                print("j")
                print(j)

                print(" The {} set is often represented as {{0}} ".format("empty"))


                #### indexes for DI excel cells management
                k = 80*j      #i con j
                l = 40*i      #k con l


                contvalueX = i + 1  #con zero da errore allora +1
                contvalueY = j + 1  #con zero da errore allora +1

                self.txt1 = tkinter.Text(self.root, width='10', height='1')


                #Reading excel cells file

                if (wsH.Cells(contvalueX, contvalueY ).Value != None):

                    self.txt1.insert('1.0', wsH.Cells(contvalueX, contvalueY ).Value)#ws.Cells(1,i).Value
                    self.txt1.tag_add("start", "1.0", "1.13")
                    if (contvalueY == 1 ):  
                        self.txt1.tag_config("start", background="white", foreground="red")
                    #self.txt1.tag_configure("red", foreground="red")
                    #self.txt1.highlight_pattern("word", "red")
                    #self.txt1 = tkinter.Text(self.root, width='10', height='1', text = ws.Cells(1,i).Value)
                    self.txt1.place(x=85+k, y=80+l)  #5 + 80
                    print("if")

                else:  #None case
                    print("else")
                    self.txt1.insert('1.0', "")
                    self.txt1.place(x=85+k, y=80+l)
                    if (contvalueY == 1 ):  
                        self.txt1.tag_config("start", background="white", foreground="red")




        wbH.Close()
        xl.Quit()


if __name__ == '__main__':
    root = tkinter.Tk()
    w, h = root.winfo_screenwidth(), root.winfo_screenheight()
    root.geometry("%dx%d+0+0" % (w, h))
    applicazione(root)
    root.mainloop()

The application runned:

application image without scrollbar

I read data from an excel file (lettura function) but i would like to add an horizontal and a vertical scrollbar i read first of all this:

Adding a scrollbar to a group of widgets in Tkinter

but use "grid" that i do not use and i'm not able to associate my double "for" "Text" to the vertical scroll bar (Lettura function)

The following code is edited with the scrollbar but does not work:

import tkinter as tk

from win32com.client import Dispatch
from tkinter import *
#from tkinter import ttk
import tkinter

class Example(tk.Frame):
    def __init__(self, root):

        tk.Frame.__init__(self, root)
        root.title('Controllo dati per fatturazione elettronica - Manticle - Smith & Nephew Italia')
        #tk.Frame(root, width=100, height=450).pack()



        self.canvas = tk.Canvas(root,  borderwidth=0, background="#C0C0C0")
        self.frame = tk.Frame(self.canvas, 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, anchor="nw", 
                                  tags="self.frame")

        self.frame.bind("<Configure>", self.onFrameConfigure)


        self.titoli_BFT = ["Num_Doc", "Cod_Art", "Unita Misura", "Tot_Prod", "Quant_Prod", "Perc_IVA_Prod", "Tot_IVA_Prod",
                           "Linea_Prod", "Sconto", "Perc_Sconto", "Tipo_Sconto", "Cod_Art2", "Desc_Art"]

        self.titoli_HFT = ["Dest_Cod_FIS_P_Iva", "Cod_Cli", "Dest_RagSoc1", "Dest_RagSoc2",
                           "Dest_Indirizzo", "Dest_CAP", "Dest_Localita", "Dest_Provincia", "Cli_Cod_Fis_P_Iva",
                            "Cod_Dest", "Cli_RagSoc1", "Cli_RagSoc2", "Cli_Indirizzo", "Cli_CAP",
                           "Cli_Localita", "Cli_Provincia", "Tipo_Doc", "pre_Num_Doc", "Num_Doc",
                            "Data_Doc", "Vs_Rif", "Data_Rif", "Blank", "Blank2", "CPT", "Scad_Pagamento",
                           "Descr", "Num_Ord", "Tot_Imp", "Tot_IVA", "Tot_Doc", "Nazione", "IPA", "Reg_Fiscale"]


        #self.inizializza_widgets()
        self.populate()
        self.lettura()




    def inizializza_widgets(self):
        #label title

        self.lblins=tk.Label(root, text="Controllo dati per fatturazione elettronica", font=("Helvetica", 12))
        self.lblins.place(x=10, y=10)



        for i in range (0,len(self.titoli_HFT)):
            j = 80*i
            self.lblnome=tk.Label(root, text= self.titoli_HFT[i], font=("Helvetica", 8))
            self.lblnome.place(x=85+j, y=50)


        #965 560
        tk.Button(root, text='Inserisci', width='10').place(x=645, y=590)
        #pulsante lettura
        tk.Button(root, text='Modifica', width='10').place(x=725, y=590)

        tk.Button(root, text='Indietro', width='10').place(x=805, y=590)

        tk.Button(root, text='Avanti', width='10').place(x=885, y=590)


    def lettura(self):
            xl= Dispatch("Excel.Application")
            xl.Visible = True

            wbH = xl.Workbooks.Open(r'C:\Users\\Marco\\LAVORO\\Smith&Nephew\\appRonca\\fonte\\HFT_SAP_2.csv')
            print("wbH")

            wsH=wbH.WorkSheets(1) # get a reference to the first sheet



            cont = 0

            MAX = 9  #13 lunghezza visibile senza barra navigatrice del numero di righe nella finestra 13
            cont = 0







            for i in range(0, MAX):
                for j in range(0,len(self.titoli_HFT)):
                    print("for for")
                    cont = cont + 1

                    print("cont")
                    print(cont)

                    #### INDEXES
                    k = 80*j      #i con j
                    l = 40*i      #k con l


                    contvalueX = i + 1  #con zero da errore allora +1
                    contvalueY = j + 1  #con zero da errore allora +1

                    self.txt1 = tk.Text(root, width='10', height='1')




                    #Lettura celle del file HFT

                    if (wsH.Cells(contvalueX, contvalueY ).Value != None):

                        self.txt1.insert('1.0', wsH.Cells(contvalueX, contvalueY ).Value)#ws.Cells(1,i).Value
                        self.txt1.tag_add("start", "1.0", "1.13")
                        if (contvalueY == 1 ):  
                            self.txt1.tag_config("start", background="white", foreground="red")

                        self.txt1.place(x=85+k, y=80+l)  #5 + 80
                        print("if")

                    else: #None case
                        print("else")
                        self.txt1.insert('1.0', "")
                        self.txt1.place(x=85+k, y=80+l)
                        if (contvalueY == 1 ):  #### qui si richiama la funziona regole con tutte le regole
                            self.txt1.tag_config("start", background="white", foreground="red")

            wbH.Close()
            xl.Quit()



    def onFrameConfigure(self, event):
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

if __name__ == "__main__":
    root=tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

and this: How to add a scrollbar to a window with tkinter? that is not organise like a class.

how can i implement the 2 scrollbars?

UPDATE

new version:

from win32com.client import Dispatch
from tkinter import *
from tkinter import ttk
import tkinter


class applicazione:


    def __init__(self, root):
        self.root = root

        # Top-level frame

        self.frame = ttk.Frame(self.root, relief="sunken")

        # Canvas creation with double scrollbar
        hscrollbar = ttk.Scrollbar(self.frame, orient = tkinter.HORIZONTAL)
        vscrollbar = ttk.Scrollbar(self.frame, orient = tkinter.VERTICAL)
        self.canvas = tkinter.Canvas(self.frame, bd=0, highlightthickness=0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set)
        vscrollbar.config(command = self.canvas.yview)
        hscrollbar.config(command = self.canvas.xview)


        # Add controls here
        self.subframe = ttk.Frame(self.canvas)

        #Packing everything
        self.subframe.pack(padx   = 15, pady   = 15, fill = tkinter.BOTH, expand = tkinter.TRUE)
        hscrollbar.pack( fill=tkinter.X, side=tkinter.BOTTOM, expand=tkinter.FALSE)
        vscrollbar.pack( fill=tkinter.Y, side=tkinter.RIGHT, expand=tkinter.FALSE)
        self.canvas.pack(side = tkinter.LEFT, padx  = 5, pady   = 5, fill = tkinter.BOTH, expand= tkinter.TRUE)
        self.frame.pack( padx   = 5, pady   = 5, expand = True, fill = tkinter.BOTH)


        self.canvas.create_window(0,0, window = self.subframe)
        self.root.update_idletasks() # update geometry
        self.canvas.config(scrollregion = self.canvas.bbox("all"))
        self.canvas.xview_moveto(0) 
        self.canvas.yview_moveto(0)


        self.root.title('Controllo dati per fatturazione elettronica - Manticle - Smith & Nephew Italia')
        ttk.Frame(self.root, width=300, height=250).pack()


        #### Titles
        self.titoli_HFT = ["Dest_Cod_FIS_P_Iva", "Cod_Cli", "Dest_RagSoc1", "Dest_RagSoc2",
                           "Dest_Indirizzo", "Dest_CAP", "Dest_Localita", "Dest_Provincia", "Cli_Cod_Fis_P_Iva",
                            "Cod_Dest", "Cli_RagSoc1", "Cli_RagSoc2", "Cli_Indirizzo", "Cli_CAP",
                           "Cli_Localita", "Cli_Provincia", "Tipo_Doc", "pre_Num_Doc", "Num_Doc",
                            "Data_Doc", "Vs_Rif", "Data_Rif", "Blank", "Blank2", "CPT", "Scad_Pagamento",
                           "Descr", "Num_Ord", "Tot_Imp", "Tot_IVA", "Tot_Doc", "Nazione", "IPA", "Reg_Fiscale"]



        self.inizializza_widgets()


    def inizializza_widgets(self):

        self.lblins=tkinter.Label(self.root, text="Controllo dati per fatturazione elettronica", font=("Helvetica", 12))
        self.lblins.place(x=10, y=10)

        for i in range (0,len(self.titoli_HFT)):
            j = 80*i
            self.lblnome=tkinter.Label(self.root, text= self.titoli_HFT[i], font=("Helvetica", 8))
            self.lblnome.place(x=85+j, y=50)

        ttk.Button(self.root, text='Inserisci', width='10').place(x=645, y=590)

        ttk.Button(self.root, text='Modifica', width='10').place(x=725, y=590)

        ttk.Button(self.root,  text='Indietro', width='10').place(x=805, y=590)

        ttk.Button(self.root,  text='Avanti', width='10').place(x=885, y=590)



if __name__ == '__main__':
    root = tkinter.Tk()
    root.title( "Double scrollbar with tkinter" )
    w, h = root.winfo_screenwidth(), root.winfo_screenheight()
    root.geometry("%dx%d+0+0" % (w, h))
    applicazione(root)
    root.mainloop()

回答1:


I've also struggled with creating a double scrollbar window. Here is an implementation using pack layout manager (you should be able to tailor it for a grid layout) :

import tkinter as tk
from tkinter import ttk

# Top-level frame
root = tk.Tk()
root.title( "Double scrollbar with tkinter" )
root.minsize(width = 600, height = 600)
frame = ttk.Frame(root, relief="sunken")

# Canvas creation with double scrollbar
hscrollbar = ttk.Scrollbar(frame, orient = tk.HORIZONTAL)
vscrollbar = ttk.Scrollbar(frame, orient = tk.VERTICAL)
sizegrip = ttk.Sizegrip(frame)
canvas = tk.Canvas(frame, bd=0, highlightthickness=0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set)
vscrollbar.config(command = canvas.yview)
hscrollbar.config(command = canvas.xview)


# Add controls here
subframe = ttk.Frame(canvas)

#Packing everything
subframe.pack(padx   = 15, pady   = 15, fill = tk.BOTH, expand = tk.TRUE)
hscrollbar.pack( fill=tk.X, side=tk.BOTTOM, expand=tk.FALSE)
vscrollbar.pack( fill=tk.Y, side=tk.RIGHT, expand=tk.FALSE)
sizegrip.pack(in_ = hscrollbar, side = tk.BOTTOM, anchor = "se")
canvas.pack(side = tk.LEFT, padx  = 5, pady   = 5, fill = tk.BOTH, expand= tk.TRUE)
frame.pack( padx   = 5, pady   = 5, expand = True, fill = tk.BOTH)


canvas.create_window(0,0, window = subframe)
root.update_idletasks() # update geometry
canvas.config(scrollregion = canvas.bbox("all"))
canvas.xview_moveto(0) 
canvas.yview_moveto(0)


# launch the GUI
root.mainloop()

(Tested with Python 3.4).

Exemples :

It's not perfect, since it lacks the small block on the bottom right corner.

UPDATE 1 : Added Sizegrip to get the bottom right resizing corner

UPDATE 2 : Added working solution to OP's updated code

from win32com.client import Dispatch
from tkinter import *
from tkinter import ttk
import tkinter


class applicazione(object):


    def __init__(self, root):
        self.root = root

        # Top-level frame
        self.root.title('Controllo dati per fatturazione elettronica - Manticle - Smith & Nephew Italia')

        self.frame = ttk.Frame(self.root, width=300, height=250)

        # Canvas creation with double scrollbar
        hscrollbar = ttk.Scrollbar(self.frame, orient = tkinter.HORIZONTAL)
        vscrollbar = ttk.Scrollbar(self.frame, orient = tkinter.VERTICAL)
        sizegrip = ttk.Sizegrip(self.frame)
        self.canvas = tkinter.Canvas(self.frame, bd=0, highlightthickness=0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set)
        vscrollbar.config(command = self.canvas.yview)
        hscrollbar.config(command = self.canvas.xview)


        # Add controls here
        self.subframe = ttk.Frame(self.canvas)        


        #### Titles
        self.titoli_HFT = ["Dest_Cod_FIS_P_Iva", "Cod_Cli", "Dest_RagSoc1", "Dest_RagSoc2",
                           "Dest_Indirizzo", "Dest_CAP", "Dest_Localita", "Dest_Provincia", "Cli_Cod_Fis_P_Iva",
                            "Cod_Dest", "Cli_RagSoc1", "Cli_RagSoc2", "Cli_Indirizzo", "Cli_CAP",
                           "Cli_Localita", "Cli_Provincia", "Tipo_Doc", "pre_Num_Doc", "Num_Doc",
                            "Data_Doc", "Vs_Rif", "Data_Rif", "Blank", "Blank2", "CPT", "Scad_Pagamento",
                           "Descr", "Num_Ord", "Tot_Imp", "Tot_IVA", "Tot_Doc", "Nazione", "IPA", "Reg_Fiscale"]



        self.inizializza_widgets()

        #Packing everything
        self.subframe.pack(fill = tkinter.BOTH, expand = tkinter.TRUE)
        hscrollbar.pack( fill=tkinter.X, side=tkinter.BOTTOM, expand=tkinter.FALSE)
        vscrollbar.pack( fill=tkinter.Y, side=tkinter.RIGHT, expand=tkinter.FALSE)
        sizegrip.pack(in_= hscrollbar, side = BOTTOM, anchor = "se")
        self.canvas.pack(side = tkinter.LEFT, padx  = 5, pady  = 5, fill = tkinter.BOTH, expand= tkinter.TRUE)
        self.frame.pack( padx   = 5, pady  = 5, expand = True, fill = tkinter.BOTH)


        self.canvas.create_window(0,0, window = self.subframe)
        self.root.update_idletasks() # update geometry
        self.canvas.config(scrollregion = self.canvas.bbox("all"))
        self.canvas.xview_moveto(0) 
        self.canvas.yview_moveto(0)    


    def inizializza_widgets(self):

        self.LabelFrame = ttk.Frame(self.subframe)
        self.lblins = tkinter.Label(self.LabelFrame, text="Controllo dati per fatturazione elettronica", font=("Helvetica", 12))
        self.lblins.pack()

        for i in range (0,len(self.titoli_HFT)):
            j = 80*i
            self.lblnome=tkinter.Label(self.LabelFrame, text= self.titoli_HFT[i], font=("Helvetica", 8))
            self.lblnome.pack(side = LEFT)#place(x=85+j, y=50)

        self.ContentFrame = ttk.Frame(self.subframe, width = 600, height = 600)

        self.ButtonsFrame = ttk.Frame(self.subframe)
        ttk.Frame(self.ButtonsFrame).pack(side=LEFT, fill = X, expand=TRUE)
        ttk.Button(self.ButtonsFrame, text='Inserisci', width='10').pack(side = LEFT)
        ttk.Button(self.ButtonsFrame, text='Modifica', width='10').pack(side = LEFT)
        ttk.Button(self.ButtonsFrame,  text='Indietro', width='10').pack(side = LEFT)
        ttk.Button(self.ButtonsFrame,  text='Avanti', width='10').pack(side = LEFT)
        ttk.Frame(self.ButtonsFrame).pack(side=RIGHT, fill = X, expand=TRUE)

        self.LabelFrame.pack(side = TOP, fill = X, expand=TRUE)
        self.ContentFrame.pack(fill = BOTH, expand = TRUE)
        self.ButtonsFrame.pack(side = BOTTOM, fill = X, expand = TRUE)



if __name__ == '__main__':
    root = tkinter.Tk()
    root.title( "Double scrollbar with tkinter" )
    w, h = root.winfo_screenwidth(), root.winfo_screenheight()
    root.geometry("%dx%d+0+0" % (0.99*w, 0.9*h))
    applicazione(root)


    root.mainloop()




回答2:


Just to expand on the answer by @georgesl and demonstrate the use of the ttk sizegrip and also to show that grid works nicely for this kind of task, here is a short example showing a text widget with 2 scrollbars and the sizegrip in the corner.

# Demonstrate text widget with two scrollbars and the sizegrip.
import tkinter as tk
import tkinter.ttk as ttk

root = tk.Tk()
text = tk.Text(root)
vs = ttk.Scrollbar(root, orient="vertical")
hs = ttk.Scrollbar(root, orient="horizontal")
sizegrip = ttk.Sizegrip(root)

# hook up the scrollbars to the text widget
text.configure(yscrollcommand=vs.set, xscrollcommand=hs.set, wrap="none")
vs.configure(command=text.yview)
hs.configure(command=text.xview)

# grid everything on-screen
text.grid(row=0,column=0,sticky="news")
vs.grid(row=0,column=1,sticky="ns")
hs.grid(row=1,column=0,sticky="news")
sizegrip.grid(row=1,column=1,sticky="news")
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)

def fill():
    for n in range(30):
        text.insert("end", 'hello ' * 20, "", "\n")
root.after(20, fill)
root.mainloop()



回答3:


The process to add both a horizontal and vertical scrollbar to a collection of widgets is precisely the same as the solution provided in this answer: https://stackoverflow.com/a/3092341/7432. That answer shows only a vertical scrollbar, but adding a horizontal one is just a matter of a couple lines of code.

The solution is very straight-forward:

  • add widgets to a frame using whatever method you want
  • add the frame to a canvas using the create_window method of the canvas
  • add scrollbars to the canvas in the usual way
  • set the scrollregion attribute of the canvas to be big enough to incude the entire frame that was added
    • do this whenever you add or remove widgets from the frame
    • you might also need to do this whenever the canvas changes size


来源:https://stackoverflow.com/questions/31533623/how-to-add-2-scrollbars-with-tkinter-in-python-3-4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!