Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table cell value does not update #47

Open
vnahmias opened this issue Mar 13, 2019 · 7 comments
Open

Table cell value does not update #47

vnahmias opened this issue Mar 13, 2019 · 7 comments

Comments

@vnahmias
Copy link

Hello i am facing a really weird issue,

I have a file "editorWindow2.py" which when it's called creates a tk frame containing several tableCanvas :
image

Everything works like a charm i can click on cells and change their values to finally export the whole thing into an xml file.

However sometimes i call the same file from an other entry point in the program but this time the cells are no more editable and i have no clues why. I have checked that i call the window with exactly the same type of objects and data as i do in the case where it works.

Here is the code :

class editionWindowModel2():

    def __init__(self):
        pass

class editionWindowView2():

    def __init__(self,master,count):
        self.frames=[]
        for i in range(count):
            self.frames.append(tk.Frame(master))
            self.frames[i].pack(fill=tk.BOTH, expand=True)



class editionWindowController2():

    def __init__(self,data,count):

        self.root = tk.Tk()
        self.root.geometry("1920x1200")

        self.canvas=tk.Canvas(self.root)
        self.container=tk.Frame(self.canvas)
        self.model=editionWindowModel2()
        self.view=editionWindowView2(self.container,count)

        self.vsb = tk.Scrollbar(self.root, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)

        self.vsb.pack(side="right", fill="y")
        self.canvas.pack(side="left", fill=tk.BOTH, expand=True)
        self.canvas.create_window(4,4,window=self.container, anchor="nw", tags="self.container")

        self.container.bind("<Configure>", self.onFrameConfigure)



        self.data=data
        tables=[]#This variable will regroup as many table as the number of metric present in the orginal file
        y=0
        for metric in self.data :
            x=0
            tables.append(TableCanvas(self.view.frames[y],editable=True,width=1700,cellwidth=200,rows=metric.rows,cols=5,rowselectedcolor='#B0E0E6',colselectedcolor='#B0E0E6'))
            colname=tables[y].model.getColumnName(4)
            self.colorCol(tables[y],"#98FB98")
            tables[y].model.columnwidths[colname]=1100
            tables[y].show()
            tables[y].model.setValueAt("Metric ID :",x,0)
            #rest of the table is filled like the line above.

I precise that i am beginner with tkinter so please don't be too hard on me ahah

Let me explain more clearly : my program has two ways to be used, First user can chose to edit an xml file so he can import a file in order to edit it.

class firstWindowView():

    def __init__(self,master):
        self.frame = tk.Frame(master).grid(row=0,column=0,sticky="NSEW")


class firstWindowController():

    def __init__(self):

        self.root = tk.Tk()
        self.model=firstWindowModel()
        self.view=firstWindowView(self.root)

        L1 = tk.Label(self.root, text = "Chose an action :").grid(row=0,column=1)

        importButton=tk.Button(self.root,text="Import from XML",width=20,command=self.importXml).grid(row=0,column=2)
        exportButton=tk.Button(self.root,text="Create your own",width=20,command=self.exportToXml).grid(row=1,column=2)

    def run(self):
        self.root.title("Raspberry Pi Data Sender")
        self.root.mainloop()


    def importXml(self):
        self.root.destroy()
        browser=XmlBrowserController()
        browser.run()



    def exportToXml(self):
        self.root.destroy()
        metricsCreator=metricsController()
        metricsCreator.run()

in case where he choses "import", next window called is this one :

class XmlBrowserView():

    def __init__(self,master):
        self.frame = tk.Frame(master)


class XmlBrowserController():

    def __init__(self):

        self.root = tk.Tk()
        self.model=XmlBrowserModel()
        self.view=XmlBrowserView(self.root)
        self.fileName=tk.StringVar()
        self.fileName =  fd.askopenfilename(initialdir = "../",title = "Select file")

        L1 = tk.Label(self.root, text = "XML file Path : "+self.fileName).grid(row=0,column=0)
        editButton=tk.Button(self.root,text="Edit",width=10,command=self.open).grid(row=0,column=1)
        cancelButton=tk.Button(self.root,text="Cancel",width=10,command=self.quit).grid(row=1,column=1)

    def run(self):
        self.root.title("Load an XML file")
        self.root.mainloop()


    def open(self):

        self.model.fileName=self.fileName
        serializer=Serializer()
        self.model.root=serializer.importFromFile(self.model.fileName)
        display=displayController(self.model.root)
        self.root.destroy()
        display.run()

and finally

class displayView():

    def __init__(self,master):
        self.frame = tk.Frame(master).grid(row=0,column=0,sticky="NSEW")

