我试图用Kivy编写一个计算器GUI。
这是代码:
experiment.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, NumericProperty, BooleanProperty, StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
import calculator_calc
Builder.load_file("calculatorgui.kv")
class CalculatorScreen1(Screen):
pass
class CalculatorScreen2(Screen):
pass
class CalculatorModeIndicator(BoxLayout):
pass
class CalculatorMonitor1(BoxLayout):
pass
class CalculatorButtons(BoxLayout):
pass
screen_manager = ScreenManager()
screen_manager.add_widget(CalculatorScreen1(name = "screen1"))
screen_manager.add_widget(CalculatorScreen2(name = "screen2"))
class Calculator(App):
expression_tokens = ListProperty([])
expression_value = StringProperty("")
angle_mode = StringProperty("degrees")
angle_mode_text = StringProperty("D")
button_mode = NumericProperty(1)
button_mode_text = StringProperty("1ST")
store_mode = BooleanProperty(False)
def build(self):
return screen_manager
def switch_screen(self, screen):
screen_manager.current = screen
def set_button_mode(self, button_mode):
self.button_mode = button_mode
if button_mode == 1:
self.button_mode_text = "1ST"
elif button_mode == 2:
self.button_mode_text = "2ND"
elif button_mode == 3:
self.button_mode_text = "3RD"
def set_angle_mode(self, angle_mode):
calculator_calc.evaluate(f"angle_mode {angle_mode}")
self.angle_mode = angle_mode
if angle_mode == "degrees":
self.angle_mode_text = "D"
elif angle_mode == "radians":
self.angle_mode_text = "R"
elif angle_mode == "gradians":
self.angle_mode_text = "G"
def add_token(self, token):
self.expression_tokens.append(token)
def calculate(self, expression):
result = calculator_calc.evaluate(expression)
self.expression_value = str(result)
calculator_calc.evaluate(f"ANS = {result}")
Calculator().run()
calculatorgui.kv
#:kivy 1.11.1
<CalculatorScreen1>:
BoxLayout:
orientation: "vertical"
CalculatorModeIndicator:
CalculatorMonitor1:
CalculatorButtons:
<CalculatorScreen2>:
BoxLayout:
orientation: "vertical"
Label:
text: "This is Screen 2"
Button:
text: "Screen2"
on_press: app.switch_screen("screen1")
<CalculatorModeIndicator>:
Label:
size_hint_x: None
width: "30dp"
text: app.button_mode_text
Label:
size_hint_x: None
width: "30dp"
text: app.angle_mode_text
<CalculatorMonitor1>:
orientation: "vertical"
Label:
size_hint_y: None
height: "30dp"
text_size: self.size
halign: "left"
valign: "top"
text: '"".join(app.expression_tokens)'
Label:
size_hint_y: None
height: "30dp"
text_size: self.size
halign: "right"
valign: "bottom"
text: 'app.expression_value'
<CalculatorButtons>:
orientation: "vertical"
BoxLayout:
Button:
text: "1ST"
on_press: app.set_button_mode(1)
Button:
text: "2ND"
on_press: app.set_button_mode(2)
Button:
text: "3RD"
on_press: app.set_button_mode(3)
BoxLayout:
Button:
text: "DEGREES"
on_press:
app.set_angle_mode("degrees")
Button:
text: "RADIANS"
on_press:
app.set_angle_mode("radians")
Button:
text: "GRADIANS"
on_press:
app.set_angle_mode("gradians")
BoxLayout:
Button:
text: "A"
on_press: app.add_token(self.text) if not app.store_mode else app.store("A")
Button:
text: "B"
on_press: app.add_token(self.text) if not app.store_mode else app.store("B")
Button:
text: "C"
on_press: app.add_token(self.text) if not app.store_mode else app.store("C")
Button:
text: "D"
on_press: app.add_token(self.text) if not app.store_mode else app.store("D")
Button:
text: "E"
on_press: app.add_token(self.text) if not app.store_mode else app.store("E")
# BoxLayout:
# Button:
# text: "sin" if app.button_mode == 1 else "asin" if app.button_mode == 2 else "sinh"
# on_press: app.add_token(f"{self.text}(")
# Button:
# text: "cos" if app.button_mode == 1 else "acos" if app.button_mode == 2 else "cosh"
# on_press: app.add_token(f"{self.text}(")
# Button:
# text: "tan" if app.button_mode == 1 else "atan" if app.button_mode == 2 else "tanh"
# on_press: app.add_token(f"{self.text}(")
# Button:
# text: "log"
# on_press: app.add_token(self.text + "(")
# Button:
# text: "ln"
# on_press: app.add_token(self.text + "(")
BoxLayout:
Button:
text: "("
on_press: app.add_token(self.text)
Button:
text: ")"
on_press: app.add_token(self.text)
Button:
text: "STO"
on_press: app.store_mode = True
Button:
text: "swt"
on_press: app.switch_screen("screen2")
Button:
text: ","
on_press: app.add_token(self.text)
BoxLayout:
Button:
text: "7"
on_press: app.add_token(self.text)
Button:
text: "8"
on_press: app.add_token(self.text)
Button:
text: "9"
on_press: app.add_token(self.text)
Button:
text: "DEL"
on_press: app.expression_tokens = app.expression_tokens[:-1]
Button:
text: "AC"
on_press:
app.expression_tokens = []
BoxLayout:
Button:
text: "4"
on_press: app.add_token(self.text)
Button:
text: "5"
on_press: app.add_token(self.text)
Button:
text: "6"
on_press: app.add_token(self.text)
Button:
text: "*"
on_press: app.add_token(self.text)
Button:
text: "/"
on_press: app.add_token(self.text)
BoxLayout:
Button:
text: "1"
on_press: app.add_token(self.text)
Button:
text: "2"
on_press: app.add_token(self.text)
Button:
text: "3"
on_press: app.add_token(self.text)
Button:
text: "+"
on_press: app.add_token(self.text)
Button:
text: "-"
on_press: app.add_token(self.text)
BoxLayout:
Button:
text: "0"
on_press: app.add_token(self.text)
Button:
text: "000"
on_press: app.add_token(self.text)
Button:
text: "."
on_press: app.add_token(self.text)
Button:
text: "ANS"
on_press: app.add_token(self.text)
Button:
text: "="
on_press: app.calculate("".join(app.expression_tokens))
当我尝试运行脚本时,控制台返回以下错误消息:
(venv) C:\Users\Wendelin\Documents\Programming\calculation>c:/Users/Wendelin/Documents/Programming/calculation/venv/Scripts/python.exe c:/Users/Wendelin/Documents/Programming/calculation/Calculator/experiment.py
[INFO ] [Logger ] Record log in C:\Users\Wendelin\.kivy\logs\kivy_19-12-19_29.txt
[INFO ] [deps ] Successfully imported "kivy_deps.gstreamer" 0.1.17
[INFO ] [deps ] Successfully imported "kivy_deps.glew" 0.1.12
[INFO ] [deps ] Successfully imported "kivy_deps.sdl2" 0.1.22
[INFO ] [Kivy ] v1.11.1
[INFO ] [Kivy ] Installed at "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\__init__.py"
[INFO ] [Python ] v3.7.5 (tags/v3.7.5:5c02a39a0b, Oct 15 2019, 00:11:34) [MSC v.1916 64 bit (AMD64)]
[INFO ] [Python ] Interpreter at "c:\Users\Wendelin\Documents\Programming\calculation\venv\Scripts\python.exe"
[INFO ] [Factory ] 184 symbols loaded
[INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil, img_gif (img_ffpyplayer ignored)
[INFO ] [Window ] Provider: sdl2
[INFO ] [GL ] Using the "OpenGL" graphics system
[INFO ] [GL ] GLEW initialization succeeded
[INFO ] [GL ] Backend used <glew>
[INFO ] [GL ] OpenGL version <b'4.4.0 - Build 20.19.15.4463'>
[INFO ] [GL ] OpenGL vendor <b'Intel'>
[INFO ] [GL ] OpenGL renderer <b'Intel(R) Iris(TM) Graphics 540'>
[INFO ] [GL ] OpenGL parsed version: 4, 4
[INFO ] [GL ] Shading version <b'4.40 - Build 20.19.15.4463'>
[INFO ] [GL ] Texture max size <16384>
[INFO ] [GL ] Texture max units <32>
[INFO ] [Window ] auto add sdl2 input provider
[INFO ] [Window ] virtual keyboard not allowed, single mode, not docked
[INFO ] [Text ] Provider: sdl2
Traceback (most recent call last):
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 249, in create_handler
return eval(value, idmap), bound_list
File "c:\Users\Wendelin\Documents\Programming\calculation\Calculator\calculatorgui.kv", line 38, in <module>
text: app.angle_mode_text
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\parser.py", line 75, in __getattribute__
object.__getattribute__(self, '_ensure_app')()
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\parser.py", line 70, in _ensure_app
app.bind(on_stop=lambda instance:
AttributeError: 'NoneType' object has no attribute 'bind'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 692, in _apply_rule
rctx['ids'])
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 254, in create_handler
cause=tb)
kivy.lang.builder.BuilderException: Parser: File "c:\Users\Wendelin\Documents\Programming\calculation\Calculator\calculatorgui.kv",
line 38:
...
36: size_hint_x: None
37: width: "30dp"
>> 38: text: app.angle_mode_text
39:
40:
...
AttributeError: 'NoneType' object has no attribute 'bind'
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 249, in create_handler
return eval(value, idmap), bound_list
File "c:\Users\Wendelin\Documents\Programming\calculation\Calculator\calculatorgui.kv", line 38, in <module>
text: app.angle_mode_text
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\parser.py", line 75, in __getattribute__
object.__getattribute__(self, '_ensure_app')()
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\parser.py", line 70, in _ensure_app
app.bind(on_stop=lambda instance:
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:/Users/Wendelin/Documents/Programming/calculation/Calculator/experiment.py", line 39, in <module>
screen_manager.add_widget(CalculatorScreen1(name = "screen1"))
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\uix\relativelayout.py", line 265, in __init__
super(RelativeLayout, self).__init__(**kw)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\uix\floatlayout.py", line 65, in __init__
super(FloatLayout, self).__init__(**kwargs)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\uix\widget.py", line 361, in __init__
rule_children=rule_children)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\uix\widget.py", line 469, in apply_class_lang_rules
rule_children=rule_children)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 538, in apply
rule_children=rule_children)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 659, in _apply_rule
child, crule, rootrule, rule_children=rule_children)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 657, in _apply_rule
root=rctx['ids']['root'], rule_children=rule_children)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\uix\widget.py", line 469, in apply_class_lang_rules
rule_children=rule_children)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 538, in apply
rule_children=rule_children)
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 707, in _apply_rule
e), cause=tb)
kivy.lang.builder.BuilderException: Parser: File "c:\Users\Wendelin\Documents\Programming\calculation\Calculator\calculatorgui.kv",
line 38:
...
36: size_hint_x: None
37: width: "30dp"
>> 38: text: app.angle_mode_text
39:
40:
...
BuilderException: Parser: File "c:\Users\Wendelin\Documents\Programming\calculation\Calculator\calculatorgui.kv", line 38:
...
36: size_hint_x: None
37: width: "30dp"
>> 38: text: app.angle_mode_text
39:
40:
...
AttributeError: 'NoneType' object has no attribute 'bind'
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 249, in create_handler
return eval(value, idmap), bound_list
File "c:\Users\Wendelin\Documents\Programming\calculation\Calculator\calculatorgui.kv", line 38, in <module>
text: app.angle_mode_text
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\parser.py", line 75, in __getattribute__
object.__getattribute__(self, '_ensure_app')()
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\parser.py", line 70, in _ensure_app
app.bind(on_stop=lambda instance:
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 692, in _apply_rule
rctx['ids'])
File "c:\Users\Wendelin\Documents\Programming\calculation\venv\lib\site-packages\kivy\lang\builder.py", line 254, in create_handler
cause=tb)
因此,似乎我以某种方式无法正确访问该应用程序实例。 但是,我查看了Kivy文档,并按规定使用了应用程序标识符。
我该怎么办?任何帮助将不胜感激。
答案 0 :(得分:0)
问题在于,在加载Properties
文件时,尚未定义App
中的kv
。您可以通过将Builder.load_file()
移到App
中来更正此错误,这样就已经定义了Properties
:
screen_manager = ScreenManager()
class Calculator(App):
expression_tokens = ListProperty([])
expression_value = StringProperty("")
angle_mode = StringProperty("degrees")
angle_mode_text = StringProperty("D")
button_mode = NumericProperty(1)
button_mode_text = StringProperty("1ST")
store_mode = BooleanProperty(False)
def build(self):
Builder.load_file("calculatorgui.kv")
screen_manager.add_widget(CalculatorScreen1(name = "screen1"))
screen_manager.add_widget(CalculatorScreen2(name = "screen2"))
return screen_manager