npyscreen简单应用(二)- NPSAppManaged

程序结构

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

如果setNextFormswitchForm传入参数为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")
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容