Сводка о том, что идет не так
Я пытаюсь добавить корневой виджет в существующее приложение .kv, где указанный произвольный корневой виджет создается с помощью kivy.lang.Builder.load_string method
.Это будет хорошо работать, если строка kivy, предоставленная в Builder, представляет действительный и допустимый код .kv.Ожидается, что иначе не получится.
Для этого я добавил блок try
- except
в надежде обнаружить любую ошибку, которая могла вызвать сбой при добавлении соответствующих виджетов kivy.Соответствующий Exception
затем используется внутри всплывающего сообщения, после которого недопустимые виджеты, в конечном счете, не должны добавляться.
Для некоторых входов это работает должным образом (при появлении ошибки отображается всплывающее сообщение).Тем не менее, для определенных строковых входов, приложение вылетает, не перехватывая ответственных ошибок.Теперь мне интересно, почему эти ошибки не были пойманы и как их правильно отловить.Ниже приведен точный код.
Мое приложение
Мое приложение состоит из одного .py
и одного .kv
файла 1 , как показано ниже (упрощенно):
# main.kv
ScreenManager:
Screen:
name: 'string_screen'
BoxLayout:
orientation: 'vertical'
TextInput:
id: code_text
text: app.text
Button:
text: 'call'
on_release: app.call()
Screen:
name: 'called_screen'
BoxLayout:
id: render_layout
<Button>:
size_hint: 0.5, None
height: '1.2cm'
<MsgPopup>:
size_hint: .75, .6
title: "Attention"
BoxLayout:
orientation: 'vertical'
padding: 10
spacing: 20
Label:
id: message_label
size_hint_y: 0.4
text: "Label"
Button:
text: 'Dismiss'
size_hint_y: 0.4
on_press: root.dismiss()
И файл python:
# main.py
from kivy.app import App
from kivy.properties import StringProperty
from kivy.lang import Builder
from kivy.uix.popup import Popup
class MainApp(App):
text = StringProperty()
kv = None
def call(self):
kv_text = self.root.ids['code_text'].text
try:
self.kv = Builder.load_string(kv_text)
print(self.kv)
self.root.ids['render_layout'].clear_widgets()
print('cleared')
self.root.ids['render_layout'].add_widget(self.kv)
print('added')
self.root.current = 'called_screen'
self.root.transition.direction = 'left'
print('swiped')
except Exception as e:
popup = MsgPopup(e)
popup.open()
class MsgPopup(Popup):
def __init__(self, msg):
super().__init__()
self.ids.message_label.text = str(msg)
if __name__ == '__main__':
MainApp().run()
1 На самом деле мое приложение состоит из некоторого дополнительного и более сложного кода, но этой упрощенной версии достаточно длявоспроизводить нежелательное поведение.
Как видно из кода, приложение состоит из двух экранов.Основным элементом первого является TextInput
, из которого создается второй.Приведенные ниже два изображения демонстрируют отсутствие ошибок.
Ниже приведен пример правильного поведения, когда текстовый ввод содержит все, что приводит к ошибке:
Неожиданное поведение
Это последнее изображение правильно показывает всплывающее сообщение.Однако при вводе следующего ввода в поле TextInput, например:
FloatLayout:
Label:
text: "Hello World"
pos_hint: 0.5, 0.7
Что является ошибкой в аргументе значения pos_hint
.Затем приложение вылетает, когда я нажимаю кнопку call .И вместо ожидаемого всплывающего сообщения я получаю фактическую трассировку стека!
<kivy.uix.floatlayout.FloatLayout object at 0x0000016F7F0FC800>
cleared
File "C:/Users/ajdin/.PyCharmCE2019.1/config/scratches/scratch_1.py", line 34, in <module>
added
swiped
MainApp().run()
File "C:\Users\ajdin\Anaconda3\lib\site-packages\kivy\app.py", line 826, in run
runTouchApp()
File "C:\Users\ajdin\Anaconda3\lib\site-packages\kivy\base.py", line 502, in runTouchApp
EventLoop.window.mainloop()
File "C:\Users\ajdin\Anaconda3\lib\site-packages\kivy\core\window\window_sdl2.py", line 727, in mainloop
self._mainloop()
File "C:\Users\ajdin\Anaconda3\lib\site-packages\kivy\core\window\window_sdl2.py", line 460, in _mainloop
EventLoop.idle()
File "C:\Users\ajdin\Anaconda3\lib\site-packages\kivy\base.py", line 346, in idle
Clock.tick_draw()
File "C:\Users\ajdin\Anaconda3\lib\site-packages\kivy\clock.py", line 588, in tick_draw
self._process_events_before_frame()
File "kivy\_clock.pyx", line 427, in kivy._clock.CyClockBase._process_events_before_frame
File "kivy\_clock.pyx", line 467, in kivy._clock.CyClockBase._process_events_before_frame
File "kivy\_clock.pyx", line 465, in kivy._clock.CyClockBase._process_events_before_frame
File "kivy\_clock.pyx", line 167, in kivy._clock.ClockEvent.tick
File "C:\Users\ajdin\Anaconda3\lib\site-packages\kivy\uix\floatlayout.py", line 116, in do_layout
for key, value in c.pos_hint.items():
AttributeError: 'tuple' object has no attribute 'items'
Process finished with exit code 1
Мой ожидаемый вывод здесь будет аналогичен предыдущему: показанное выше сообщение трассировки стека показывается во всплывающем окне, безсбой приложения! .Я ожидаю, что из-за способа обработки исключения в обратном вызове кнопки:
kv_text = self.root.ids['code_text'].text
try:
self.kv = Builder.load_string(kv_text)
print(self.kv)
self.root.ids['called_screen'].clear_widgets()
print('cleared')
self.root.ids['called_screen'].add_widget(self.kv)
print('added')
self.root.current = 'called_screen'
self.root.transition.direction = 'left'
print('swiped')
except Exception as e:
popup = MsgPopup(e)
popup.open()
Поэтому, если в методе load_string произошла ошибка, я ожидаю ее отловить.В противном случае, если это пройдет каким-то образом, я ожидаю отловить ошибку в методе add_widget.Однако из приведенной выше трассировки стека кажется, что все эти операторы успешно проходят с ошибочным вводом текста !.Вы можете увидеть это по напечатанным выводам в трассировке стека:
...
<kivy.uix.floatlayout.FloatLayout object at 0x0000016F7F0FC800>
cleared
File "C:/Users/ajdin/.PyCharmCE2019.1/config/scratches/scratch_1.py", line 34, in <module>
added
swiped
...
Он печатает все операторы в блоке try, сигнализируя, что он прошел через него без каких-либо ошибок , верно?
Вопрос
Таким образом, если вышеупомянутая сгенерированная ошибка не была обнаружена, что ее вызвало и как / где я могу ее правильно отловить, чтобы приложение в конечном итоге соответствовало предполагаемому поведению (Ошибкасамое большее всплывающее сообщение)?