Taporp
Taporp

Reputation: 88

Kivy's ScreenManager and Popups don't want to work together

as stated in the title - I'm stuck. I've been playing with the code around and everything works as long as I keep ScreenManager and Popup separate. Once combined - they refuse to cooperate. Anyway, here is the simple app that shows the problem I'm having.

from kivy.lang import Builder
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import Screen, ScreenManager

class First(GridLayout,Screen):
    def show_popup(self):
        Popp().open()
    pass

class Second(Screen):
    pass

class Popp(Popup):
    pass

class ScreenManagement(ScreenManager):
    pass

app = Builder.load_file("main.kv")

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


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

And main.kv file

ScreenManagement:
    First:
    Second:

<First>:
    name:"First"
    rows: 2
    Button:
        text: "FirstButton"
        on_release: app.root.current = "Second"
    Button:
        text: "Show popup"
        on_release: root.show_popup()

<Second>:
    name:"Second"
    Button:
        text: "BUTTON"
        on_release: app.root.current = "First"

<Popp>:
    title: "testing"
    text: "Hello world"
    size_hint: None,None
    size: 400,400
    auto_dismiss: False
    Button:
        text: "Okay"
        on_press: root.dismiss()

App starts, first and second screen are working but when trying to get popup up I end up with:

kivy.uix.popup.PopupException: Popup can have only one widget as content

Somehow Screen is seen as a widget inside of Popp? Or am I terribly misinterpreting kivy docs?

Upvotes: 3

Views: 1797

Answers (3)

pd shah
pd shah

Reputation: 1406

I have same problem with using kivy Builder.load_file and Popup, they dont work together. the solution is simple, build popup in python code side. this is a loading popup example:

python:

    from kivy.app import App
    from kivy.uix.popup import Popup
    from kivy.factory import Factory
    from kivy.properties import ObjectProperty
    from kivy.clock import Clock
    from kivy.lang import Builder
    from kivy.uix.popup import Popup
    from kivy.uix.image import Image
    from kivy.uix.label import Label
    from kivy.uix.boxlayout import BoxLayout

    import time, threading


    buildKV = Builder.load_file("example.kv")

    class ExampleApp(App):
        def show_popup(self):
            content = BoxLayout(orientation= "vertical")
            image=Image(source= 'files/loading.gif', anim_delay= 0)
            label=Label(text= 'Model is Running.\nBe Patient Please.')
            content.add_widget(image)
            content.add_widget(label)
            self.popup = Popup(title='Model is Running.',
                      size_hint=(.250, .785),
                      content=content, auto_dismiss=False)

            self.popup.open()

        def process_button_click(self):
            # Open the pop up
            self.show_popup()

            # Call some method that may take a while to run.
            # I'm using a thread to simulate this
            mythread = threading.Thread(target=self.something_that_takes_5_seconds_to_run)
            mythread.start()

        def something_that_takes_5_seconds_to_run(self):
            thistime = time.time()
            while thistime + 10 > time.time(): # 5 seconds
                time.sleep(1)

            # Once the long running task is done, close the pop up.
            self.pop_up.dismiss()

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

kivy:

   BoxLayout:
        Button:
            height: 40
            width: 100
            size_hint: (None, None)
            text: 'Click Me'
            on_press: app.process_button_click()

Upvotes: 0

picibucor
picibucor

Reputation: 773

Put the elements in the Popup inside a layout, for example: Boxlayout.

Here's what I mean:

<Popp>:
    title: "testing"
    BoxLayout:
        orientation: 'vertical'
        size_hint: None,None
        size: 400,400
        Label:
           text: "Hello world"
        Button:
            text: "Okay"
            on_press: root.dismiss()

Upvotes: 1

jligeza
jligeza

Reputation: 4703

It's a bug with loading kv file, it should throw an exception in this case.

What you are doing in the code is loading the kv file twice, what causes some weird behavior. Just delete the Builder.load_file(..) and it will work. The file is going to be loaded automatically.

Also, never do double subclassing of widgets like class First(GridLayout, Screen) as it might lead to some problems. Instead, create a grid layout inside the screen.

Upvotes: 1

Related Questions