程序结构
npyscreen应用主要由表单(Form Object)、表单部件(Widget Object)和应用对象(Application Objects)组成。
- Widget Object: Input,CheckBox,Radio,SlideBar等表单组件。
- Form Object: Widgetght的容器,表单尺寸通常为控制台的尺寸。
- Application: Application提供管理应用环境的便捷方法, 可以减少多屏幕程序在交互时可能出现的错误,并且在开发时可以通过此对象使用npyscreen提供的附加特性。
import npyscreen
# Application Object
class MyTestApp(npyscreen.NPSAppManaged):
def onStart(self):
self.registerForm("MAIN", MainForm())
# Form 表单对象
class MainForm(npyscreen.Form):
def create(self):
# weight 对象
self.add(npyscreen.TitleText, name = "Text:", value= "Hellow World!" )
def afterEditing(self):
self.parentApp.setNextForm(None)
if __name__ == '__main__':
TA = MyTestApp()
TA.run()
如果觉得上面的代码对于创建一个应用程序太繁琐了,npyscreen的作者为我们提供了另一种更为简便的方式来创建程序。
import npyscreen
# 使用函数代替class来创建Form对象
def myFunction(*args):
F = npyscreen.Form(name='My Test Application')
# 在Form中添加一个文本输入框, 并在外面接收输入框的值
wd = F.add_widget(npyscreen.TitleText, name = "Text:", value= "Hello World!" )
# F.edit() 在执行时,在显示交互界面后会等待用户操作后,再返回wd的值;而使用F.display()时,程序会直接获取运行并输出wd的值
F.edit()
return wd.value
if __name__ == '__main__':
# 使用npyscreen的warpper构建应用程序
retVal = npyscreen.wrapper_basic(myFunction)
print(retVal)
面向对象
虽然npyscreen提供的wrapper可以很轻松的创建简单程序,但当Form对象中包含众多Widget时,我们就需要自定义一个Form对象来统一管理Widget。
想要创建自定义的Form对象,只需要继承npyscreen.Form,然后重写create
方法即可。
class CustomForm(npyscreen.Form):
def create(self):
self.name = self.add(npyscreen.TitleText, name='Name')
self.age = self.add(npyscreen.TitleText, name='Age')
self.date = self.add(npyscreen.TitleDateCombo, name='Date')
在上面的例子中,我们了解了如何自定义Form
对象来管理我们的页面部件,但在程序中仍然需要我们手动去调用edit
方法来显示页面。这样的调用方式不但不够优雅,还容易引发深度递归的问题。接下来我们来看看如何使用NPSAppManaged
类来管理程序中的Form(NPSAppManaged是管理应用程序的最佳方式),使用NPSAppManaged时,不需要像普通的NPSApp那样编写自定义主循环,NPSAppManaged将自主管理程序中的每个Form,用户只需要调用run
方法即可。
class MyApplication(npyscreen.NPSAppManaged):
def onStart(self):
self.addForm('MAIN', CustomForm, name='New Form')
NPSAppManaged
使用MAIN Form
作程序入口,使用NPSAppManaged
管理程序时一定要指定MAIN对应的Form,否则会抛出self._LAST_NEXT_ACTIVE_FORM = self._Forms[self.NEXT_ACTIVE_FORM] KeyError: 'MAIN'
异常。
NPSAppManaged
注册Form
NPSAppManaged提供了三种注册Form的方法
# 方法一
NPSAppManaged.addForm(*id*, *FormClass*, ...)
# 方法二
NPSAppManaged.addFormClass(*id*, *FormClass* ...)
# 方法三
NPSAppManaged.registerForm(id, fm)
addForm方法
NPSAppManaged.addForm(*id*, *FormClass*, ...)
方法的参数列表中,id
接收一个字符串作为Form的唯一标识,FormClass
接收一个Form类,由addForm方法创建一个Form的实例,并返回该Form实例的弱引用。而多余的参数将作为Form类构造函数的参数。
addFormClass方法
NPSAppManaged.addFormClass(*id*, *FormClass*, ...)
, 这个方法传入的参数与addForm
方法相同,方法接收一个Form Class做参数,多余的参数传入Form的构造函数。而此方法与addForm
方法的区别在于,每次被编辑时都是创建一个新的Form实例。
registerForm方法
NPSAppManaged.registerForm(id, fm)
方法与上面两个方法都不同,它接收的参数是一个Form的实例,并将这个实例注册到NPSAppManaged管理的Form集合中。这里需要注意一下,registerForm只有两个参数,因为Form实例在方法前已经实例化了,这里就不再接收和创建Form相关的参数。
通过以上三种方法创建的Form实例都可以通过self.parentApp
来获取到NPSAppManaged
对象,如果想要移除Form,可以调用removeForm(id)
方法。
运行Application
通过前面的方法,我们已经能够创建并注册自定义的Form对象到NPSAppManaged应用中,接下来只要调用NPSAppManaged.run()
方法就可以让程序运行起来了,如果你运行之后发现出现了self._LAST_NEXT_ACTIVE_FORM = self._Forms[self.NEXT_ACTIVE_FORM] KeyError: 'MAIN'
,别急,那可能是我忘记告诉你设置程序的初始Form了。
NPSAppManaged.run()
执行时,会默认将Form id为‘MAIN’的Form作为初始Form显示在界面内,如果没有正确的设置‘MAIN’Form,就会出现类似上面提到的异常情况。当然,如果你不想使用‘MAIN’作为初始Form的id名称,可以在调用run方法前修改NPSAppManaged.STARTING_FORM
的值,来指定初始Form的id。
现在重新执行run方法应该就可以成功的运行程序了,当然现在我们的程序只有一个Form,太简陋,读者可以试着多创建几个Form,通过下列方法去按自己的方式控制程序显示。
方法名 | 说明 |
---|---|
NPSAppManaged.setNextForm(formid) | 设置下一个显示的Form |
NPSAppManaged.setNextFormPrevious() | 将当前Form的上一个Form设置为下一个显示 |
NPSAppManaged.switchForm(formid) | 切换到指定Form |
NPSAppManaged.switchFormPrevious() | 切换到指定Form的上一个Form |
如果
setNextForm
或switchForm
传入参数为None
,则退出程序
NPSAppManaged 生命周期函数
用于通过通过重写NPSAppManaged的部分方法来控制NPSAppManaged的生命周期
方法 | 说明 |
---|---|
NPSAppManaged.onInMainLoop() | 在每个屏幕之间切换时调用(首屏不会调用) |
NPSAppManaged.onStart() | 初始化方法,可以在这里设置Form |
NPSAppManaged.onCleanExit() | 程序正常退出时调用此方法 |
Form.beforeEditing() | 在Form初始前执行 |
Form.afterEditing() | 在退出Form时执行 |
完整代码
import npyscreen
class CustomForm(npyscreen.Form):
def create(self):
self.name = self.add(npyscreen.TitleText, name='Name')
self.age = self.add(npyscreen.TitleText, name='Age')
self.date = self.add(npyscreen.TitleDateCombo, name='Date')
self.myDepartment = self.add(npyscreen.TitleSelectOne, max_height=3,
name='Department',
values=['Option 1', 'Option 2', 'Option 3'],
scroll_exit=True)
# scroll_exit True 方向键上下超过可选数量时, 会直接切换到上一个或下一个Widget
# false 时, 只能通过tab切换widget
def afterEditing(self):
self.parentApp.addForm('SecondForm', CustomSecondForm, name='Second Form')
self.parentApp.setNextForm('SecondForm')
class CustomSecondForm(npyscreen.Form):
def create(self):
self.info = self.add(npyscreen.TitleText, value="Second Form")
def afterEditing(self):
# self.parentApp.setNextFormPrevious()
self.parentApp.setNextForm(None)
class MyApplication(npyscreen.NPSAppManaged):
def onStart(self):
self.addForm('MAIN', CustomForm, name='First Form')
# self.addForm(MyApplication.STARTING_FORM, CustomForm, name='New Form')
def onInMainLoop(self):
print('onInMainLoop')
super().onInMainLoop()
def onCleanExit(self):
print('onCleanExit')
super().onCleanExit()
if __name__ == '__main__':
# 设置自定义的初始Form id, 设置后, 'MAIN'将无法使用
# MyApplication.STARTING_FORM = 'MyMain'
TestApp = MyApplication().run()
print("Application Exit")