1

Though I think that the solution might be similar to this one: tkinter, display a value from subwindow in mainwindow , I still decided to ask this question since I have trouble to figure it out on my own.

I have the list "fields" with which I am creating any given number of rows, with two labes inside of them. After opening a subwindow, I want to be able to manipulate that list (in my example simply just append at the moment) and after clicking on a button (here "ADD"), I want the mainwindow to update, so that it shows the rows of the manipulated list. It works fine for the most part but I dont what is the best way to update the mainwindow in this example.

The only solution I was able to come up with, is to destroy the mainwindow and recreate it but I have the feeling that this might not be the best solution. Is there a better one?

import tkinter as tk

a=0
fields=[("a",1),("c",2),("e",3)]

class clsApp(object):

    def __init__(self):
        self.root=tk.Tk()
        self.root.title("MainWindow")
        ##Labels##
        self.rootLabel=tk.Label(self.root, text="WindowAppExperiment", padx=100)
        self.aLabel=tk.Label(self.root, text=a, padx=100)
        ##Buttons##
        self.BtExit=tk.Button(self.root, text="Quit", fg="red", command=self.root.quit)
        ###self.BtNewWindow=tk.Button(self.root, text ="Edit", command=lambda:self.clsNewWindow(self.root, self.aLabel).run())
        self.BtNewField=tk.Button(self.root, text ="New Field", padx=30, command=lambda:self.clsNewFields(self.root).run())

    def grid (self):
        self.rootLabel.pack()
        self.aLabel.pack()
        self.fckPackFields()
        self.BtNewField.pack()
        self.BtExit.pack(side="left")
        ###self.BtNewWindow.pack(side="right")

    def fckPackFields(self):
        if fields:
            for field in fields:
                ##create labels##
                row=tk.Frame(self.root)
                nameLabel=tk.Label(row, text =field[0], width=20, anchor="w")
                valueLabel=tk.Label(row, text =field[1], width=5)
                ##pack labels##
                row.pack(side="top", fill="x", padx=5, pady=5)
                nameLabel.pack(side="left")
                valueLabel.pack(side="right", expand=True, fill="x")


    def run(self):
        self.grid()
        self.root.mainloop()
        self.root.destroy()

    class clsNewFields(object):

        def __init__(self, Parent):
            self.parent=Parent
            ##Window##
            self.top=tk.Toplevel()
            self.top.title("Add Fields")
            ##Labels##
            self.enterNameLabel=tk.Label(self.top, text ="Enter fieldname", padx=10)
            self.enterValueLabel=tk.Label(self.top, text ="Enter value", padx=10)
            ##Entryfields##
            self.EntryName=tk.Entry(self.top)
            self.EntryValue=tk.Entry(self.top)
            ##Buttons##
            self.BtADD=tk.Button(self.top, text ="ADD", command=lambda:self.fckAddField(self.EntryName, self.EntryValue))
            self.BtClose=tk.Button(self.top, text ="Close", command=self.top. quit)

        def grid(self):
            self.enterNameLabel.pack()
            self.enterValueLabel.pack()
            self.EntryName.pack()
            self.EntryValue.pack()
            self.BtADD.pack()
            self.BtClose.pack()

        def fckAddField(self, Name, Value):
            self.name=Name.get()
            self.value=Value.get()
            global fields
            fields.append((self.name, self.value))
            print(fields)
            self.parent.update


        def run(self):
            self.grid()
            self.top.mainloop()
            self.top.destroy()



clsApp().run()
Community
  • 1
  • 1
Bubibob
  • 191
  • 1
  • 13
  • i believe you can use `main.update()` where `main` is your main window. – Joseph Farah Nov 08 '15 at 18:36
  • 1
    Unfortunately not. I have it already there in the form: self.parent.update() . The one in this example is admittedly missing the "()" but I have tried that one out as well. – Bubibob Nov 08 '15 at 19:02

1 Answers1

0

Welcome to StackOverflow.

First of all - do you really want to declare the clsNewFields inside your clsApp ? Yes, the Fields should be used inside App, but i do not see a need for using class-in-class-declaration.

Second - you are packing the Fields in def fckPackFields(self):. This is not automatically called when you update it.

You are not calling update function by using self.parent.update.

You are using global variable for fields, what does not really suit your needs. Why not having a list inside your App-class like:

    def __init__(self):
        self.__fields=[]
    def __set_fields(self, value):
        self.__fields=value
    def __get_fields(self):
        return self.__fields
    Fields = property(__get_fields, __set_fields)

    def __loadUI(self, event=None):
        # This function should be called at the end of __init__
        self.fieldFrame=tk.Frame(self.root)
        self.fieldFrame.pack(side="top")

    def fckPackFields(self):
        #First clean area
        [...]
        #Then add fields
        for field in self.__fields:
            # create the row, etc.
            # !!! but do it inside self.fieldFrame !!!
            [...]

I would prefer using grid instead of pack over here, because there I think it is easier to place a frame at a certain position, then you could just destroy self.fieldFrame and recreate it at the same position for placing the fields in it.

UPDATE:

Just checked your code again. With some simple tricks your can tweak your GUI to do what you want:

    def __init__(self):    
        self.fieldFrame=None   #this line has been added

    #completely reworked this function
    def grid(self):
        self.rootLabel.grid(row=1, column=0, columnspan=2, sticky=tk.NW+tk.SE)
        self.fckPackFields()
        self.BtNewField.grid(row=3, column=0, sticky=tk.NW+tk.SE)
        self.BtExit.grid(row=3, column=1, sticky=tk.NW+tk.SE)

    #Only one line changed / one added
    def fckPackFields(self):
        self.__cleanFields()    #added this line, function beyond
        if fields:
            for field in fields:
                ##create labels##
                row=tk.Frame(self.fieldFrame)    #add the row to the fieldFrame
                [...]
    #In here we destroy and recreate fieldFrame as needed
    def __cleanFields(self):
        if self.fieldFrame: 
                self.fieldFrame.destroy()
        ##FieldFrame##
        self.fieldFrame=tk.Frame(self.root)
        self.fieldFrame.grid(row=2, column=0, columnspan=2)

In clsNewFields:


    def fckAddField(self, Name, Value):
        [...]
        self.parent.fckPackFields() # instead of self.parent.update

EDIT:

Have a look at these two questions:

I did not mean to point out that nested classes are to be avoided in general but I do want to focus you into the thought of "is there a real necessity or benefit of it for my use-case".

Community
  • 1
  • 1
R4PH43L
  • 2,122
  • 3
  • 18
  • 30
  • HI, thanks for your answer! I did not do it exactly the way you did but you have set me on the right track. You also helped me to improve my program quite a bit. But I still have one question. If I understand you right, using class-in-class-declaration is something that I should avoid. Why is that so? – Bubibob Nov 15 '15 at 21:30
  • See my __EDIT:__ above – R4PH43L Nov 16 '15 at 05:54