How to use ScrollView in KV

44 views
Skip to first unread message

Abraham Francisco

unread,
Aug 12, 2020, 2:55:51 PM8/12/20
to Kivy users support
Its me, the alarm app guy. I'm on to my next implementation quest and I've decided I want to change out how I have to manually input the time in the 'alarmedit' page and be able to scroll through number selections to input your desired time.

I believe using ScrollView would be the answer, so I thought I'd use the kv example from the documentation and paste it in my code just to see it working in a conceptual manner first but I get this error:

   if current_property[:3] == 'on_':
 TypeError: 'NoneType' object is not subscriptable

What is this telling me? And before anything else, I'm going to most likely need three scrolls (1 for hrs, 1 for mins, and 1 for pm/am). Is it possible to have that many scrolls in one boxlayout?

I'm going for something like this:

The top half where the numbers can be scrolled by touch.

Here's my code. I only just threw the kv example from the doc in:

    from kivy.app import App
    from kivy.lang import Builder
    from kivy.clock import Clock
    from kivy.properties import StringProperty
    from kivy.uix.label import Label
    from kivy.uix.screenmanager import Screen
    from kivy.uix.image import Image
    from kivy.uix.behaviors import ToggleButtonBehavior
    import os
    from kivy.uix.popup import Popup
    from kivy.core.audio import SoundLoader
    
    from time import strftime
    
    kv = """
    <Home@Screen>:
        BoxLayout:
            orientation: 'vertical'
            MyClock:
                font_size: 50
                text: self.current_time
            Button:
                background_color: (128,0,0,.6)
                background_down: '(0, 0, .3, 1)'
                text: 'Set Alarm'
                on_press: root.manager.current = 'alarm_page'
    
    <AlarmPage@Screen>:
        GridLayout:
            rows: 4
            Button:
                text: 'Alarm 1'
                on_release: root.manager.current = 'edit1_page'
    
            Button:
                text: 'Alarm 2'
                on_release: root.manager.current = 'edit2_page'
            Button:
                text: 'Put alarms on this page'
                on_release: root.manager.current = 'home_page'
    
    <AlarmEdit>:
        BoxLayout:
            orientation: 'vertical'
            ScrollView:
                do_scroll_x: False
                do_scroll_y: True
    
                Label:
                    size_hint_y: None
                    height: self.texture_size[1]
                    text_size: self.width
                    padding: 2, 2
                    text:
                        'really some amazing text\n' * 10
            GridLayout:
                cols: 4  
                Label:
                    text: 'Set Time (00:00):'
                TextInput:
                    id: alarmtime
                    text: root.alarm_time
                ToggleButton:
                    text: 'AM'
                    group:'am/pm'
                    state: root.alarm_am_state
                    on_state: root.alarm_am_state = self.state
                ToggleButton:
                    text: 'PM'
                    group:'am/pm'
                    state: root.alarm_pm_state
                    on_state: root.alarm_pm_state = self.state
            Button:
                text: "Set Alarm"
                on_press: 
                    root.set_alarm()
                    root.manager.current = 'home_page'
    
    BoxLayout:
        ScreenManager:
            id: sm
            Home:
                name: 'home_page'
            AlarmPage:
                name: 'alarm_page'
            AlarmEdit:
                name: 'edit1_page'
            AlarmEdit:
                name: 'edit2_page'
        """
    
    
    class MyClock(Label):
        current_time = StringProperty(strftime("%I:%M:%S %p"))
    
        def __init__(self, **kwargs):
            Clock.schedule_interval(self.update_time, 1)
            super().__init__(**kwargs)
    
        def update_time(self, dt):
            self.current_time = strftime("%I:%M:%S %p")
            app = App.get_running_app()
            t1 = app.root.ids.sm.get_screen('edit1_page').alarm(self.current_time)
    
    
    class AlarmEdit(Screen):  # Moved to the screen
        alarm_time = StringProperty()
        alarm_am_state = StringProperty('down')  # set default values
        alarm_pm_state = StringProperty('normal')
        passed_alarm = StringProperty()
    
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            if os.path.isfile("alarm1_details.txt"):
                with open("alarm1_details.txt", "r") as f:
                    d = f.read().split(",")
                    self.alarm_time = d[0]
                    self.alarm_am_state = d[1]
                    self.alarm_pm_state = d[2]
    
        def set_alarm(self):
            self.alarm_time = self.ids.alarmtime.text
    
            with open("alarm1_details.txt", "w") as f:
                f.write(f"{self.ids.alarmtime.text},{self.alarm_am_state},{self.alarm_pm_state}")
    
        def alarm(self, current_time):
            am_pm = {'down': 'AM', 'normal': 'PM'}[self.alarm_am_state]
            a_time = f"{self.alarm_time}:00 {am_pm}"
    
            if a_time[1] == ':':
                a_time = "0" + a_time
    
            print(f"a: {a_time} ct: {current_time}")
            if a_time == current_time:
                popup = Popup(title='Alarm 1', content=Label(text=self.alarm_time), size_hint=(None, None), size=(400, 400))
                popup.open()
                sound = SoundLoader.load("fire-truck-air-horn_daniel-simion.wav")
                sound.play()
    
    
    class MyButton(ToggleButtonBehavior, Label, Image):
        def __init__(self, **kwargs):
            super(MyButton, self).__init__(**kwargs)
            self.source = 'atlas://data/images/defaulttheme/checkbox_off'
    
        def on_state(self, widget, value):
            if value == 'down':
                self.source = 'atlas://data/images/defaulttheme/checkbox_on'
            else:
                self.source = 'atlas://data/images/defaulttheme/checkbox_off'
    
    
    class MainApp(App):
        def build(self):
            return Builder.load_string(kv)
    
    
    if __name__ == "__main__":
        MainApp().run()

Thanks for the help yal!

Robert Flatt

unread,
Aug 12, 2020, 3:20:20 PM8/12/20
to Kivy users support
   if current_property[:3] == 'on_':
 TypeError: 'NoneType' object is not subscriptable

What is this telling me?

Subscripting selects a subset of a list,  a list of list elements is selected with the [:3]  syntax, exactly what that sub list is any web Python tutorial will tell you.
"object not subscriptable" means whatever is to the left of the [:3] is not a list, so you can not get its subscript.
So "current_property" is not a list, to understand what a list is see any Python tutorial ;)
'NoneType' means that "current_property" has not been assigned a value, so it has no type.
So there is no list to subscript which is the error. A type might be list, int, float, etc. (...Python tutorial...).

To fix this you need to know what "current_property" does and if you want that behavior in your code, if you want it then you must assign it an appropriate value.
A good study project :)

Elliot Garbus

unread,
Aug 12, 2020, 4:01:22 PM8/12/20
to kivy-...@googlegroups.com

This kind of error can be difficult to find.  It is an error from the kv parser.  It can be a problem with indentation.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/7708cb23-16ee-4fee-84e7-e5b4a53ab377o%40googlegroups.com.

 

Elliot Garbus

unread,
Aug 12, 2020, 4:27:10 PM8/12/20
to kivy-...@googlegroups.com

Two subtle mistakes.   The need to escape the \n is what caused the problems.

 

<AlarmEdit>:
    BoxLayout:
        orientation: 'vertical'
        ScrollView:
            do_scroll_x: False
            do_scroll_y: True
            Label:
                size_hint_y: None
                height: self.texture_size[1]
                text_size: self.width, None                # Missing , the y value for size
                padding: 2, 2
                text:'really some amazing text
\\n' * 50    # Need to escape the \n This is a string in a string.

 

 

From: Robert Flatt
Sent: Wednesday, August 12, 2020 12:20 PM
To: Kivy users support
Subject: [kivy-users] Re: How to use ScrollView in KV

 

   if current_property[:3] == 'on_':

--

Elliot Garbus

unread,
Aug 12, 2020, 4:32:28 PM8/12/20
to kivy-...@googlegroups.com

Yes,  You can put multiple scrollviews in one BoxLayout.

 

From: Abraham Francisco
Sent: Wednesday, August 12, 2020 11:56 AM
To: Kivy users support

--

You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.

Reply all
Reply to author
Forward
0 new messages