简体   繁体   English

使用Tkinter将滚动条添加到框架(Python)

[英]Adding a scrollbar to a frame using Tkinter (Python)

I've a simple GUI thats shows the users some options, after putting the number of the initial options to be shown. 在放置要显示的初始选项数量之后,我有一个简单的GUI,可以为用户显示一些选项。 In this case, 4: 在这种情况下,4:

初始

By clicking on Add row you can add a row to the GUI. 通过单击Add row ,可以将行添加到GUI。 The thing is that if the user wants 100 options, the GUI becomes extra big and all the options are not shown. 问题是,如果用户想要100个选项,则GUI会变得很大,并且所有选项都不会显示。 大

So I would like to have a scrollbar only on the options space, not the rest parts. 所以我只想在选项空间上有一个滚动条,而不是其余部分。 Sorry for the bad Photoshop, but I would like to have something like this: 对不起,Photoshop不好,但是我想要这样的东西: 理想的解决方案

The options space is the FrameTwo , so I would like to have the entire FrameTwo inside of scrollbar like the image above. 选项空间是FrameTwo ,所以我想像上面的图像一样在滚动条内部放置整个FrameTwo

# -*- coding: utf-8 -*-
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
import datetime

class Planificador(Frame):
    def __init__(self,master):
        Frame.__init__(self, master)
        self.master = master
        self.initUI()

    def initUI(self):
        self.master.title("Plan")
        self.frameOne = Frame(self.master)
        self.frameOne.grid(row=0,column=0)
        self.frameTwo = Frame(self.master)
        self.frameTwo.grid(row=1, column=0)
        self.frameThree = Frame(self.master)
        self.frameThree.grid(row=2, column=0)

        # Borrar esto?
        self.txt = Text(self)
        self.txt.pack(fill=BOTH, expand=1)

        self.piezastext = Label(self.frameOne, text = " Amount of pieces ", justify="center")
        self.piezastext.grid(row=1, column=0)
        self.entrypiezas = Entry(self.frameOne,width=3)
        self.entrypiezas.grid(row=2, column=0, pady=(5,5))
        self.aceptarnumpiezas = Button(self.frameOne,text="Click me", command=self.aceptar_piezas,width=8)
        self.aceptarnumpiezas.grid(row=6, column=0, pady=(5,5))

    def aceptar_piezas(self):
        try:
            val = int(self.entrypiezas.get())
            self.aceptar_piezas_ok()
        except ValueError:
            showerror('Error', "Introduce un numero")

    def aceptar_piezas_ok(self):
        self.num_piezas = self.entrypiezas.get()

        self.piezastext.grid_remove()
        self.entrypiezas.grid_remove()
        self.aceptarnumpiezas.grid_remove()

        self.optionmenus_piezas = list()
        self.numpiezas = []
        self.numerolotes = []
        self.optionmenus_prioridad = list()
        self.lotes = list()

        self.mispiezas = ['One', 'Two', 'Three', 'Four', 'Five']

        self.n = 1
        while self.n <= int(self.num_piezas):
            self.textopieza = Label(self.frameTwo, text = "Pieza: ", justify="left")
            self.textopieza.grid(row=self.n, column=0)

            var = StringVar()
            menu = OptionMenu(self.frameTwo, var, *self.mispiezas)
            menu.config(width=10)
            menu.grid(row=self.n, column=1)
            var.set("One")
            self.optionmenus_piezas.append((menu, var))

            self.numpiezastext = Label(self.frameTwo, text = "Numero de piezas: ", justify="center")
            self.numpiezastext.grid(row=self.n, column=2, padx=(10,0))
            self.entrynumpiezas = Entry(self.frameTwo,width=6)
            self.entrynumpiezas.grid(row=self.n, column=3, padx=(0,10))
            self.entrynumpiezas.insert(0, "0")

            self.textoprioridad = Label(self.frameTwo, text = "Prioridad: ", justify="center")
            self.textoprioridad.grid(row=self.n, column=4)
            var2 = StringVar()
            menu2 = OptionMenu(self.frameTwo, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
            menu2.config(width=10)
            menu2.grid(row=self.n, column=5)
            var2.set("Normal")
            self.optionmenus_prioridad.append((menu2, var2))

            self.lotestext = Label(self.frameTwo, text = "Por lotes?", justify="center")
            self.lotestext.grid(row=self.n, column=6, padx=(10,0))
            self.var1 = IntVar()
            self.entrynumlotes = Checkbutton(self.frameTwo, variable=self.var1)
            self.entrynumlotes.grid(row=self.n, column=7, padx=(5,10))
            self.lotes.append(self.var1)
            self.numpiezas.append(self.entrynumpiezas)

            self.n += 1

        self.anadirpiezas = Button(self.frameThree, text="Add row", command=self.addpieza, width=10)
        self.anadirpiezas.grid(row=0, column=2, pady=(10,10))

        self.calculotext = Label(self.frameThree, text = "Other stuff ")
        self.calculotext.grid(row=1, column=2, padx=(10,0), pady=(10,10))

        self.graspbutton = Button(self.frameThree, text="OPT 1", width=10)
        self.graspbutton.grid(row=2, column=1)

        self.parettobutton = Button(self.frameThree, text="OPT 2",width=10)
        self.parettobutton.grid(row=2, column=2, pady=(10,10), padx=(10,0))

        self.parettoEvolbutton = Button(self.frameThree, text="OPT 2", width=10)
        self.parettoEvolbutton.grid(row=2, column=3, pady=(10,10), padx=(10,0))


    def addpieza(self):
            self.textopiezanuevo = Label(self.frameTwo, text = "Pieza: ", justify="left")
            self.textopiezanuevo.grid(row=int(self.num_piezas)+1, column=0)

            var = StringVar()
            menu = OptionMenu(self.frameTwo, var, *self.mispiezas)
            menu.grid(row=self.n, column=1)
            menu.config(width=10)
            menu.grid(row=int(self.num_piezas)+1, column=1)
            var.set("One")
            self.optionmenus_piezas.append((menu, var))

            self.numpiezastext = Label(self.frameTwo, text = "Numero de piezas: ", justify="center")
            self.numpiezastext.grid(row=int(self.num_piezas)+1, column=2, padx=(10,0))
            self.entrynumpiezas = Entry(self.frameTwo,width=6)
            self.entrynumpiezas.grid(row=int(self.num_piezas)+1, column=3, padx=(0,10))
            self.entrynumpiezas.insert(0, "0")

            self.textoprioridad = Label(self.frameTwo, text = "Prioridad: ", justify="center")
            self.textoprioridad.grid(row=int(self.num_piezas)+1, column=4)
            var2 = StringVar()
            menu2 = OptionMenu(self.frameTwo, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
            menu2.config(width=10)
            menu2.grid(row=int(self.num_piezas)+1, column=5)
            var2.set("Normal")
            self.optionmenus_prioridad.append((menu2, var2))

            self.lotestext = Label(self.frameTwo, text = "Por lotes?", justify="center")
            self.lotestext.grid(row=int(self.num_piezas)+1, column=6, padx=(10,0))
            self.var1 = IntVar()
            self.entrynumlotes = Checkbutton(self.frameTwo, variable=self.var1)
            self.entrynumlotes.grid(row=int(self.num_piezas)+1, column=7, padx=(5,10))
            self.lotes.append(self.var1)

            self.numpiezas.append(self.entrynumpiezas)
            self.num_piezas = int(self.num_piezas)+1

if __name__ == "__main__":
    root = Tk()
    aplicacion = Planificador(root)
    root.mainloop()

FrameOne is used to put an image I removed to make this example more simple. FrameOne用于放置我删除的图像,以使此示例更简单。 And FrameThree are the buttons you can see at the bottom of the GUI. FrameThree是您可以在GUI底部看到的按钮。

So it would be very helpful if someone could give me a hand and tell me how to put the entire FrameTwo inside of a scrollbar as you can see on the third image. 因此,如果有人可以帮助我并告诉我如何将整个FrameTwo放在滚动条中,这将非常有帮助,如您在第三张图片上看到的那样。

Thanks in advance. 提前致谢。

One of your problems, is that "frameTwo" has no limits to it's size. 您的问题之一是“ frameTwo”对其大小没有限制。 If you don't limit it's size, any scrollbar you add, never will act. 如果不限制其大小,则添加的任何滚动条都不会起作用。 But limiting the size of you frame have the inconvenient of limit the number of lines you can grid, making the scrollbar useless again. 但是,限制帧的大小会限制网格的行数,因此很不方便,从而使滚动条不再有用。

A solution is creating a frame inside the "frameTwo", to receive the pieces you create. 一种解决方案是在“ frameTwo”内部创建一个框架,以接收您创建的作品。 This way, by one hand, allow you to limit the size of "frameTwo" and attach the scrollbar to it, and by other hand, allow you to grid the pieces you add to the frame located inside "frameTwo", named, let's say, "ListFrame". 这样,一方面,您可以限制“ frameTwo”的大小并附加滚动条,另一方面,您可以将添加到“ frameTwo”中的框架的片段网格化,命名为,“ ListFrame”。 when "ListFrame" size becomes bigger than "frameTwo" size, you can now make the scrollbar work. 现在,当“ ListFrame”的大小大于“ frameTwo”的大小时,可以使滚动条起作用。

I change your code with the changes mentioned above. 我通过上述更改更改了您的代码。 Check it out. 看看这个。 The changes are commented in the code. 更改在代码中注释。 Sorry for the short explanation, but i'm a bit hurry. 简短的解释很抱歉,但是我有点着急。 I may edit this answer when I have more time. 我有更多时间时可以编辑此答案。

PS: Sorry if my english is not the best PS:对不起,如果我的英语不是最好的话

# -*- coding: utf-8 -*-
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
import datetime

class Planificador(Frame):
    def __init__(self,master):
        Frame.__init__(self, master)
        self.master = master
        self.initUI()

    def initUI(self):
        self.master.title("Plan")
        self.frameOne = Frame(self.master)
        self.frameOne.grid(row=0,column=0)

        self.frameTwo = Frame(self.master)
        self.frameTwo.grid(row=1, column=0)

        #Creating of a new frame, inside of "frameTwo" to the objects to be inserted
        #Creating a scrollbar

        #The reason for this, is to attach the scrollbar to "FrameTwo", and when the size of frame "ListFrame" exceed the size of frameTwo, the scrollbar acts
        self.canvas=Canvas(self.frameTwo)
        self.listFrame=Frame(self.canvas)
        self.scrollb=Scrollbar(self.master, orient="vertical",command=self.canvas.yview)
        self.scrollb.grid(row=1, column=1, sticky='nsew')  #grid scrollbar in master, but
        self.canvas['yscrollcommand'] = self.scrollb.set   #attach scrollbar to frameTwo

        self.canvas.create_window((0,0),window=self.listFrame,anchor='nw')
        self.listFrame.bind("<Configure>", self.AuxscrollFunction)
        self.scrollb.grid_forget()                         #Forget scrollbar because the number of pieces remains undefined by the user. But this not destroy it. It will be "remembered" later.

        self.canvas.pack(side="left")
        self.frameThree = Frame(self.master)
        self.frameThree.grid(row=2, column=0)

        # Borrar esto?
        self.txt = Text(self)
        self.txt.pack(fill=BOTH, expand=1)

        self.piezastext = Label(self.frameOne, text = " Amount of pieces ", justify="center")
        self.piezastext.grid(row=1, column=0)
        self.entrypiezas = Entry(self.frameOne,width=3)
        self.entrypiezas.grid(row=2, column=0, pady=(5,5))
        self.aceptarnumpiezas = Button(self.frameOne,text="Click me", command=self.aceptar_piezas,width=8)
        self.aceptarnumpiezas.grid(row=6, column=0, pady=(5,5))

    def AuxscrollFunction(self,event):
        #You need to set a max size for frameTwo. Otherwise, it will grow as needed, and scrollbar do not act
        self.canvas.configure(scrollregion=self.canvas.bbox("all"),width=600,height=500)

    def aceptar_piezas(self):



        #IMPORTANT!!! All the objects are now created in "ListFrame" and not in "frameTwo"
        #I perform the alterations. Check it out
        try:
            val = int(self.entrypiezas.get())
            self.aceptar_piezas_ok()
            self.scrollb.grid(row=1, column=1, sticky='nsew')  #grid scrollbar in master, because user had defined the numer of pieces
        except ValueError:
            showerror('Error', "Introduce un numero")

    def aceptar_piezas_ok(self):
        self.num_piezas = self.entrypiezas.get()

        self.piezastext.grid_remove()
        self.entrypiezas.grid_remove()
        self.aceptarnumpiezas.grid_remove()

        self.optionmenus_piezas = list()
        self.numpiezas = []
        self.numerolotes = []
        self.optionmenus_prioridad = list()
        self.lotes = list()

        self.mispiezas = ['One', 'Two', 'Three', 'Four', 'Five']

        self.n = 1
        while self.n <= int(self.num_piezas):
            self.textopieza = Label(self.listFrame, text = "Pieza: ", justify="left")
            self.textopieza.grid(row=self.n, column=0)

            var = StringVar()
            menu = OptionMenu(self.listFrame, var, *self.mispiezas)
            menu.config(width=10)
            menu.grid(row=self.n, column=1)
            var.set("One")
            self.optionmenus_piezas.append((menu, var))

            self.numpiezastext = Label(self.listFrame, text = "Numero de piezas: ", justify="center")
            self.numpiezastext.grid(row=self.n, column=2, padx=(10,0))
            self.entrynumpiezas = Entry(self.listFrame,width=6)
            self.entrynumpiezas.grid(row=self.n, column=3, padx=(0,10))
            self.entrynumpiezas.insert(0, "0")

            self.textoprioridad = Label(self.listFrame, text = "Prioridad: ", justify="center")
            self.textoprioridad.grid(row=self.n, column=4)
            var2 = StringVar()
            menu2 = OptionMenu(self.listFrame, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
            menu2.config(width=10)
            menu2.grid(row=self.n, column=5)
            var2.set("Normal")
            self.optionmenus_prioridad.append((menu2, var2))

            self.lotestext = Label(self.listFrame, text = "Por lotes?", justify="center")
            self.lotestext.grid(row=self.n, column=6, padx=(10,0))
            self.var1 = IntVar()
            self.entrynumlotes = Checkbutton(self.listFrame, variable=self.var1)
            self.entrynumlotes.grid(row=self.n, column=7, padx=(5,10))
            self.lotes.append(self.var1)
            self.numpiezas.append(self.entrynumpiezas)

            self.n += 1

        self.anadirpiezas = Button(self.frameThree, text="Add row", command=self.addpieza, width=10)
        self.anadirpiezas.grid(row=0, column=2, pady=(10,10))

        self.calculotext = Label(self.frameThree, text = "Other stuff ")
        self.calculotext.grid(row=1, column=2, padx=(10,0), pady=(10,10))

        self.graspbutton = Button(self.frameThree, text="OPT 1", width=10)
        self.graspbutton.grid(row=2, column=1)

        self.parettobutton = Button(self.frameThree, text="OPT 2",width=10)
        self.parettobutton.grid(row=2, column=2, pady=(10,10), padx=(10,0))

        self.parettoEvolbutton = Button(self.frameThree, text="OPT 2", width=10)
        self.parettoEvolbutton.grid(row=2, column=3, pady=(10,10), padx=(10,0))


    def addpieza(self):
            self.textopiezanuevo = Label(self.listFrame, text = "Pieza: ", justify="left")
            self.textopiezanuevo.grid(row=int(self.num_piezas)+1, column=0)

            var = StringVar()
            menu = OptionMenu(self.listFrame, var, *self.mispiezas)
            menu.grid(row=self.n, column=1)
            menu.config(width=10)
            menu.grid(row=int(self.num_piezas)+1, column=1)
            var.set("One")
            self.optionmenus_piezas.append((menu, var))

            self.numpiezastext = Label(self.listFrame, text = "Numero de piezas: ", justify="center")
            self.numpiezastext.grid(row=int(self.num_piezas)+1, column=2, padx=(10,0))
            self.entrynumpiezas = Entry(self.listFrame,width=6)
            self.entrynumpiezas.grid(row=int(self.num_piezas)+1, column=3, padx=(0,10))
            self.entrynumpiezas.insert(0, "0")

            self.textoprioridad = Label(self.listFrame, text = "Prioridad: ", justify="center")
            self.textoprioridad.grid(row=int(self.num_piezas)+1, column=4)
            var2 = StringVar()
            menu2 = OptionMenu(self.listFrame, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
            menu2.config(width=10)
            menu2.grid(row=int(self.num_piezas)+1, column=5)
            var2.set("Normal")
            self.optionmenus_prioridad.append((menu2, var2))

            self.lotestext = Label(self.listFrame, text = "Por lotes?", justify="center")
            self.lotestext.grid(row=int(self.num_piezas)+1, column=6, padx=(10,0))
            self.var1 = IntVar()
            self.entrynumlotes = Checkbutton(self.listFrame, variable=self.var1)
            self.entrynumlotes.grid(row=int(self.num_piezas)+1, column=7, padx=(5,10))
            self.lotes.append(self.var1)

            self.numpiezas.append(self.entrynumpiezas)
            self.num_piezas = int(self.num_piezas)+1

if __name__ == "__main__":
    root = Tk()
    aplicacion = Planificador(root)
    root.mainloop()

You have option menus, labels, entry boxes, and checkbuttons in FrameTwo. 您在FrameTwo中具有选项菜单,标签,输入框和复选框。 How would you expect a scrollbar for the entire frame would work? 您希望整个框架的滚动条如何工作? Would it scroll all widgets at the same time? 它会同时滚动所有小部件吗? Tkinter scrollbars are generally attached to listboxes, canvases, entry widgets, and text fields. Tkinter滚动条通常附加到列表框,画布,条目小部件和文本字段。 http://effbot.org/zone/tkinter-scrollbar-patterns.htm Come up with a simple example that illustrates the problem for further help. http://effbot.org/zone/tkinter-scrollbar-patterns.htm提出一个简单的示例来说明问题,以寻求进一步的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM