2

I'm pretty new to kivy, and have been having this problem accessing my canvas rectangle. I need to keep it updated as I load images throughout the code and so the size of the window changes but unlike other properties such as textboxes or images, I wasn't able to access it using id or group. Would really appreciate any help :)

my python code:

import kivy
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget

GUI = Builder.load_file('style.kv')


class NotebookScreen(GridLayout):

    def __init__(self, **kwargs):
        self.rows = 1
        super(NotebookScreen, self).__init__(**kwargs)
        self.bind(pos=self.update_background, size=self.update_background)


    def update_background(self, *args):
        background = self.ids

        #can't seem to access rectangle here...

        # background.size = self.size
        # background.pos = self.pos


class MainApp(App):

    def build(self):
        return NotebookScreen()


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

my kv code:

<NotebookScreen>
    GridLayout:
        id: back_layout
        cols: 1
        rows: 1
        canvas:
            Color:
                rgba: 1, 1, 1, 1
            Rectangle:
                id: rect
                pos: self.center
                size: self.width, self.height

        Image:
            id: notebook_image
            source: 'images/notebook.jpg'
  • I think you can access it via the `canvas.children` property of the GridLayout it's contained within. – inclement Apr 16 '20 at 17:48
  • The `Rectangle` in your `GridLayout` should update automatically (thanks to `kv`). Note that setting `pos: self.center` puts the lower left corner of the `Rectangle` at the center of the `GridLayout`. – John Anderson Apr 16 '20 at 18:24

1 Answers1

0

I just found myself needing to change a background (Rectangle), and it was surprisingly difficult. Eventually figured it out. Here are some code-fragments that will do the job:

kv-lang:

<SecondWindow>:
    name: "game_screen"
    id: "game_screen_id"
    map_width: 300
    map_height: 100
    bmp_source: '/Code/kivy/exp/screens/road_100.png'

    RelativeLayout:
        name: "game_layout"
        id: "game_layout_id"
        size: root.width, root.height
        canvas.after:
            Rectangle:
                size: self.parent.map_width, self.parent.map_height
                source: self.parent.bmp_source
        Button:
            text: "change bitmap"
            size_hint: (0.2, 0.1)
            pos_hint: {"top": 1, "right": 0.5}
            on_release:
                self.parent.parent.test_click(parent=self.parent.parent)

Python:

class SecondWindow(Screen):
    def test_click(self, *args, **kwargs):
        print(f"SecondWindow here, got {args=}, {kwargs=}")
        sub_layout = kwargs['parent']
        print(f"\n{sub_layout.bmp_source=}")
        sub_layout.bmp_source = '/Code/kivy/exp/screens/road_200.png'
        sub_layout.map_width = 900
        sub_layout.map_height = 600

The key insight I got from How to set Rectangle Id. You need to set the source to a variable, rather than a string - then you can access that variable in code, and the Rectangle will auto-update.

There are several things that are kludgy here. I experimented with ids, but given that I was loading a .kv file inside an app, finding the exact id I wanted was tricky, so I just passed in button.parent.parent as a parameter to a function. Note the function is attached to the Screen, which is a Widget several layers up - because the Screen is the first object that exists both in Python and kv-lang.

Since you're binding to a property-change, that won't be an issue for you. It only came up for me because I wanted a button-click to change things.

Of course you can also change other variables, such as width/height, and since the Rectangle points to them, it just "magically" updates. I don't know if you care about source, but that's what got me into this.

John C
  • 6,285
  • 12
  • 45
  • 69