Python Forum
Button in one class, methods in another one
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Button in one class, methods in another one
#1
Hi, I spent 2 days trying to solve this little exercice, creating a face with button open or closing his mouth.
I do have 2 questions about this code :

  1. I cannot delete the round face to create a closed mouth, line 40 and line 43, python says : AttributeError: 'Button_Can' object has no attribute 'opened_mouth'. How could I make this work ?
  2. How could I avoid to repeat the circle function on line 17 in the Button_Can Class ?

    Thanks for any help that could enlighten my poor coding skills

    from tkinter import *
    
    class Button_Can(Frame):
    	def __init__(self):
    		Frame.__init__(self)
    		self.larg,self.haut=200,200
    		self.can=Canvas(self.master,width=self.larg,height=self.haut,bg='ivory')
    		self.can.pack()
    		self.b1=Button(self.master,text='Open it !',command=self.openit)
    		self.b2=Button(self.master,text='Close it !',command=self.closeit)
    		self.b1.pack(side=RIGHT)
    		self.b2.pack(side=LEFT)
    	def openit(self):
    		Face.openMouth(self)
    	def closeit(self):
    		Face.closeMouth(self)
    	def circle(self,x, y, r, coul ='black'):
    		"Draw a circle center x,y radius r "
    		self.can.create_oval(x-r, y-r, x+r, y+r, outline=coul)
    
    class Face():
    	def __init__(self,can):
    		self.can=can
    		"Draw a face"
    		can.delete(ALL)
    		cc =[[100, 100, 80, 'red'],[70, 70, 15, 'blue'], 
    		[130, 70, 15, 'blue'],[70, 70, 5, 'black'],
    		[130, 70, 5, 'black'],[44, 115, 20, 'red'], 
    		[156, 115, 20, 'red'],[100, 95, 15, 'purple']] 
    		i =0
    		while i < len(cc):
    			el = cc[i] 
    			self.circle(el[0], el[1], el[2], el[3])
    			i += 1 
    
    	def circle(self,x, y, r, coul ='black'):
    		"Draw a circle center x,y radius r "
    		self.can.create_oval(x-r, y-r, x+r, y+r, outline=coul)
    	def openMouth(self):
    		self.can.delete(self.closed_mouth)
    		self.opened_mouth=self.circle(100, 145, 30, 'purple')
    	def closeMouth(self):
    		self.can.delete(self.opened_mouth)
    		self.closed_mouth=self.can.create_line(80,145,120,145,fill='purple')
    
    A=Button_Can()
    B=Face(A.can)
Reply
#2
That is not the best way to interact classes with each other. The best solution would be to make the Face object in the canvas class like this:

from tkinter import *
 
