【发布时间】:2020-02-08 08:13:43
【问题描述】:
在尝试创建一个小部件来模拟多项选择测验的功能时,我遇到了一个我找不到任何解决方案的错误。我阅读了this post 并没有找到任何适用于我的具体情况的内容。
我正在尝试从 .JSON 文件加载一组设置,并将它们用作我的 KV 对象的主要属性。例如,从文件中加载“canvas_color”设置并将该值分配给我的小部件的画布颜色。
当我尝试这样做时,我得到了错误:
AttributeError: 'MultipleChoiceT' object has no attribute 'settings'
我的 .py 文件包含“缺失”属性:
import kivy
import json
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.app import App
kivy.require("1.11.1")
Builder.load_file("MultipleChoice_text.kv")
class MultipleChoiceT(BoxLayout):
# collects info from json file and assigns it to settings var
with open('widget_settings.json', 'r') as file:
settings = json.load(file)["MultipleChoice_settings"][0]
print(settings)
test = 'hello'
def __init__(self, **kwargs):
super(MultipleChoiceT, self).__init__(**kwargs)
self.app = App.get_running_app()
print(self.app)
self.w_width = 0.5
self.w_height = 1
self.data = {'pressed_btn': 0, 'btn_text': None}
# the function called for when the toggle button is on_state
def pressed(self, instance):
self.data['pressed_btn'] = self.get_id(instance)
self.data['btn_text'] = instance.text
print(self.data)
# changes the bottom label when submit button is pressed
def submit(self):
self.bottom_label.text = f"ID: {self.data['pressed_btn']} TEXT: {self.data['btn_text']}"
# returns the id of the given instance
@staticmethod
def get_id(instance):
for id, widget in instance.parent.ids.items():
if widget.__self__ == instance:
return id
# null method for now, not implemented
def change_question(self, new_text):
self.question_label.text = str(new_text)
# prints text when the next question button is pressed
def next_question(self):
print('next question pressed')
# returns the dimensions for the toggle buttons based on their text length and font size defined in settings json
def get_dimension(self, instance):
if len(instance.text) < 25:
width = ((len(instance.text) / 2) * instance.font_size) * 1.1
else:
width = (len(instance.text) / 2) * instance.font_size
height = instance.font_size * 1.35
return width * self.settings["btn_scalar"], height * self.settings["btn_scalar"]
class Test(BoxLayout):
pass
class MainApp(App):
def build(self):
return Test()
if __name__ == "__main__":
MainApp().run()
还有我的 .kv 文件(是的,我知道缩进已关闭,仅在这篇文章中):
<MultipleChoiceT@BoxLayout>:
orientation: 'vertical'
padding: 10
id: main_layout
bottom_label: bottom_label
canvas:
Color:
rgba: root.settings["canvas_color"]
Rectangle:
pos: self.x + 5, self.y + 5
size: self.width - 10, self.height - 10
Label:
id: question_label
font_size: root.settings["font_size"]
text: 'Sample question'
text_size: self.size[0] + 5, self.size[1]
valign: 'middle'
height: self.font_size * 1.33
size_hint: 1, None
color: root.settings["label_text_color"]
Label:
size_hint_y: None
height: 10
ToggleButton:
id: btn1
background_color: root.settings["button_bg_color"]
color: root.settings["button_text_color"]
font_size: root.settings["font_size"]
text: 'Option1'
group: 'MultChoice'
on_state: root.pressed(self)
size: root.get_dimension(self)
size_hint: None, None
halign: 'center'
valign: 'center'
Label:
size_hint_y: 0.1
ToggleButton:
id: btn2
background_color: root.settings["button_bg_color"]
color: root.settings["button_text_color"]
font_size: root.settings["font_size"]
text: '4785839409fjvojrvn eijofgj4389'
group: 'MultChoice'
on_state: root.pressed(self)
size: root.get_dimension(self)
size_hint: None, None
halign: 'center'
valign: 'center'
Label:
size_hint_y: 0.1
ToggleButton:
id: btn3
background_color: root.settings["button_bg_color"]
color: root.settings["button_text_color"]
font_size: root.settings["font_size"]
text: 'Option3'
group: 'MultChoice'
on_state: root.pressed(self)
size: root.get_dimension(self)
size_hint: None, None
halign: 'center'
valign: 'center'
Label:
size_hint_y: 0.1
ToggleButton:
id: btn4
background_color: root.settings["button_bg_color"]
font_size: root.settings["font_size"]
color: root.settings["button_text_color"]
text: 'A sample question type'
group: 'MultChoice'
on_state: root.pressed(self)
size: root.get_dimension(self)
size_hint: None, None
halign: 'center'
valign: 'center'
Label:
size_hint: 1, 0.5
GridLayout:
id: bottom_layout
cols: 4
size_hint_y: None
canvas:
Color:
rgba: root.settings["second_canvas_color"]
Rectangle:
pos: self.x, self.y
size: self.width, self.height
Button:
id: submit_btn
text: 'Press to submit'
on_press: root.submit()
font_size: root.settings["font_size"]
background_color: root.settings["second_btn_bg_color"]
color: root.settings["second_btn_txt_color"]
# for text wrapping
size: root.get_dimension(self)
text_size: self.size
halign: 'center'
valign: 'center'
Label:
id: bottom_label
text: 'answer'
font_size: root.settings["font_size"]
color: root.settings["second_lbl_txt_color"]
size_hint_x: main_layout.size_hint_x * 2
# for text wrapping
size: root.get_dimension(self)
text_size: self.size
halign: 'center'
valign: 'center'
Button:
id: next_btn
text: 'Next question'
font_size: root.settings["font_size"]
background_color: root.settings["second_btn_bg_color"]
color: root.settings["second_btn_txt_color"]
on_press: root.next_question()
# for text wrapping
size: self.texture_size
text_size: self.size
halign: 'center'
valign: 'center'
<Test@BoxLayout>:
orientation: 'horizontal'
MultipleChoiceT:
MultipleChoiceT:
每当运行 MultipleChoice_text.py 文件时,我都会在 MultipleChoice_text.kv 的第 11 行收到一条错误消息,指出 MultipleChoiceT 对象没有属性“设置”也许这只是我对属性如何/是什么的理解。但是当我自己运行文件时,没有尝试在一个布局中包含多个 MultipleChoiceT 小部件,它运行得很好。
我目前的想法是设置属性是在实例级别进行的,并且仅在创建实例时才创建。直到调用root.settings[whatever] 之后才会创建实例。我不确定如何解决这个问题。
我试图将设置属性的创建移动到不同的类中,以查看是否可以在调用它之前对其进行初始化,但我没有运气。我也尝试将设置属性导入到 kv 文件中,但这也没有做任何事情。我最接近的尝试是自己运行MultipleChoiceT 小部件,并让它成为应用程序中唯一的东西。当代码如下时有效:
class MainApp(App):
def build(self):
return MultipleChoiceT()
MainApp().run()
任何帮助或指点都将不胜感激,因为这是 2 周后到期的学校项目 :) 如果需要,我可以发布完整的错误消息,但我发现其中唯一有用的是说明缺失属性的行。
作为旁注,PyQt5 是在 python 中进行 GUI 开发的更好选择吗?我研究了它并选择不走那条路,因为我没有找到支持可扩展应用程序的方法。而且,论坛帖子很少
【问题讨论】: