从“on_enter”内部调用时 Kivy 弹出错误行为

Posted

技术标签:

【中文标题】从“on_enter”内部调用时 Kivy 弹出错误行为【英文标题】:Kivy Popup misbehaviour when called from inside 'on_enter' 【发布时间】:2020-12-22 16:30:15 【问题描述】:

我正在尝试显示一个弹出窗口,以防今天是 DB 上的日期。

问题是弹出窗口,但它似乎是在主屏幕后面构建的。 我想这是由于在“on_enter”方法上被调用,但无法解决这个问题。

请注意,此“设置”按钮是从主屏幕呈现的,而不是从弹出窗口本身呈现的。

这是我的 main.py:

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen, ScreenManager
from datetime import date, datetime
from calendar import weekday
from kivymd.toast import toast
from kivymd.uix.list import TwoLineIconListItem
from kivymd.uix.picker import MDDatePicker, MDTimePicker
from datahelper import CreateTable, InsertEstudo, DeletStudy, ReadStudy, UpdateStudy
from kivy.factory import Factory


class Gerenciador(ScreenManager):
    pass


class Main(Screen):
    # def verificar_estudos(self):
    def on_enter(self, *args):
        ler_dbestudos = ReadStudy()
        resultado = ler_dbestudos.ler_estudos()
        for s in resultado:
            dia = s[2].split("-")[-1]
            mes = s[2].split("-")[-2]
            ano = s[2].split("-")[0]
            print(f"dia/mes/ano")
        dia_hoje = date.today().day
        mes_hoje = date.today().month
        ano_hoje = date.today().year

        if int(dia) == dia_hoje:
            print('Hoje é dia de revisão de matéria')
            tudo = self.children
            Factory.DiaDeRevisao().open()
        if int(dia) + 14 == dia_hoje:
            print('Hoje é dia de revisão de matéria')
            Factory.DiaDeRevisao().open()
        if int(mes)+1 == mes_hoje:
            print('Hoje é dia de revisão de matéria')
            Factory.DiaDeRevisao().open()


class Revisao(Screen):
    def ver_estudos(self, *args):
        read_studies = ReadStudy()
        studies = read_studies.ler_estudos()
        for s in studies:
            self.ids.scrollviewid.add_widget(TwoLineIconListItem(text=s[1], secondary_text=s[2]))

    def ver_lista(self, *args):
        for r in range(20):
            self.ids.scrollviewid.add_widget(TwoLineIconListItem(text='Azul', secondary_text="Texto Secundário"))


class AddStudy(Screen):
    def open_calendar(self):
        date_dialog = MDDatePicker(callback=self.get_date)
        if self.ids.dtinist.focused == True:
            date_dialog.open()

    def get_date(self, *args):
        '''
          :type date: <class 'datetime.date'>
          '''
        print(args[0])
        print(type(args[0]))
        self.ids.dtinist.focused = False
        self.ids.dtinist.text = str(args[0])
        self.ids.dtinist.focused = False
        return args[0]

    def open_clock(self):
        time_dialog = MDTimePicker()
        time_dialog.bind(time=self.get_time)
        if self.ids.tminist.focused == True:
            time_dialog.open()

    def get_time(self,*args):
        self.ids.tminist.focused = False
        self.ids.tminist.text = str(args[1])
        self.ids.tminist.focused = False
        return args[1]

    def selected(self, path, selection):
        tipo = selection[0].split(".")[-1]
        print(tipo)
        if tipo == 'mp3':
            toast('Arquivo MP3 selecionado')
            with open(selection[0], 'rb') as f:
                barq = f.read()
                insert = InsertEstudo()
                insert.criar_novo_estudo()

    def confirm_new(self):
        materia = self.ids.materia_estudo.text
        data_estudo = self.ids.dtinist.text
        hora_estudo = self.ids.tminist.text
        insert_new_study = InsertEstudo()

        if insert_new_study.criar_novo_estudo(materia, data_estudo, hora_estudo):
            toast('Estudo adicionado com sucesso')
        else:
            toast('Algo deu muito errado. O estudo não foi adicionado. Tente novamente mais tarde')


class SettingsScreen(Screen):

    def select_path(self, path):
        print(path)
        '''It will be called when you click on the file name
        or the catalog selection button.

        :type path: str;
        :param path: path to the selected directory or file;
        '''

        self.exit_manager()
        toast(path)

    def open_file_manager(self):
        self.file_manager.show('/')  # output manager to the screen
        self.manager_open = True

    def exit_manager(self):
        self.manager_open = False
        self.file_manager.close()


class SelectAlarm(Screen):
    def selected(self, path, selection):
        tipo = selection[0].split(".")[-1]
        print(tipo)
        if tipo == 'mp3':
            toast('Arquivo MP3 selecionado')
            with open(selection[0], 'rb') as f:
                barq = f.read()
                insert = InsertEstudo()
                insert.criar_novo_estudo()
        else:
            toast('Por favor, seleecione um arquivo mp3')


class BoraEstudarApp(MDApp):

    def on_pause(self):
        return True

    def build(self):
        data_hoje = f"date.today().year-date.today().month-date.today().day"
        sm = Gerenciador()
        sm.add_widget(Main(name='Principal'))
        sm.add_widget(SettingsScreen(name='Preferencias'))
        sm.add_widget(AddStudy(name='NovaMateria'))
        sm.add_widget(Revisao(name='Revisoes'))
        sm.add_widget(SelectAlarm(name='SelecionarAlarme'))

        return sm


