ScreenManager Produces Duplicate Screen

74 views
Skip to first unread message

Timothy King

unread,
Dec 31, 2019, 8:57:06 PM12/31/19
to Kivy users support
I'm trying to create an app with 2 screens. The "list" screen shows Congress members in a tabbed panel and the "details" screen will show information about the selected member. When I run the app, I get a duplicate "list" screen like so:

Screenshot from 2019-12-31 17-43-53.png


Here is the .py file (sorry, you can't run the code because API key is needed):


from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.screenmanager import ScreenManager, Screen

import config
from congress import Congress

class ListScreen(Screen):
    pass

class DetailScreen(Screen):
    pass

class ScreenManagement(ScreenManager):
    pass

class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                 RecycleBoxLayout):
    ''' Adds selection and focus behaviour to the view. '''
   
class SelectableLabel(RecycleDataViewBehavior, Label):
    ''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableLabel, self).refresh_view_attrs(
            rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected
        if is_selected:
            print("selection changed to {0}".format(rv.data[index]))
        else:
            print("selection removed for {0}".format(rv.data[index]))

class OpenCongress(BoxLayout):
    API_KEY = config.APP_CONFIG['api_key']
    dictSenate = {}
    dictHouse = {}

    def __init__(self, **kwargs):
        # super(OpenCongress, self).__init__(**kwargs)
        super().__init__()

        self.congress = Congress(self.API_KEY)
        self.getChamberList('senate')
        self.getChamberList('house')

    def getChamberList(self, chamber):
        all_members = self.congress.members.filter(chamber)

        # print (all_members)
        num_results = int(all_members[0]['num_results'])

        member_list = all_members[0]['members']

        i = 0
        while i < num_results:
            first_name = member_list[i]['first_name']
            last_name = member_list[i]['last_name']
            state = member_list[i]['state']
            party = member_list[i]['party']
            memberLine = str.format('%s %s (%s) %s' % (first_name, last_name, party, state))

            if chamber == 'senate':
                self.dictSenate[i] = member_list[i]['id']
                self.rv.data.append({'text': memberLine})
            else:
                self.dictHouse[i] = member_list[i]['id']
                self.rv2.data.append({'text': memberLine})

            i += 1

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

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

 
#:kivy 1.0.9
<ScreenManagement>:
    ListScreen:
        name: 'list'
    DetailScreen:
        name: 'detail'
 
<ListScreen>:
    OpenCongress:

<DetailScreen>:
    BoxLayout:
        Button:
            text: 'Go To Main'
            on_press: app.root.current = 'list'
 
<SelectableLabel>:
    canvas.before:
        Color:
            rgba: (128, 0, 128, .1) if self.selected else (128, 128, 128, .3)
        Rectangle:
            size: self.size
            pos: self.pos
    value: ''
    Label:
        text: root.value

<OpenCongress>:
    rv: rv
    rv2: rv2
    orientation: 'vertical'

    BoxLayout:
        orientation: 'horizontal'
        height: dp(30)
        size_hint_y: None
        rows: 1
        TextInput:
            id: search_chamber
            height: dp(30)
            hint_text: 'Search'
            multiline: False
            padding: dp(5), dp(5), 0, 0

    TabbedPanel:
        do_default_tab: False

        TabbedPanelItem:
            text:"Senate"

            RecycleView:
                id: rv
                scroll_type: ['bars', 'content']
                scroll_wheel_distance: dp(128)
                bar_width: dp(10)
                viewclass: 'SelectableLabel'

                SelectableRecycleBoxLayout:
                    default_size: None, dp(56)
                    default_size_hint: 1, None
                    size_hint_y: None
                    height: self.minimum_height
                    orientation: 'vertical'
                    spacing: dp(2)

        TabbedPanelItem:
            text:"House"

            RecycleView:
                id: rv2
                scroll_type: ['bars', 'content']
                scroll_wheel_distance: dp(128)
                bar_width: dp(10)
                viewclass: 'SelectableLabel'

                SelectableRecycleBoxLayout:
                    default_size: None, dp(56)
                    default_size_hint: 1, None
                    size_hint_y: None
                    height: self.minimum_height
                    orientation: 'vertical'
                    spacing: dp(2)

    Button:
        text: 'Go To Detail'
        size_hint_y: None
        on_press: app.root.current = 'detail'
         

 Any assistance will be much appreciated.

Elliot Garbus

unread,
Jan 1, 2020, 1:02:22 PM1/1/20
to kivy-...@googlegroups.com
Create a runnable example, and I’ll be happy to help. 

Sent from my iPad

On Dec 31, 2019, at 6:57 PM, Timothy King <timc...@gmail.com> wrote:


I'm trying to create an app with 2 screens. The "list" screen shows Congress members in a tabbed panel and the "details" screen will show information about the selected member. When I run the app, I get a duplicate "list" screen like so:

--
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/d15c56da-a411-42f6-9b42-7bebed5f5ca7%40googlegroups.com.
<Screenshot from 2019-12-31 17-43-53.png>

Timothy King

unread,
Jan 1, 2020, 2:36:32 PM1/1/20
to Kivy users support
Here is the code with the API key. You will need to do a 'pip install python-congress'. Thanks in advance.

main.py

    # API_KEY = config.APP_CONFIG['api_key']
    API_KEY = 'yVbIvFN2w9CBAvRLcTHheLYA4o8mDmjJqPlpagma'

-----------------------------------------------------------------------
opencongress.kv

#:kivy 1.10

<ScreenManagement>:
    ListScreen:
        name: 'list'
    DetailScreen:
        name: 'detail'
 
<ListScreen>:
    OpenCongress:

<DetailScreen>:
    BoxLayout:
        Button:
            text: 'Go To Main'
            on_press: app.root.current = 'lis
  
<SelectableLabel>:
    canvas.before:
        Color:
            rgba: (128, 0, 128, .1) if self.s
        Rectangle:
            size: self.size
            pos: self.pos
    value: ''
    Label:
        text: root.value

<OpenCongress>:
    rv: rv
    rv2: rv2
    orientation: 'vertical'

    BoxLayout:
        orientation: 'horizontal'
        height: dp(30)
        size_hint_y: None
        rows: 1

        TextInput:
            id: search_chamber
            height: dp(30)
            hint_text: 'Search'
            size_hint_y: None
            multiline: False
            padding: dp(5), dp(5), 0, 0

    TabbedPanel:
        do_default_tab: False

        TabbedPanelItem:
            text:"Senate"

            RecycleView:
                id: rv
                scroll_type: ['bars', 'conten
                scroll_wheel_distance: dp(128
                bar_width: dp(10)
                viewclass: 'SelectableLabel'

                SelectableRecycleBoxLayout:
                    default_size: None, dp(56
                    default_size_hint: 1, Non
                    size_hint_y: None
                    height: self.minimum_heig
                    orientation: 'vertical'
                    spacing: dp(2)

        TabbedPanelItem:
            text:"House"

            RecycleView:
                id: rv2
                scroll_type: ['bars', 'conten
                scroll_wheel_distance: dp(128
                bar_width: dp(10)
                viewclass: 'SelectableLabel'

                SelectableRecycleBoxLayout:
                    default_size: None, dp(56
                    default_size_hint: 1, Non
                    size_hint_y: None
                    height: self.minimum_heig
                    orientation: 'vertical'
                    spacing: dp(2)

    Button:
        text: 'Go To Detail'
        size_hint_y: None
        on_press: app.root.current = 'detail'
-----------------------------------------------------------------------------

Elliot Garbus

unread,
Jan 1, 2020, 4:06:00 PM1/1/20
to kivy-...@googlegroups.com

The core issue is you are automatically pulling in the kv file – because it matches the name of the App, and you are instancing the app in the return from build.

 

I recommend, not returning anything from build() and instance your layout in the kv file.

This me create a root widget in the kv file, not just rules.

 

At the bottom of your kv file simply add:

 

ScreenManagement:

 

This will instance the screen.

--

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.

Timothy King

unread,
Jan 1, 2020, 7:10:37 PM1/1/20
to Kivy users support
I changed:

class OpenCongressApp(App):
   
def build(self):
       
return OpenCongress()


To:

class OpenCongressApp(App):
   
pass


And added "ScreenManager:" to the end of the kv file, but I'm still getting the duplicate screen. Thanks again for your help.

On Tuesday, December 31, 2019 at 5:57:06 PM UTC-8, Timothy King wrote:

Elliot Garbus

unread,
Jan 1, 2020, 7:33:26 PM1/1/20
to kivy-...@googlegroups.com
Attach the files, rather than cutting and pasting. I’ll give it a try. 

Sent from my iPhone

On Jan 1, 2020, at 5:10 PM, Timothy King <timc...@gmail.com> wrote:


--
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.

Timothy King

unread,
Jan 1, 2020, 8:43:13 PM1/1/20
to Kivy users support
Files are attached. Thanks.


On Tuesday, December 31, 2019 at 5:57:06 PM UTC-8, Timothy King wrote:
main.py
opencongress.kv

Elliot Garbus

unread,
Jan 1, 2020, 10:48:34 PM1/1/20
to Kivy users support
A few changes attached.
I've made some comments where I made changes.

class OpenCongress(BoxLayout):
...

def __init__(self, **kwargs):
# super(OpenCongress, self).__init__(**kwargs)
        super().__init__(**kwargs)  # ***** **kwargs was missing *************

This is why you had things 'doubled'.
rv was not initialized at the time this constructor runs, so I moved calls to on_start()
# self.getChamberList('senate')
# self.getChamberList('house')
# ***** rv is not yet initialized at initialization, called at on_start()
main.py
opencongress.kv

Timothy King

unread,
Jan 2, 2020, 12:27:18 PM1/2/20
to Kivy users support
Thank you so much for your help.


On Tuesday, December 31, 2019 at 5:57:06 PM UTC-8, Timothy King wrote:
Reply all
Reply to author
Forward
0 new messages