如何在python 3.4中添加2个带tkinter的滚动条?

时间:2015-07-21 08:10:59

标签: python tkinter scrollbars tkinter-canvas

我有以下代码:

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 application image without scrollbar ".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()

应用程序已运行:

{{0}}

我从excel文件中读取数据(lettura函数) 但我想添加一个水平和垂直滚动条,我首先阅读:

Adding a scrollbar to a group of widgets in Tkinter

但使用我不使用的“网格”,我无法将我的双“for”“Text”关联到垂直滚动条(Lettura函数)

使用滚动条编辑以下代码但不起作用:

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

并且: How to add a scrollbar to a window with tkinter?  这不像是一个班级组织。

如何实现2个滚动条?

更新

新版本:

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

3 个答案:

答案 0 :(得分:2)

我也在努力创建一个双滚动条窗口。以下是使用pack布局管理器的实现(您应该可以为grid布局定制它):

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

(使用Python 3.4测试)。

例子: enter image description here enter image description here

它并不完美,因为它缺少右下角的小块。

更新1:添加Sizegrip以获得右下角的调整大小

更新2:为OP的更新代码添加了工作解决方案

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

enter image description here

答案 1 :(得分:1)

只是为了扩展@georgesl的答案并展示ttk sizegrip的使用,并且还表明grid很适合这种任务,这里有一个简短的例子,展示了一个带有2个滚动条的文本小部件和角落里的尺寸。

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

答案 2 :(得分:0)

将水平和垂直滚动条添加到窗口小部件集合的过程与此答案中提供的解决方案完全相同:https://stackoverflow.com/a/3092341/7432。该答案仅显示一个垂直滚动条,但添加一个水平滚动条只需要几行代码。

解决方案非常简单:

  • 使用您想要的任何方法将小部件添加到框架
  • 使用画布的create_window方法将画布添加到画布
  • 以通常的方式将滚动条添加到画布
  • 将画布的scrollregion属性设置得足够大,以包含添加的整个帧
    • 每当您从框架中添加或删除小部件时都会执行此操作
    • 每当画布改变大小时,您可能还需要这样做