AttributeError при попытке создать экран консоли с помощью urwid
Код ниже создает макет и отображает некоторый текст в макете. Далее макет отображается на экране консоли с использованием необработанного модуля отображения из библиотеки urwid. (Более подробную информацию о моем полном проекте можно почерпнуть из вопросов в совете по виджетам для консольного проекта и urwid для консольного проекта. Мой запрос помощи по скайпу находится здесь.) Однако выполнение кода завершается неудачно, так как возникает ошибка AttributeError, как описано ниже. Просматривая исходный код для urwid в /usr/lib64/python2.7/site-packages/urwid, я вижу, что и main_loop.py, и curses_display.py имеют функцию draw_screen с разными аргументами: main_loop.py -> def draw_screen (self):
curses_display.py> def draw_screen (self, (столбцы, строки), r):
Нужно ли указывать, какой использовать что-то вроде импорта draw_screen из команды specificFile? Или есть что-то принципиально неправильное, я смотрю на концепцию холста? Я также вижу, что класс фрейма (класс Frame (BoxWidget):) в файле /usr/lib64/python2.7/site-packages/urwid/ container.py имеет функцию рендеринга (def render (self, size, focus) = Ложь):)
Ошибка при запуске кода:
Traceback (most recent call last):
File "./yamlUrwidUIPhase6.py", line 104, in <module>
main()
File "./yamlUrwidUIPhase6.py", line 98, in main
form.main()
File "./yamlUrwidUIPhase6.py", line 51, in main
self.loop.run()
File "/usr/lib64/python2.7/site-packages/urwid/main_loop.py", line 274, in run
self.screen.run_wrapper(self._run)
File "/usr/lib64/python2.7/site-packages/urwid/raw_display.py", line 237, in run_wrapper
return fn()
File "/usr/lib64/python2.7/site-packages/urwid/main_loop.py", line 285, in _run
self.draw_screen()
File "/usr/lib64/python2.7/site-packages/urwid/main_loop.py", line 508, in draw_screen
canvas = self._topmost_widget.render(self.screen_size, focus=True)
AttributeError: 'NoneType' object has no attribute 'render'
Код:
import sys
sys.path.append('./lib')
import os
from pprint import pprint
import random
import urwid
ui=urwid.raw_display.Screen()
class FormDisplay(object):
def __init__(self):
global ui
self.ui = ui
self.palette = self.ui.register_palette([
('Field', 'dark green, bold', 'black'), # information fields, Search: etc.
('Info', 'dark green', 'black'), # information in fields
('Bg', 'black', 'black'), # screen background
('InfoFooterText', 'white', 'dark blue'), # footer text
('InfoFooterHotkey', 'dark cyan, bold', 'dark blue'), # hotkeys in footer text
('InfoFooter', 'black', 'dark blue'), # footer background
('InfoHeaderText', 'white, bold', 'dark blue'), # header text
('InfoHeader', 'black', 'dark blue'), # header background
('BigText', RandomColor(), 'black'), # main menu banner text
('GeneralInfo', 'brown', 'black'), # main menu text
('LastModifiedField', 'dark cyan, bold', 'black'), # Last modified:
('LastModifiedDate', 'dark cyan', 'black'), # info in Last modified:
('PopupMessageText', 'black', 'dark cyan'), # popup message text
('PopupMessageBg', 'black', 'dark cyan'), # popup message background
('SearchBoxHeaderText', 'light gray, bold', 'dark cyan'), # field names in the search box
('SearchBoxHeaderBg', 'black', 'dark cyan'), # field name background in the search box
('OnFocusBg', 'white', 'dark magenta') # background when a widget is focused
])
urwid.set_encoding('utf8')
def main(self):
global ui
#self.view = ui.run_wrapper(formLayout)
self.ui.start()
self.view = formLayout()
self.loop = urwid.MainLoop(self.view, self.palette, unhandled_input=self.unhandled_input)
self.loop.run()
def unhandled_input(self, key):
if key == 'f8':
quit()
return
def formLayout():
global ui
text1 = urwid.Text("Urwid 3DS Application program - F8 exits.")
text2 = urwid.Text("One mission accomplished")
textH = urwid.Text("topmost Pile text")
cols = urwid.Columns([text1,text2])
pile = urwid.Pile([textH,cols])
fill = urwid.Filler(pile)
textT = urwid.Text("Display")
textSH = urwid.Text("Pile text in Frame")
textF = urwid.Text("Good progress !")
frame = urwid.Frame(fill,header=urwid.Pile([textT,textSH]),footer=textF)
dim = ui.get_cols_rows()
#ui is treated as global handle for all functions, either belonging
#to any class or standalone functions such as formLayout
#need to check if screen has been started
if not ui._started:
print("Screen has not been started, so no use of rendering.Thus return :-( ")
return
ui.draw_screen(dim, frame.render(dim, True))
return
def RandomColor():
'''Pick a random color for the main menu text'''
listOfColors = ['dark red', 'dark green', 'brown', 'dark blue',
'dark magenta', 'dark cyan', 'light gray',
'dark gray', 'light red', 'light green', 'yellow',
'light blue', 'light magenta', 'light cyan', 'default']
color = listOfColors[random.randint(0, 14)]
return color
def main():
form = FormDisplay()
form.main()
########################################
##### MAIN ENTRY POINT
########################################
if __name__ == '__main__':
main()
Я не хочу менять функцию formLayout, так как я намерен добавить больше к этой базовой структуре кода, где будет добавлена другая функция, которая многократно вызывает formLayout, чтобы продолжать обновлять экран, основываясь на чтении значений из файла yml. У меня уже есть отдельный код, который занимается чтением файла yaml и извлечением из него упорядоченных словарей. После выяснения того, как заставить работать базовую консоль urwid, я могу перейти к интеграции обоих компонентов для создания моего окончательного приложения.
1 ответ
Ошибка атрибута была удалена путем добавления следующих строк в коде, как показано в этом вопросе.
строка 1:self.loop.widget = self.view
в main
класса FormDisplay
строка 2: делать return Frame
вместо return
в функции formLayout()
строка 3: добавлены строки для обработки нажатий клавиш в unhandled_input
функция