Understanding classes

39 views
Skip to first unread message

Daniel Leal

unread,
Jan 3, 2021, 2:02:38 PM1/3/21
to Kivy users support
Hello everyone! :)

I am trying yo learn python/kivy and since I am not very familiar to object programing, I am also taking the chance to try to understand it. In this code I am trying to make a very simple app with two buttons. One draw a rectangle and the other would be to disable the "Draw" button.
I am not capable to understand why the "Disable" button is not working. The error is: "NameError: name 'DrawButton' is not defined".
Here is the code:
What am I doing wrong? Can someone try to give me some hints?
Thank you! :)

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line
from kivy.core.window import Window
from kivy.graphics import Rectangle


class DrawArea(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def DrawRectangle(self):
        with self.canvas:
            Color(1,0,0,0.5mode="rgba")
            Rectangle(pos=(100,100), size=(100,50))


class DrawApp(App):
    def build(self):
        self.title = "TestApp"
        Window.size = (400300)
        Window.clearcolor = (102/255,102/255,102/255,1)
        parent = Widget()
        self.painter = DrawArea()
        
        DrawButton = Button(
            text = "Draw",
            font_size = 14,
            pos = (1010),
            size_hint = (NoneNone),
            size = (7030),
            color = (6464641)
        )
        DrawButton.bind(on_release = self.DrawSomething)
        
        DisableDrawButton = Button(
            text = "Disable Draw Button",
            font_size = 14,
            pos = (15010),
            size_hint = (NoneNone),
            size = (15030),
            color = (6464641)
        )
        DisableDrawButton.bind(on_press = self.call_back)
        
        parent.add_widget(self.painter)
        parent.add_widget(DrawButton)
        parent.add_widget(DisableDrawButton)
        return parent

    def DrawSomething(selfobj):
        DrawArea.DrawRectangle(self.painter)

    def call_back(selfelem):
        DrawButton.disabled = True


if __name__ == '__main__':
    DrawApp().run()

Elliot Garbus

unread,
Jan 3, 2021, 3:17:18 PM1/3/21
to kivy-...@googlegroups.com

The distinction between a class and instance is a little confusing.  You can think of the class a recipe for an object, and the instance is the object.

You created an instance of the DrawArea and saved it to self.painter, you needed to use the instance to call the draw_rectangle method.

 

Here are some resources I hope you will find helpful:

https://realpython.com/python3-object-oriented-programming/

https://pep8.org/

 

The code example below will run, and addresses your issue.

 

 

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line
from kivy.core.window import Window
from kivy.graphics import Rectangle


class DrawArea
(Widget):

   
def draw_rectangle(self):  # change name CamelCase for classes, snake_case for methods.  See pep8
       
with self.canvas:
            Color(
1, 0, 0, 0.5, mode="rgba")
            Rectangle(
pos=(100, 100), size=(100, 50))


class DrawApp(App):
   
def build(self):
       
self.title = "TestApp"
       
Window.size = (400, 300)
        Window.clearcolor = (
102 / 255, 102 / 255, 102 / 255, 1)
        parent = Widget()
       
self
.painter = DrawArea()

       
self.draw_button = Button(         # name change
           
text="Draw",
           
font_size=14,
           
pos=(10, 10),
           
size_hint=(None, None),
           
size=(70, 30),
           
color=(64, 64, 64, 1)
        )
       
self.draw_button.bind(on_release=self.draw_something)

        disable_button = Button(
           
text="Disable Draw Button",
           
font_size=14,
           
pos=(150, 10),
           
size_hint=(None, None),
           
size=(150, 30),
           
color=(64, 64, 64, 1)
        )
        disable_button.bind(
on_press=self.call_back)

        parent.add_widget(
self.painter)
        parent.add_widget(
self.draw_button)
        parent.add_widget(disable_button)
       
return parent

   
def draw_something(self, obj):
       
self.painter.draw_rectangle()

   
def call_back(self, elem):
       
self.draw_button.disabled = True


if
__name__ == '__main__':
    DrawApp().run()

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/a8308e42-12fd-46b6-8c4c-7765b68c5a49o%40googlegroups.com.

 

Elliot Garbus

unread,
Jan 3, 2021, 3:21:29 PM1/3/21
to kivy-...@googlegroups.com

One additional change… You want to add widgets to Layouts, not other widgets.

 

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line
from kivy.core.window import Window
from kivy.graphics import Rectangle
from kivy.uix.floatlayout import FloatLayout


class DrawArea(Widget):

   
def draw_rectangle(self):  # change name CamelCase for classes, snake_case for methods.  See pep8
       
with self.canvas:
            Color(
1, 0, 0, 0.5, mode="rgba")
            Rectangle(
pos=(100, 100), size=(100, 50))


class DrawApp(App):
   
def build(self):
       
self.title = "TestApp"
       
Window.size = (400, 300)
        Window.clearcolor = (
102 / 255, 102 / 255, 102 / 255, 1
)
        parent = FloatLayout()
       
self.painter = DrawArea()

       
self.draw_button = Button(         # name change
           
text="Draw",
           
font_size=14,
           
pos=(10, 10),
           
size_hint=(None, None),
           
size=(70, 30),
           
color=(64, 64, 64, 1)
        )
       
self.draw_button.bind(on_release=self.draw_something)

        disable_button = Button(
           
text="Disable Draw Button",
           
font_size=14,
           
pos=(150, 10),
           
size_hint=(None, None),
           
size=(150, 30),
           
color=(64, 64, 64, 1)
        )
        disable_button.bind(
on_press=self.call_back)

        parent.add_widget(
self.painter)
        parent.add_widget(
self.draw_button)
        parent.add_widget(disable_button)
       
return parent

   
def draw_something(self, obj):
       
self.painter.draw_rectangle()

   
def call_back(self, elem):
       
self.draw_button.disabled = True


if
__name__ == '__main__':
    DrawApp().run()

Daniel Leal

unread,
Jan 3, 2021, 4:23:52 PM1/3/21
to Kivy users support
Thanks a lot for your answer. I will study carefully your explanation. Thank's also for the the resources to check.
Greetings from Portugal :)

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Daniel Leal

