Kivy Tutorials

Popup Window in Kivy KV Language

This article can be read in about 23 minutes.

This section describes how to display a pop-up window in Kivy. There are several ways to display a pop-up window, but here is some code written in the Dynamic class rules of the kv language.

Structure of a Popup

Kivy’s popups are not displayed in a separate window, but rather are pseudo-screens in the same window.

The structure of a popup is divided into several parts as shown below.

Kivy application explaining the structure of popup.
  1. Popup window: The black area is the popup window.
  2. Title: The part with the text string at the top.
  3. Separator: The light blue line.
  4. Content area: The area where widgets to be displayed in the popup window are placed.

Configuring a Popup

There are several ways to create popups, but here I will explain how to write popups using dynamic class rules in the kv language, which is the easiest to write and read. for more information about dynamic class rules in the kv language, see the following article.

Below is a sample of a commonly used pop-up setup.

Sample 1 of Kivy app popup

popup1.py

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

class RootWidget(BoxLayout):  
    pass
        
class Popup1(App):
    def build(self):
        return RootWidget()

if __name__ == '__main__':
    Popup1().run()

popup1.kv

#:import Factory kivy.factory.Factory

<CustomPopup@Popup>:
    # Popup settings
    title: 'Popup Title'
    title_align: 'center'
    title_color: 100/255, 100/255, 100/255, 1
    #title_font: './font_file.ttf'
    title_size: sp(15)

    separator_color: 180/255, 164/255, 176/255, 1
    separator_height: dp(4)

    auto_dismiss: False

    size_hint: 0.6, 0.4
    background: ''
    background_color: 228/255, 216/255, 225/255, 1
    
    #  Content Area Settings
    BoxLayout:
        orientation: 'vertical'
        canvas.before:
            Color:
                rgba: 207/255, 190/255, 202/255, 1
            Rectangle:
                size: self.size
                pos: self.pos

        Label: 
            text: 'Pop-up'
            color: 100/255, 100/255, 100/255, 1
        
        Button:
            text: 'Close'
            background_color: 215/255, 145/255, 197/255, 1
            on_release: root.dismiss()

<RootWidget>:
    Button:
        text: 'Open Popup'
        on_release: Factory.CustomPopup().open()

Code Explanation

In the kv file, write popup window settings, then content settings, in that order.

Import Factory to instantiate a dynamic class rules.

#:import < Alias Name > < Module name >
#:import Factory kivy.factory.

Import can also be done with kv files.’ #’ is not a comment. ‘ Factory’ part is an alias and can be any name.

<CustomPopup@Popup>:

Define a dynamic class rules that extends the Popup class, and define the properties of the Popup class in the next line.

Setting the Title

The following is a title-related setting.

    title: 'Popup Title'
    title_align: 'center'
    title_color: 100/255, 100/255, 100/255, 1
    #title_font: './font_file.ttf'
    title_size: sp(15)
title: 'Popup Title'

The title sets the title characters. Default is [No title].

title_align: 'center'

The title_align sets the horizontal position. The property value can be one of [left,center,right,justify]. The default is left. justufy is the line alignment when multiple lines are used.

title_color: 100/255, 100/255, 100/255, 1

The title_color sets the text color of the title. The default is [1, 1, 1, 1] and can also be specified in hexadecimal. For more information on setting the color, please refer to the following article.

title_font: './font_file.ttf'

The title_font specifies the font file for the title. It is recommended that absolute paths be used.

title_size: sp(15)

The title_size sets the font size of the title. The default is 14sp. The above is written in a way to convert to other units.

Set the Separator

The following are separator-related settings.

separator_color: 180/255, 164/255, 176/255, 1
separator_height: dp(4)
separator_color: 180/255, 164/255, 176/255, 1

The separator_color sets the color of the separator line. Defaults to [47 / 255, 167 / 255, 212 / 255, 1].

separator_height: dp(4)

The separator_height sets the height of the separator. The default is 2dp.

Sets the behavior when the user clicks outside of the popup

auto_dismiss: False

The auto_dismiss sets whether the popup window will close if clicked outside the popup window area. The default is True; False does not do this and requires the implementation of a button.

Setting the size of the popup

Kivy does not have a property to set the size of the popup, so use size_hint.

size_hint: 0.6, 0.4

For more information on size_hint, please refer to the following article.

Setting the Background Color of a Popup Window

There is no property to set the background color of a popup window, so use background_color.

background: ''
background_color: 228/255, 216/255, 225/255, 1

The important thing here is to clear the default background information once: specify an empty string for background, and set the background color with background_color on the next line.

Set the Content Area

This area defines the layout for the root widget and places the widget as a tree, similar to the description of class rules.

   BoxLayout:
        orientation: 'vertical
        canvas.before: 'vertical'
            Color: rgba: 207/257
                rgba: 207/255, 190/255, 202/255, 1
            Rectangle: self.size
                size: self.size
                pos: self.pos

        Label: text 
            text: "It's a popup"
            color: 100/255, 100/255, 100/255, 1

If you want to set the background color of the Content area, use canvas, the same as setting the layout background color. See the following article for layout background colors.

Implementing a Popup Close Button

Kivy popup does not have a event function for buttons, so you will need to create your own function. dismiss() method can only be used to close a button.

        Button:
            text: 'Close'
            background_color: 215/255, 145/255, 197/255, 1
            on_release: root.dismiss()
on_release: root.dismiss()

Call dismiss() using the on_release() or on_press().

Executing a Popup Window

To execute a popup window, call the open() method on any widget using the on_release() or on_press().

<RootWidget>:
    Button:
        text: "Open popup"
        on_release: Factory.CustomPopup().open()

