简体   繁体   中英

Python 3: Tkinter frames and unexpected behaviour

I'm currently trying to create a program in tkinter that has multiple screens, however I am running into a strange problem:when I try to raise a particular screen to the front, it doesnt appear. The code I use to create the differnt screens is this:

class PokemonDecklistCreatorApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
        container.pack(side='top', fill='both', expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        for F in (MainMenu, DecksMenu, DeckEditor, CardViewerDeckEditor,DeckNotes,SearchMenu, StandardSearch, AdvancedSearch, RandomSearch, SearchResults,CardViewerSearchResults, ExtrasMenu, CardExplanationGuide, AboutProgram):
            try:
                frame = F(parent=container, controller=self)
                pageName = F.__name__
                self.frames[pageName] = frame
                frame.grid(row=0, column=0, sticky='nsew')
            except Exception as e:
                print(e)
        self.show_frame('MainMenu')

    def show_frame(self, page):
        frame = self.frames[page]
        frame.tkraise()

Then the user can use the Search Screens to specify the criteria to search for, then the doSearch function is called which should destroy the old SearchResults screen (by popping from the self.frames dict and garbage collecting).

class RandomSearch(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.parent = parent
        [some widgety code here]
        self.btnSearch = tk.Button(self, text='Gotta Search \'em All!', command=self.doSearch, font=('Lucida Grande',24))
        self.btnSearch.place(x=450, y=670, width=500, height=40)

    def doSearch(self,* args,** kwargs):
        self.controller.frames.pop('SearchResults')
        frame=SearchResults(parent=self.parent,controller=self.controller,searchTerms=[])
        pageName = SearchResults.__name__
        self.controller.frames[pageName]=frame
        self.controller.show_frame('SearchResults')


class SearchResults(tk.Frame):

    def __init__(self, parent, controller,searchTerms=None):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        [more widgety stuff]

However, the problem is that when I try running the doSearch function it creates the new object but doesn't display it. It remains on the same screen and I can still interact with it as usual, as if it didnt change scrreens at all!

I have checked the creation of new objects by putting print(id(self.frames['SearchResults'])) in the show_frame function and it shows a different ID each time I press the button).

I also know that the problem is not with the self.controller.show_frame('SearchResults') line as I have tried self.controller.show_frame('MainMenu') and this worked as expected.

What have I done wrong?

Consider this code:

def doSearch(self,* args,** kwargs):
    ...
    frame=SearchResults...)
    pageName = SearchResults.__name__
    self.controller.frames[pageName]=frame
    self.controller.show_frame('SearchResults')

You never add the frame the the controller by calling grid . You likely need to add this statement:

    frame.grid(row=0, column=0, sticky='nsew')

I can't see any reason for needing to take a frame off of the list (without destroying it!) and putting a new one in its place. You've created a memory leak. Intead, you should just add a method in SearchResults that recreates or resets the widgets inside the existing SearchResults page.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM