代码,使用urwid库,下面应该在控制台屏幕上显示yml文件的内容(如给定的here)(根据Application Form布局:
代码是:
import sys
sys.path.append('./lib')
import os
from pprint import pprint
import random
import urwid
ui = urwid.raw_display.Screen()
pile = urwid.Pile([])
from collections import OrderedDict
import yaml_ordered_dict
import collections
import yaml
import itertools
import copy
class FormDisplay(object):
def __init__(self):
global ui
#self.ui = urwid.raw_display.Screen()
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)
#urwid initialisation first or yml readin first. i chose yml reading
yOrDict = yaml_ordered_dict.load('ApplyForm.yml')
yOrDictLevel1 = yOrDict.get('ApplyForm')
self.ui.start()
self.view = formLayout(yOrDictLevel1)
self.loop = urwid.MainLoop(self.view, self.palette)
self.loop.widget = self.view
self.loop.run()
def find_value(needle, container):
# Already found the object. Return.
if isinstance(container, basestring) and needle in container:
return True
values = None
if isinstance(container, dict):
values = container.values()
elif hasattr(container, '__iter__'):
values = container.__iter__()
if values is None:
return False
# Check deeper in the container, if needed.
for val in values:
if find_value(needle, val):
return True
# No match found.
return False
def getChildMap(tmpMap):
tMap = tmpMap
tmpLen = len(tMap)
listOfKeys = tMap.keys()
topKey = listOfKeys[0]
#print('topkey', topKey)
mapObtained = tMap.get(topKey)
#print('getChildMap',mapObtained)
return mapObtained
def getMapForKeyIndex(tmpMap,index):
listOfKeysForMap = tmpMap.keys()
i = index
mapObtained = collections.OrderedDict(itertools.islice(tmpMap.items(), i, i+1))
#print(type(mapObtained))
#print("getMapForKeyIndex: key and map",i,mapObtained)
return mapObtained
def checkValOfKey(key,tmpMap):
tMap = tmpMap
for k, v in tMap.items():
if k == key :
tVal = tMap[key]
#print('checkValOfKey:tVal',tVal)
return tVal
def removeTopItem(tmpMap):
tMap = tmpMap
listOfKeys = tMap.keys()
topKey = listOfKeys[0]
del tMap[topKey]
return tMap
def createBlock(mapToWorkWith) :
global pile
#pile = urwid.Pile([])
tmapToWorkWith = copy.deepcopy(mapToWorkWith)
tmapToWorkWith = getChildMap(tmapToWorkWith)
#print('createBlock: tmapToWorkWith', tmapToWorkWith)
reducedMapToCarry = copy.deepcopy(tmapToWorkWith)
listOfKeys = tmapToWorkWith.keys()
#if blockPresentAsValueInMap(tmapToWorkWith) == True :
if checkValOfKey('$type',tmapToWorkWith) == 'Block' :
#create a block nd pile
print('XXXXXXXXcreate block and pile listXXXXXXXX')
#pile = urwid.Pile([])
keytoBeginPile = 2
#if displayPresentAsKeyInMap(tmapToWorkWith) == True :
#if checkContainmentOfKeyInMap('$display',(tmapToWorkWith)) :
reducedMapToCarry = removeTopItem(reducedMapToCarry)
reducedMapToCarry = removeTopItem(reducedMapToCarry)
if (tmapToWorkWith.has_key('$display')) == True :
print('display value ',tmapToWorkWith['$display'])
displayText = tmapToWorkWith['$display']
text = urwid.Text(('GeneralInfo', displayText),
align='center')
pile.contents.append(text)
keytoBeginPile +=1
#addDisplayToPile
reducedMapToCarry = removeTopItem(reducedMapToCarry)
for k in range(keytoBeginPile,len(tmapToWorkWith)) :
#//get the value of key at indexkeytoBeginPile in tmapToWorkWith
tmpMap = tmapToWorkWith.get(listOfKeys[k])
if checkValOfKey('$type',tmpMap) != 'Block' :
print('##add to Pile##')
print('display value ',tmpMap['$display'])
displayText = tmpMap['$display']
text = urwid.Text(('GeneralInfo', displayText),
align='center')
#pile.contents.append(text,options='pack')
pile.append(text)
keytoBeginPile +=1
reducedMapToCarry = removeTopItem(reducedMapToCarry)
#print('for Loop traversal: map', reducedMapToCarry)
#mapToPass(pop)
continue
else :
createBlock(reducedMapToCarry)
#return urwid.LineBox(urwid.AttrWrap(urwid.Overlay(urwid.LineBox(urwid.Padding(
# pile, align='center', left=3, right=3)), Banner, 'center', 150, 'middle', None),
# 'GeneralInfo'))
def formLayout(topMap):
global ui
global pile
f3 = open('OrderedMapInFinalApp.yaml',"w")
newMap = topMap #check if needed at all
yaml.dump(newMap, f3)
content = urwid.SimpleListWalker([])
listbox = urwid.ListBox(content)
#orderedMap has come
#read the key value and start for loop
print('lenght of map',len(newMap))
for i in range(len(newMap)):
mapToWorkWith = getMapForKeyIndex(newMap,i)
#print('for loop i nd mapToWorkWith Is',i,mapToWorkWith)
if i == 0 :
if (checkValOfKey('$type',mapToWorkWith) == 'Block') :
print('1st key read')
continue
else :
if (mapToWorkWith.has_key('TITLE') == True):
print('2nd key read')
continue
else :
pile = ([])
createBlock(mapToWorkWith)
#content.append(addBlockToOverallLayout())
content.append(pile)
continue
fill = urwid.Filler(listbox)
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, listbox.render(dim, True))
return frame
#return listbox
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():
#global ui
form = FormDisplay()
form.main()
########################################
##### MAIN ENTRY POINT
########################################
if __name__ == '__main__':
main()
#
代码使用ui
来表示控制台屏幕。
我使用了一个全局列表框api,它将包含来自yml文件的值,其值为$ display。代码未能给出以下错误:
Traceback (most recent call last):
File "./yamlUrwidUIPhase8FrameFinalAppC.py", line 308, in <module>
main()
File "./yamlUrwidUIPhase8FrameFinalAppC.py", line 302, in main
form.main()
File "./yamlUrwidUIPhase8FrameFinalAppC.py", line 61, in main
self.loop.run()
File "/home/gehna/urwidWorkInProgress/urwid/main_loop.py", line 272, in run
self.screen.run_wrapper(self._run)
File "/home/gehna/urwidWorkInProgress/urwid/raw_display.py", line 242, in run_wrapper
return fn()
File "/home/gehna/urwidWorkInProgress/urwid/main_loop.py", line 312, in _run
self.draw_screen()
File "/home/gehna/urwidWorkInProgress/urwid/main_loop.py", line 563, in draw_screen
canvas = self._topmost_widget.render(self.screen_size, focus=True)
File "/home/gehna/urwidWorkInProgress/urwid/widget.py", line 141, in cached_render
canv = fn(self, size, focus=focus)
File "/home/gehna/urwidWorkInProgress/urwid/container.py", line 1058, in render
focus and self.focus_part == 'body')
File "/home/gehna/urwidWorkInProgress/urwid/widget.py", line 141, in cached_render
canv = fn(self, size, focus=focus)
File "/home/gehna/urwidWorkInProgress/urwid/decoration.py", line 811, in render
top, bottom = self.filler_values(size, focus)
File "/home/gehna/urwidWorkInProgress/urwid/decoration.py", line 796, in filler_values
height = self._original_widget.rows((maxcol,),focus=focus)
AttributeError: 'ListBox' object has no attribute 'rows'
我用ddd和pydb调试器检查了代码的解析部分,解析yml部分似乎没问题,print语句正确地给出了$ display的值。我使用ui的方式有问题吗?我应该使用draw_screen吗?
答案 0 :(得分:1)
奇怪,您的代码应该按原样运行。我在创建Frames并给出错误的参数顺序时遇到了同样的错误,所以我最好的猜测是改变这一行
frame = urwid.Frame(fill,header=urwid.Pile([textT,textSH]),footer=textF)
到
frame = urwid.Frame(fill,urwid.Pile([textT,textSH]))
或
frame = urwid.Frame(header=urwid.Pile([textT,textSH]),fill)
暂时丢弃页脚,直到你在Frame内找到正确的参数顺序然后将其放回去。
答案 1 :(得分:1)
我在尝试将QuestionBox tutorial example放入ListBox时遇到了同样的错误。这answer为我解决了这个问题。
import urwid
def exit_on_q(key):
if key in ('q', 'Q'):
raise urwid.ExitMainLoop()
class QuestionBox(urwid.Filler):
def keypress(self, size, key):
if key != 'enter':
return super(QuestionBox, self).keypress(size, key)
self.original_widget = urwid.Text(
u"Nice to meet you,\n%s.\n\nPress Q to exit." %
edit.edit_text)
edit = urwid.Edit(u"What is your name?\n")
fill = urwid.BoxAdapter(QuestionBox(edit), height=2)
lb = urwid.ListBox([fill])
loop = urwid.MainLoop(lb, unhandled_input=exit_on_q)
loop.run()