• uick Guide to Python's Snack Module


    Quick Guide to Python's Snack Module

    uick Guide to Python's Snack Module

    Written by Jared Riley

    Snack is a python library based on newt that can be used to
    create a simple text based User interface. This is the package
    that was used by Red Hat to create their installation along with
    a number of configuration tools. It is an ideal platform upon
    which to create installation and configuration scripts,
    particularly if you don't want to rely on X, or you want to
    avoid complexity.

    The newt RPM on Red Hat Linux comes with two sample python
    programs: peanuts.py, and popcorn.py. From these it is expected
    that the programmer will be able to figure out what to do.
    There is also an SGML guide to the newt C library. From this
    you can also make some inferences, but some things are
    different in the python world. You should read this document
    anyway because it gives an overview of how newt/snack programs work.

    I have used snack to create a configuration program for
    software that will run on a server without X Windows installed.
    Along the way, I had to read the sample programs, Red Hat's
    installation program, and the C Library documentation.
    Hopefully the information here will help you do it with far less
    effort.

    Other Resources

    I have only documented what I have used. If you would like to
    undertake more complex programs or use features not discussed,
    here are some other places to look. Unless otherwise mentioned,
    these files are contained in the newt or newt-devel RPMS on Red
    Hat. Their location may be different on your version of Linux.

    1. snack.py

      This is the interface to the newt library. Whatever is in
      this file is what you are allowed to access from your
      program.

    2. tutorial.sgml

      This file documents some of the calls in the newt library
      for C. Not every call is documented, and not every call is
      available through snack.

      If you are like me and you can't figure out how to get
      something readable out of sgml in less than half a day, you
      can find it on the internet. I found it
      here.

    3. peanuts.py and popcorn.py

      These sample programs come with the newt-devel RPM on Red
      Hat. Between them, they use most of the widgets that are
      available in snack.

    Loading Snack

    To use the snack module, import it into your program.

    from snack import *

    Snack provides the SnackScreen class, which you must allocate
    before you can do anything.

    screen = SnackScreen()

    This call will paint your console a lovely blue. It will stay
    this way forever, unless you call the finish method.

    screen.finish()

    Calling the finish method is very important. If you don't call
    it, then your screen will be left in a fairly unusable state
    when you exit python. To recover, you will have to call
    reset from the shell. You may also have to fix your
    interrupt and end of file keys (stty intr ^C; stty eof ^D).

    Another caveat is that newt takes over your terminal and
    prevents signals due to keystrokes. ^Z and ^C will not work, so
    you should make an effort to provide a way to exit the program
    cleanly. There is a way to allow job control keystrokes to
    function correctly that will be discussed later.

    Forms and Grids

    You can't do very much with snack without using Forms and
    Grids. These two items have been combined into the GridFormHelp
    and GridForm classes, but I will leave those for you to figure
    out. Instead, I will show how to use basic Forms and Grids to
    create your display. In a later section I will show the types
    of Widgets that can be used.


    screen = SnackScreen()
    upperleft = Widget()
    upperright = Widget()
    lowerleft = Widget()
    lowerright = Widget()
    g = Grid(2, 2)
    g.setField(upperleft, 0, 0, (0, 0, 1, 1))
    g.setField(upperright, 1, 0)
    g.setField(lowerleft, 0, 1)
    g.setField(lowerright, 1, 1, growx = 1, growy = 1)

    screen.gridWrappedWindow(g, "Title Text")
    f = Form()
    f.add(g)
    result = f.run()
    screen.popWindow()
    screen.finish()

    Grid

    The call to grid sets the size of the grid. The width comes
    before the height, so in this case, the grid will be two widgets
    wide and 2 widgets high.

    After creating the grid, the widgets are added into the grid
    using the setField method. The second and third parameters are
    the location in the grid where the widget is to be placed.
    Again, the horizontal parameter comes before the vertical
    setting. Since python is zero based, the available positions
    are 0 to horizontal size - 1.

    snack will not complain if you put more than one widget into
    the same location in the grid. However, it will put all of the
    elements on top of each other, so you are unlikely to be pleased
    with the result.

    In the first call to setField, I have used the optional padding
    argument. This is a tuple listing how much room is to be left
    around the widget in the grid. The order of the widget is
    (Left, Top, Right, Bottom).

    The last call to setField has used the growx and growy
    parameters. These are used when you have different sized
    widgets. In order to make your window appear balanced, snack
    will add extra space into a smaller widget if it can so that the size
    of that widget will be grown to be the size of the widgets
    around it.

    You may create a grid, and then put that grid into another
    grid's field. In this way you can create windows with different numbers
    of fields in different rows or columns.

    Before the grid can be displayed on the screen, you must call
    screen.gridWrappedWindow(). This configures the grid and
    readies it for display.

    Form

    The Form is the thing that holds all of the widgets and
    displays them on the screen. It returns the widget that caused
    the form to be exited. Once the form has returned, you must
    call the screen.popWindow() method to remove the window from the
    screen.

    You must add each widget to the form. However, there is a
    shortcut. If you have put all of your elements into a grid,
    then you can just add the grid. This will recursively add each
    element from the grid to the form.

    reflow(text, width, flexDown = 5, flexUp = 5)

    This is the only function in the snack library.
    reflow takes some text and reformats it to fit into the
    parameters given. flexDown and flexUp are
    guidelines to the library as to how many lines it should try to
    fit the text into while it is reconfiguring. reflow
    takes line breaks literally, so if you are
    going to use strings enclosed by """, then you should use line
    continuation characters to keep each paragraph together.

    reflowreturns a tuple of the new wrapped text, the
    width of the text, and the actual height after adjustments.

    Widget Classes

    Here is a list of the different types of Widgets, and some of
    the parameters to the init function, and their methods:

    • Button(text)

      Buttons are pretty simple. The text that you pass to the
      button is what will be displayed on the button. There isn't
      really a way to change the text later, so to do that, you
      would have to create a new button.

    • CompactButton(text)

      These are the same as buttons, but they don't have a nice
      border. Use them when you are cramped for space on the
      screen.

    • Checkbox(text, isOn = 0)

      This produces a box that can be turned on or off. It is
      independent of other checkboxes that you might have in the
      form. The text is displayed adjacent to the box.
      isOn is optional, and sets the initial value of the
      box.

      The Checkbox has the following methods:

      • value()

        Returns whether the box is on or not.

      • selected()

        Returns whether the box is currently selected or not.
        This is different from whether or not the box is on as
        returned by value().

      • setFlags(flag, sense)

        setFlags is used to change whether or not a
        user can actually select the checkbox. The possible
        values of sense are FLAGS_SET,
        FLAGS_RESET, and FLAGS_TOGGLE. FLAGS_SET
        sets a particular flag to true. FLAGS_RESET sets the
        flag to false. FLAGS_TOGGLE sets it to the opposite
        value of what it currently is.

        The only flag currently allowed is
        FLAG_DISABLED. This flag sets whether or not
        the checkbox can be selected, and thereby changed.

      • setValue()

        Sets the current value of the checkbox.

    • SingleRadioButton(text, group, isOn = 0)

      A Radio button is a widget, of which only one in a group can be
      selected. group is the group of radio buttons to
      which this button belongs. If there are no other buttons in
      the group yet, then pass in None. If you have other
      buttons, pass in one of the other buttons to associate the
      buttons together.

      It has the following methods:

      • selected()

        Returns whether this button is the one in the group
        that is selected.

    • Listbox(height, scroll = 0,
      returnExit = 0, width = 0, showCursor = 0)

      A list box offers a list of selection. Only one thing can
      be selected at a time. If you want to have multiple
      selections, use a CheckboxTree.

      height is how
      many lines there should be in the box. scroll
      determines whether or not a scroll bar is present.
      returnExit says that if the ENTER key is pressed
      while in the box, the form should be exited. width
      is the number of characters wide the Listbox should be.
      showCursor sets the status of the text cursor. In
      general, you want to have it off because having it on is
      fairly ugly.

      There is quite a bit you can do with a list box.

      • append(text, item)

        Adds an entry to the end of the Listbox. text
        is whatever text you want to be displayed
        in the list box. item is any object you would
        like. You can pass in an integer, a string, or anything
        at all.

      • insert(text, item, before)

        Inserts an entry before another entry in the Listbox.
        before is whatever object you passed in for
        another item in the Listbox (not the display text). If
        you pass in "None" for before, then this item will be
        inserted at the beginning of the list.

      • delete(item)

        Removes something from the Listbox. item is
        whatever you passed in to the listbox before when you
        added the element to the list.

      • replace(text, item)

        Replaces another element with this element. The
        element it replaces will be given by item. The new
        element in the list will still return the same item.

      • current()

        Returns the item corresponding to the current selection
        in the Listbox. It does not return the text.

      • setCurrent(item)

        Selects the entry in the Listbox given by
        item.

      • clear()

        Empties the Listbox.

    • Textbox(width, height, text, scroll = 0, wrap = 0)

      A Textbox displays some text. width,
      height, and text are fairly obvious. They
      set the size of the box and the text that should be
      displayed in it. scroll determines whether or not
      there is a vertical scrollbar on the box. There is no such
      thing as a horizontal scrollbar in snack, so you should
      probably use wrap to keep everything inside the
      box.

      Textbox offers only one method. setText(text) lets
      you change the text that will be displayed in the box.

    • TextboxReflowed(width, text, flexDown = 5, flexUp = 10,
      maxHeight = -1)

      This is a Textbox that uses reflow to
      configure the text that will be displayed.

    • Scale(width, total)

      Scales are different from other widgets in that they are
      intended to be updated on the fly. This means that you must
      use some other features of the Form and SnackScreen classes
      that are not required by other widgets.

      width is the character width of the scale on the screen.
      total is the amount that the scale should be out
      of.

      The Scale class has only one method:

      • set(amount)

        amount is a value between 0 and the
        total parameter used to set up the Scale.

      Here is an example of using a scale. Notice that instead
      of running the form, the draw method is used instead. Also,
      the screen must be refreshed every time that we want to see
      what has happened.

      screen = SnackScreen()
      g = Grid(1, 1)
      s = Scale(40, 1000)
      s.set(0)
      g.setField(s, 0, 0)
      screen.gridWrappedWindow(g, "Scale Example")
      f = Form()
      f.add(s)

      for i in range(1000):
      for j in range(10000):
      pass
      s.set(i)
      f.draw()
      screen.refresh()

      screen.finish()

      If you had other components on the form, and you wanted to
      get user input, then you would have to run the form at this
      point to get the result of the user's input. However, the
      scale would no longer be updated once the form was run.

    • Entry(width, text = "", hidden = 0, password = 0, scroll
      = 1, returnExit = 0)

      width is the size of the field where text is
      entered. text is the initial value of the entry.
      hidden hides the text from view. The user can't
      tell that anything is there, and when they edit, they can't
      tell what they are typing. password displays the
      value of the entry as a series of '*'. scroll
      allows the user to scroll horizontally if the text of the
      entry is too wide to fit in the space it has.
      returnExit indicates that the containing Form
      should exit when the ENTER key is pressed in the box.

      Entry boxes have the following methods:

      • value()

        This returns the text that is currently in the
        Entry.

      • set(text)

        Changes the text that is currently in the Entry.

      • setFlags(flag, sense)

        setFlags is used to change whether or not a
        user can actually select the Entry and change it's
        value. The possible
        values of sense are FLAGS_SET,
        FLAGS_RESET, and FLAGS_TOGGLE. FLAGS_SET
        sets a particular flag to true. FLAGS_RESET sets the
        flag to false. FLAGS_TOGGLE sets it to the opposite
        value of what it currently is.

        The only flag currently allowed is
        FLAG_DISABLED. This flag sets whether or not
        the Entry can be selected, and thereby changed.

    Useful Combination Classes

    There are several classes which have been defined for
    convenience because they are so common.

    • RadioBar(screen, buttonlist)

      This class provides an easy way to set up a group of radio
      buttons, instead of doing everything yourself.

      buttonlist is a list of tuples containing
      information about each button to be contained in the group.
      Each tuple has three elements. The first is a title for the
      button. The second element is an object to return if the
      Radio button is currently selected. The third is either 0
      or 1. If 1, it indicates that this button is the default.

      RadioBar has the
      following methods:

      • add(title, value, default = None)

        This method creates a new Radio Button and adds it to the
        group. value is an object associated with the
        button that will be returned by getSelection

      • getSelection()

        Returns the value associated with the Radio button that
        is currently selected.

    • ButtonBar(screen, buttonlist)

      This class provides an easy way to set up a group of
      buttons without having to do everything yourself. The
      comments in snack.py suggest that when a ButtonBar is added
      to a grid, the growx parameter be set.

      buttonlist is a list of buttons that can take
      three different types of button descriptions in the
      list.

      1. If the element is a tuple consisting of three elements,
        then the elements are assumed to be the following:

        1. The text to display in the button.

        2. The value to return to the user when the
          buttonPressed method is called.

        3. A hotkey to be associated
          with the button.

      2. A tuple consisting of only two elements is the same as
        for three elements, but without a hotkey.

      3. A string is also acceptable. In this case, the
        text for the button is set to the string. The value for
        the button is set to the lower case value of the
        string.

      A ButtonBar has only one method:
      buttonPressed(result). result is the return
      value from calling Form.run(). If the Form exited because
      of a hotkey mapped to one of the buttons, or because one of
      the buttons was pressed, this function will return the value
      associated with that button. Otherwise, it will return
      None.

    • CheckboxTree(height, scroll = 0)

      This class creates a container for a tree of Checkboxes.
      An entry in the tree can either be a branch with checkboxes
      and branches under it, or it can be a checkbox.

      There are several methods associated with a CheckboxTree:

      • append(text, item = None, selected = 0)

        This method adds an element to the end of the top level
        of the CheckboxTree.

        As usual, text is the display text for this
        item. item is an object of your choice. It
        should be unique for any elements that will be accessed
        later by the class. If you don't supply an item, the
        text will be used. selected indicates whether
        the item is initially selected.

      • addItem(text, path, item = None, selected = 0)

        This method allows you to add an item to the
        CheckboxTree anywhere in the tree. The parameters are
        the same as for the append method, except for the
        path parameter.

        path is a tuple of integers which indicates to
        the CheckboxTree where this item should be placed in the
        tree. The last element of the tuple should be
        snackArgs['append'] to indicated that the tuple
        is terminated. Here is an example of adding several things to a
        CheckboxTree:

        tree = CheckboxTree(height = 5, scroll = 1)
        tree.addItem("First", (snackArgs['append'], ))
        tree.addItem("Second", (snackArgs['append'], ))
        tree.addItem("A", (0, snackArgs['append']))
        tree.addItem("B", (0, snackArgs['append']))
        tree.addItem("X", (0, 1, snackArgs['append']))

        This would produce a tree with containing five
        entries. Initially, only the items labeled
        First and Second would be displayed.
        Second would be a Checkbox, while First would
        be expandable. If you expanded
        First, you would see underneath it the
        A, and B items. A would be a
        checkbox, and B would be expandable. Finally, if you
        expanded B, you would see a Checkbox for
        X.

      • getCurrent()

        Returns the item that the cursor is currently
        highlighting.

      • getSelection()

        Returns a list of all items that are currently
        selected.

      • setEntry(item, text)

        Changes the text associated with this particular
        item.

      • setEntryValue(item, selected = 1)

        Set whether or not the entry associated with this item
        is selected.

      • getEntryValue(item)

        Return whether or not the entry associated with this
        item is selected.

    Common Dialog Functions

    There are three functions that can be used to display common
    dialog boxes.

    • ListboxChoiceWindow(screen, title, text, items, buttons =
      ('Ok', 'Cancel'), width = 40, scroll = 0, height = -1,
      default = None, help = None)

      This function displays a dialog with some descriptive text,
      a listbox, and buttons at the bottom. It returns a tuple
      consisting of the button
      that was pressed to exit the dialog, and the entry in the
      list that was selected. It's parameters are:

      • screen

        A valid SnackScreen

      • title

        The title for the dialog box.

      • text

        Text that should be displayed at the top of the dialog
        box before the Listbox.

      • items

        This can be a list or tuple of things to display in the
        Listbox. Each item in the list should be either a
        string or a tuple. If it is a tuple, the first field is
        the text to display, and the second is an item
        associated with that text. If a string, then the text
        to display is set to the string, and the item returned
        will be the numeric position of the entry in the
        Listbox.

      • buttons

        The buttons parameter is passed directly through to a
        ButtonBar.

      • width

        This is used as the width of the text box at the top of
        the dialog.

      • scroll
      • height
      • default

        All of these items are given to the
        Listbox.

      • help

        This is the argument passed to the help callback
        function. See the section on help
        for more information.

    • ButtonChoiceWindow(screen, title, text, buttons = ['Ok',
      'Cancel'], width = 40, x = None, y = None, help = None)

      This function displays some text to the user and a set of
      buttons for them to press at the bottom of the dialog. It
      returns the button that was pressed.

      The parameters mean the following things:

      • screen

        A valid SnackScreen.

      • title

        The title for the dialog box.

      • text

        The text to be displayed in the dialog box.

      • buttons

        The buttons parameter is passed directly through to a
        ButtonBar.

      • width

        This is used as the width of the Textbox.

      • x, y

        These parameters are used to set the location of the Window on
        the screen. If they are not given, the window is centered,
        which is probably what you want.

      • help

        This is the argument passed to the help callback
        function. See the section on help
        for more information.

    • EntryWindow(screen, title, text, prompts, allowCancel =
      1, width = 40, entryWidth = 20, buttons = [ 'Ok', 'Cancel'
      ], help = None)

      This function displays a window with a set of Entries in it
      to be filled in by the user. It returns the button that was
      pressed to exit the dialog.

      The parameters mean the following things:

      • screen

        A valid SnackScreen.

      • title

        The title for the dialog box.

      • text

        The text to be displayed in the dialog box.

      • buttons

        The buttons parameter is passed directly through to a
        ButtonBar.

      • prompts

        This is a list of the prompts to be used as labels for
        each Entry. A string is used as the label for the
        Entry. On the other hand, if the prompt is a tuple,
        then the first element of the tuple is used as the
        tuple, and the second element is assumed to be an
        already existing Entry.

      • allowCancel

        This isn't actually used for anything in the version of
        snack that I worked with.

      • width

        This is used as the width of the Textbox.

      • entryWidth

        This value is used as the width for each Entry.

      • buttons

        As usual, this is passed through to a
        ButtonBar widget.

      • help

        This is the argument passed to the help callback
        function. See the section on help
        for more information.

    help

    There are two ways to provide help to the user.

    The first method is
    to display a single line of help on the bottom of the screen and
    is quite easy to do. This is done using the
    pushHelpLine and popHelpLine methods of the
    SnackScreen class. These calls must be bracketing. That is,
    each pushHelpLine must match with a call to
    popHelpLine.

    A default help line is displayed if none is supplied, or if you
    try to set the help line to None. If you wish to
    remove the help line entirely, push a string with a space
    (" ").

    The second method for providing help is to do something when
    the user presses <F1>. An example action for <F1>
    would be to bring up a dialog box with detailed explanations of
    the screen, and instructions on how to fill out the dialog box.
    To do this, you must create a function, and arrange for it to be
    called when the user presses <F1>. The
    helpCallback method of SnackScreen lets you set the
    help function.

    Your help callback function should take two parameters (in
    addition to self). The first is the SnackScreen which is making
    the call. The second is an object which is used to indicate
    what screen the callback is coming from. Writing the actual
    function is fairly simple. Use the object to look up the help
    text that should be displayed in a dictionary and display it
    Alternatively, you could just put everything into the main
    object so that all the help callback has to do is display what
    it is given.

    The next thing to do is arrange for the help callback to be
    called with the correct object at the right time. This is done
    when you create your Form. The Form class takes an option help
    parameter. It is this parameter that will be passed to the
    callback.

    Hotkeys

    Hotkeys are useful for providing your users with a way to
    navigate your dialog boxes without being forced to always tab to
    a button. If you have several widgets in a form, tabbing to the
    correct button quickly becomes tedious.

    In general, <F1> is always defined as
    help, while <F12> is defined as exit
    the Form. The ButtonBar widget provides an easy way to use hot
    keys. Passing in a third element in a tuple for a button causes
    the hot key to be set to that element.

    If you want to add a hot key to a Form, then you can use the
    addHotKey method. This method will be called automatically for
    any widgets with a hotkeys list as member of the class.

    Available hot keys are defined in the hotkeys dictionary in the
    snack.py module. You can see there that the correct way to use
    a hot key is to pass in it's matching string.

    If a hot key is pressed to exit the form, it will be the return
    value of running the form. You can check this directly, or pass
    it to your ButtonBar to find out the equivalent button.

    It is actually possible to add your own hot keys to the hotkeys
    dictionary.

    import snack
    ESC = '^['
    snack.hotkeys[ESC] = ord(ESC)
    snack.hotkeys[ord(ESC)] = ESC

    In this example, ESC is set to the actual value of the escape
    key. You can produce this by typing Ctrl-V ESC in vi, or Ctrl-Q
    ESC in emacs. Note that the key is double mapped in the dictionary.


    Jared Riley



    Last modified: Mon Nov 11 16:36:10 EST 2002

  • 相关阅读:
    pip install 报错xcrun: error: active developer path ("/Applications/Xcode.app/Contents/Developer") does not exist
    python virtualenv安装并指定python版本
    python安装ldap报错
    linux服务查看安装目录
    python利用paramiko执行服务器命令
    Python subprocess模块
    Django定义全局变量
    uwsgi: invalid option -- 'x'
    将博客搬至CSDN
    jpeg图片格式编解码移植(1)
  • 原文地址:https://www.cnblogs.com/lexus/p/2368378.html
Copyright © 2020-2023  润新知