kivy 使用附加类来存储来自多个屏幕的数据

Posted

技术标签:

【中文标题】kivy 使用附加类来存储来自多个屏幕的数据【英文标题】:kivy using addtional class to store data from multiple screens 【发布时间】:2018-01-12 23:19:40 【问题描述】:

我想向我的 kivy 应用程序添加一个额外的类,它只是一个信息存储库。我不确定在哪里执行此操作,或者是否建议使用这种方法。

该应用有多个屏幕。每个屏幕都允许用户进行选择。用户的选择就是我想要存储在附加类中的内容。附加类将存储数据,然后最终使用 MQTT 将数据发送出去。另外,我想将类定义保存在一个单独的文件中,这样我就可以将程序组织成逻辑有序的块。

(请记住,我只分享了一小部分代码,但这应该足以表达我的问题)

我的 kivy python 代码:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from storage import Storage  # <<========================== this is the addtional class

# Screen Manager
class MyScreenManager(ScreenManager):
    pass


# Background Color
class BG(FloatLayout):
    pass


class VendorScreen(Screen):
    pass


class InvoiceScreen(Screen):
    def __init__(self, **kwargs):
        super(InvoiceScreen, self).__init__(**kwargs)
        self.invoice = ''

    def keyEntry(self, number):  # ............ Digit Pressed
        invoice = self.ids.invoice  # ......... link to kivy Label
        invoice.text += number  # ............. append number to invoice

    def keyBack(self):  # ..................... Backspace
        invoice = self.ids.invoice  # ......... link to kivy Label
        invoice.text = invoice.text[:-1]  # ... remove last digit

    def set_invoice(self):
        invoice = self.ids.invoice
        self.invoice = invoice.text


class MainControlScreen(Screen):
    pass


# Main-Execution
class mySuperApp(App):
    def build(self):
        return MyScreenManager()


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

我的kv码:

#:kivy 1.0.9

<MyScreenManager>:
    VendorScreen:  # ........ Incoming Delivery, Screen 2b
        name: 'vendor_screen'
    InvoiceScreen: # ........ .................. Screen 3b
        name: 'invoice_screen'
    MainControlScreen:  # ... .................. Screen 4b
        name: 'main_control_screen'

<BG>
    AsyncImage:
        source: 'img/screen1_background4.png'
        size_hint: 1, 1

<VendorScreen>
    BG:
    FloatLayout:
        Button:
            text: 'name1'
            color: 1.0, 0.6, 0.0, 1
            font_size: 40
            size_hint_x: 0.45
            size_hint_y: 0.35
            pos_hint: 'x': 0.03, 'y': 0.50
            on_release:
                root.manager.transition.direction = 'left'
                root.manager.current = 'invoice_screen'
        Button:
            text: 'name2'
            color: 1.0, 0.6, 0.0, 1
            font_size: 40
            size_hint_x: 0.45
            size_hint_y: 0.35
            pos_hint: 'x': 0.52, 'y': 0.50
            on_release:
                root.manager.transition.direction = 'left'
                root.manager.current = 'invoice_screen'
        Button:
            text: 'name3'
            color: 1.0, 0.6, 0.0, 1
            font_size: 40
            size_hint_x: 0.45
            size_hint_y: 0.35
            pos_hint: 'x': 0.03, 'y': 0.10
            on_release:
                root.manager.transition.direction = 'left'
                root.manager.current = 'invoice_screen'
        Button:
            text: 'name4'
            color: 1.0, 0.6, 0.0, 1
            font_size: 40
            size_hint_x: 0.45
            size_hint_y: 0.35
            pos_hint: 'x': 0.52, 'y': 0.10
            on_release:
                root.manager.transition.direction = 'left'
                root.manager.current = 'invoice_screen'

<InvoiceScreen>
    BG:
        canvas:
            Color:
                rgba: 0.90, 0.90, 0.90, 0.5
            Rectangle:
                pos: (40, 295)
                size: (320, 35)
            Color:
                rgba: 0, 0, 0, 1
            Line:
                points: 40, 295, 360, 295, 360, 330, 40, 330, 40, 295
                width: 1
    BoxLayout:
        orientation: 'horizontal'  # break it up into left / right
        FloatLayout:
            Label:
                pos_hint: 'x':0, 'y':.25
                font_size: 30
                text: 'Enter Invoice Number'
                color: 0.1, 0.1, 1, 1
            Label:
                id: invoice
                pos_hint: 'x':0, 'y':.15
                font_size: 30
                text: ''  # initially blank
                color: 0, 0, 0, 1
        GridLayout:
            cols: 3  # number of columns
            rows: 4  # number of rows
            Button:
                text: '1'
                on_release: root.keyEntry('1')
            Button:
                text: '2'
                on_release: root.keyEntry('2')
            Button:
                text: '3'
                on_release: root.keyEntry('3')
            Button:
                text: '4'
                on_release: root.keyEntry('4')
            Button:
                text: '5'
                on_release: root.keyEntry('5')
            Button:
                text: '6'
                on_release: root.keyEntry('6')
            Button:
                text: '7'
                on_release: root.keyEntry('7')
            Button:
                text: '8'
                on_release: root.keyEntry('8')
            Button:
                text: '9'
                on_release: root.keyEntry('9')
            Button:
                text: '< DEL'
                on_release: root.keyBack()
            Button:
                text: '0'
                on_release: root.keyEntry('0')
            Button:
                text: 'Done'
                on_release:
                    root.set_invoice()
                    root.manager.transition.direction = 'left'
                    root.manager.current = 'main_control_screen'

<MainControlScreen>
    BG:
        canvas:
            Color:
                rgba: 0, 0, 1, 1
            Line:
                points: 500, 180, 770, 180, 770, 450, 500, 450, 500, 180
                width: 3
    FloatLayout:
        Label:  # foreground
            pos_hint: 'x': 0.30, 'y': 0.13
            font_size: 80
            text: '5'
            color: 1.0, 0.6, 0.0, 1
        Button:
            size_hint_x: 0.2
            size_hint_y: 0.1
            pos_hint: 'x': 0.05, 'y': 0.05
            text: 'Auto-Reject'
            on_release:
                root.manager.transition.direction = 'up'
                root.manager.current = 'vendor_screen'
        Button:
            size_hint_x: 0.2
            size_hint_y: 0.1
            pos_hint: 'x': 0.75, 'y': 0.05
            text: 'Photo' 
            on_release:
                root.manager.transition.direction = 'left'
                root.manager.current = 'invoice_screen'

最后是我的额外课程:

from datetime import datetime, date
import calendar


class Storage(object):
    def __init__(self):
        self.invoice = 0
        self.unit_name = ''
        self.unit_number = ''
        self.receiver = ''
        self.vendor = ''
        self.day = calendar.day_name[date.today().weekday()]
        self.delivery_time = datetime.now()  
        self.package_condition = True
        self.email = ''
        self.location = ('32.0, -117.0',)
        self.duration = 0  
        self.img = 'img.jpg'

所以我的问题是,我在哪里以及如何使用我的附加类“存储”?我希望所有 kivy 类都能够访问它的单个实例,但我不知道该怎么做。

我尝试在 mySuperApp().run() 之前实例化一个类,但我无法在其他类中访问它。我尝试使用global 来访问该实例,但这不起作用。

我考虑过从类继承,但我不确定如何做到这一点...我从不同屏幕中的 Storage 继承开始,但是,这不允许我访问包含所有数据的单个实例是,我不得不从多个类中提取实例变量来收集完整的数据集。然后我尝试在 Storage 中继承 mySuperApp,然后从 Storage 中运行 ScreenManager,但这不起作用。它运行了,但我无法从其他类访问实例变量。也许我需要在所有其他类中继续从 Storage 继承?

我不确定如何处理这个问题,因为 kivy 部分只是程序的一小部分。最后,我将需要几个额外的课程,但我不明白如何或在哪里链接这些课程。获得概念后,我会将其应用于其他必要的课程,但我不知道从哪里开始。

【问题讨论】:

我刚刚了解了类变量。这似乎有效。我目前在我的所有屏幕类中都继承了 Storage。当我在屏幕之间移动时,我正在更新存储类变量,这给出了我想要的行为。 【参考方案1】:

您可以使用ScreenManager 共享数据。ScreenManager 将始终是所有屏幕的父级。 因此,您可以通过以下三种方式访问​​管理器。

root.manager:Screen 都有一个名为manager 的属性,即ScreenManager,这个Screen 就在其中。所以你可以像这样从任何屏幕访问它。

root.parent: 如果Widget 位于另一个小部件中,它们都将具有parent。在这种情况下,Screen 的父级是 ScreenManager。因此,您可以从任何这样的屏幕访问它。

app.root: 每个应用程序都有一个root。在这种情况下,应用程序的根是ScreenManager。所以你可以像这样从任何地方访问它。

试试这个例子,用三个按钮演示:

from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
from kivy.properties import StringProperty


class MyScreenManager(ScreenManager):
    shared_data = StringProperty("")


class Screen1(Screen):
    pass

class Screen2(Screen):
    pass


root = Builder.load_string('''

<Screen1>:
    name: "screen1"
    BoxLayout:
        orientation: "vertical"
        TextInput:
            on_text:
                root.manager.shared_data = self.text
        Label:
            text:
                root.manager.shared_data
        Button:
            text: "Go to screen2"
            on_release: root.manager.current = "screen2"

        Button:
            text: "root.manager.shared_data"
            on_release:
                print(root.manager.shared_data)
        Button:
            text: "root.parent.shared_data"
            on_release:
                print(root.parent.shared_data)
        Button:
            text: "app.root.shared_data"
            on_release:
                print(app.root.shared_data)



<Screen2>:
    name: "screen2"
    BoxLayout:
        orientation: "vertical"
        TextInput:
            on_text:
                root.manager.shared_data = self.text
        Label:
            text:
                root.manager.shared_data
        Button:
            text: "Go to screen1"
            on_release: root.manager.current = "screen1"


MyScreenManager:
    Screen1:
    Screen2:

''')



class MyApp(App):
    def build(self):
        return root

【讨论】:

在代码的 kivy 部分; Screen1,在任何小部件下,当您编写“root.manager.shared_data”时,“manager”是指类管理器还是内置调用?我正在使用您的示例,但稍作修改,我遇到了问题。 你能再举一个例子吗?在 screen1 上添加一个按钮,将“shared_data”的字符串文本简单地打印到控制台。我试过了,它返回 . @twegner 编辑并添加了三个按钮,解释了访问数据的三种不同方式。 这是一个绝妙的答案。我已经看到这些数据的片段分布在许多不同的文档中,但是将它们放在一个扩展的解释中确实可以清除这些东西。非常感谢! @twegner 很高兴它有帮助。谢谢。

以上是关于kivy 使用附加类来存储来自多个屏幕的数据的主要内容,如果未能解决你的问题,请参考以下文章

R Shiny 框中的可移动多个项目 - 类似于附加的屏幕截图

如何附加来自多个 csv 文件的值?

如何在房间数据库dao中附加两个或多个子查询,而这些子查询存储在变量中

JPA - 映射来自实体的附加计算值

使用 Caliburn.Micro 附加到多个事件

任何人都可以让我知道附加屏幕截图的编码格式是什么? [关闭]