#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2004
    Posts
    12
    Rep Power
    0

    Tkinter problem - removing a frame


    I'am programming a GUI for a instant messaging service. I found some online code on the web which i have integreated to my code. The code is also listed below(http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/188537)

    I cant figure out how to remove a frame. If I use:
    frame.destroy() it is gone... but the button to select the frame/screen is still there. I want that button removed. If you try to run the below code. Then you take for instance the screen 2 button. I want to be able to remove the screen and the button.

    Any sugestion how to solve it? I have tried to read some documentaion on frames but i just cant figure it out. And I have tryed to look at the methods available for frames dir(frame). But there is nothing that points out to be my soloution.

    I am using python 2.2

    Here is a code example:

    PHP Code:
    # file: notebook.py
    # A simple notebook-like Tkinter widget.
    # Copyright 2003, Iuri Wickert (iwickert yahoo.com)

    from Tkinter import *

    class 
    notebook:
        
        
        
    # initialization. receives the master widget
        # reference and the notebook orientation
        
    def __init__(selfmasterside=LEFT):
            
            
    self.active_fr None
            self
    .count 0
            self
    .choice IntVar(0)

            
    # allows the TOP and BOTTOM
            # radiobuttons' positioning.
            
    if side in (TOPBOTTOM):
                
    self.side LEFT
            
    else:
                
    self.side TOP

            
    # creates notebook's frames structure
            
    self.rb_fr Frame(masterborderwidth=2relief=RIDGE)

            
    #self.rb_fr.grid(row=0,col=0,rowspan=2)
            
    self.rb_fr.pack(side=sidefill=BOTH)

            
            
    self.screen_fr Frame(masterborderwidth=2relief=RIDGE)
            
    self.screen_fr.pack(fill=BOTH)
            
    #self.rb_fr.grid(row=0,col=0,rowspan=2)

        # return a master frame reference for the external frames (screens)
        
    def __call__(self):

            return 
    self.screen_fr

            
        
    # add a new frame (screen) to the (bottom/left of the) notebook
        
    def add_screen(selffrtitle):
            
            
    Radiobutton(self.rb_frtext=titleindicatoron=0, \
                
    variable=self.choicevalue=self.count, \
                
    command=lambdaself.display(fr))
            
    b.pack(fill=BOTHside=self.side)
            
    #b.grid(row=self.count,col=1)

            # ensures the first frame will be
            # the first selected/enabled
            
    if not self.active_fr:
                
    #fr.grid(row=self.count,col=0)
                
    fr.pack(fill=BOTHexpand=1)
                
    self.active_fr fr

            self
    .count += 1
            
            
        
    # hides the former active frame and shows 
        # another one, keeping its reference
        
    def display(selffr):
            
            
    self.active_fr.forget()
            
    fr.pack(fill=BOTHexpand=1)
            
    #fr.grid(row=0,col=1)
            
    self.active_fr fr

    ###-------------------------------------------------------
    ###-------------------------------------------------------
    # file: test.py
    # simple demonstration of the Tkinter notebook

    from Tkinter import *
    from notebook import *

    Tk()
    notebook(aLEFT)

    # uses the notebook's frame
    f1 Frame(n())
    b1 Button(f1text="Button 1")
    e1 Entry(f1)
    # pack your widgets before adding the frame 
    # to the notebook (but not the frame itself)!
    b1.grid(row=0,col=0)
    e1.grid(row=1,col=0)
    #b1.pack(fill=BOTH, expand=1)
    #e1.pack(fill=BOTH, expand=1)

    f2 Frame(n())
    b2 Button(f2text='Button 2')
    b3 Button(f2text='Beep 2'command=lambda:Tk.bell(a))
    b2.grid(row=0,col=1)
    b3.grid(row=1,col=1)

    #b2.pack(fill=BOTH, expand=1)
    #b3.pack(fill=BOTH, expand=1)

    f3 Frame(n())

    n.add_screen(f1"Screen 1")
    n.add_screen(f2"Screen 2")
    n.add_screen(f3"dummy")

    if 
    __name__ == "__main__":
            
    a.mainloop() 
  2. #2
  3. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    13
    Here is a quick hack to add a delete screen method.
    Code:
    class notebook:
        
        
        # initialization. receives the master widget
        # reference and the notebook orientation
        def __init__(self, master, side=LEFT):
            self.screens = {}
            self.active_fr = None
            self.count = 0
            self.choice = IntVar(0)
    
            # allows the TOP and BOTTOM
            # radiobuttons' positioning.
            if side in (TOP, BOTTOM):
                self.side = LEFT
            else:
                self.side = TOP
    
            # creates notebook's frames structure
            self.rb_fr = Frame(master, borderwidth=2, relief=RIDGE)
    
            #self.rb_fr.grid(row=0,col=0,rowspan=2)
            self.rb_fr.pack(side=side, fill=BOTH)
    
            
            self.screen_fr = Frame(master, borderwidth=2, relief=RIDGE)
            self.screen_fr.pack(fill=BOTH)
            #self.rb_fr.grid(row=0,col=0,rowspan=2)
    
        # return a master frame reference for the external frames (screens)
        def __call__(self):
    
            return self.screen_fr
    
            
        # add a new frame (screen) to the (bottom/left of the) notebook
        def add_screen(self, fr, title):
            
            self.screens[title] = {'button':Radiobutton(self.rb_fr, text=title, indicatoron=0,
                                            variable=self.choice, value=self.count,
                                            command=lambda: self.display(fr)),
                                   'frame':fr}
            self.screens[title]['button'].pack(fill=BOTH, side=self.side)
            if not self.active_fr:
                self.screens[title]['frame'].pack(fill=BOTH, expand=1)
                self.active_fr = self.screens[title]['frame']
                
            self.count += 1
            
        def del_screen(self,title):
            #delete screen indexed by title
            self.screens[title]['button'].destroy()
            self.screens[title]['frame'].destroy()
            del self.screens[title]
            
        # hides the former active frame and shows
        # another one, keeping its reference
        def display(self, fr):
            
            self.active_fr.forget()
            fr.pack(fill=BOTH, expand=1)
            #fr.grid(row=0,col=1)
            self.active_fr = fr
    I have not added error checking or code checks for when the screen to delete is the same as displayed or if there is only one screen but you can easily add checks.

    grim
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2004
    Posts
    12
    Rep Power
    0
    Thank you very much. That solution helped alot

    I added some more hack and the active frame is deleted which suits my application better. And now it is also possible to create the same frame twice.

    Seriously, you saved my day I was a bit frustrated yesterday.

    Code:
       def del_screen(self):
            screen_list = self.screens.values()
            screen_key = self.screens.keys()
            
            for i in range(len(screen_list)):
                b = screen_list[i].values()
                # unnecessary, but in case other values are added to the self.screen[title] dictionary 
                for j in range(len(b)):
                    if b[j]==self.active_fr:
                        screen_list[i]['button'].destroy()
                        del self.screens[screen_key[i]]
                        
            self.active_fr.destroy()
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2004
    Posts
    12
    Rep Power
    0
    Hm... i begin to like your solution even more as I am thinking about it... since we now store the information about the button in a dictionary I can easily change its configuration (e.g. change the colour when something new has happend in the screen). And I want to notify the user

    But that will be saturdays work

    But then another problem (i havent tried to solve it yet though) comes up, how do I change one of the buttons color from my standard colors?

    something like this:

    self.screen[title]['button'] = 'new config'

    but how do i make it appear? do I use just update? Or delete and add the button again? hm... now I see that Radiobutton has a flash function... can try that one but I want it to flash until the user hits the button... it prob. does. I'll try on saturday

    Thanks anyway
  8. #5
  9. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    13
    Yep the dictionary is great for keeping stuff grouped and accessible.

    To change it's colour you would do:
    self.screens[title]['button'].configure(bg='red')
    and it happens immediately.

    By the way have you checked out Python Mega Widgets PMW ?

    grimey
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2004
    Posts
    12
    Rep Power
    0
    No... not before now atleast

    I am pritty satisfied wiht how everything looks for now... so I rather concentrate on putting everything together smoothely. But the next time I am going to use Tkinter I will take a closer look at that module.

    Thanks again for the last tip

IMN logo majestic logo threadwatch logo seochat tools logo