0

i have dynamically addable and delete able entry fields that i want to set inside a frame or canvas inside of a main frame but when i try the frame dissappears or dynamically grows with the entry fields. i want the canvas to use the scrollbar if entry fields exceed the window size.

from tkinter import *
import tkinter as tk
class Demo2:
    def __init__(self, master):
        global rows

    self.master = master      
    self.frame = tk.Frame(self.master)
    master.title("test")

    self.frame.pack()
    addboxButton = Button(self.frame, text='<Add Time Input>', fg="Red", command=self.addBox)
    addboxButton.pack()

this is where my buttons are added and deleted.

def addBox(self):         
    def delete():
        delboxButton.grid_remove()
        ent1.delete(0,END)
        ent2.delete(0,END)
        ent1.grid_remove()
        ent2.grid_remove()
    root = self.frame
    frame=Frame(root,width=900,height=900)
    frame.pack()
    canvas=Canvas(frame,bg='#FFFFFF',width=700,height=300,scrollregion=(0,0,700,300))
    vbar=Scrollbar(frame,orient=VERTICAL)
    vbar.pack(side=RIGHT,fill=Y)
    vbar.config(command=canvas.yview)
    canvas.config(width=700,height=300)
    canvas.config(yscrollcommand=vbar.set)
    canvas.pack(side=LEFT,expand=TRUE,fill=BOTH)

I am trying to figure out now how to make the first set of entry start out on the screen when its opened. and bind the add call to an action.

    i = 0
    ent1 = Entry(canvas)
    ent1.grid(row=i, column=0,sticky="nsew")
    i += 1
    i = 0
    ent2 = Entry(canvas)
    ent2.grid(row=i, column=1,sticky="nsew")
    i += 1        

    delboxButton = Button(canvas, text='delete', fg="Red", command=delete)
    delboxButton.grid(row=0 ,column=2)

root = tk.Tk()
root.title("test Complete")
root.geometry("500x500")
app = Demo2(root)
root.mainloop()
Brandon
  • 103
  • 1
  • 1
  • 7
  • why are you creating a new canvas for every "box"? Also, a canvas can only scroll things created with `create_window`, so adding a frame with `pack` won't allow that frame to be scrolled. – Bryan Oakley Mar 09 '17 at 16:06
  • I do not want to create a new canvas per entry added. thats why im here asking for a point in the right direction i am trying the create_window now but it does not delete the fields when i click delete. @brianOakley – Brandon Mar 09 '17 at 16:24
  • Ok i went with you create window and it adds them but it stacks them one on top of the other. i tried using the i = 10 and then i += 20 i used 20 because thats the required amount of space so they don't over lap. but it doesn't add the amount required to the row count. – Brandon Mar 09 '17 at 20:31

1 Answers1

1

The normal way this is tackled is to create a single frame and add it to the canvas with the canvas create_window method. Then, you can put whatever you want in the frame using pack, place or grid.

For a description of the technique see Adding a scrollbar to a group of widgets in Tkinter

Here's an example illustrating how the technique works for widgets created by a button. I didn't include the delete functionality or the ability for everything to resize properly to keep the example short, but you seem to have a pretty good idea of how to make the delete function work and I don't know exactly what sort of resize behavior you want.

import tkinter as tk

class Demo2:
    def __init__(self, master):
        self.master = master
        self.entries = []

        self.canvas = tk.Canvas(master, width=400, height=200)
        self.vsb = tk.Scrollbar(master, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)
        self.add_button = tk.Button(master, text="Add", command=self.add)
        self.container = tk.Frame()

        self.canvas.create_window(0, 0, anchor="nw", window=self.container)
        self.add_button.pack(side="top")
        self.vsb.pack(side="right", fill="y")
        self.canvas.pack(side="left", fill="both", expand=True)

        # start with 3 entry widgets
        self.add()
        self.add()
        self.add()

    def add(self):
        entry = tk.Entry(self.container)
        entry.pack(side="top", fill="x")
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

        self.entries.append(entry)

root = tk.Tk()
demo = Demo2(root)
root.mainloop()
Community
  • 1
  • 1
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thank you for your replies I'm going to look at your example as soon as I get back to my computer I guess I'm just not wording my question correctly. It gets me in trouble a lot on here. – Brandon Mar 09 '17 at 22:45
  • this is pretty close thank you for the link im trying to see if i can make it work. on the example it populates the fields from a for statement. and the i = 0 , i+=1 does not change my row counts like before . i will continue to test it and see if i can get it working . – Brandon Mar 10 '17 at 00:47
  • ok from what i can tell from using the example you posted as a guide line. i moved my canvas to top frame instead of addbox. and the part where it has canvas.configure(scrollregion=canvas.bbox("all")) is where i loose everything i delete this line and it all shows back up but then i still cant scroll.and my new entries are hidden. – Brandon Mar 10 '17 at 03:35
  • @Brandon: I've updated my answer with an example. Run the example and click the "add" button a few times and you should see the scrollbar activate when there are more entries than will fit. – Bryan Oakley Mar 10 '17 at 03:58
  • i adjusted you code just a little added 2 entry fields to the add(self) switched to grid and did a count for row. packed button to the right and will be adding some labels to the bottom . again thank you for your help im just trying to get a better understanding of this i like doing it. and i also set to where it would only start with one row. – Brandon Mar 10 '17 at 16:15
  • @BryanOakley Hi Bryan, your script helped me a lot. Thank you very much for that. I now have only one question on how I can activate the scroll bar right after booting the program? When I populate a long list of entry, I expect that the scrollbar is usable right away. I tried to change the height of the Canvas widget to 20 to see if the scrollbar is activated after add 3 blank entries, however, it was not. Hope that you can help me on this issue. Thank Bryan – Pham Cong Minh Jun 19 '19 at 10:22
  • @PhamCongMinh: any time you put something in the canvas you have to reset the `scrollregion`. – Bryan Oakley Jun 19 '19 at 13:34
  • @BryanOakley : I used self.canvas.configure(scrollregion=self.canvas.bbox("all")) but it did not work. I expected that I can see the scrollbar is active (not being greyed out) right after running the script. My temporary solution now is that I have to add a random entry, then I can see the scrollbar turned from inactive to active – Pham Cong Minh Jun 19 '19 at 14:21
  • @BryanOakley since I consider "adding something" as a solution to activate the scrollbar, I tried to add self.canvas.configure(scrollregion=self.canvas.bbox("all")) under three lines add(), or even tried to invoke the button (self.add_button.invoke()) but both ways did not work out. Hope that you understand my problem. – Pham Cong Minh Jun 19 '19 at 14:38
  • @BryanOakley hi Bryan, I have solved the problem, I tried solution here [here](https://www.reddit.com/r/learnpython/comments/8ohyvo/tkinter_scrollbar_in_python_36/) . So we let the program reset the scrollregion itself by using `frame = tk.Frame(self.canvas) self.canvas.create_window(4, 4, window=frame, anchor='nw') # Canvas equivalent of pack() frame.bind("", self._on_frame_configure)` with `def _on_frame_configure(self, event=None): self.canvas.configure(scrollregion=self.canvas.bbox("all"))` – Pham Cong Minh Jun 19 '19 at 15:32