python - 仅在选择所有旋转器时,如何将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()
解决方案
感谢您创建一个独立的示例,这要好得多。您仍然可以通过删除一些 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_manager
Screen 的属性,但不存在这样的属性。如果您阅读文档,您会发现您真正想要访问的是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 toTrue
later.
推荐阅读
- python - 在 python 中与应用程序的 UI 交互
- heroku - ESP 模块连接并在 Heroku 的 PostgreSQL 中工作
- java - 传递 TimeUnits 并转换为毫秒
- c++ - 我应该将数字存储在字符中以节省内存吗?
- css - 使用 dart sass 实现,grunt-sass 不编译 css 文件而不抛出错误
- asp.net-mvc - 浏览器应重定向时返回 json
- java - 与异常处理有关的基本 Java While(true) 问题
- salt-stack - 如何用盐重新启动系统服务?
- database - 什么是数据库上下文中的分类帐?
- sql - 电子邮件地址作为 SQL 中的表