1
votes

I have been trying but failed to do the below. I have one label frame with some entry boxes. I want to add a button so that user can add multiple frames in the tool along with the entry boxes and buttons below the existing label frame.And when the new frame is added the text box below should get shifted. my code for tkinter is below:

from Tkinter import *
root=Tk()
root.title("CIME")
step = LabelFrame(root,text="Enter Details:")
step.grid(row=0, columnspan=7, sticky='W',padx=5, pady=5, ipadx=5, ipady=5)
Label(step,text="Competitors",font = "Arial 8 bold italic").grid(row=0,sticky='E', padx=5, pady=2)
Label(step,text="Keywords",font = "Arial 8 bold italic").grid(row=1,sticky='E', padx=5, pady=2)
Label(step,text="Project Name",font = "Arial 8 bold italic").grid(row=2,sticky='E', padx=5, pady=2)
e1 = Entry(step)
e2=Entry(step)
e3=Entry(step)
e1.grid(row=0,column=1,columnspan=7, sticky="WE", pady=3,padx=5)
e2.grid(row=1,column=1,columnspan=7, sticky="WE", pady=3,padx=5)
e3.grid(row=2,column=1,columnspan=7, sticky="WE", pady=3,padx=5)
tex = Text(master=root)
scr=Scrollbar(root,orient =VERTICAL,command=tex.yview)
scr.grid(padx=1, column=7, rowspan=15, columnspan=1, sticky=NS)
tex.grid(row = 4,column=1)
tex.config(yscrollcommand=scr.set,font=('Arial', 8, 'bold', 'italic'))
#tex['yscrollcommand'] = sb.set
Button(step,text ="Search Words",width=10,font = "Arial 8 bold    italic",activebackground="red",command=roll).grid(row=3,column=0,sticky=W,pady=4,padx=5)
Button(step,text="Google Search",width=10,font = "Arial 8 bold italic",command = links).grid(row=3,column=2,sticky=W,pady=4,padx=5)
Button(step,text="Extraxt Text",width=10,font = "Arial 8 bold italic",command = create).grid(row=3,column=4,sticky=W,pady=4,padx=5)
mainloop()

enter image description here

2

2 Answers

2
votes

The first part of the solution is to create a function to create the labelframe and entry widgets. Even better is to move that code into a class, so you can treat the whole thing as if it were a single widget. This will make your code easier to understand, and much easier to layout visually.

For example:

class CustomFrame(LabelFrame):
    def __init__(self, parent, text):
        LabelFrame.__init__(self, parent, text=text)

        Label(self,text="Competitors",font = "Arial 8 bold italic").grid(row=0,sticky='E', padx=5, pady=2)
        Label(self,text="Keywords",font = "Arial 8 bold italic").grid(row=1,sticky='E', padx=5, pady=2)
        Label(self,text="Project Name",font = "Arial 8 bold italic").grid(row=2,sticky='E', padx=5, pady=2)
        self.e1=Entry(self)
        self.e2=Entry(self)
        self.e3=Entry(self)
        self.e1.grid(row=0,column=1,columnspan=7, sticky="WE", pady=3,padx=5)
        self.e2.grid(row=1,column=1,columnspan=7, sticky="WE", pady=3,padx=5)
        self.e3.grid(row=2,column=1,columnspan=7, sticky="WE", pady=3,padx=5)

        Button(self,text ="Search Words",width=10,font = "Arial 8 bold italic", activebackground="red",
               command=roll).grid(row=3,column=0,sticky=W,pady=4,padx=5)
        Button(self,text="Google Search",width=10,font = "Arial 8 bold italic",
               command = links).grid(row=3,column=2,sticky=W,pady=4,padx=5)
        Button(self,text="Extraxt Text",width=10,font = "Arial 8 bold italic",
               command = create).grid(row=3,column=4,sticky=W,pady=4,padx=5)

    def getValues(self):
        """Return a dictionary of values from the widget"""
        return {"competitors": self.e1.get(),
                "keywords": self.e2.get(),
                "name": self.e3.get()
        }

