我正在编写一个简单的词汇应用程序,当用户提交答案时,如果回答正确与否,则会显示一个弹出窗口。到目前为止,此方法仍然有效,但是当应该关闭/关闭弹出窗口时,应用程序崩溃,提示AttributeError: 'MyScreenManager' object has no attribute 'close_pop'
这确实是有道理的,因为close_pop方法是在PopupWindow类中定义的(如果可能的话,我想将不同的关注点分开)
我虽然有两种可能的解决方案,但不知道如何实现它们:
1:从MyScreenManager类中调用close_pop方法,但我不知道如何引用应关闭的弹出对象
2:调整kv部分:
<PopupWindow>:
pLabel: pLabel
Label:
id: pLabel
size_hint: .6, .2
pos_hint:{'x': .2, 'top': 1}
font_name: 'static/NotoSansSC-Regular.otf'
Button:
text: 'Close'
size_hint: .8, .2
pos_hint:{'x': .1, 'y': .1}
on_release: app.root.close_pop()
不调用根类(MyScreenManager),而是执行类似app.PopupWindow.close_pop()
的操作,但这也不起作用。
我能够在没有screenmanager的情况下使它工作(并将所有方法放入一个类“ Mainwindow”(那时它也是根类)),但是为了进一步增强,我想使用屏幕管理器:)
任何其他好的解决方案也都可以使用-非常感谢!
这是我的Python代码:
import random
import pandas as pd
import unidecode
from kivy.app import App
#from kivy.uix.gridlayout import GridLayout
#from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
#from kivy.uix.actionbar import ActionBar
#from kivy.uix.label import Label
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class MainWindow(Screen):
userInput = ObjectProperty(None)
vocab = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainWindow, self).__init__(**kwargs)
self.df = pd.read_excel(r"static/HSK1-Vocabulary-List.xlsx")
self.en = self.df['English']
self.zh = self.df['Chinese']
self.pinyin = self.df['Pinyin']
self.rd = None
def btn_submit(self):
if self.rd is None:
pLabel = "Please start before submitting!"
elif not self.userInput.text:
pLabel = "Please enter something!"
else:
pLabel = self.validate(self.userInput.text)
self.btn_next()
PopupWindow(pLabel).open_popup()
def btn_next(self):
self.userInput.text = ""
self.rd = random.randint(0, self.df.shape[0]-1)
self.vocab.text = "What is '{}' in Chinese?".format(self.en[self.rd])
def validate(self, answer):
def replace_tones(orig_voc):
unaccented_voc = unidecode.unidecode(orig_voc)
return(unaccented_voc)
if answer == self.zh[self.rd]:
#correct+=1
return("Well done, even in chinese characters!")
elif answer == self.pinyin[self.rd]:
#correct+=1
return("Well done, you also got the correct tones!")
elif answer == replace_tones(self.pinyin[self.rd]):
#correct+=1
return("Well done! Keep in mind the tones '{}'".format(self.pinyin[self.rd]))
else:
return("Sorry, that was not correct!\nThe correct vocab is {}".format(self.pinyin[self.rd]))
#cnt+=1
class PopupWindow(FloatLayout):
def __init__(self, userInput):
super().__init__()
self.pLabel.text = userInput
def open_popup(self):
content = PopupWindow(self.pLabel.text)
self.pop = Popup(title="Result", content=content, size_hint=(None, None), size=(400, 400))
self.pop.open()
def close_pop(self):
self.pop.dismiss()
class DashboardWindow(Screen):
pass
class MyScreenManager(ScreenManager):
pass
#def close_pop(self):
# print("This should close the popup...")
KV = Builder.load_file("main.kv")
class VocabularyTrainer(App):
def build(self):
return KV
if __name__ == "__main__":
app = VocabularyTrainer()
app.run()
还有我的.kv文件:
MyScreenManager:
MainWindow:
DashboardWindow:
<MainWindow>:
name: 'main'
vocab: vocab
userInput: userInput
GridLayout:
size: root.width, root.height
rows: 4
ActionBar:
id: actBar
background_image: ''
background_color: (0.53, 0.808, 0.98, 1)
ActionView:
ActionPrevious:
ActionButton:
text: 'Quiz'
ActionButton:
text: 'Training'
ActionButton:
text: 'Settings'
Label:
id: vocab
text: 'Welcome to the Chinese Learning App!'
TextInput:
id: userInput
hint_text: 'Enter answer'
width: 300
multiline: False
on_text_validate: root.btn_submit()
font_name: 'static/NotoSansSC-Regular.otf'
GridLayout:
cols: 3
Button:
text: 'Submit'
on_press: root.btn_submit()
Button:
text: 'Start/Skip'
on_press: root.btn_next()
Button:
text: 'Dashboard'
on_press: app.root.current = 'dashboard'
<PopupWindow>:
pLabel: pLabel
Label:
id: pLabel
size_hint: .6, .2
pos_hint:{'x': .2, 'top': 1}
font_name: 'static/NotoSansSC-Regular.otf'
Button:
text: 'Close'
size_hint: .8, .2
pos_hint:{'x': .1, 'y': .1}
on_release: app.root.close_pop()
<DashboardWindow>:
name: 'dashboard'
GridLayout:
rows: 2
Label:
text: '<e.g. PieChart Results>'
Button:
text: 'Go back'
on_press: app.root.current = 'main'
答案 0 :(得分:2)
问题是您的PopupWindow
每次使用时都会创建两个PopupWindows
。更好的方法是像这样创建一个:
class PopupWindow(FloatLayout):
def __init__(self, userInput):
super().__init__()
self.pLabel.text = userInput
self.pop = Popup(title="Result", content=self, size_hint=(None, None), size=(400, 400))
def open_popup(self):
self.pop.open()
def close_pop(self):
self.pop.dismiss()
然后在您的kv
中,您可以使用:
<PopupWindow>:
pLabel: pLabel
Label:
id: pLabel
size_hint: .6, .2
pos_hint:{'x': .2, 'top': 1}
font_name: 'static/NotoSansSC-Regular.otf'
Button:
text: 'Close'
size_hint: .8, .2
pos_hint:{'x': .1, 'y': .1}
on_release: root.close_pop()
答案 1 :(得分:1)
您应该将其分解为一个简单的问题示例。从到目前为止我所看到的,您应该尝试将btn_submit方法更改为类似这样的方法,以使弹出窗口易于访问:
def btn_submit(self):
if self.rd is None:
pLabel = "Please start before submitting!"
elif not self.userInput.text:
pLabel = "Please enter something!"
else:
pLabel = self.validate(self.userInput.text)
self.btn_next()
self.mypopup = PopupWindow(pLabel)
self.mypopup.open_popup()
,然后您应该可以使用屏幕管理器访问它,如下所示:
class MyScreenManager(ScreenManager):
def close_pop(self):
print("This should close the popup...")
self.get_screen('main').mypopup.close_pop()