0

I do not know that much python, so I don't know if this problem is more kivy or python. I want to call the parents' method on a click/press. But I cannot access a root object (AttributeError: 'IssueButton' object has no attribute 'root') nor a global variable that I defined earlier (NameError: name 'global_screen_manager' is not defined)

I am using a ScreenManager to switch Screens and I am using a ListView with ListAdapter to create these buttons that I want to call this method I am talking about. Another funny thing that I do not get is that this very button has several parents above it, like a GridLayout.

How can I define a root for this IssueButton at the bottom of the py-file? Is there another good way to call the method on-detail_press from IssueScreen? Is it ok to use a global for a ScreenManager or is there a preferred way to pass a reference?

Thanks in advance!

Here's my code: github.com/timokramer/repodigger

The py:

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

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.listview import ListItemButton
from kivy.properties import ObjectProperty, ListProperty
from kivy.network.urlrequest import UrlRequest
import re


class RepodiggerApp(App):

    def build(self):
        root = Manager()
        global global_screen_manager
        global_screen_manager = root
        return root


class Manager(ScreenManager):
    login_screen = ObjectProperty(None)
    issue_screen = ObjectProperty(None)
    detail_screen = ObjectProperty(None)
    burndown_screen = ObjectProperty(None)


class DetailScreen(Screen):

    def __init__(self, **kwargs):
        super(DetailScreen, self).__init__(**kwargs)

    def populate_details(self):
        pass


class BurndownScreen(Screen):
    def __init__(self, **kwargs):
        super(BurndownScreen, self).__init__(**kwargs)


class LoginScreen(Screen):
    def get_input(self, text_input):
        if text_input != "":
            self.parse_input(text_input)

    def parse_input(self, text_input):
        if re.search(".[/].", text_input):
            self.make_request(text_input)
        else:
            print("not a valid repo!")

    def make_request(self, text_input):
        headers = {'User-Agent': 'timokramer/repodigger'}
        req = UrlRequest(
            'https://api.github.com/repos/' + text_input + '/issues',
            on_success=self.parse_request,
            on_failure=self.parse_failure,
            on_error=self.parse_error,
            req_headers=headers,
            debug=True
        )
        req.wait()
        if req.is_finished:
            print("Request Finished")

    def parse_request(self, req, results):
        print('Succeeded requesting Github Issues')
        global_screen_manager.current = 'Issue Screen'
        global_screen_manager.get_screen('Issue Screen').build_issue_widgets(results)

    def parse_failure(self, req, result):
        print('There was a problem: "', result['message'], '"')

    def parse_error(self, req, error):
        print('There was an error: ', error)


class IssueScreen(Screen):
    my_item_strings = ListProperty([])

    def __init__(self, **kwargs):
        kwargs['cols'] = 1
        super(IssueScreen, self).__init__(**kwargs)

    def build_issue_widgets(self, issues):
        for issue in issues:
            if issue['state'] == 'open':
                self.my_item_strings.append(issue['title'])
        self.issues_list.item_strings = self.my_item_strings
        self.issues_list.adapter.data.clear()
        self.issues_list.adapter.data.extend(self.my_item_strings)
        self.issues_list._trigger_reset_populate()

    def on_burndown_press(self):
        global_screen_manager.current = 'Burndown Screen'

    def on_change_press(self):
        global_screen_manager.current = 'Login Screen'

    def on_detail_press(self):
        global_screen_manager.current = 'Detail Screen'
        global_screen_manager.get_screen('Detail Screen').populate_details()


class IssueButton(ListItemButton):
    def on_detail_press(self):
        print(self.parent)
        print(self.parent.parent)
        print(self.parent.parent.parent)
        print(self.parent.parent.parent.parent)
        print(self.parent.parent.parent.parent.parent)
        self.parent.parent.parent.parent.parent.on_detail_press()


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

The kv:

#: import Repodigger Repodigger
#: import ListAdapter kivy.adapters.listadapter.ListAdapter

<Manager>:
    id: screen_manager
    login_screen: login_screen
    issue_screen: issue_screen
    detail_screen: detail_screen
    burndown_screen: burndown_screen
    canvas.before:
        Color:
            rgba: .1, .1, .1, 1
        Rectangle:
            pos: self.pos
            size: self.size
    LoginScreen:
        id: login_screen
        name: 'Login Screen'
        manager: screen_manager
    IssueScreen:
        id: issue_screen
        name: 'Issue Screen'
        manager: screen_manager
    DetailScreen:
        id: detail_screen
        name: 'Detail Screen'
        manager: screen_manager
    BurndownScreen:
        id: burndown_screen
        name: 'Burndown Screen'
        manager: screen_manager

<BurndownScreen>:
    BoxLayout:
        id: burndown_screen
        Button:
            text: 'BURNDOWN!'

<IssueScreen>
    issues_list: issues_list
    BoxLayout:
        size_hint: 1, 1
        orientation: 'vertical'
        ListView:
            id: issues_list
            size_hint: 1, .8
            adapter:
                ListAdapter(data=[], cls=Repodigger.IssueButton)
        BoxLayout:
            orientation: 'horizontal'
            size_hint: 1, .05
            Button:
                size_hint: .2, 1
                text: "change Repository"
                on_press: root.on_change_press()
            Button:
                size_hint: .2, 1
                text: "show Burndown"
                on_press: root.on_burndown_press()

<IssueButton>:
    on_press: self.on_detail_press()

<DetailScreen>:
    BoxLayout:
        id: detail_screen
        orientation: 'vertical'
        Button:
            text: "Detail View"

<LoginScreen>:
    BoxLayout:
        id: login_screen
        size_hint: .7, .1
        pos_hint: {'center_x': .5, 'center_y': .3}
        rows:1
        Label:
            text: "Enter Github-Repo"
            text_size: self.width-10, self.height-10
            valign: 'middle'
            halign: 'center'
            size_hint_x: .3
        TextInput:
            id: text_input
            on_text_validate: root.get_input(self.text)
            text: ""
            hint_text: "eg. timokramer/repodigger"
            text_size: self.width-10, self.height-10
            valign: 'middle'
            halign: 'center'
            padding_y: ( self.height - self.line_height ) / 2
            size_hint_x: .5
            multiline: False
        Button:
            id: ok_button
            on_press: root.get_input(text_input.text)
            text: "OK"
            text_size: self.width-20, self.height-20
            valign: 'middle'
            halign: 'center'
            size_hint_x: .2
Totem
  • 7,189
  • 5
  • 39
  • 66
Timo
  • 320
  • 3
  • 14
  • how to use global in python http://stackoverflow.com/questions/4693120/use-of-global-keyword-in-python – kiok46 Jun 19 '15 at 19:13
  • I get a different error when I try to run your code. An exception trying to clear an ObservableList. You didn't say where you were getting the error, but your use of "root" looks fine to me. As for a global variable, I would avoid using globals, especially in kivy. You should instead put them in objects that will use them. If a lot of objects need to use something (like a screen manager), you should put it in the App class, which can be referenced from any widget. – bj0 Jun 19 '15 at 21:44
  • Thanks for the answers so far. @bj0: This error is new to me but it is still work in progress. I want to access the root at the bottom of the py-file where instead I used parent.parent.parent... Somehow I cannot access a root nor the global variable from inside there. – Timo Jun 20 '15 at 09:00
  • 1
    Your code is laid out in an uncoventional manner for kivy. It might even be causing you problems. I would have a look at tutorials on kivy.org to see a proper layout if I were you. In your kv file, any widget between < and > is a root widget. Within it's 'block' indented beneath it, referring to root will always refer to that widget. So doing, root.somefunc() beneath will call the function somefunc in the Manager class. This in turn could be set to trigger on the press of a button for example – Totem Jun 21 '15 at 14:22

0 Answers0