Next, you can use that function to create your initial set of widgets. Also, because you want to add new label frames, it's better to use pack to manage these frames so you don't have to keep adding rows to the grid. So, I recommend you create a container just for the labelframes. You can then use pack to stack them one on top of the other.

Your main program then looks something like this:

root = Tk()
root.title("CIME")

frames = Frame(root)
frames.grid(row=0, column=0, sticky="nsew")
tex = Text(master=root)
scr=Scrollbar(root,orient =VERTICAL,command=tex.yview)
scr.grid(row = 1, column=1, padx=1, sticky=NS)
tex.grid(row = 1, column=0)
tex.config(yscrollcommand=scr.set,font=('Arial', 8, 'bold', 'italic'))

step = CustomFrame(frames, "Enter Details:")
step.pack(side="top")

mainloop()

Now, it's simply a matter of creating a new instance every time you need another frame. If you keep a reference to the widget, you can use the getValues method to return a dictionary containing the values of each input widget.

Now you just need a very simple function to create a new instance of CustomFrame and pack it inside of frames. It would look something like this:

def newFrame():
    f = CustomFrame(frames, "Another Frame")
    f.pack(side="top")

... though, you'll probably want to append f to a list or dictionary so that you can get the values at some later point in your code.

0
votes

Define a function that generate Enter detail label frame. And call it in the callback function of the new button.

from Tkinter import *
def roll(): pass
def links(): pass
def create(): pass
root=Tk()
root.title("CIME")

rows = 0
def create_detail_frame():
    global rows
    step = LabelFrame(root,text="Enter Details:")
    step.grid(row=rows, columnspan=7, sticky='W',padx=5, pady=5, ipadx=5, ipady=5)
    Label(step,text="Competitors",font = "Arial 8 bold italic").grid(row=0,sticky='E', padx=5, pady=2)
    Label(step,text="Keywords",font = "Arial 8 bold italic").grid(row=1,sticky='E', padx=5, pady=2)
    Label(step,text="Project Name",font = "Arial 8 bold italic").grid(row=2,sticky='E', padx=5, pady=2)
    e1 = Entry(step)
    e2 = Entry(step)
    e3 = Entry(step)
    e1.grid(row=0,column=1,columnspan=7, sticky="WE", pady=3,padx=5)
    e2.grid(row=1,column=1,columnspan=7, sticky="WE", pady=3,padx=5)
    e3.grid(row=2,column=1,columnspan=7, sticky="WE", pady=3,padx=5)
    Button(step,text ="Search Words",width=10,font = "Arial 8 bold    italic",activebackground="red",command=roll).grid(row=3,column=0,sticky=W,pady=4,padx=5)
    Button(step,text="Google Search",width=10,font = "Arial 8 bold italic",command=links).grid(row=3,column=2,sticky=W,pady=4,padx=5)
    Button(step,text="Extraxt Text",width=10,font = "Arial 8 bold italic",command = create).grid(row=3,column=4,sticky=W,pady=4,padx=5)
    rows += 1

    # Reposition text, scroll
    #scr.grid_forget()
    #tex.grid_forget()
    #scr.grid(row=rows, padx=1, column=7, rowspan=15, columnspan=1, sticky=NS)
    #tex.grid(row=rows,column=1)

    # Reposition text, scroll
    scr.grid(row=rows)
    tex.grid(row=rows)

tex = Text(master=root)
scr=Scrollbar(root,orient =VERTICAL,command=tex.yview)
scr.grid(row=1, padx=1, column=7, rowspan=15, columnspan=1, sticky=NS)
tex.grid(row=1,column=1)
tex.config(yscrollcommand=scr.set,font=('Arial', 8, 'bold', 'italic'))

Button(root, text='Add detail frame', command=create_detail_frame).grid(row=0, column=7)
create_detail_frame()

mainloop()

NOTE: I used a global variable rows to keep track of how many grid rows are there above the text widget.