The namespace Factory is the alias name defined in the import statement, followed by CustomPopup(), which is the subclass name described in the dynamic class rules definition.

Implementing OK and Cancel Buttons in Popup

Here is a example code to implement the processing of the buttons. It was difficult for me because I stuck to dynamic class rules. It was a good learning experience for me. Since I went to the trouble of writing the code, I also wrote the Factory in a py file.

Kivy example of a popup window.

popup2.py

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.factory import Factory

class RootWidget(BoxLayout):
    popup_instance = None  # Variables that manage popup instances

    def open_popup(self):
        # Open popup
        self.popup_instance = Factory.CustomPopup()
        self.popup_instance.open()

    def on_ok(self):
        self.ids.label.text = 'OK pressed.'
        self.dismiss_popup()  # Close popup

    def on_cancel(self):
        self.ids.label.text = 'Cancel pressed.'
        self.dismiss_popup()  # Close popup

    def dismiss_popup(self):
        # Close only if popup is open
        if self.popup_instance:
            self.popup_instance.dismiss()
            self.popup_instance = None

class Popup2(App):
    def build(self):
        return RootWidget()

if __name__ == '__main__':
    Popup2().run()

popup2.kv

<CustomPopup@Popup>:
    # Popup settings
    title: 'Popup Title'
    title_align: 'center'
    title_color: 100/255, 100/255, 100/255, 1
    #title_font: './font_file.ttf'
    title_size: sp(15)

    separator_color: 180/255, 164/255, 176/255, 1
    separator_height: dp(4)

    auto_dismiss: False

    size_hint: 0.6, 0.4
    background: ''
    background_color: 228/255, 216/255, 225/255, 1
    
    # Content Area Settings
    BoxLayout:
        orientation: 'vertical'
        canvas.before:
            Color:
                rgba: 207/255, 190/255, 202/255, 1
            Rectangle:
                size: self.size
                pos: self.pos
        Label: 
            text: 'Popup!'
            color: 100/255, 100/255, 100/255, 1
        BoxLayout:
            padding: 30, 30
            spacing: 10
            Button:
                text: 'OK'
                on_press: app.root.on_ok()               
            Button:
                text: 'Cancel'
                on_press: app.root.on_cancel()

<RootWidget>:
    Label:
        id: label
        text: 'You can see the popup here.'
        font_size: 30
    Button:
        text: 'Open Popup'
        font_size: 30
        on_release: root.open_popup()

Code Explanation

Below are the functions defined in the Python code.

open_popup()    # Register to Factory and execute popup.
on_ok()         # It is called when the "OK" button is pressed.
on_cancel()     # called when the "cancel" button is pressed.
dismiss_popup() # Function called when popup is closed.

Normally, a popup can be closed by calling dismiss(), but since functions registered with the Factory() are separated from other functions here, the popup instance cannot be referenced due to the scope. For example, closing a popup with on_ok() requires a popup instance, but since an instance is created with open_popup(), it cannot be referenced, so a class variable that references the popup instance is defined. Therefore, create dismiss_popup() and call dismiss_popup() with on_ok() or on_cancel() to close the popup.

Python Code

popup_instance = None

Defined to reference popup instances from other functions. The initial value is None.

   def open_popup(self).
        # Open a popup
        self.popup_instance = Factory.CustomPopup()
        self.popup_instance.open()

The open_popup() registers the popup with Factory() and executes it. Since the dynamic class rules is only defined, it must be registered with the Factory() and an instance must be created.

from kivy.factory import Factory

popup_instance = Factory.

Assign an instance of CustomPopup() to popup_instance.

self.popup_instance.open()

The open() launches the popup.

def on_ok(self):
    self.ids.label.text = 'Cancel pressed.'
    self.dismiss_popup()  # close the popup

In on_ok(), the ‘OK’ or ‘Cancel’ button is displayed on the Label when it is pressed. It also handles the closing of the popup.

self.ids.label.text = "Cancel was pressed."

The text property of Label’s id “label” is referenced and changed.

self.dismiss_popup()

Calling dismiss_popup() is used to close the popup.

   def on_cancel(self):
        self.ids.label.text = 'Cancel was pressed.'
        self.dismiss_popup() # close the popup

The same process is used in on_cancel() as in on_ok().

  def dismiss_popup(self)
        # Close a popup only if it is open
        if self.popup_instance:
            self.popup_instance.dismiss()
            self.popup_instance = None

In dismiss_popup() we are closing the popup.

if self.popup_instance:

Evaluates whether an instance is assigned to popup_instance and executes the next process only if the popup is activated.

self.popup_instance.dismiss()

Closes the popup with dismiss().

self.popup_instance = None

The instance assigned to popup_instance is dismissed in case the popup is invoked a second time or later.

KV File

            Button:
                text: 'OK'
                on_press: app.root.on_ok()               
            Button:
                text: 'Cancel'
                on_press: app.root.on_cancel()

The on_press() calls on_ok() or on_cancel() when clicked. Normally, this can be called with just the root keyword, but since we are using a dynamic class rules, CustomPopup() cannot be referenced by root because it does not exist in the root widget tree.

Before we discuss app.root, let’s review the class structure. A dynamic class rules, written in Python code, looks like this

class CustomPopup(Popup):
    pass

class RootWidget(BoxLayout):
    pass

Since dynamic class rules are subclasses that inherit from a class, they have a different scope than the root widget; it is the root widget that can be referenced by the root keyword, so in this case it is app.root.

The app keyword can refer to an instance of the App class. That is, an instance of the currently running application. And the root keyword can refer to the root widget. By connecting these two keywords and making app.root, we are accessing the methods that root has via the app keyword.

For more information on routes and other keywords and id, please see the following article.

Comment

Copied title and URL