在python中将def从一个类调用到另一个类

时间:2018-01-19 13:18:20

标签: python kivy kivy-language

我有两个文件demo.pydemo.kv 谁能告诉我如何将函数从一个类调用到另一个类?我想从def calculate(self):调用def on_text(self, text_input, value):。现在我正在使用代码

def on_text(self, text_input, value):
    App.get_running_app().User.calculate()

但是它给出了错误AttributeError:'测试'对象没有属性'用户'

demo.py

from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.uix.popup import Popup

Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (500, 400)

class User(Popup):
    total_value = ObjectProperty(None)

    def add_more(self):
        self.ids.rows.add_row()

    def calculate(self):
        rows = self.ids.rows
        total = 0
        for row in rows.children:
            text = row.ids.number_input.text
            total += int(text) if text != "" else 0  # validate if the entry is not empty
        self.total_value.text = str(total)

class Row(BoxLayout):
    col_data = ListProperty(["?", "?", "?", "?", "?"])
    button_text = StringProperty("")
    col_data3 = StringProperty("")
    col_data4 = StringProperty("")

    def __init__(self, **kwargs):
        super(Row, self).__init__(**kwargs)
        self.ids.number_input.bind(text=self.on_text)

    def on_text(self, text_input, value):
        print('Calling')
        App.get_running_app().User.calculate()



class Rows(BoxLayout):
    row_count = 0

    def __init__(self, **kwargs):
        super(Rows, self).__init__(**kwargs)
        self.add_row()

    def add_row(self):
        self.row_count += 1
        self.add_widget(Row(button_text=str(self.row_count)))


class rv(BoxLayout):
    data_items = ListProperty([])
    mode = StringProperty("")

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


    def add(self):
        self.mode = "Add"
        popup = User()
        popup.open()


class MainMenu(BoxLayout):
    content_area = ObjectProperty()

    def display(self):
        self.rv = rv()
        self.content_area.add_widget(self.rv)

class Test(App):

    def build(self):
        self.root = Builder.load_file('demo.kv')
        return MainMenu()


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

demo.kv

<Row>:
    size_hint_y: None
    height: self.minimum_height
    height: 40

    Button:
        text: root.button_text
        size_hint_x: None
        top: 200

    TextInput:
        text: root.col_data3
        width: 300
    TextInput:
        id: number_input
        text: root.col_data4
        width: 300
        input_filter: 'int'


<Rows>:
    size_hint_y: None
    height: self.minimum_height
    orientation: "vertical"

<User>:
    id: user
    total_value:total_value
    BoxLayout:
        orientation: "vertical"
        padding : 20, 5


        BoxLayout:
            orientation: "horizontal"
            #padding : 10, 10
            spacing: 10, 10
            size: 450, 40
            size_hint: None, None

            Label:
                size_hint_x: .2
                text: "Number"
                text_size: self.size
                valign: 'bottom'
                halign: 'center'

            Label:
                size_hint_x: .4
                text: "name"
                text_size: self.size
                valign: 'bottom'
                halign: 'center'

            Label:
                size_hint_x: .4
                text: "Value"
                text_size: self.size
                valign: 'bottom'
                halign: 'center'




        ScrollView:
            Rows:
                id: rows

        BoxLayout:
            orientation: "horizontal"
            padding : 10, 5
            spacing: 10, 10
            size: 200, 40
            size_hint: None, None

            Label:
                size_hint_x: .7
                text: "Total value"

            TextInput:
                id: total_value
                on_focus:root.test()



        BoxLayout:
            orientation: "horizontal"
            size_hint_x: .2
            size_hint_y: .2

            Button:
                text: "+Add More"
                on_press: root.add_more()

<rv>:
    BoxLayout:
        orientation: "vertical"

        Button:
            size_hint: .25, .03
            text: "+Add"
            on_press: root.add()

        GridLayout:
            size_hint: 1, None
            size_hint_y: None
            height: 25
            cols: 3

        BoxLayout:
            orientation: "vertical"

<MenuButton@Button>:
    text_size: self.size
    valign: "middle"
    padding_x: 5
    size : (100, 40)
    size_hint : (None, None)
    background_color: 90 , 90, 90, 90
    background_normal: ''
    color: 0, 0.517, 0.705, 1
    border: (0, 10, 0, 0)

<MainMenu>:
    content_area: content_area

    BoxLayout:
        orientation: 'vertical'
        spacing : 10

        BoxLayout:
            canvas.before:
                Rectangle:
                    pos: self.pos
                    size: self.size

            size_hint_y: 2

            MenuButton:
                text: 'Menu'
                size : (50, 12)
                on_release: root.display()

        BoxLayout:
            id: content_area
            size_hint_y: 30

2 个答案:

答案 0 :(得分:1)

在不访问kivy层次结构树的情况下解决此问题的一种方法是使用全局变量,但建议不要滥用此类变量,因为其滥用所产生的错误很难跟踪。

[...]
class Row(BoxLayout):
    [...]

    def on_text(self, text_input, value):
        print('Calling')
        popup.calculate()

class rv(BoxLayout):
    [...]
    def add(self):
        self.mode = "Add"
        global popup
        popup = User()
        popup.open()
[...]

答案 1 :(得分:1)

这可能与此问题重复:Im New on kivy Python classes

首先:

class Test(App):

    def build(self):
        self.root = Builder.load_file('demo.kv')
        return MainMenu()

这有点不必要,你可以改为:

class demo(App):

    def build(self):
        return MainMenu()

应用程序搜索小写名称等于应用程序名称的kv文件。

其次:

<User>:
    id: user
    total_value:total_value

这不是你在kivy Widgets中使用id的方式。当您定义Kivy Widget时,即:

class KivyWidgetName(KivyLayout):
    pass

<KivyWidgetName>:

您正在创建课程。将自定义窗口小部件添加到父窗口小部件时,您将创建该KivyWidget类的对象。然而,有时候如果你不止一个,你需要给它们id,这样它们的父母就可以将它们彼此分开。

即:

<RootWidget>:
    KivyWidgetName:
        id: first_instance
    KivyWidgetName:
        id: second_instance

所以现在RootWidget可以访问该类的两个不同版本,如果它想要访问第一个版本,它可以这样做:

self.ids.first_instance

您也可以通过它们出现的索引号来访问它们,所以这个 也可以通过以下方式完成:

self.ids[1]

然而,显式通常比隐式

更好

第三,你对此有正确的想法:

App.get_running_app().User.calculate()

但它应该是这样的:

App.get_running_app().root.ids.[INSERTID]

因此,在这种情况下,您正在获取应用程序的根小部件(即),然后您需要使用ID来获取正确的地址。

例如,拿这个:

:     用户:         id:&#39; user_one&#39;     用户:         id:&#39; user_two&#39;

要访问用户计算功能,您可以执行以下操作:

App.get_running_app().root.ids.user_one.calculate

如果您有许多孩子,在找到用户之前,您必须寻找他们的所有ID:

例如:

<TestWidget>:
    User:
        id: 'user_one'
    User:
        id: 'user_two'

<RootWidget>:
    TestWidget:
        id: 'test_one'
    TestWidget:
        id: 'test_two'

因此,要获得测试二的用户之一,您可以这样做:

App.get_running_app()。root.ids.test_two.ids.user_one.calculate

你可能需要重新安排你的rootwidget是一个只包含你的主菜单的东西,以帮助你解决这个问题,但这个决定最终取决于你。