Loop through array stops increasing index (Orig: Message widget text randomly not refreshing)
<p>I have an automatically generated report in txt file that gets update every 5 or so seconds and looks like this:</p>

<pre><code>Report Data Start Time:;00:00 25/08/2016Report;Va1;Val2;Val3;Val4;Val5;Val6;Val7
X;6;4;0;0;32;3;0.8125
Y;2;1;0;0;0;0;0
Z;5;1;0;0;0;0;0
[empty last line]
</code></pre>

<p>In tkinter, I created a GUI that would read the data and display it in real time in a sort of a table. The widgets are generated procedurally and stored in a collection under a predefined name, later they are called based on this name and their content modified.
However when the data is read and put into the widgets some cells, seemingly at random, are empty. When I say randomly, it is actually pretty consistent (col2, row2 and col5 to 7, row2 to 3) BUT when I change the report file somehow, the new value may or may not appear (this really is very random).</p>

<p>(Significantly) shortened version of the code with the same problem here:</p>

<pre><code>import tkinter as tk

class MainApplication(tk.Frame):

    global SkillWidgets
    SkillWidgets = {}


    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)       
        self.parent = parent
        self.create_stuff()
        self.refresh()


    def create_stuff(self):        
        screen_width = tkGUI.winfo_screenwidth()
        screen_height = tkGUI.winfo_screenheight()
        iSW = screen_width/1000
        iSH = screen_height/1000

        tkFrSkills = tk.Frame(tkGUI)
        tkFrSkills.place(x=(100*iSW)+20, y=20+(50*iSH), bordermode=tk.INSIDE, height=screen_height/2-(100+50*iSH), width=screen_width)

        for iRow in range(1,4):
            for iCol in range(1,8):
                tkMsg = tk.Message(tkFrSkills, text="", font=("Arial", 36), relief = tk.GROOVE, bd = 2, width = 100)
                tkMsg.place (x=((iCol-1)*100*iSW), y=(75*iRow*iSH)-(75*iSH), bordermode=tk.INSIDE, width = 100*iSW, height = 75*iSH)
                SkillWidgets[(iRow,iCol)] = tkMsg



    def refresh(self):
        fSkills = open("report.txt")
        sSkContents = fSkills.read()
        fSkills.close()

        SkLines = sSkContents.split("\n")
        del(SkLines[len(SkLines)-1])

        iSkRow = 0
        for sSkLine in SkLines:  
            if "X" in sSkLine:
                iSkRow = 1
            if "Y" in sSkLine:
                iSkRow = 2
            if "Z" in sSkLine:
                iSkRow = 3       

            if iSkRow &gt; 0:
                SkItems = sSkLine.split(";")
                SkItems[1], SkItems[2], SkItems[3], SkItems[4] = SkItems[2], SkItems[4], SkItems[1], SkItems[3]
                SkItems[2] = str(int(SkItems[3])-int(SkItems[1]))              
                del(SkItems[0])                                      
             ***print(SkLines[iSkRow])

                for sSkItem in SkItems:

                    iSkCol = SkItems.index(sSkItem)+1
                ****print("Row=",iSkRow,"Col=",iSkCol,"sSkItem=",sSkItem)
               *****print("Row=",iSkRow,"Col=",iSkCol,"widget text =", SkillWidgets[(iSkRow,iSkCol)].cget("text"))
                    SkillWidgets[(iSkRow,iSkCol)].config(text = sSkItem)
                ****print("Row=",iSkRow,"Col=",iSkCol,"sSkItem=",sSkItem)
               *****print("Row=",iSkRow,"Col=",iSkCol,"widget text =", SkillWidgets[(iSkRow,iSkCol)].cget("text"))
                    print("----------")


        self.after(1000,self.refresh)

if __name__ == "__main__":
    tkGUI = tk.Tk()
    tkGUI.attributes("-fullscreen", True)
    MainApplication(tkGUI).pack(side="top", fill="both", expand=True)
    tkGUI.mainloop()
</code></pre>

<p><strong>EDIT:</strong>
I forgot to mention that I tried to print the values I am inputting (code adjusted - I highlighted the places with a number of asterisks</p>

<p>*** this print gives correctly the relevant lines, however for some reason it runs through the cycle twice, giving</p>

<pre><code>X;6;4;0;0;32;3;0.8125
Y;2;1;0;0;0;0;0
Z;5;1;0;0;0;0;0
</code></pre>

<p>**** this print correctly gives out the value I want to input to the widget</p>

<p>***** this print is getting to the root of the issue:
a) if inputted value is to be "1", the loop does not go through 2:2 at all but gives only 2:1 twice and the first print shows the value of the widget as "1" (because I guess it went through 2:1 just before)
b) if the inputted value is to be "2" and more, it works as intended - loop goes through 2:1, 2:2, 2:3 as expected</p>

