首页 > 解决方案 > 仅在选择所有旋转器时,如何将python文件部分中的screenmanager调用以更改屏幕

问题描述

我在这里发表了一篇文章(Triggering screenmanager to change screen in Kivy from an if conditional),方法是用不同的方法尝试相同的任务。我在那里没有得到任何解决方案,所以我正在尝试一种不同的方法。但是,我现在遇到了不同的问题。

我正在为用户创建日期和时间选择选项。为此,我正在尝试创建一个仅在所有微调器都选择了值时才移动到下一个屏幕(单击时)的按钮。

为了让程序识别何时单击了微调器(日、小时和分钟微调器),我为状态分配了一个“真”值(d_state、m_state、h_state 和 A_state 分别代表日、分钟、小时、Am/Pm ) 在每个微调器的 .py 代码中。

仅当所有微调器都具有以下状态时,屏幕管理器才会从 screen_two 切换到 screen_three:True。单击微调器(并选择一个选项)时,我分配 True 。

大多数代码按预期工作,除了类 ScreenTwo 中 switch_screen 函数中的 self.screen_manager.current = 'screen_two' 行。我知道这一点,因为我最初用一些打印语句替换了 self.screen_manager.current = 'screen_two' 行以进行调试,并且它们运行良好。这意味着只有 screen_manager 行不工作。

我用尽可能少的代码创建了我的代码的可运行版本(显示我的问题)。

import kivy

kivy.require('1.11.1')

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.config import Config
from kivy.animation import Animation
from kivy.clock import Clock
from datetime import datetime
from datetime import timedelta
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.base import runTouchApp
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.base import runTouchApp
from kivy.uix.spinner import Spinner

Builder.load_string("""
<ScreenTwo>:
    FloatLayout:
        Button:
            background_color: 1, 1, 1, 1
            size: (400, 130)
            size_hint: (None, None)
            pos_hint: {'right': 0.6, 'center_y': 0.3}
            on_press:
                root.hours_checking()
                root.switch_screen()
        Spinner:
            id: day
            size_hint: None, None
            size: 100, 44
            pos_hint: {'center': (.5, .5)}
            text: 'Day'
            values: 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'
            on_text:
                root.on_day_select(self.text)
                self.curr_selection: 'True'
        Spinner:
            id: hours
            size_hint: None, None
            size: 100, 44
            pos_hint: {'center': (.1, .5)}
            text: 'Hour'
            values: '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'
            on_text:
                root.on_hours_select(self.text)
                self.curr_selection: 'True'
        Spinner:
            id: minutes
            size_hint: None, None
            size: 100, 44
            pos_hint: {'center': (.3, .5)}
            text: 'Minutes'
            values: '00', '15', '30', '45'
            on_text:
                root.on_minutes_select(self.text)
                self.curr_selection: 'True'
        Spinner:
            id: AmPm
            size_hint: None, None
            size: 100, 44
            pos_hint: {'center': (.4, .5)}
            text: 'AM/PM'
            values: 'a.m', 'p.m'
            on_text:
                root.on_AmPm_select(self.text)
                self.curr_selection: 'True'
""")

class ScreenTwo(Screen):
    def on_day_select(self, text): #Function assigns selected day from spinner to a variable
        global day, d_status
        day = str(text)
        d_status = 'True'

    def on_hours_select(self, text): #Function assigns selected 12-hour from spinner to a variable
        global hours, h_status
        hours = int(text)
        h_status = 'True'

    def on_minutes_select(self, text): #Function assigns selected minute from spinner to a variable
        global minutes, m_status
        minutes = int(text)
        m_status = 'True'

    def on_AmPm_select(self,text): #Function assigns selected a.m/p.m from spinner to a variable
        global AmPm, A_status
        AmPm = str(text)
        A_status = 'True'

    def hours_checking(self): #Function converts 12hr time to 24hr time
        global AmPm
        global hours
        global minutes
        global day
        try:
            if 1 <= hours <= 11 and AmPm == 'a.m':
                pass
            elif 1 <= hours <= 12 and AmPm == 'p.m':
                hours += 12
            elif hours == 12 and AmPm == 'a.m':
                hours = 0
        except:
            print('error1') #This line was used for my debugging output
        else:
            try: #This line is for the case when hours and AmPm are selected, but the other variables aren't
                print(day, hours, minutes)
            except:
                print('error2') #This line is used for my debugging output

    def switch_screen(self): #This function checks that all spinners have selected values
        global d_status, h_status, m_status, A_status
        try:
            if d_status == h_status == m_status == A_status == 'True': 
                self.screen_manager.current = 'screen_two' #This line does not execute for some reason, and the screen does not switch even if all the spinners have values selected
            else:
                pass
        except:
            print('error3') #This line was used for my debugging output
    pass


class ScreenThree(Screen):
    pass

# The ScreenManager controls moving between screens
screen_manager = ScreenManager()

# Add the screens to the manager and then supply a name
# that is used to switch screens
screen_manager.add_widget(ScreenTwo(name="screen_two"))
screen_manager.add_widget(ScreenThree(name="screen_three"))


class KivyTut2App(App):
    def build(self):
        return screen_manager


sample_app = KivyTut2App()
sample_app.run()

标签: pythonpython-3.xkivykivy-language

解决方案


感谢您创建一个独立的示例,这要好得多。您仍然可以通过删除一些 Spinner 来缩短它,因为它们在重要代码中都是相同的,但现在没关系。

您的代码最大的问题是您使用了裸异常,except:. 它们捕获所有异常类型,因此您不知道它们发生的原因,它们仅用于隐藏真正的问题。相反,使用它except SomeSpecificException:来处理您期望遇到的特定问题将是一种很好的做法,这样如果出现其他问题,您的程序仍然会崩溃 - 这就是您想要的,因为您还没有计划过那件事并且没有明智的方法可以继续。

如果您删除error3裸露的,那么您的问题就会暴露出来:

 Traceback (most recent call last):
   File "so06.py", line 123, in switch_screen
     self.screen_manager.current = 'screen_two'
 AttributeError: 'ScreenTwo' object has no attribute 'screen_manager'

您的问题是您正在尝试访问screen_managerScreen 的属性,但不存在这样的属性。如果您阅读文档,您会发现您真正想要访问的是self.manager.

其他问题:

  • 屏幕实际上仍然不会改变,因为您将其设置current"screen_two"当前活动屏幕的名称。
  • 不要'True'用来表示发生了什么事,使用实际的布尔值True
  • Don't use global variables, for all the normal reasons that you can look up. Especially, don't use them without initialising them, that means your code raises a NameError if the button is clicked before these variables exist. Maybe that's why you added the bad except: lines, but that only makes things worse. The neater solution would be to use properties of the ScreenTwo object, which you can initialise to sensible values (i.e. False) then set to True later.

推荐阅读