【问题标题】:How to make a countdown timer which is button controlled and sends out a notification on end如何制作一个按钮控制的倒数计时器并在结束时发出通知
【发布时间】:2021-08-05 02:45:51
【问题描述】:

大家好,看到这个的任何人都非常感谢您抽出时间来查看我的问题。

我有一个程序正在使用 kivy、kivymd 和 pyobjus 来当前容纳多个窗口,并且现在在 mac 上会发出通知!唯一的问题是我需要在 20 分钟的计时器结束后发出通知,而不是在开始时。我完全不知道该怎么做。希望有人可以提供任何东西吗?代码在下面,干杯!

from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.picker import MDDatePicker
from kivymd.uix.picker import MDThemePicker
from kivy.config import Config
from kivy.uix.boxlayout import BoxLayout
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import MDList
from kivy.properties import ObjectProperty
from kivymd.uix.navigationdrawer import MDNavigationDrawer
from kivy.properties import StringProperty, ListProperty
from kivy.animation import Animation
from kivy.properties import StringProperty, NumericProperty
from kivy.lang import Builder
from kivy.core.window import Window
from plyer import notification
import threading
from pyobjus import autoclass, objc_str
from pyobjus.dylib_manager import load_framework, INCLUDE
import time
import os
import subprocess
from kivy.clock import Clock
from kivy.uix.label import Label
from datetime import datetime, date, time
 

load_framework(INCLUDE.AppKit)


Config.set('graphics', 'width', '1600')
Config.set('graphics', 'height', '1200')


KV = '''
<Box@BoxLayout>:
    bg: .65, .48, .35, 1 
       
             

BoxLayout:
    Rectangle:    
        size: 1600, 1200

    Box:
        bg: app.theme_cls.bg_light
    Box:
        bg: app.theme_cls.bg_normal
    Box:
        bg: app.theme_cls.bg_dark
    Box:
        bg: app.theme_cls.bg_darkest
            
'''
            
screen_helper = """
ScreenManager:
    MenuScreen:
    HomeScreen:
    BreakScreen:
    SettingsScreen
        
<MenuScreen>:
    name: 'menu'
    
  
        
    MDLabel:
        rectangle:
        background_color: .65, .48, .35, 1           
        size: 300, 700
        pos_hint: {'center_x':0.1, 'center_y':0.0}
        
                
    MDLabel:
        text: "Welcome to"
        font_style: 'H2'
        size:500, 500
        pos_hint: {'center_x':0.95,'center_y':0.84}
        
    MDLabel:
        text: "LEAF"
        font_style: 'H3'
        size:500, 500
        pos_hint: {'center_x':1.045,'center_y':0.7}
        
        
    MDFlatButton:
        text: 'Calendar'
        font_style: 'H6'
        pos_hint: {'center_x':0.091,'center_y':0.65}
        on_release: app.show_date_picker()
            
            
    MDFlatButton:
        text: 'Home'
        font_style: 'H6'
        pos_hint: {'center_x':0.076,'center_y':0.57}
        on_press: root.manager.current = 'home'
        
    MDFlatButton:
        text: 'Settings'
        font_style: 'H6'
        pos_hint: {'center_x':0.09,'center_y':0.49}
        on_press: root.manager.current = 'settings'
        
            
    MDRectangleFlatButton:
        text: 'Continue'
        font_style: 'H6'
        pos_hint: {'center_x':0.61,'center_y':0.345}
        on_press: root.manager.current = 'home'
   


    
<HomeScreen>:
    name: 'home'    
    
    Image
        source: '/Users/oats/Downloads/LEAF 1.0/Assets/MenuScreen.png'
        pos_hint: {'center_x':0.5,'center_y':0.8}
        size_hint_y: None 
        height: dp(60) 
        

        
    MDToolbar:
        id: toolbar
        title: "Home"
        pos_hint: {"top": 1}
        elevation: 5
        left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
        
    Widget:

        MDNavigationDrawer:
            id: nav_drawer
    
            ContentNavigationDrawer:
                orientation: 'vertical'
                padding: "8dp"
                spacing: "8dp"
                

                MDFlatButton:
                    text: 'Return to menu'
                    font_style: 'Subtitle1'
                    on_release: root.manager.current = 'menu'

                MDFlatButton:
                    text: 'Open Calendar'
                    font_style: 'Subtitle1'
                    on_release: app.show_date_picker()
                    
                MDFlatButton:
                    text: 'Open Settings'
                    font_style: 'Subtitle1'
                    on_press: root.manager.current = 'settings'
                    
                MDLabel:
                    size_hint_y: None
                    text: '. '
        
                MDLabel:
                    size_hint_y: None
                    text: ' '
        
                MDLabel:
                    size_hint_y: None
                    text: ' '
        
                MDLabel:
                    size_hint_y: None
                    text: ' '
         
                MDLabel:
                    size_hint_y: None
                    text: ' '

                MDLabel:
                    size_hint_y: None
                    text: ' '



         
            
    
<BreakScreen>:
    name: 'break'
    
<SettingsScreen>:
    name: 'settings'
    
    
    MDFlatButton:
        text: 'Return to menu'
        font_style: 'H6'
        pos_hint: {'center_x':0.1,'center_y':0.05}
        on_press: root.manager.current = 'menu'
        
    MDFloatingActionButton:
        icon: 'palette'
        md_bg_color: 0, 0.039, 0.867, 0.557
        pos_hint: {'center_x':0.9,'center_y':0.5}
        on_release: app.show_theme_picker() 
        
    MDFloatingActionButton:
        icon: 'moon-waning-crescent'
        theme_text_color: "Custom"
        md_bg_color: 0, 0.039, 0.867, 0.557
        pos_hint: {'center_x':0.9,'center_y':0.3}
        on_press: self.theme_cls.theme_style = "Dark"  # "Light"
        
    MDFloatingActionButton:
        icon: 'MDFloatingActionButton'
        icon: 'lightbulb'
        pos_hint: {'center_x':0.9,'center_y':0.1}
        on_press: self.theme_cls.theme_style = "Light"  # "Dark"
    

        
"""  

