community icon indicating copy to clipboard operation
community copied to clipboard

Color Constants Do Not Work in Canvas

Open ongtw opened this issue 2 years ago • 3 comments

Software Versions

  • Python: 3.8
  • OS: macOS Big Sur
  • Kivy: 2.1.0
  • Kivy installation method: compile and install from GitHub source

Describe the bug Using the pure Python way in kivy docs [Adding a Background to a Layout] (https://kivy.org/doc/stable/guide/widgets.html#adding-widget-background), if I declare GREEN = Color(0, 1, 0, 1) and use it in place of the Color(0, 1, 0, 1) in the canvas instructions, it does not work. The background renders as a white rectangle instead of green.

Expected behavior Expect identical behavior to original sample code.

Code To Reproduce Error/Bug

from kivy.app import App
from kivy.graphics import Color, Rectangle
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button


GREEN = Color(0, 1, 0, 1)    # want to use constants for readability/scalability


class RootWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        self.add_widget(
            Button(
                text="Hello World",
                size_hint=(0.5, 0.5),
                pos_hint={"center_x": 0.5, "center_y": 0.5},
            )
        )


class MainApp(App):
    def build(self):
        self.root = root = RootWidget()
        root.bind(size=self._update_rect, pos=self._update_rect)
        with root.canvas.before:
            GREEN  # why does this not work?! :(
            # Color(0, 1, 0, 1)  # green; colors range from 0-1 not 0-255
            self.rect = Rectangle(size=root.size, pos=root.pos)
        return root

    def _update_rect(self, instance, value):
        self.rect.pos = instance.pos
        self.rect.size = instance.size


if __name__ == "__main__":
    MainApp().run()

ongtw avatar Mar 10 '22 04:03 ongtw

hmm i do not think this is a bug with is used in a context manager, ( ie root.canvas.before), so GREEN is actually not available there you can do

        root.canvas.before.add(GREEN)
        with root.canvas.before:
            self.rect = Rectangle(size=root.size, pos=root.pos)

but im sure there is a better way

p0lygun avatar Mar 10 '22 13:03 p0lygun

After some trial-and-error, I found a better way:

        with root.canvas.before:
            Color(*GREEN)
            self.rect = Rectangle(size=root.size, pos=root.pos)

Above works even though GREEN alone does not. Likely it has something to do with how the Python interpreter works. So GREEN is available within the context manager, since GREEN is declared as a "global variable".

ongtw avatar Mar 11 '22 00:03 ongtw

How that context manager works is clear to me. If you instantiate a graphics instruction (Color in this case) inside the context manager, it will be automatically added to the canvas.

GREEN = Color(0, 1, 0, 1)  # outside the context manager, you need to add it to a canvas manually.
root.canvas.add(GREEN)

with root.canvas:
    GREEN = Color(0, 1, 0, 1)  # inside the context manager, automatically added to the canvas

gottadiveintopython avatar Aug 09 '22 02:08 gottadiveintopython

@gottadiveintopython:

I concur with the above. Merely mentioning a value (i.e. GREEN) isn't going to have any effect. You need to be executing something (e.g. Colour.__init__()) for the context manager to have a chance to change behaviour.

But this is going to be subtle for newbies. The documentation doesn't attempt to address it.

I am making this Issue about documenting the behaviour, rather than the behaviour being wrong.

Julian-O avatar Oct 31 '23 13:10 Julian-O