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”的字符串文本简单地打印到控制台。我试过了,它返回以上是关于kivy 使用附加类来存储来自多个屏幕的数据的主要内容,如果未能解决你的问题,请参考以下文章
R Shiny 框中的可移动多个项目 - 类似于附加的屏幕截图