unread,
Jan 3, 2021, 5:10:17 PM1/3/21
to Kivy users support

The "disable_button" should be also "self.disable_button" ??
It works anyway...

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Elliot Garbus

unread,
Jan 3, 2021, 6:22:56 PM1/3/21
to kivy-...@googlegroups.com

The disable_button does not need to be an instance variable self.disable_button, because it is only used in the local scope of build().

 

The instance variable self.painter is initialized and created in build() and also using in draw_something().  It is used in multiple methods in the class.  It is part of the classes state.  Same with self.draw_button.  As you add more capabilities you will likely need to make disable_button an instance variable.

 

It is customary in python to declare all of a classes instance variables in the classes __init__() method.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/c1922e89-775d-4796-9d15-ff2c5b78e7d8o%40googlegroups.com.

 

Daniel Leal

unread,
Jan 4, 2021, 4:37:30 PM1/4/21
to Kivy users support
Ok, understood...

What if one wants to disable the button from the  other class? Like Following... I am getting the "NameError: name 'self' is not defined" when pressing the  "down arrow key".

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line
from kivy.core.window import Window
from kivy.graphics import Rectangle


class DrawArea(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._keyboard = Window.request_keyboard(self._on_keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_key_down)

    def _on_keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_key_down)
        self._keyboard = None

    def _on_key_down(selfkeyboardkeycodetextmodifiers):
        if keycode[1] == 'up':
            with self.canvas:
                Color(1,0,0,0.5mode="rgba")
                Rectangle(pos=(100,100), size=(100,50))
        if keycode[1] == 'down':
            DrawApp.disable_next_button()

    def draw_rectangle(self):
        with self.canvas:
            Color(0,1,0,0.5mode="rgba")
            Rectangle(pos=(100,100), size=(100,50))

class DrawApp(App):
    def build(self):
        self.title = "TestApp"
        Window.size = (400300)
        Window.clearcolor = (102/255,102/255,102/255,1)
        parent = Widget()
        self.painter = DrawArea()
        
        self.DrawButton = Button(
            text = "Draw",
            font_size = 14,
            pos = (1010),
            size_hint = (NoneNone),
            size = (7030),
            color = (6464641)
        )
        self.DrawButton.bind(on_release = self.draw_something)
        
        DisableDrawButton = Button( #Este não precisa de ser uma "instance variable". Por isso não tem o ".self". Porque é apenas usado no scope local do "build().
            text = "Disable Draw Button",
            font_size = 14,
            pos = (15010),
            size_hint = (NoneNone),
            size = (15030),
            color = (6464641)
        )
        DisableDrawButton.bind(on_press = self.call_back)
        
        parent.add_widget(self.painter)
        parent.add_widget(self.DrawButton)
        parent.add_widget(DisableDrawButton)
        return parent

    def draw_something(selfobj):
        self.painter.draw_rectangle()

    def call_back(selfelem):
        self.DrawButton.disabled = True
        self.painter.canvas.clear()

    def disable_next_button():
        self.DrawButton.disabled = False

Pranav Balaji Pooruli

unread,
Jan 4, 2021, 5:10:55 PM1/4/21
to kivy-...@googlegroups.com
It is highly recommended you learn OOP before learning Kivy. I actually didn't know OOP but saw a video on YT by Tech With Tim about buttons in Pygame. That's when I sort of understood classes and self-taught myself. Then I started learning Kivy. It wasn't that hard after understanding classes. I'd tried learning Kivy before, but hadn't understood a thing. After learning Kivy, I started learning KivyMD (Kivy Material Design, I recommend you learn it too after learning Kivy). Now I'm pretty good at mobile app development with Python and am working on my second app for Android and iOS. Good luck, I hope to know when you get your first app published! 

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/dfa8b94f-9d65-4417-86e7-fe922451a69ao%40googlegroups.com.

Elliot Garbus

unread,
Jan 5, 2021, 12:00:08 AM1/5/21
to kivy-...@googlegroups.com

def _on_key_down(selfkeyboardkeycodetextmodifiers):

        if keycode[1] == 'up':

            with self.canvas:

                Color(1,0,0,0.5mode="rgba")

                Rectangle(pos=(100,100), size=(100,50))

        if keycode[1] == 'down':

            app = App.get_running_app()

            app.disable_next_button()

 

 

You need to get the object, the method you want disable_next_button() is a method of App.  The instance of app is App.get_running_app()

Read: https://kivy.org/doc/stable/api-kivy.app.html#kivy.app.App.get_running_app

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/dfa8b94f-9d65-4417-86e7-fe922451a69ao%40googlegroups.com.

 

Daniel Leal

unread,
Jan 5, 2021, 2:27:30 PM1/5/21
to Kivy users support
SUPER THANKS!!
:)

Daniel Leal

unread,
Jan 5, 2021, 4:33:11 PM1/5/21
to Kivy users support
Reply all
Reply to author
Forward
0 new messages