Problem passing a function to a popup in Kivy?

28 Views Asked by At

Problem description

For this example I use Kivy 2.3.0 and Python 3.9.13. There are two main screen buttons. Each button opens a popup. Each popup's button is bind to a method. The problem is the time of execution of the method bind to the Action-2 button.

  • correct behaviour: the button-1 opens the popup-1 when pressed. The popup button Action-1 runs the method_1 when pressed.
  • problematic behaviour: when pressed, the button-2 opens the popup-2 and runs the method_2 at the same time. The popup button Action-2 does nothing when pressed.

Question

Is it possible to pass the method_2 to the popup-2 so it will behave correctly as the popup-1 situation i.e. execute when pressing the action-2 button?

 #!/usr/bin/python3 python3
# -*- coding: utf-8 -*-


# positioning and size of the kivy window
from kivy.config import Config
Config.set('graphics','resizable',1)    # if 0, the window will have a fixed size. If 1, the window will be resizable.
Config.set('graphics','position','custom')
Config.set('graphics','left',10)
Config.set('graphics','top',10)
Config.set('graphics','width',600)      # 800 max for 7" touchscreen display
Config.set('graphics','height',360)     # 480 max for 7" touchscreen display
Config.set('graphics','borderless',1)   # If set to 1, removes the window border/decoration. Window resizing must also be disabled to hide the resizing border.
Config.set('graphics','show_cursor',0)  # Set whether or not the cursor is shown on the window.

# managing the kivy window
from kivy.core.window import Window
Window.show_cursor = True   # Set whether or not the cursor is shown on the window.

# kivy modules first, if not Kivy may cause problems
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.clock import mainthread
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.factory import Factory
kivy.require('2.0.0')

# common modules
import os, sys
import time
import signal
import inspect

# set environment variables to avoid "segmentation error" due to raspbian version
os.environ["KIVY_WINDOW"] = "sdl2"
os.environ["KIVY_GL_BACKEND"] = "sdl2"
os.environ["KIVY_IMAGE"] = "sdl2"

        
###############################################################################################################
###############################################################################################################

# kivy gui classes
# main screen
class MainScreen(Screen):
    def __init__(self, **kwargs):
        self.name="MAIN SCREEN"
        super(Screen, self).__init__(**kwargs)

# screen manager
class WindowManager(ScreenManager):
    pass
    # def __init__(self, **kwargs):
    #   self.name="WINDOW MANAGER"
    #   super(Screen, self).__init__(**kwargs)

# popup class
class Popup1(Popup):
    def __init__(self, obj, **kwargs):
        super(Popup1, self).__init__(**kwargs)
        self.obj = obj

# popup class
class Popup2(Popup):
    def __init__(self, obj, **kwargs):
        super(Popup2, self).__init__(**kwargs)
        self.obj = obj

######################################################################################################
######################################################################################################

# main app class 
class Test(App):

    # screen messages
    MainScreenTitle = "MainScreenTitle"
    MainScreenLabel = "MainScreenLabel"
    MainScreenButtonText1 = "Popup-1"
    MainScreenButtonText2 = "Popup-2"
    MainScreenButtonText3 = "Exit"


    def MainScreenButton1(self):    # opens popup-1
        # set the text of the popup
        self.Popup1Button1 = "Action-1"
        self.Popup1Button2 = "Dismiss"
        self.Popup1Title = "Title of Popup-1"
        self.Popup1Label = "Label of Popup-1"
        # set the popup structure
        self.popupMessage = Popup1(self)
        self.popupMessage.open()

    def MainScreenButton2(self):    # opens popup-2
        # set the text of the popup
        self.Popup2Button1 = "Action-2"
        self.Popup2Button2 = "Dismiss"
        self.Popup2Title = "Title of Popup-2"
        self.Popup2Label = "Label of Popup-2"
        self.popupMethod = self.method_2()
        # set the popup structure
        self.popupMessage = Popup2(self)
        self.popupMessage.open()
    
    def MainScreenButton3(self):    # exit button
        exit()  # exit the app

    
    def method_1(self):
        try:
            msg = "do something by pressing the button Action-1"
            print(str(msg))
        except Exception as e:
            msg = f"exception: {str(e)}"
            print(str(msg))
            pass
    
    
    def method_2(self):
        try:
            msg = "do something by pressing the button Action-2"
            print(str(msg))
        except Exception as e:
            msg = f"exception: {str(e)}"
            print(str(msg))
            pass
    

    def cancel(self):
        try:
            self.popupMessage.dismiss()
        except Exception as e:
            msg = f"dismiss popup exception: {e}"
            print(str(msg))


    def build(self):        
        sm = Builder.load_string("""
    
WindowManager:
    canvas:
        Color:
            rgb: 1, 1, 1
        Rectangle:
            size: self.size
    MainScreen:

<MainScreen>:
    name: "MainScreen"
    # size_hint: 1, 1
    size_hint: 1, .99
    auto_dismiss: True
    title: app.MainScreenTitle       
    title_align: "center"
    BoxLayout:
        orientation: "vertical"
        spacing: 10
        BoxLayout:
            orientation: "horizontal"
            spacing: 5
            size_hint: 1, 0.3
            Button:
                font_size: 30
                text: app.MainScreenButtonText1
                on_press: 
                    app.MainScreenButton1()
            Button:
                font_size: 30
                text: app.MainScreenButtonText2
                on_press:
                    app.MainScreenButton2()
            Button:
                font_size: 30
                text: app.MainScreenButtonText3
                on_press:
                    app.MainScreenButton3()
            
        BoxLayout:
            orientation: "horizontal"
            spacing: 10
            size_hint: 1, 0.7
            
###########################################################################
                        
<Popup1>:
    size_hint: 1, 1
    auto_dismiss: False
    title: app.Popup1Title       
    title_align: "center"
    title_size: 30
    BoxLayout:
        orientation: "vertical"
        Label:
            font_size: '30sp'
            text: app.Popup1Label
        BoxLayout:
            orientation: "horizontal"
            spacing: 10
            size_hint: 1, 0.5
            Button:
                font_size: 50
                text: app.Popup1Button1
                on_press:
                    app.method_1() # binded method
                    root.dismiss()
            Button:
                font_size: 50
                text: app.Popup1Button2
                on_press:
                    app.cancel()
                    root.dismiss()
            
<Popup2>:
    size_hint: 1, 1
    auto_dismiss: False
    title: app.Popup2Title       
    title_align: "center"
    title_size: 30
    BoxLayout:
        orientation: "vertical"
        Label:
            font_size: '30sp'
            text: app.Popup2Label
        BoxLayout:
            orientation: "horizontal"
            spacing: 10
            size_hint: 1, 0.5
            Button:
                font_size: 50
                text: app.Popup2Button1
                on_press:
                    app.popupMethod # method passed as variable
                    root.dismiss()
            Button:
                font_size: 50
                text: app.Popup2Button2
                on_press:
                    app.cancel()
                    root.dismiss()
        """)

        return sm
  

# main #################################################################
if __name__ == '__main__':
    
    try:
        Test().run()
    except Exception as e:
        msg = f"exception in Test: {e}"
        print(str(msg))
1

There are 1 best solutions below

2
John Anderson On

In your MainScreenButton2() method, the line

self.popupMethod = self.method_2()

is executing the method self.method_2(). If you want to reference the method without executing it, change that line to:

self.popupMethod = self.method_2

without the ().

Another required change is in your kv string. Just the opposite of the first change, in kv you must include () inside kv. Try changing:

app.popupMethod # method passed as variable

to:

app.popupMethod() # method passed as variable