if __name__ == "__main__":
    boraestudar = BoraEstudarApp()
    boraestudar.run()

这是我的 kv 文件:

#:import Factory kivy.factory.Factory
<ScreenManager>:


<DiaDeRevisao@Popup>:
    title: 'Atenção dia de revisão'
    auto_dismiss: False
    size_hint:0.7,0.7
    BoxLayout:
        canvas.before:
            Color:
                rgba:(1,1,1,1)
            Rectangle:
                size: self.size
                pos: self.pos
        BoxLayout:
            orientation:'vertical'
            MDLabel:
                text:'Hoje é dia de revisão'
            Button:
                text: 'OK'
                on_press: root.dismiss()

<FileChooserPop@Popup>:
    title:'Escolha o arquivo de audio MP3'
    BoxLayout:
        canvas.before:
            Color:
                rgba:(0,0,0,0.35)
            Rectangle:
                size: self.size
                pos: self.pos

        orientation: 'vertical'

        BoxLayout:
            size_hint_y: None
            height: sp(52)

            Button:
                text: 'Icon View'
                on_press: fc.view_mode = 'icon'
            Button:
                text: 'List View'
                on_press: fc.view_mode = 'list'

        FileChooser:
            id: fc
            FileChooserIconLayout
            FileChooserListLayout

        BoxLayout:
            size_hint_y: None
            MDTextButton:
                size_hint_x:0.4
                text: 'Voltar'
                on_press: root.dismiss()

            MDIconButton:
                halign:'center'
                icon:'content-save'
                on_press:root.selected(fc.path, fc.selection)
                on_release: root.manager.current = 'Principal'

<Main>:
    BoxLayout:
        orientation:"vertical"
        spacing:'50dp'
        padding:'70dp'
        BoxLayout:
            MDTextButton:
                text: 'Revisões'
                on_press: root.manager.current = 'Revisoes'
#                on_release:Factory.FileChooserPop().open()
        BoxLayout:
            Button:
                text: 'Settings'
                on_press: root.manager.current = 'Preferencias'
        BoxLayout:
            MDIconButton:
                icon: "plus"
                on_press: root.manager.current = 'NovaMateria'


<AddStudy>:
    BoxLayout:
        orientation:'vertical'
        spacing:'100sp'
        padding: '100dp'
        MDTextField:
            id:materia_estudo
            hint_text: 'Matéria'

        MDTextField:
            id: dtinist
            text: ''
            hint_text: 'data do Estudo'
            on_focus: root.open_calendar()

        MDTextField:
            id:tminist
            text:''
            hint_text: 'Hora do Estudo'
            on_focus: root.open_clock()

        BoxLayout:
            MDTextButton:
                text:'Voltar'
                on_press: root.manager.current = 'Principal'
            MDTextButton:
                text: 'Salvar'
                on_press: root.confirm_new()
<SettingsScreen>:
    BoxLayout:
        MDTextButton:
            text: 'Selecionar Alarme'
            on_press: root.manager.current = 'SelecionarAlarme'


<SelectAlarm>:
    BoxLayout:
        canvas.before:
            Color:
                rgba:(0,0,0,0.35)
            Rectangle:
                size: self.size
                pos: self.pos

        orientation: 'vertical'

        BoxLayout:
            size_hint_y: None
            height: sp(52)

            Button:
                text: 'Icon View'
                on_press: fc.view_mode = 'icon'
            Button:
                text: 'List View'
                on_press: fc.view_mode = 'list'

        FileChooser:
            id: fc
            FileChooserIconLayout
            FileChooserListLayout

        BoxLayout:
            size_hint_y: None
            MDTextButton:
                size_hint_x:0.4
                text: 'Voltar'
                on_press: root.manager.current = 'Principal'

            MDIconButton:
                halign:'center'
                icon:'content-save'
                on_press:root.selected(fc.path, fc.selection)
                on_release: root.manager.current = 'Principal'

<Revisao>:
    BoxLayout:
        orientation:'vertical'
        BoxLayout:
            ScrollView:
                do_scroll_y: True
                size_hint_y: None
                height: '500dp'
                MDList:
                    id:scrollviewid
        BoxLayout:
            size_hint_y: 0.15
            MDTextButton:
                size_hint_x: None
                text:"Voltar"
                on_release: root.manager.current = 'Principal'
            MDTextButton:
                text:"Ver Lista"
                on_release: root.ver_estudos()


这很奇怪,我想不通。

感谢您的帮助。干杯!

【问题讨论】:

【参考方案1】:

问题是on_enter() 事件被触发得太早,所以PopupMain Screen 之前被绘制。您可以通过在显示Popup 之前添加一个非常短的延迟来解决此问题。我改变了:

Factory.DiaDeRevisao().open()

到:

Clock.schedule_once(lambda dt: Factory.DiaDeRevisao().open())

将提供该延迟并允许Popup 显示在Screen 之上。

【讨论】:

太棒了!绝对正确。我知道时间有问题,但完全忘记了时钟的事情......谢谢,伙计!

以上是关于从“on_enter”内部调用时 Kivy 弹出错误行为的主要内容,如果未能解决你的问题,请参考以下文章

在 Kivy 中制作(继续)选项屏幕

Kivy 弹出 Filechooser 传递变量(选择)

在 Kivy/Python 中作为线程运行时表现奇怪的函数

如何在 Kivy 应用程序启动时满足特定条件时自动弹出警报

安装 KIVY 时出错:为啥执行后出现错误:“python -m pip install kivy”?

输入直到离开kivy时如何调用函数?