class displayController():

    def __init__(self,xmlElement):

        self.root = tk.Tk()
        self.root.grid_rowconfigure(0, weight=1)
        self.root.grid_columnconfigure(0, weight=1)
        self.model=displayModel(xmlElement)
        self.tree=xmlElement
        self.view=displayView(self.root)
        self.fileName=tk.StringVar()
        self.count=0

        tree=self.prettify(xmlElement)
        L1 = tk.Label(self.root,justify="left",anchor="w",text = tree).grid(row=0,column=0,sticky="NSEW")

        saveButton2=tk.Button(self.root,text="Edit",width=10,command=self.save2).grid(row=self.count+2,column=0)
        cancelButton=tk.Button(self.root,text="Cancel",width=10,command=self.quit).grid(row=self.count+1,column=0)
    def save2(self):
        root=self.model.xmlElement
        metricsTable=[]
        count=1
        testCounter=0
        for metric in root.findall("{http://standards.iso.org/iso-iec/19086/-2/ed-1/en}Metric"):
            testCounter+=1
            count+=1
            params=[]
            rules=[]
            metricRefs=[]
            expressions=[]
            m=Metric(metric.get('id'),metric.get('source'),metric.get('scale'),metric.get('description'),metric.get('note'),metric.get('category'))
            for param in metric.findall('{http://standards.iso.org/iso-iec/19086/-2/ed-1/en}Parameter'):
                p=Parameter(param.get('id'),param.get('parameterStatement'),param.get('unit'),param.get('description'),param.get('note'))
                params.append(p)
            for expression in metric.findall('{http://standards.iso.org/iso-iec/19086/-2/ed-1/en}Expression'):
                e=Expression(expression.get('id'),expression.get('expressionStatement'),expression.get('expressionLanguage'),expression.get('description'),expression.get('note'),expression.get('unit'))
                expressions.append(e)
            for rule in metric.findall('{http://standards.iso.org/iso-iec/19086/-2/ed-1/en}Rule'):
                r=Rule(rule.get('id'),rule.get('ruleStatement'),rule.get('ruleLanguage'),rule.get('description'),rule.get('note'))
                rules.append(r)
            for ref in metric.findall('{http://standards.iso.org/iso-iec/19086/-2/ed-1/en}UnderlyingMetricRef'):
                reference=UnderlyingMetricRef(ref.get('refid'))
                metricRefs.append(reference)

            m.parameters=params
            m.rules=rules
            m.underlyingMetrics=metricRefs
            m.expression=expressions
            m.rows=self.metricRowsCounter(metric,m)
            metricsTable.append(m)

        #print(type(metricsTable))
        #print(metricsTable)
        self.root.destroy()
        editor=editionWindowController2(metricsTable,count)
        editor.run()

and the last window called is the one i first showed you with the tkintertable.

the other use case changes only in the first windows :

class metricsView():

    def __init__(self,master):
        self.frame = tk.Frame(master)


class metricsController():

    def __init__(self):

        self.root = tk.Tk()
        self.model=metricsModel()
        self.view=metricsView(self.root)

        self.metricList=[]

        newMetricButton=tk.Button(self.root,text="Add a new metric",width=20,command= lambda : self.newMetric(self.metricList)).grid(row=0,column=0)

        printButton=tk.Button(self.root,text="Print your file",width=20,command= lambda : self.toString(self.metricList)).grid(row=0,column=1)

        saveButton=tk.Button(self.root,text="Save",width=20,command=lambda:self.save(self.metricList)).grid(row=0,column=2)

        cancelButton=tk.Button(self.root,text="Quit",width=20,command=self.cancel).grid(row=0,column=3)

    def run(self):
        self.root.title("Metrics Creator")
        self.root.mainloop()

    def toString(self,metrics):
        xmlTree=self.treeBuilder(metrics)
        print(type(xmlTree))
        display=displayController(xmlTree)
        display.run()

and at this point the display is called with an object of the same type as it is in the first case.

@vnahmias
Copy link
Author

Hi @dmnfarrell do you have any news for this bug ?

@dmnfarrell
Copy link
Owner

Did you say you can interact with the table. There is code in tkintertable/Testing.py that tests this very thing and it seems to work. You could take a look at it. It might be a key binding problem but you have given no error messages. It sounds like more to do with your own app.

@vnahmias
Copy link
Author

The thing is that i checked every common mistakes i may have made, i checked the type of what comes out of the display controller and what comes it my editorController in both cases and they are all of the same type. I checked binding of every function and their buttons. In the case where i can't modify the table, i simply can't do anything else.

@dmnfarrell
Copy link
Owner

It would be best if you made a minimal example of 2 tables that works and then add more features into it bit by bit. If a minimal example works then something specific to your app is causing it. Your code is quite long and I can't go through it all in detail.

@vnahmias
Copy link
Author

vnahmias commented Mar 26, 2019

Hello @dmnfarrell i tried to print every variables in both cases and they have same types each time i don't see what i am missing man. I also have duplicated files for both use cases to try to see a difference between both behavior, i try to modify the second file to get something working but it doesn't here is the code where i can't edit cells :

class editionWindowView2():

    def __init__(self,master,count):
        self.frames=[]
        for i in range(count):
            self.frames.append(tk.Frame(master))
            self.frames[i].pack(fill=tk.BOTH, expand=True)



class editionWindowController2():

    def __init__(self,data,count):

        self.root = tk.Tk()
        self.root.geometry("1920x1200")

        self.model=editionWindowModel2()
        self.view=editionWindowView2(self.root,count)

        y=0
        self.data=data
        tables=[]#This variable will regroup as many table as the number of metric present in the orginal file
        for i in range(len(self.data)) :
            table=(TableCanvas(self.view.frames[i],editable=True,width=1700,cellwidth=200,rows=data[i].rows,cols=5,rowselectedcolor='#B0E0E6',colselectedcolor='#B0E0E6'))
            table.show()
            tables.append(table)

        for metric in self.data :
            x=0
            tables[y].model.setValueAt("Metric ID :",x,0)
            tables[y].model.setValueAt("Metric Source :",x+1,0)
            tables[y].model.setValueAt("Metric Scale :",x+2,0)

            tables[y].model.setValueAt(metric.id,x,1)
            tables[y].model.setValueAt(metric.source,x+1,2)
            tables[y].model.setValueAt(metric.scale,x+2,2)


            x+=3
            if(metric.description!=None):
                tables[y].model.setValueAt("Metric Description :",x,0)
                tables[y].model.setValueAt(metric.description,x,2)
                x+=1
            elif(metric.category!=None):
                tables[y].model.setValueAt("Metric Category :",x,0)
                tables[y].model.setValueAt(metric.category,x,2)
                x+=1
            for expression in metric.expression:
                tables[y].model.setValueAt("Expression ID :",x,0)
                tables[y].model.setValueAt("Expression Statement :",x+1,0)
                tables[y].model.setValueAt("Expression Language:",x+2,0)
                tables[y].model.setValueAt(expression.id,x,3)
                tables[y].model.setValueAt(expression.expressionStatement,x+1,4)
                tables[y].model.setValueAt(expression.expressionLanguage,x+2,4)
                x+=3
                if(expression.description!=None):
                    tables[y].model.setValueAt("Expression Description :",x,0)
                    tables[y].model.setValueAt(expression.description,x,4)
                    x+=1
                elif(expression.note!=None):
                    tables[y].model.setValueAt("Expression Note :",x,0)
                    tables[y].model.setValueAt(expression.note,x,4)
                    x+=1
                elif(expression.unit!=None):
                    tables[y].model.setValueAt("Expression Unit :",x,0)
                    tables[y].model.setValueAt(expression.unit,x,4)
                    x+=1
            try:
                for param in metric.parameters:
                    tables[y].model.setValueAt("Parameter ID :",x,0)
                    tables[y].model.setValueAt("Parameter Statement :",x+1,0)
                    tables[y].model.setValueAt("Parameter Unit :",x+2,0)
                    tables[y].model.setValueAt(param.id,x,3)
                    tables[y].model.setValueAt(param.parameterStatement,x+1,4)
                    tables[y].model.setValueAt(param.unit,x+2,4)
                    x=x+3
                    if(param.description!=None):
                        tables[y].model.setValueAt("Parameter Description :",x,0)
                        tables[y].model.setValueAt(param.description,x,4)
                        x+=1
                    elif(param.note!=None):
                        tables[y].model.setValueAt("Parameter Note :",x,0)
                        tables[y].model.setValueAt(param.note,x,4)
                        x+=1
            except :
                pass
            try:
                for rule in metric.rules:
                    tables[y].model.setValueAt("Rule ID :",x,0)
                    tables[y].model.setValueAt("Rule Statement :",x+1,0)
                    tables[y].model.setValueAt("Rule Language :",x+2,0)
                    tables[y].model.setValueAt(rule.id,x,3)
                    tables[y].model.setValueAt(rule.ruleStatement,x+1,4)
                    tables[y].model.setValueAt(rule.ruleLanguage,x+2,4)

                    x=x+3
                    if(rule.description!=None):
                        tables[y].model.setValueAt("Rule Description :",x,0)
                        tables[y].model.setValueAt(rule.description,x,4)
                        x+=1
                    elif(rule.note!=None):
                        tables[y].model.setValueAt("Rule Note :",x,0)
                        tables[y].model.setValueAt(rule.note,x,4)
                        x+=1
            except :
                pass
            try:
                for ref in metric.underlyingMetrics:
                    tables[y].model.setValueAt("UnderlyingMetricRef :",x,0)
                    tables[y].model.setValueAt(ref.refid,x,3)
                    x=x+1
            except :
                pass
            colname=tables[y].model.getColumnName(4)
            self.colorCol(tables[y],"#98FB98")
            tables[y].model.columnwidths[colname]=1100
            tables[y].show()

            y+=1



        exportButton=tk.Button(self.root,text="Export To Xml",width=15,command=lambda: self.exportToXml(tables)).pack()
        cancelButton=tk.Button(self.root,text="Quit",width=15,command=self.quit).pack()

@vnahmias
Copy link
Author

vnahmias commented Apr 8, 2019

I have finally found what causes cells not alterable, in file MetricsController function toString(), i had not wrote the line self.root.destroy() which closes previous window before dsiplaying the new one, because wanted to be able to come back to that previous window. I think there is some kind of conflict between tkintertable and tk loops or something like this. Please if you have some time take a look at it and if you find what is wrong please keep me updated i wanna know !

@dmnfarrell
Copy link
Owner

So if your change fixes the problem why do you still think tkintertable cause a conflict of some kind? there is only one tkinter thread running at once and all the widgets run in that I believe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants