python - 从 Kivy 应用程序获取用户输入并使用 Python 附加到谷歌表格
问题描述
我正在尝试制作一个简单的 Python Kivy 应用程序(使用 kv 文件进行布局),我将使用它来保存我的零件库存以供工作。我对 python 和 kivy 很陌生,所以我需要一些指导。
基本功能之一是允许用户在“将零件添加到库存”屏幕(四个屏幕之一)上输入新零件。用户输入包括四个项目(零件名称、序列号、现有数量和所需的最低数量)。
一旦用户输入此信息并按下“提交”按钮,我希望将该数据附加到我使用 Google Drive/Sheets API(我是能够开始工作)。
我在网上找到的大多数示例应用程序只有一个屏幕,并且只处理一种类型的用户输入(通常是文本,而我的输入是文本和整数)。
我很困惑我需要将我的 id 放在 kv 文件中的哪个位置(我假设在 AddPartWindow 布局下),当按下不在根类中的按钮时如何调用函数,如何存储用户输入到列表中,因为我不确定 ObjectProperty 函数到底在做什么,最后,如何将该列表附加到我的谷歌表中的新行。
我不是在寻找剪切和粘贴的答案,只是一些方向会很好,因为我无法为我正在尝试做的事情找到一个好的参考。我的主要困惑在于拥有多个屏幕,以及如何在不同屏幕及其各自的类之间传输数据。数据是否应该只通过单个根类汇集?或者每个类都可以用来处理来自应用程序中各自屏幕(窗口)的数据吗?ObjectProperty 函数到底在做什么?我发现 kivy 网站在描述属性类时有点复杂。
任何帮助/方向将不胜感激。
这是 main.py 代码:
import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('My_First_Project-3d753d98320e.json', scope)
client = gspread.authorize(creds)
iQue_sheet = client.open("InventoryBackend").sheet1
#root layout
class InventoryWindow(Screen):
pass
#Layout in question
class AddPartWindow(Screen):
#Is there anything else I need to do with these before saving into a list or dictionary?
part_name = ObjectProperty(None)
serial_number = ObjectProperty(None)
on_hand_cnt = ObjectProperty(None)
min_needed = ObjectProperty(None)
#This function should save the user input into a list, np, and then append to the google sheet iQue_sheet
#Wasn't sure if it should be a list or a dictionary.
#I'm assuming .text is type-casting each object to a string. Can this be used for numerical inputs?
def new_part(self):
np = [self.part_name.text, self.serial_number.text, self.on_hand_cnt.text, self.min_needed.text]
iQue_sheet.append(np)
class OnOrderWindow(Screen):
pass
class OrderFormWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class InventoryApp(App):
def build(self):
#These are used to enable going back and forth between screens using buttons
sm = ScreenManager()
sm.add_widget(InventoryWindow(name='inv_window'))
sm.add_widget(OnOrderWindow(name='on_order_window'))
sm.add_widget(AddPartWindow(name='add_part_window'))
sm.add_widget(OrderFormWindow(name='order_form_window'))
return sm
if __name__ == "__main__":
InventoryApp().run()
这是我的 .kv 布局文件,Add Part 窗口是最后一个布局:
WindowManager:
InventoryWindow:
OnOrderWindow:
OrderFormWindow:
AddPartWindow:
<ItemLabel@Label>
font_size: '15sp'
halign: 'left'
valign: 'middle'
text_size: self.size
<ItemButton@Button>
pos_hint: {'center_x':0.5, 'center_y':0.5}
size_hint: 0.65, 0.2
<ItemButton2@Button>
pos_hint: {'center_x':0.5, 'center_y':0.5}
size_hint: 0.65, 0.2
on_release:
app.root.current = "order_form_window"
<InventoryWindow>:
name: "inv_window"
add_probe: add_probe
FloatLayout:
Label:
text: 'Inventory'
font_size: '25sp'
size_hint: (1, 0.17)
pos_hint: {'x': 0, 'y': 0.87}
GridLayout:
cols: 4
padding:[10, 65, 10, 10]
spacing: 5
BoxLayout:
orientation: 'vertical'
ItemLabel:
text:'iQue3: Probe/Tubing'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Add'
on_release:
root.new_part()
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Sub'
BoxLayout:
orientation: 'vertical'
ItemButton2:
text:'Order'
BoxLayout:
orientation: 'vertical'
ItemLabel:
text:'Gen2: Probe/Tubing'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Add'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Sub'
BoxLayout:
orientation: 'vertical'
ItemButton2:
text:'Order'
BoxLayout:
orientation: 'vertical'
ItemLabel:
text:'Beads'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Add'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Sub'
BoxLayout:
orientation: 'vertical'
ItemButton2:
text:'Order'
BoxLayout:
orientation: 'vertical'
ItemLabel:
text:'iQue3 Fluid Maint. Kit'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Add'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Sub'
BoxLayout:
orientation: 'vertical'
ItemButton2:
text:'Order'
BoxLayout:
orientation: 'vertical'
ItemLabel:
text:'Screener Fluid Maint. Kit'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Add'
BoxLayout:
orientation: 'vertical'
ItemButton:
text:'Sub'
BoxLayout:
orientation: 'vertical'
ItemButton2:
text:'Order'
BoxLayout:
orientation: 'vertical'
GridLayout:
cols: 2
size_hint: 1, 0.15
padding: [10, 0, 10, 10]
BoxLayout:
Button:
text: 'Add Part to Inventory'
font_size: '18sp'
size_hint: (1, 0.75)
on_release:
app.root.current = "add_part_window"
root.manager.transition.direction = "right"
Button:
text: 'On Order'
font_size: '18sp'
size_hint: (1, 0.75)
on_release:
app.root.current = "on_order_window"
root.manager.transition.direction = "left"
<OnOrderWindow>:
name: "on_order_window"
FloatLayout:
Label:
text: 'On Order'
font_size: '25sp'
size_hint: (1, 0.17)
pos_hint: {'x': 0, 'y': 0.87}
GridLayout:
cols: 2
size_int: 1, .15
padding:[10, 510, 10, 10]
Button:
text: "Inventory"
font_size: '18sp'
size_hint: (1, 0.6)
on_release:
app.root.current = "inv_window"
root.manager.transition.direction = "right"
Button:
text:"Add Part to Inventory"
size_hint: (1, 0.6)
font_size: '18sp'
on_release:
app.root.current = "add_part_window"
root.manager.transition.direction = "left"
<OrderFormWindow>
name: "order_form_window"
FloatLayout:
Label:
text: 'Order Form'
font_size: '25sp'
size_hint: (1, 0.17)
pos_hint: {'x': 0, 'y': 0.87}
GridLayout:
cols:2
padding: [50, 50, 50, 120]
ItemLabel:
text: "Part: "
ItemLabel:
text: "Populate Part Here"
ItemLabel:
text: "Serial Number: "
ItemLabel:
text: "Populate SN Here"
ItemLabel:
text: "On Hand: "
ItemLabel:
text: "Populate On Hand Count Here"
ItemLabel:
text: "Minimum Needed: "
ItemLabel:
text: "Populate Min Needed Here"
ItemLabel:
text: "Order Quantity"
TextInput:
halign: 'left'
valign: 'middle'
input_type: 'number'
input_filter: 'int'
multiline:False
GridLayout:
cols:2
size_hint: 1, 0.15
padding: [10, 0, 10, 10]
Button:
text:"Cancel"
on_release: app.root.current = "inv_window"
Button:
text:"Submit Order"
on_release: app.root.current = "on_order_window"
#This is the add part screen layout I'm referring to
<AddPartWindow>
name: "add_part_window"
#These are the id's I was referring to:
part_name: part_name
serial_number: serial_number
on_hand_cnt: on_hand_cnt
min_needed: min_needed
FloatLayout:
Label:
text: 'Add Part to Inventory'
font_size: '25sp'
size_hint: (1, 0.17)
pos_hint: {'x': 0, 'y': 0.86}
GridLayout:
cols:2
padding: [50, 100, 50, 120]
spacing: 5
ItemLabel:
text: "Name of Part: "
TextInput:
id: part_name
halign: 'left'
valign: 'middle'
multinline:False
ItemLabel:
text: "Serial Number: "
TextInput:
id: serial_number
halign: 'left'
valign: 'middle'
multiline:False
ItemLabel:
text: "How Many On Hand?: "
TextInput:
id: on_hand_cnt
halign: 'left'
valign: 'middle'
multinline:False
ItemLabel:
text: "Minimum Needed?: "
TextInput:
id: min_needed
halign: 'left'
valign: 'middle'
multiline:False
GridLayout:
cols:2
size_hint: 1, 0.15
padding: [10, 0, 10, 10]
Button:
text:"Cancel"
on_release:
app.root.current = "inv_window"
root.manager.transition.direction = "left"
#Here is the button I'm referring to, I realize that putting "root." in front of new_part() is not
#the correct thing to put, so it's a placeholder for now:
Button:
text:"Submit"
on_release:
root.new_part()
app.root.current = "inv_window"
root.manager.transition.direction = "left"
当我在四个字段中输入输入并单击提交按钮时,我得到的当前错误是:
File "C:\Users\edr27\kivy_venv\lib\site-packages\kivy\uix\behaviors\button.py", line 179, in on_touch_up
self.dispatch('on_release')
File "kivy\_event.pyx", line 705, in kivy._event.EventDispatcher.dispatch
File "kivy\_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
File "kivy\_event.pyx", line 1132, in kivy._event.EventObservers._dispatch
File "C:\Users\edr27\kivy_venv\lib\site-packages\kivy\lang\builder.py", line 57, in custom_callback
exec(__kvlang__.co_value, idmap)
File "C:\Users\edr27\PycharmProjects\pythonProject\inventory.kv", line 345, in <module>
root.new_part()
File "C:\Users\edr27\PycharmProjects\pythonProject\main.py", line 35, in new_part
np = [self.part_name.text, self.serial_number.text, self.on_hand_cnt.text, self.min_needed.text]
AttributeError: 'NoneType' object has no attribute 'text'
编辑:
以下是我如何实现 Oussama 的答案以使其正常工作,我所要做的就是更新 AddPartWindow 类:
class AddPartWindow(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.np = []
def submit(self):
self.part_name = self.ids.part_name.text
self.serial_number = self.ids.serial_number.text
self.on_hand_cnt = self.ids.on_hand_cnt.text
self.min_needed = self.ids.min_needed.text
self.np = [self.part_name, self.serial_number, self.on_hand_cnt, self.min_needed]
iQue_sheet.append_row(self.np)
我还进行了此更改,以便附加到工作簿的第 3 页而不是第 1 页:
iQue_sheet = client.open("InventoryBackend").get_worksheet(2)
解决方案
这个 main.py 可以随意导入你需要的东西。这是你想做的一个简单的例子
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.app import App
Builder.load_file('the.kv')
class fscreen(widget):
def __init__(self, **kwargs):
supper().__init__(**kwargs)
self.np = []
def submit(self):
self.part_name = self.ids.Pname.text
self.serial_number = self.ids.Snumber.text
self.on_hand_cnt = self.ids.onhabdcnt.text
self.min_needed = self.ids.minneeded.text
self.np = [self.part_name, self.serial_number, self.on_hand_cnt, self.min_needed]
iQue_sheet.append(self.np)
class secscreen(widget):
def __init__(self, **kwargs):
supper().__init__(**kwargs)
pass
class thscreen(widget):
def __init__(self, **kwargs):
supper().__init__(**kwargs)
pass
class theapp(App):
def build(self):
self.screenm = ScreenManager()
self.screen = Screen(name = "first screen")
screen.add_widget(self.fscreen)
self.screenm.add_widget(screen)
if __name__ = "__main__":
theapp.run()
这是.kv文件
<fscreen>
TextInput:
id: Pname
hint_text: 'partname'
TextInput:
id: Snumber
hint_text: 'serialnumber'
TextInput:
id: onhandcnt
hint_text: 'on hand cnt'
TextInput:
id: minneeded
hint_text: 'min nedded'
Button:
text: 'Submit'
on_press: root.submit()
推荐阅读
- javascript - 如何让函数等到前一行代码完成
- python - CART_SESSION_ID 持有什么?
- c# - 如何在简单的计算器中将 Console.ReadLine() 转换为 double ?C# 异常问题
- firebase - Bigquery crashlytics 数据集计划间隔
- python - 将新值分配给特定索引处的张量
- python - 如何在 Django admin 中将内联 ForeignKey 查询集限制为实例本身
- intellij-idea - Intellij Idea 调试无法访问 maven 存储库:连接被拒绝
- javascript - 从图像 url 创建文件对象
- ios - 如何将 iphone 连接到在 mac 上运行的本地服务器?
- package - PSM 封装的替代方案