Как вызвать экранный менеджер в части файла Python, чтобы изменить экраны только тогда, когда все счетчики выбраны - PullRequest
1 голос
/ 10 ноября 2019

Я сделал предыдущий пост здесь (Запуск диспетчера экрана для изменения экрана в Kivy с условного условия if), попытавшись выполнить ту же задачу другим способом. У меня там не было никаких решений, поэтому я пробую другой метод. Однако сейчас я сталкиваюсь с другими проблемами.

Я создаю опцию выбора дня и времени для пользователя. Для этого я пытаюсь создать кнопку, которая переходит к следующему экрану (при нажатии), когда для всех счетчиков выбраны значения.

Чтобы программа могла определить момент нажатия на счетчики (день), счетчики часов и минут), я назначил значение True для состояния (d_state, m_state, h_state и A_state для дня, минуты, часа, Am / Pm соответственно) в коде .py для каждого счетчика.

Диспетчер экрана переключится с screen_two на screen_three только в том случае, если все счетчики имеют состояние: True. Я назначаю True, когда на спиннер нажимают (и выбирается опция).

Большая часть кода работает как положено, за исключением строки self.screen_manager.current = 'screen_two' в функции switch_screen в классеScreenTwo. Я знаю это, потому что изначально я заменил строку 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()

1 Ответ

2 голосов
/ 10 ноября 2019

Спасибо за создание отдельного отдельного примера, это намного лучше. Вы все еще можете сократить его, удалив некоторые из 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 экрана, но такого атрибута не существует. Если вы прочитаете документацию , вы обнаружите, что на самом деле вы хотите получить доступ self.manager.

Другие проблемы:

  • Экран все еще выигрална самом деле не меняется, потому что вы устанавливаете current на "screen_two", который является именем активного в данный момент экрана.
  • Не используйте 'True', чтобы указать, что что-то произошло, используйте фактическое логическое значениезначение True.
  • Не используйте глобальные переменные по всем обычным причинам, которые вы можете посмотреть. В частности, не используйте их без инициализации, это означает, что ваш код вызывает ошибку NameError, если кнопка нажата до того, как эти переменные существуют. Может быть, поэтому вы добавили плохие строки except:, но это только ухудшает ситуацию. Более подходящим решением будет использование свойств объекта ScreenTwo, которые можно инициализировать разумными значениями (например, False), а затем установить True позднее.
...