0

Please allow me to explain the problem I am facing. I am a undergraduate student who started learning Python a couple of month ago. So, I am new and please bear with me if the experts found them rather naive.

The intention was very simple. I want to place 5 menu buttons in parallel (say in one row, well, this is not the pressing issue though) in a tkinter parent frame. What I did was to introduce 5 sub-frames and place the menu button on them one by one. The idea to use sub-frame was to make space for centering and better layout. Using the most straight-forward fashion, I did it one by one: Define a sub-frame and place a menu button. It all worked well.

Now I am trying to avoid the repeated codes and to lay out the menu buttons and sub-frames using for loops, since the sub-frames and buttons are technically identical except the gird locations and labels are different. I came up with the following code.

Python compiler didn't report any errors. But, only the last button ("Other") was displayed while other buttons are missing. I am having difficulty sorting out what exactly went wrong.

indBtnFrame = [tkinter.Frame(self.parent)] * 5   
    for i in range(len(indBtnFrame)):
        column_index = (i+1)*2
        indBtnFrame[i].grid(column=column_index,
                        row=0,
                        columnspan=2,
                        rowspan=1,
                        sticky="WENS")
        for r in range(1): # 1 row in total.
            indBtnFrame[i].rowconfigure(r, weight=1)
        for c in range(1): # 1 column in total.
            indBtnFrame[i].columnconfigure(c, weight=1)
        # To fix the grid size. 
        indBtnFrame[i].grid_propagate(False)

    indBtnLabel = ["Street",
                   "City",
                   "Postcode",
                   "Province",
                   "Other"]

    indBtn = []
    for i in range(len(indBtnLabel)):
        button_label = tkinter.StringVar()
        button_label.set(str(indBtnLabel[i]))
        temp_widget = tkinter.Menubutton(indBtnFrame[i],
                                     textvariable=button_label,
                                     relief=tkinter.GROOVE)
        indBtn.append(temp_widget)

    for i in range(len(indBtn)):
        indBtn[i].grid(column=0, row=0,
                       columnspan=1, rowspan=1,
                       sticky="WENS")
        indBtn[i].menu = tkinter.Menu(indBtn[i], tearoff=0)
        indBtn[i]["menu"] = indBtn[i].menu
X...
  • 173
  • 1
  • 2
  • 12
  • 1
    I can't test your code because it's not a [mcve]. However, `indBtnFrame = [tkinter.Frame(self.parent)] * 5` creates a list containing 5 references to a single Frame. Try `indBtnFrame = [tkinter.Frame(self.parent) for i in range(5)]` – PM 2Ring Nov 28 '16 at 10:26
  • Well, magic! Your comment works like a charm. Is it possible to give me a bit more hints on this specific Pythonic style of [... for i in range] statement. This shall help me learn faster. Many thanks. Further I will later do my best to follow the principle of "Minimal, Complete and Verifiable" when posting codes. – X... Nov 28 '16 at 10:30
  • 1
    It's called a [List Comprehension](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions). Regarding the cause of your problem, you should take a look at [Python list of lists, changes reflected across sublists unexpectedly](http://stackoverflow.com/questions/240178/python-list-of-lists-changes-reflected-across-sublists-unexpectedly). – PM 2Ring Nov 28 '16 at 10:36
  • Excellent tutorial. My feeling as a beginner is that flexibility in Python comes with rather in-depth knowledge. – X... Nov 28 '16 at 10:44
  • The official Python tutorial is excellent, but it is aimed at people who already know how to program, it's not for raw beginners. You may also be interested in the other tutorials mentioned in the SO Python wiki: [What tutorial should I read?](http://sopython.com/wiki/What_tutorial_should_I_read%3F) – PM 2Ring Nov 28 '16 at 11:00

0 Answers0