class Button_Can(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.larg,self.haut=200,200
        self.can=Canvas(self.master,width=self.larg,height=self.haut,bg='ivory')
        self.can.pack()
        self.face = Face(self.can)
        self.b1=Button(self.master,text='Open it !',command=self.face.openMouth)
        self.b2=Button(self.master,text='Close it !',command=self.face.closeMouth)
        self.b1.pack(side=RIGHT)
        self.b2.pack(side=LEFT)
 
class Face():
    def __init__(self, can):
        self.can = can
        self.setup()
        
    def setup(self):
        self.can.delete(ALL)
        cc =[[100, 100, 80, 'red'],[70, 70, 15, 'blue'], 
        [130, 70, 15, 'blue'],[70, 70, 5, 'black'],
        [130, 70, 5, 'black'],[44, 115, 20, 'red'], 
        [156, 115, 20, 'red'],[100, 95, 15, 'purple']] 
        i =0
        while i < len(cc):
            el = cc[i] 
            self.circle(el[0], el[1], el[2], el[3])
            i += 1 
            
        self.opened_mouth = None
        self.closed_mouth = None
 
    def circle(self,x, y, r, coul ='black'):
        "Draw a circle center x,y radius r "
        self.can.create_oval(x-r, y-r, x+r, y+r, outline=coul)
    def openMouth(self):
        #self.can.delete(self.closed_mouth)
        self.setup()
        self.opened_mouth=self.circle(100, 145, 30, 'purple')
    def closeMouth(self):
        #self.can.delete(self.opened_mouth)
        self.setup()
        self.closed_mouth=self.can.create_line(80,145,120,145,fill='purple')

root = Tk()
A=Button_Can()
B=Face(A.can)
root.mainloop()
NOTE: I am more use to pygame's redraw everything style... every frame, so i am not sure if tkinter has a method to just delete a portion of the canvas or not. So i just redrew everything.
Recommended Tutorials:
Reply
#3
Thanks for your very fast reply metulburr,
I am still trying to erase just the mouth. But I don't understand why my erase methode, using what you said above, doesn't work :
When I click the erase button, nothing happens, no error message either.
from tkinter import *

class C1(Frame):
	def __init__(self):
		Frame.__init__(self)
		self.larg,self.haut=100,100
		self.can=Canvas(self.master,width=self.larg,height=self.haut,bg='ivory')
		self.can.pack()
		self.c2=C2(self.can)
		self.b1=Button(self.master,text='Erase',command=self.c2.erase)
		self.b1.pack()
		
	

class C2():
	def __init__(self,can):
		self.can=can	
		self.redline=self.can.create_line(10, 10, 90, 90, fill ='red',width=5)

	def erase(self):
		self.can.delete(self.redline)


root = Tk()
A=C1()
canevas =A.can
B=C2(canevas)
root.mainloop()
Reply
#4
You are creaing two objects with C2 class. One inside C1 on line 9, and another at line 27. Comment out the line 27 one. What is happening is you are creating two lines overlapping each other, where one only has access to delete it.
from tkinter import *
 
class C1(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.larg,self.haut=100,100
        self.can=Canvas(self.master,width=self.larg,height=self.haut,bg='ivory')
        self.can.pack()
        self.c2=C2(self.can)
        self.b1=Button(self.master,text='Erase',command=self.c2.erase)
        self.b1.pack()
         
     
 
class C2():
    def __init__(self,can):
        self.can=can    
        self.redline=self.can.create_line(10, 10, 90, 90, fill ='red',width=5)
 
    def erase(self):
        self.can.delete(self.redline)
 
 
root = Tk()
A=C1()
canevas =A.can
#B=C2(canevas)
root.mainloop()
Recommended Tutorials:
Reply
#5
The easiest way to control or work with objects in tkinter is to use tags.
I don't see the need for 2 classes here
from tkinter import Tk,Frame,Canvas,Button,RIGHT,LEFT
  
class Button_Can(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.pack(expand='yes',fill='both')
        self.larg,self.haut=200,200
        self.can=Canvas(self.master,width=self.larg,height=self.haut,bg='ivory')
        self.can.pack()        
        self.b1=Button(self.master,text='Open it !',command=self.openMouth)
        self.b2=Button(self.master,text='Close it !',command=self.closeMouth)
        self.b3=Button(self.master,text='delete it!',command=self.delete_mouth)
        self.b1.pack(side=RIGHT)
        self.b2.pack(side=LEFT)
        self.b3.pack(side='bottom')
        self.setup()
    def setup(self):
        
        cc =[[100, 100, 80, 'red'],[70, 70, 15, 'blue'], 
        [130, 70, 15, 'blue'],[70, 70, 5, 'black'],
        [130, 70, 5, 'black'],[44, 115, 20, 'red'], 
        [156, 115, 20, 'red'],[100, 95, 15, 'purple']] 
        i =0
        while i < len(cc):
            el = cc[i] 
            self.circle(el[0], el[1], el[2], el[3])
            i += 1 
        
  
    def circle(self,x, y, r, coul ='black'):
        "Draw a circle center x,y radius r "
        self.can.create_oval(x-r, y-r, x+r, y+r, outline=coul)
    def openMouth(self):
        self.can.delete('bouche')        
        self.opened_mouth= self.can.create_oval(70, 115, 130, 175,
                                                outline='purple',tag='bouche')
    def closeMouth(self):
        self.can.delete('bouche')        
        self.closed_mouth=self.can.create_line(80,145,120,145,
                                               fill='purple', tag='bouche')
    def delete_mouth(self):
        self.can.delete('bouche')
if __name__ == '__main__': 
    root = Tk()
    root.title('la visage')
    A=Button_Can()
    root.mainloop()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Kivy] Acces atributes from a button defined in a class inside the .kv Tomli 2 2,054 Jun-10-2021, 01:05 AM
Last Post: Tomli
  [Tkinter] Modify Class on Button Click KDog 4 3,904 May-11-2021, 08:43 PM
Last Post: KDog
  Class function does not create command button Heyjoe 2 2,227 Aug-22-2020, 08:06 PM
Last Post: Heyjoe
  [PySimpleGui] How to alter mouse click button of a standard submit button? skyerosebud 3 4,949 Jul-21-2019, 06:02 PM
Last Post: FullOfHelp
  Button click doesnt work from my second class/layout in Python imamideb 0 2,327 Feb-13-2018, 12:09 PM
Last Post: imamideb
  Overriding tkinter button methods Lubik_ 3 6,109 Sep-26-2017, 10:24 AM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020