class MenuScreen(Screen):
    pass


class HomeScreen(Screen):
    pass


class BreakScreen(Screen):
    pass

class SettingsScreen(Screen):
    pass

class ContentNavigationDrawer(BoxLayout):
    pass

class DrawerList(ThemableBehavior, MDList):
    pass

class IncrediblyCrudeClock(Label):
    a = NumericProperty(1200)  # seconds

    def start(self):
        Animation.cancel_all(self)  # stop any current animations
        self.anim = Animation(a=0, duration=self.a)
        def finish_callback(animation, incr_crude_clock):
            incr_crude_clock.text = "FINISHED"
        self.anim.bind(on_complete=finish_callback)
        self.anim.start(self)

    def on_a(self, instance, value):
        self.text = str(round(value, 1))




    
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(HomeScreen(name='profile'))
sm.add_widget(BreakScreen(name='upload'))
sm.add_widget(SettingsScreen(name='settings'))



class LeafApp(MDApp):

    
    def show_date_picker(self):
        date_dialog = MDDatePicker()
        date_dialog.open()

    def show_theme_picker(self):
        theme_dialog = MDThemePicker()
        theme_dialog.open()



   
    def notify(title, text):   
        os.system("""
              osascript -e 'display notification "{}" with title "{}"'
              """.format(text, title))
              
    notify("LEAF", "Hey, its been twenty minutes, take a break?")
        
        
    def timer_loop(self):
            
            time.sleep(5)
            

    
    def build(self):
        crudeclock = IncrediblyCrudeClock()
        crudeclock.start()
        screen = Builder.load_string(screen_helper)
        return screen
    

    

    
LeafApp().run()

【问题讨论】:

    标签: python macos kivy kivymd


    【解决方案1】:

    不要将Animation用作计时器,而是尝试像这样使用Clock.schedule_once()

    def build(self):
        Clock.schedule_once(partial(LeafApp.notify, "LEAF", "Hey, its been twenty minutes, take a break?"), 1200)
        screen = Builder.load_string(screen_helper)
        return screen
    

    notify() 方法稍作改动:

    @staticmethod
    def notify(title, text, *args):
        os.system("""
              osascript -e 'display notification "{}" with title "{}"'
              """.format(text, title))
        # schedule another notify
        Clock.schedule_once(partial(LeafApp.notify, "LEAF", "Hey, its been another twenty minutes, take a break?"), 1200)
    

    *args 处理 Clock.schedule_once() 添加到 notify() 调用的参数 (dt)。然后notify() 方法会在另外 20 分钟内安排对自己的另一个调用。 @staticmethod 装饰器表明notify() 方法是一个静态方法,无需LeafApp 的实际实例即可调用。 partial() 允许您定义方法调用及其参数。

    并删除该行:

    notify("LEAF", "Hey, its been twenty minutes, take a break?")
    

    在开始时导致通知。

    【讨论】:

    • 一定会尝试非常感谢您的帮助救命!
    • 嗨,非常感谢约翰。这基本上保存了我的课程项目!我希望如果我选择你或其他人的大脑没问题。我想知道这个过程是否可以通过 kivy 在按下按钮后激活。不确定这是否可能,但如果有办法,那就太好了。根据 下的说法,我可以按下 MDFlatButton 或其他按钮触发计时过程。只是想知道这是否可能?
    • 当然,只需让按钮on_press 触发执行Clock.schedule_once() 的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    相关资源
    最近更新 更多