简体   繁体   中英

Displaying a background image in Kivy

I just started to learn Kivy so I am still familiar with its functionalities. I am trying to put an image as a background to my app main page. This is what I did:

class Prin(BoxLayout):
    def __init__(self,**kwargs):
        super(Prin,self).__init__(**kwargs)
        layout = BoxLayout(orientation='vertical')
        with self.canvas:
            self.rect = Rectangle(source='test.png', pos=layout.center, size=(self.width, self.height))
        self.text = Label(text='Press start')
        fb = Button(text='Start!', size_hint =(0.5, 0.1), pos_hint ={'center_x':.5, 'y':.5}, padding=(10, 0), on_press=self.start)

        layout.add_widget(self.text)
        layout.add_widget(fb)
        self.add_widget(layout)
        
    def start(self,event):
        self.text.text = self.text.text+ "\nNew line"


class MainApp(App):
    def build(self):
            return Prin()
    

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

The desired behavior is an image covering the whole screen, that's why I've put pos=self.center, size=(self.width, self.height)

This is the output:

电流输出

So I have two questions:

1/ Why is the image appearing in the left bottom side? What widget is actually there? I am supposed to have only a BoxLayout with 2 widgets in a vertical orientation. I don't understand what is there.

2/ What should why put in size and pos to have the desired output?

I would recommend putting all graphic elements in a .kv file, so there are fewer imports and it looks better.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout

KV = ("""
<Prin>
    BoxLayout:
        orientation: 'vertical'
        canvas.before:
            Rectangle:
                pos: self.pos
                size: self.size
                source: 'test.png'
                
        Label:
            id: label
            text: 'TEXT'
                
        Button:
            text: 'Start!'
            size_hint: None, None
            size_hint: 0.5, 0.1
            pos_hint: {'center_x': .5, 'center_y': .5}
            padding: 10, 0
            on_press: root.start()
            
""")


class Prin(BoxLayout):
    Builder.load_string(KV)

    def __init__(self, **kwargs):
        super(Prin, self).__init__(**kwargs)

    def start(self):
        self.ids.label.text += "\nNew line"


class MainApp(App):
    def build(self):
        return Prin()


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

If you still want to do this not in the kv file, then the problem is in self.size , by default, this value is [100, 100] , only after calling the class and adding it to the main window it changes.

from kivy.core.window import Window

class Prin(BoxLayout):
    def __init__(self, **kwargs):
        super(Prin, self).__init__(**kwargs)

        with self.canvas.before:
            Rectangle(source='test.png', pos=self.pos, size=Window.size)

        print(self.size) # [100, 100]


...

class MainApp(App):
    def build(self):
        self.screen = Prin()
        return self.screen

    def on_start(self):
        print(self.screen.size)  # [800, 600]

And don't forget about imports when you ask a question, the code should run without any manipulation

In response to your questions:

  1. The image is appearing in that position because pos=layout.center is not a valid position and so instead sets it to a default value ( [100, 100] I believe). To fix this, change pos=layout.center to pos=layout.pos

  2. Your size is the default value also! This is getting a little technical but when you initialise your Prin class you are specifying the size of the Rectangle to be the current size of the BoxLayout . However, since it has not been initialised yet, the BoxLayout doesn't yet have a size, Again. Kivy handles this by giving it a default size.

Why are my Buttons and Labels correct?

Kivy automatically binds the children of a BoxLayout to the size and position of the BoxLayout. This binding ensures that when the position and size of the BoxLayout are changed, so too are the widgets within it ( https://kivy.org/doc/stable/api-kivy.event.html ).

Why doesn't Kivy bind the rectangle?

This has something to do with the canvas . The canvas is a drawing instruction shared by a widget, and not a property of any individual widget. Hence you'll programmatically bind your rectangle to the BoxLayout. (https://kivy.org/doc/stable/api-kivy.graphics.instructions.html )

How do I achieve this binding you speak of?

Two ways. Firstly (preferred), you can define your widgets in the KV language as this will automatically handle any binding you wish. Second, you can create an 'on_size' callback. Something like:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.graphics import Rectangle


class Prin(BoxLayout):

    def __init__(self, **kwargs):
        super(Prin, self).__init__(**kwargs)
        layout = BoxLayout(orientation='vertical')
        with self.canvas:
            self.rect = Rectangle(source='test.png', pos=layout.pos, size=self.size)
        self.text = Label(text='Press start')
        fb = Button(text='Start!', size_hint=(0.5, 0.1), pos_hint={'center_x': .5, 'y': .5}, padding=(10, 0),
                    on_press=self.start)

        layout.add_widget(self.text)
        layout.add_widget(fb)
        self.add_widget(layout)

    def start(self, *_):
        self.text.text = self.text.text + "\nNew line"

    def resize(self, *_):
        widgets = self.children[:]
        self.canvas.clear()
        self.clear_widgets()
        with self.canvas:
            self.rect = Rectangle(source='test.png', pos=self.pos, size=self.size)
        for widget in widgets:
            self.add_widget(widget)

    on_size = resize


class TestApp(App):
    def build(self):
        return Prin()


if __name__ == "__main__":
    app = TestApp()
    app.run()

I just would like to add as a BIG PS although the above code solves your problem, it does so in probably the least efficient way imaginable. It is far better to define your widget in the kv file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM