关闭另一个班级的奇异果弹出窗口

时间:2020-05-05 15:44:46

标签: kivy kivy-language

我正在编写一个简单的词汇应用程序,当用户提交答案时,如果回答正确与否,则会显示一个弹出窗口。到目前为止,此方法仍然有效,但是当应该关闭/关闭弹出窗口时,应用程序崩溃,提示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'

2 个答案:

答案 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()