Clyde
Clyde

Reputation: 143

Managing column width tkinter

I have reviewed the documentation on rowconfugre and columnconfigure, and I just do not quite understand how to get it working properly. With the following code, how can I get the 'src_entry' Entry box directly against the 'src' Checkbutton, regardless of what other widget is in column 1? Essentially, I need the size of the column to form to the width of whatever widget is in that space on the grid.

Thanks,

from tkinter import *



class Example(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent, background="white")
        self.parent = parent
        self.parent.title("TCPDUMP Creator")
        self.centerWindow()
        self.pack(fill=BOTH, expand=1)

        menubar = Menu(self.parent)
        self.parent.config(menu=menubar)
        fileMenu = Menu(menubar)
        fileMenu.add_command(label="Exit", command=self.quit)
        menubar.add_cascade(label="File", menu=fileMenu)
        self.columnconfigure(2, weight=5)

        int_lbl = Label(self, text="Interface")
        int_lbl.grid(row=1, column=0, sticky=W+E)
        self.int_entry = Entry(self, width=15)
        self.int_entry.grid(row=1, column=1)

        self.anyInt = BooleanVar()
        Checkbutton(self, text="Any", variable = self.anyInt).grid(row=1, column=2)

        int_lbl = Label(self, text="")
        int_lbl.grid(row=2, column=0, columnspan=99, sticky=W+E)

        self.notSrc = BooleanVar()
        Checkbutton(self, text = "Not--", variable = self.notSrc).grid(row=3, column=0, sticky=W+E)

        self.srcIP = BooleanVar()
        Checkbutton(self, text="Src", variable = self.srcIP).grid(row=3, column=1)

        src_entry = Entry(self, width=15)
        src_entry.grid(row=3, column=2)

        self.AndOr = StringVar()
        self.AndOr.set(None)

        Radiobutton(self, text = "And", variable = self.AndOr, value = "And").grid(row=3, column=3, pady=5, padx=2, sticky=E)
        Radiobutton(self, text = "Or", variable = self.AndOr, value = "Or").grid(row=3, column=4, pady=5, padx=10, sticky=W)

        self.notDst = BooleanVar()
        Checkbutton(self, text = "Not--", variable = self.notDst).grid(row=3, column=5, sticky=W+E)

        self.dstIP = BooleanVar()
        Checkbutton(self, text="Dst", variable = self.dstIP).grid(row=3,column=6, sticky=E, padx=0)

        dst_entry = Entry(self, width=15)
        dst_entry.grid(row=3, column=7)

        int_lbl = Label(self, text="")
        int_lbl.grid(row=4, column=0, columnspan=99, sticky=W+E)


        self.srcordst = StringVar()
        self.srcordst.set(None)

        Radiobutton(self, text = "And", variable = self.srcordst, value = "And").grid(row=4, column=1, pady=5, padx=2, sticky=E)
        Radiobutton(self, text = "Or", variable = self.srcordst, value = "Or").grid(row=4, column=2, pady=5, padx=10, sticky=W)


    def centerWindow(self):
        w = 600
        h = 300
        sw = self.parent.winfo_screenwidth()
        sh = self.parent.winfo_screenheight()
        x = (sw - w)/2
        y = (sh - h)/2.7
        self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y))




def main():
    root = Tk()
    app = Example(root)
    root.mainloop()

if __name__ == '__main__':
    main()

Upvotes: 0

Views: 5310

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 385970

The best way to do layouts is to break your UI into sections, and then layout each section independently.The reason you're having difficulty is that you're trying to force everything into a single grid, but you don't have items that naturally fit into a grid. You can make it work by using lots of invisible columns and clever use of columnspan, but there are easier ways.

In this specific case, pack and a few intermediate frames is a better solution in my opinion.

From what I see, your UI is made up of four areas:

  1. A row that has an entry for int_entry and a checkbutton
  2. A row that has several checkboxes and radiobuttons, along with an entry
  3. A row with an 'And' and 'Or' radiobutton
  4. A big blank area

The way I would do it is create four frames, one for each area:

frame1 = Frame(self, ...)
frame2 = Frame(self, ...)
frame3 = Frame(self, ...)
frame4 = Frame(self, ...)

You can then use pack to stack those frames horizontally. All of them fill their area in the horizontal direction, and the last frame takes up all of the rest of the data.

frame1.pack(side="top", fill="x")
frame2.pack(side="top", fill="x")
frame3.pack(side="top", fill="x")
frame4.pack(side="top", fill="both", expand=True)

Now, you can add widgets to each frame with little concern for how they affect the rest of the display.

For example, the "Interface" label, the entry and the "Any" checkbutton can go in frame1. pack makes for a sensible choice since you want these aligned to the left of the area (I assume...).

int_lbl = Label(frame1, text="Interface")
self.int_entry = Entry(frame1, width=15)
any_cb = Checkbutton(frame1, text="Any", ...)

int_lbl.pack(side="left")
self.int_entry.pack(side="left")
any_cb.pack(side="left")

Do the same for the other frames. Within each frame you can choose to use pack or grid, as long as you consistently use pack or grid for every widget within the frame. pack is a very natural choice when you want all of your widgets aligned in one direction in the parent widget.

Upvotes: 4

Related Questions