Dan
Dan

Reputation: 33

Kivy multiple screen management

I'm fairly new to Kivy ( been learning it two days ago) I was working on a basic calculator but came across a hurdle I couldn't jump over.
I would like to create multiple screens because I intend to add more to my calculator as I'm further learning Kivy & I don't know how to adjust ScreenManager in my code.

This is my .py file

import kivy

kivy.require('1.11.0')
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.pagelayout import PageLayout
from kivy.core.window import Window

Window.clearcolor = .3,.3,.3,1

class RootWidget(GridLayout):   
    def calculate(self, calculation):
        if calculation:
            try:
                self.display.text = str(eval(calculation))
            except Exception:
            self.display.text = "Error"
class kutuApp(App):
    def build(self):
        return RootWidget()
if __name__== '__main__':
    kutuApp().run()

And this is my .kv file

<CustButton@Button>:
    font_size: 35
    background_color: 0,0,0,0
    canvas.before:
        Color:
            rgba: (.4, .4, .4, 1) if self.state=='normal' else (0,.7,.7,1)
        RoundedRectangle:
            pos: self.pos
            size: self.size
            radius: [20, ]

<RawLayout@BoxLayout>:
     spacing: 8
     padding: 8
      size_hint: [1, .2]

<RootWidget>:
       id: calculator
      rows: 10
       display: entry
       spacing: 1

BoxLayout:
    size_hint: [1, .1]
    Label:
        text: 'Basic Calculator'
    Label:
        text: 'Made by Xrew'

BoxLayout:
    padding: 10
    TextInput:
        id: entry
        spacing: 1
        padding: 5
        font_size: 32
        multiline: True
        focus: False
#       background_color: 0, 0, 0, 1
#       foreground_color: [1, 0, 1, 1]

RawLayout:
    CustButton:
        text: '<'
        on_press: entry.text += self.text
    CustButton:
        text: '>'
        on_press: entry.text += self.text
    CustButton:
        text: '≈'
        on_press: entry.text += '=='                

RawLayout:
    orientation: 'horizontal'
    CustButton:
        text: '('
        on_press: entry.text += '('
    CustButton: 
        text: ')'
        on_press: entry.text += ')'
    CustButton:
        text: '√'
        on_press: entry.text += '**(.5)'
    CustButton:
        text: '¹/x' 
        on_press: entry.text += '1/'
RawLayout:
    orientation: 'horizontal'
    CustButton:
        text: 'Del'
        on_press: entry.text = entry.text[:-1]
    CustButton:
        text: 'x²'
        on_press: entry.text += '**2'
    CustButton:
        text: 'xⁿ'
        on_press: entry.text += '**'
    CustButton:
        text: 'π'
        on_press: entry.text += '3.14'

RawLayout:
    orientation: 'horizontal'       
    cols: 4    
    CustButton:
        text: 'Clr'
        font_color: [255,0,0,1]
 #       background_normal: ' '
    #    background_color: 1, .3, .4, .85
        on_press: entry.text = ""
    CustButton:
        text: '+'
        on_press: entry.text += self.text
        font_size: 32
    CustButton:
        text: '÷'
        on_press: entry.text += '/'
    CustButton:
        text: '×'
        on_press: entry.text += '*'

RawLayout:
    rows: 1   
    orientation: 'horizontal'
    CustButton:
        text: '7'
        on_press: entry.text += self.text
    CustButton:
        text: '8'
        on_press: entry.text += self.text
    CustButton:
        text: '9'
        on_press: entry.text += self.text
    CustButton:
        text: '-'
        on_press: entry.text += self.text

RawLayout:
    orientation: 'horizontal'
    rows: 1
    CustButton:
        text: '4'
        on_press: entry.text += self.text
    CustButton:
        text: '5'
        on_press: entry.text += self.text
    CustButton:
        text: '6'
        on_press: entry.text += self.text
    CustButton:
        text: '+'
        on_press: entry.text += self.text   

RawLayout:
    orientation: 'horizontal'
    cols: 3
    CustButton:
        text: '1'
        size_hint: [.5, 1]
        on_press: entry.text += self.text
    CustButton:
        text: '2'
        size_hint: [.5, 1]
        on_press: entry.text += self.text
    CustButton:
        text: '3'
        size_hint: [.5, 1]
        on_press: entry.text += self.text
    CustButton:
        text: ' '
        size_hint: [.5, 1]
        background_normal: ' '
        background_color: 0, 0, 0, 0

RawLayout:
    orientation: 'horizontal'
    size_hint: [1, .2]
    CustButton:
        text: '0'
        on_press: entry.text += self.text
        size_hint: [.34, 1]
    CustButton:
        text: '.'
        on_press: entry.text += self.text
        size_hint: [.17, 1]
        font_size: 32
    CustButton:
        text: '='
        on_press: calculator.calculate(entry.text)
        size_hint: [.17, 2.4]
#       background_normal: ' '
    #   background_color:  0, .5, 95, 1

Upvotes: 3

Views: 5863

Answers (1)

ikolim
ikolim

Reputation: 16041

Kivy ScreenManager

The following steps illustrates how to expand a Kivy App with ScreenManager, Screen, and Button widgets, and one of Button's events (on_release, on_press).

Py File

  1. Add import statement, from kivy.uix.screenmanager import ScreenManager, Screen
  2. Declare a class with inheritance of ScreenManager, e.g. class ScreenManagement(ScreenManager):
  3. Declare two classes with inheritance of Screen, e.g. class MenuScreen(Screen): and class CalculatorScreen(Screen):
  4. Add pass as body of the three new classes because we are going to use kv language to design their views / presentation.
  5. Replace return RootWidget() with return ScreenManagement() because now the root of the App is a Kivy ScreenManager
  6. Rename class RootWidget to class Calculator

Snippets - py

from kivy.uix.screenmanager import ScreenManager, Screen

...

class Calculator(GridLayout):
    ...    


class MenuScreen(Screen):
    pass


class CalculatorScreen(Screen):
    pass


class ScreenManagement(ScreenManager):
    pass


class kutuApp(App):
    def build(self):
        return ScreenManagement()

kv File

  1. Declare class rules, <MenuScreen>:, <CalculatorScreen>: <ScreenManagement>: which corresponds to class MenuScreen(Screen):, class CalculatorScreen(Screen):, and class ScreenManagement(ScreenManager): respectively in Python script
  2. Rename RootWidget to Calculator
  3. Instantiate Calculator: as child of class rule, <CalculatorScreen>:
  4. Instantiate MenuScreen: and CalculatorScreen: as children of class rule, <ScreenManagement>:
  5. Give name to MenuScreen: and CalculatorScreen: as name: 'menu' and name: 'calculator' respectively. This will enable us to reference them when switching screen.

Snippets - kv

<ScreenManagement>:
    MenuScreen:
        name: 'menu'
    CalculatorScreen:
        name: 'calculator'

<MenuScreen>:
    BoxLayout:
        Button:
            text: 'Goto Calculator'
            on_press: root.manager.current = 'calculator'
        Button:
            text: 'Quit'

<CalculatorScreen>:
    Calculator:

...
<Calculator>:
    id: calculator

Example

main.py

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen


Window.clearcolor = .3, .3, .3, 1


class Calculator(GridLayout):
    def calculate(self, calculation):
        if calculation:
            try:
                self.display.text = str(eval(calculation))
            except Exception:
                self.display.text = "Error"


class MenuScreen(Screen):
    pass


class CalculatorScreen(Screen):
    pass


class ScreenManagement(ScreenManager):
    pass


Builder.load_file("main.kv")


class kutuApp(App):
    def build(self):
        return ScreenManagement()


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

main.kv

<ScreenManagement>:
    MenuScreen:
        name: 'menu'
    CalculatorScreen:
        name: 'calculator'

<MenuScreen>:
    BoxLayout:
        Button:
            text: 'Goto Calculator'
            on_press: root.manager.current = 'calculator'
        Button:
            text: 'Quit'

<CalculatorScreen>:
    Calculator:

<CustButton@Button>:
    font_size: 35
    background_color: 0,0,0,0
    canvas.before:
        Color:
            rgba: (.4, .4, .4, 1) if self.state=='normal' else (0,.7,.7,1)
        RoundedRectangle:
            pos: self.pos
            size: self.size
            radius: [20, ]

<RawLayout@BoxLayout>:
    spacing: 8
    padding: 8
    size_hint: [1, .2]

<Calculator>:
    id: calculator
    rows: 10
    display: entry
    spacing: 1

    BoxLayout:
        size_hint: [1, .1]
        Label:
            text: 'Basic Calculator'
        Label:
            text: 'Made by Xrew'

    BoxLayout:
        padding: 10
        TextInput:
            id: entry
            spacing: 1
            padding: 5
            font_size: 32
            multiline: True
            focus: False
    #       background_color: 0, 0, 0, 1
    #       foreground_color: [1, 0, 1, 1]

    RawLayout:
        CustButton:
            text: '<'
            on_press: entry.text += self.text
        CustButton:
            text: '>'
            on_press: entry.text += self.text
        CustButton:
            text: '≈'
            on_press: entry.text += '=='

    RawLayout:
        orientation: 'horizontal'
        CustButton:
            text: '('
            on_press: entry.text += '('
        CustButton:
            text: ')'
            on_press: entry.text += ')'
        CustButton:
            text: '√'
            on_press: entry.text += '**(.5)'
        CustButton:
            text: '¹/x'
            on_press: entry.text += '1/'
    RawLayout:
        orientation: 'horizontal'
        CustButton:
            text: 'Del'
            on_press: entry.text = entry.text[:-1]
        CustButton:
            text: 'x²'
            on_press: entry.text += '**2'
        CustButton:
            text: 'xⁿ'
            on_press: entry.text += '**'
        CustButton:
            text: 'π'
            on_press: entry.text += '3.14'

    RawLayout:
        orientation: 'horizontal'
        cols: 4
        CustButton:
            text: 'Clr'
            font_color: [255,0,0,1]
     #       background_normal: ' '
        #    background_color: 1, .3, .4, .85
            on_press: entry.text = ""
        CustButton:
            text: '+'
            on_press: entry.text += self.text
            font_size: 32
        CustButton:
            text: '÷'
            on_press: entry.text += '/'
        CustButton:
            text: '×'
            on_press: entry.text += '*'

    RawLayout:
        rows: 1
        orientation: 'horizontal'
        CustButton:
            text: '7'
            on_press: entry.text += self.text
        CustButton:
            text: '8'
            on_press: entry.text += self.text
        CustButton:
            text: '9'
            on_press: entry.text += self.text
        CustButton:
            text: '-'
            on_press: entry.text += self.text

    RawLayout:
        orientation: 'horizontal'
        rows: 1
        CustButton:
            text: '4'
            on_press: entry.text += self.text
        CustButton:
            text: '5'
            on_press: entry.text += self.text
        CustButton:
            text: '6'
            on_press: entry.text += self.text
        CustButton:
            text: '+'
            on_press: entry.text += self.text

    RawLayout:
        orientation: 'horizontal'
        cols: 3
        CustButton:
            text: '1'
            size_hint: [.5, 1]
            on_press: entry.text += self.text
        CustButton:
            text: '2'
            size_hint: [.5, 1]
            on_press: entry.text += self.text
        CustButton:
            text: '3'
            size_hint: [.5, 1]
            on_press: entry.text += self.text
        CustButton:
            text: ' '
            size_hint: [.5, 1]
            background_normal: ' '
            background_color: 0, 0, 0, 0

    RawLayout:
        orientation: 'horizontal'
        size_hint: [1, .2]
        CustButton:
            text: '0'
            on_press: entry.text += self.text
            size_hint: [.34, 1]
        CustButton:
            text: '.'
            on_press: entry.text += self.text
            size_hint: [.17, 1]
            font_size: 32
        CustButton:
            text: '='
            on_press: calculator.calculate(entry.text)
            size_hint: [.17, 2.4]
    #       background_normal: ' '
        #   background_color:  0, .5, 95, 1

Output

MenuScreen CalculatorScreen

Upvotes: 9

Related Questions