<p>(if value to be imputted = 1)</p>

<pre><code>Row= 2 Col= 1 sSkItem= 1
Row= 2 Col= 1 widget text = 
Row= 2 Col= 1 sSkItem= 1
Row= 2 Col= 1 widget text = 1
----------
Row= 2 Col= 1 sSkItem= 1
Row= 2 Col= 1 widget text = 1
Row= 2 Col= 1 sSkItem= 1
Row= 2 Col= 1 widget text = 1
----------
</code></pre>

<p>if value to be imputted > 1</p>

<pre><code>Row= 2 Col= 1 sSkItem= 1
Row= 2 Col= 1 widget text = 
Row= 2 Col= 1 sSkItem= 1
Row= 2 Col= 1 widget text = 1
----------
Row= 2 Col= 2 sSkItem= 3
Row= 2 Col= 2 widget text = 
Row= 2 Col= 2 sSkItem= 3
Row= 2 Col= 2 widget text = 3
----------
</code></pre>

<p>c) in neither case does the loop go for rows 2&amp;3 through cols 5to7</p>

<p><strong>EDIT2:</strong>
Intriguing... now I added some more prints (nothing else though) and the value inputted into 2:2 being "1" does not seem to be a problem now (2:3 to 3:7 are still out of the loop though).</p>

<p><strong>EDIT3:</strong>
I seem to be getting to the cause... At this point, for row2 and row3, the, it simply stops increasing the index with the 5th iteration (item with index 4 is not loaded, instead item with index 3 is loaded again)</p>

<pre><code>            for sSkItem in SkItems:
                print(SkItems)
                print("item3: ", SkItems[3])
                print("item4: ", SkItems[4])
                print("item5: ", SkItems[5])
                print("item6: ", SkItems[6])
                iSkCol = SkItems.index(sSkItem)
                print("index", iSkCol)
                print("Row=",iSkRow,"Col=",iSkCol,"sSkItem=",sSkItem)
                print("Row=",iSkRow,"Col=",iSkCol,"widget text =", SkillWidgets[(iSkRow,iSkCol)].cget("text"))
                SkillWidgets[(iSkRow,(iSkCol))].config(text = sSkItem)
                print("Row=",iSkRow,"Col=",iSkCol,"sSkItem=",sSkItem)
                print("Row=",iSkRow,"Col=",iSkCol,"widget text =", SkillWidgets[(iSkRow,iSkCol)].cget("text"))
</code></pre>

<p>Resulting print-out reads as follows:</p>

<pre><code>['1', 1, '2', '0', '0', '0', '0']
item3:  0
item4:  0
item5:  0
item6:  0
index 1
Row= 1 Col= 1 sSkItem= 1
Row= 1 Col= 1 widget text = 
Row= 1 Col= 1 sSkItem= 1
Row= 1 Col= 1 widget text = 1
---
['1', 1, '2', '0', '0', '0', '0']
item3:  0
item4:  0
item5:  0
item6:  0
index 2
Row= 1 Col= 2 sSkItem= 2
Row= 1 Col= 2 widget text = 
Row= 1 Col= 2 sSkItem= 2
Row= 1 Col= 2 widget text = 2
---
['1', 1, '2', '0', '0', '0', '0']
item3:  0
item4:  0
item5:  0
item6:  0
index 3
Row= 1 Col= 3 sSkItem= 0
Row= 1 Col= 3 widget text = 
Row= 1 Col= 3 sSkItem= 0
Row= 1 Col= 3 widget text = 0
---
['1', 1, '2', '0', '0', '0', '0']
item3:  0
item4:  0
item5:  0
item6:  0
index 3
Row= 1 Col= 3 sSkItem= 0
Row= 1 Col= 3 widget text = 0
Row= 1 Col= 3 sSkItem= 0
Row= 1 Col= 3 widget text = 0
---
</code></pre>

<p>I believe your problem lies in the incorrect use of the <code>for</code> loop, specifically</p>

<pre><code>for sSkItem in SkItems:
    iSkCol = SkItems.index(sSkItem)+1
</code></pre>

<p>Will give you index of <em>first occurence</em> of <code>sSkItem</code> in <code>SkItems</code> and NOT the index of current item from your loop as you no doubt expect/want. This will break if there are any duplicate items (as there are and as you observe).</p>

<p>To fix that you can use your own counter to track the index for example:</p>

<pre><code>currentIndex = 0

for sSkItem in SkItems:
    iSkCol = currentIndex
    currentIndex += 1
</code></pre>

<p>Or use normal range for loop to iterate over <em>indexes</em> rather than items.</p>

python tkinter widget refresh