Skip to content

Class reference

yadizhou edited this page Nov 28, 2017 · 12 revisions

labpype.widget has the following classes for making new widgets. You can directly import them from labpype.widget. Alternatively, you can also import them from their own modules.

The documentation has several parts: "Inheritance guide", "APIs", and "Example". "Inheritance guide" lists all the class attributes and instance methods need to be implemented when you subclass Widget or Dialog. "APIs" lists all the useful methods you may need when implementing the child classes of Widget and Dialog. See "Example" for how to subclass and some usages of the APIs.

Widget class

Widget is the common base class of all the widgets. In order to create new widget class, you need to specify some class attributes and implement some methods when inherit from the Widget class.

Inheritance guide

For convenience, we will use the name Widget as the class name for all the following class attributes and widget as the corresponding object name for the methods, while they actually mean the child class that you inherit from Widget and the object from that child class. For example, we can create a widget class called FirstWidget whose class attribute FirstWidget.NAME is "Awesome Widget". Here, FirstWidget is the class you inherit from Widget and whose class attributes are assigned.

class FirstWidget(Widget):
    NAME = "Awesome Widget"

Note that you should never change the values of class attributes of Widget.

class attribute Widget.NAME

Default: "". The default name for the widget displayed on the canvas.

class attribute Widget.DIALOG

Default: None. The associated dialog class. The following types of value are accepted:

  • None - no associated dialog
  • DialogClass - a dialog class
  • "V" or "H" - for automatic dialog class generation using the specified orientation
  • {"ORIENTATION":"V", SIZE:(200,100)} - a dictionary of class attributes for the dialog class generated automatically

class attribute Widget.THREAD

Default: False. Whether the task should run in a separate thread so that the main canvas is not blocked. The thread should regularly check if it has been stopped using Thread.Checkpoint(). See the code of the toy example for a detailed usage.

class attribute Widget.INTERNAL

Default: None. A list values used as keys for accessing and assigning the data of the widget itself. A str can be used directly as the key. If a data field is used, the key passed to it is used as the key for the data. A data field provides more flexibility and convenience than a str. See Data fields. Some examples:

    INTERNAL = "DIAMETER"
    INTERNAL = "WIDTH", "HEIGHT"
    INTERNAL = "WIDTH", FloatField(key="HEIGHT", label="Height")

class attribute Widget.INCOMING

Default: None. Create anchors for connections to upstream widgets. It has the following form of value: (aType, key, multiple, pos, name="", anchor=None), (more anchors...). The parenthesis can be omitted if there is only one incoming anchor.

  • aType - anchor type for the anchor. See Anchor types.
  • key - key for accessing the data passed by the upstream widgets connected to this anchor.
  • multiple - does this anchor allow multiple connections?
  • pos - a str of positions. For example. "LT" indicates this anchor can be positioned to the left or to the top of the widget.
  • name - name for the anchor to be displayed in the status bar when being hovered.
  • anchor - by default (anchor=None) it uses the base anchor class Anchor to create an anchor. You can create advanced anchor classes derived from Anchor and use them here.

Some examples:

    INCOMING = ANCHOR_DNA, "DNA", True, "L", "DNA"
    INCOMING = (ANCHOR_DNA, "DNA", True, "L", "DNA"), \
               (ANCHOR_ENZYME, "ENZYME", False, "TB", "Enzyme")

class attribute Widget.OUTGOING

Default: None. Create anchor for connections to downstream widgets. It accepts aType, name="", anchor=None. The key for outgoing data is always "OUT". Therefore, you should never use "OUT" as the key for incoming or internal data. The position for outgoing anchor is always "RBT". Outgoing anchor always support multiple connections.

class attribute Widget.SINGLETON

Default: False. Whether this widget class is limited to one instance on the canvas.

instance method widget.Name()

Default behavior: return Widget.NAME. The function is called when the state of the widget is changed. You can use the Widget.IsState(state) method to determine the current state and return the text you want to display on the canvas accordingly.

instance method widget.Save(data)

Default behavior: return JSON formatted str from dumping data. data is a dict containing all the internal and outgoing data. You should override this function if the internal and outgoing data of the widget cannot be dumped by JSON. The purpose of this function is to serialize those data so that it can be loaded later.

instance method widget.Load(f)

Default behavior: return the parsed JSON document. You should override this method according the widget.Save(data) method. This method is the reverse operation of widget.Save(data). f is a file object opened in binary mode.

instance method widget.Init()

Default behavior: none. This method is called when the widget is added to the canvas. It's useful for initializing some internal data.

instance method widget.Exit()

Default behavior: none. This method is called when the widget is removed from the canvas. It's useful for cleanup the data of the widget.

instance method widget.Reset()

Default behavior: none. This method is called when the widget leaves "Done" or "Fail" state. It's useful for resetting some data between reruns.

instance method widget.Task()

Default behavior: return None. The task that this widget does. The task can be anything. It can run in the main thread as long as it's fast, otherwise it would block the UI. It can run in a thread or a subprocess. It can call and monitor an external tool. You will need to make sure that the task does not change the incoming and internal data, and the outgoing data isn't something like a generator that will be consumed when used. This method should return anything other than None to indicate the task is successful, and whatever returned will be assigned to the outgoing data of the widget.

Example

See the code in A simple demo. It demonstrates how to run a task in a separate thread or a subprocess. It also shows how to display the progress of the widget on the canvas, as well as how to terminate the thread/subprocess at any time.

APIs

instance method widget.IsState(state)

Returns True if state is the widget's current state. state is one of the five states: Idle, Wait, Work, Done, Fail. You should never call this method in widget.Task(), as it would create a deadlock if Widget.THREAD=True.

instance method widget.IsOutgoingAvailable()

This method returns True only if the outgoing anchor is connected.

instance method widget.IsIncomingAvailable()

This method returns True only if the incoming anchor(s) is connected and is in Done state.

instance method widget.IsInternalAvailable()

This method returns True only if all the internal data are not none.


Dialog class

Dialog is the common base class of all the dialogs. You will need to specify some class attributes and implement some methods for the child classes to create new dialogs.

Inheritance guide

For convenience, we will use the name Dialog as the class name for all the following class attributes and dialog as the corresponding object name for the methods, while they actually mean the child class that you inherit from Dialog and the object from that child class.

class attribute Dialog.AUTO

Default: True. Whether the dialog should automatically populate controls based on the data fields in Widget.INTERNAL.

class attribute Dialog.SIZE

Default: None. Specify the size of the dialog. Use a tuple of width and height or a wx.Size object. Use None to automatically determine the best smallest size for the dialog.

class attribute Dialog.ORIENTATION

Default: wx.VERTICAL. The orientation of the main sizer of the dialog. Use wx.HORIZONTAL for simple one line dialogs.

class attribute Dialog.MARGIN

Default: 2. The margin between controls in the dialog.

class attribute Dialog.LABEL_WIDTH

Default: 80. The width of the label for the controls.

class attribute Dialog.LINE_HEIGHT

Default: 20. The height of one line.

instance method dialog.Initialize(Sizer)

Default behavior: none. When dialogs are created, the following functions are called in order: dialog.Initialize(Sizer), automatic addition of controls for the data fields, and dialog.Finalize(Sizer). Therefore, put anything here you want to be done before automatic addition of controls.

instance method dialog.Finalize(Sizer)

Default behavior: add standard buttons. See Dialog.AddStdButton(sizer). Put anything here you want to be done after automatic addition of controls for the data fields.

instance method dialog.GetData()

Default behavior: none. Tell the dialog how to get data from the widget and set the value of the controls in the dialog.

instance method dialog.SetData()

Default behavior: none. Tell the dialog how to get the value of the controls in the dialog and set the widget's data. If Dialog.AUTO=True, then you do not need to explicitly set data for the internal data specified by data fields.

APIs

Dialog has many methods for adding UI elements programmatically. They all have the kind of name dialog.AddXXX. To use them in your dialog.Initialize(Sizer) and dialog.Finalize(Sizer) methods, you only need a very basic understanding of how sizing and positioning of controls work in wxPython. Understanding the event system is not necessary. However, if you do, you can make highly interactive dialogs. Further, if you know how to make customized UI controls, you can make the dialog more powerful.

All dialog.AddXXX methods return the controls added. To get or set the value of the controls, call the corresponding methods (see Example)

dialog.AddXXX methods have the following common arguments:

  • sizer=wx.Sizer - The sizer in which controls are added. See Sizers Overview for more details. Note that you do not need to add controls to the sizers manually, as dialog.AddXXX methods take care of it.
  • label=str - The label for the control to be created. labels have the width Dialog.LABEL_WIDTH.
  • value=str - String value of the control.
  • width=int - Width of the control. Use -1 for the control to take all the horizontal space.
  • height=int - Height of the control. Use -1 for the control to take all the vertical space.
  • style=long - A wx style argument to be passed to the control. For example, use style=wx.TE_CENTER for wx.TextCtrl added using dialog.AddTextCtrl to tell the text control to center the text.
  • inline=bool - Whether label and control should be in the same row. If False, label will appear on top of the control.
  • tag=str - A str displayed on the control.
  • tags=tuple - A tuple of strs from which one is chosen to display on the control according the the control's state.
  • choices=tuple - A tuple of strs from which selection is made.
  • onXXX - The function called when the control is "XXX"ed. For example, onClick is called when the control is clicked. All of the following forms of value are valid:
    • onXXX=funcName
    • onXXX=(funcName, funcArgs...)
    • onXXX=((funcName1, funcArgs1...), funcName2, (funcName3, funcArgs3...), ...)
  • **kwargs - Keyword arguments to be passed to the control.

instance method dialog.DisableCanvas()

Disable the main canvas. This method is used together with dialog.EnableCanvas()

instance method dialog.EnableCanvas()

Enable the main canvas. This method is used together with dialog.DisableCanvas()

instance method dialog.AddStdButton(sizer)

Add standard buttons to the dialog. This is the default behavior of dialog.Finalize(Sizer). Therefore, you normally wouldn't need to call this method unless you override dialog.Finalize(Sizer).

instance method dialog.AddSeparator(sizer)

Add a separator.

instance method dialog.AddSectionHead

dialog.AddSectionHead(sizer, tag="")

Add a separator with text.

instance method dialog.AddButton

dialog.AddButton(sizer, label="", tag="", width=80, onClick=None, **kwargs)

Add a button.

instance method dialog.AddButtonToggle

dialog.AddButtonToggle(sizer, label="", tags=(), width=80, toggle=False,
                       onClick=None, **kwargs)

Add a two-state button. toggle=bool specifies whether this button is toggled.

instance method dialog.AddButtonBundle

dialog.AddButtonBundle(sizer, label="", tags=(), width=80, rows=1,
                       toggled=0, group="", onClick=None, **kwargs)

Add a set of buttons that at any time, only one of them is toggled. toggled=int is the index of the button toggled. group=str is the name for this group of buttons. Make sure it's unique in the dialog. rows=int is the number of rows of buttons.

instance method dialog.AddPickerValue

dialog.AddPickerValue(sizer, label="", choices=(), selected=-1, width=80,
                      **kwargs)

Add a combo box from which a selection is made. selected=int is the index of the item selected. -1 indicates no selection.

instance method dialog.AddStaticText

dialog.AddStaticText(sizer, label="", value="", width=-1)

Add a static text for display purpose only.

instance method dialog.AddLineCtrl

dialog.AddLineCtrl(sizer, label="", value="", width=-1, style=0,
                   onInput=None, hint="", font=None)

Add a text control that does not allow multiple lines. hint=str is the text displayed when the control has no value. font=str is a DynaUI styled argument for the font.

instance method dialog.AddTextCtrl

dialog.AddTextCtrl(sizer, label="", value="", width=-1, height=-1, style=0,
                   inline=True, onInput=None, hint="", font=None)

Add a text control that allows multiple lines. hint=str is the text displayed when the control has no value. font=str is a DynaUI styled argument for the font.

instance method dialog.AddListBox

dialog.AddListBox(sizer, label="", choices=(), selected=-1, width=-1,
                  height=-1, onClick=None, onDClick=None, inline=True)

Add a list box for making a selection. selected=int is the index of the item selected. -1 indicates no selection.

instance method dialog.AddPickerFile

dialog.AddPickerFile(sizer, label="", value="", width=-1, width2=None, mode="L",
                     wildcard="All files (*.*)|*.*", hint="", style=0, onSelect=None)

Add a file picker. Use mode="S" for saving file, or mode="L" for loading file. Use width2 to change the width of the button for opening the load/save dialog, and width for the length of the textbox that shows the path.

Example

The following code gives a fully functional dialog that can set the widget data.

class MyWidget(Widget):
    NAME = "Dialog Example"
    DIALOG = MyDialog
    INTERNAL = "BT", "BB", "LC", "TC", "LB", "PV", "PF"

class MyDialog(Dialog):
    def Initialize(self, Sizer):
        self.AddSectionHead(Sizer, tag="SectionHead", shape="C")
        self["BN"] = self.AddButton(Sizer, label="Button", tag="Click me")
        self["BT"] = self.AddButtonToggle(Sizer, label="ButtonToggle",
                                          tags=("No", "Yes"))
        self["BB"] = self.AddButtonBundle(Sizer, label="ButtonBundle",
                                          tags=list("012345"), rows=2)
        self.AddStaticText(Sizer, label="StaticText",
                           value="Dialog Example")
        self["LC"] = self.AddLineCtrl(Sizer, label="LineCtrl")
        self["TC"] = self.AddTextCtrl(Sizer, label="TextCtrl")
        self["LB"] = self.AddListBox(Sizer, label="ListBox",
                                     choices=list("012345"), selected=3)
        self["PV"] = self.AddPickerValue(Sizer, label="PickerValue",
                                         choices=list("012345"), selected=2)
        self.AddSeparator(Sizer)
        self["PF"] = self.AddPickerFile(Sizer, label="PickerFile")

    def SetData(self):
        self.Widget["BT"] = self["BT"].IsToggled()
        self.Widget["BB"] = self["BB"].GetToggled()
        self.Widget["LC"] = self["LC"].GetValue()
        self.Widget["TC"] = self["TC"].GetValue()
        self.Widget["LB"] = self["LB"].GetStringSelection()
        self.Widget["PV"] = self["PV"].GetSelection()
        self.Widget["PF"] = self["PF"].GetValue()

    def GetData(self):
        if self.Widget["BT"] is not None:
            self["BT"].SetToggle(self.Widget["BT"])
        if self.Widget["BB"] is not None:
            self["BB"].SetToggled(self.Widget["BB"])
        if self.Widget["LC"] is not None:
            self["LC"].SetValue(self.Widget["LC"])
        if self.Widget["TC"] is not None:
            self["TC"].SetValue(self.Widget["TC"])
        if self.Widget["LB"] is not None:
            self["LB"].SetStringSelection(self.Widget["LB"])
        if self.Widget["PV"] is not None:
            self["PV"].SetSelection(self.Widget["PV"])
        if self.Widget["PF"] is not None:
            self["PF"].SetValue(self.Widget["PF"])

The dialog looks like this:


Anchor types

Anchor types are used for defining legit connections. A widget has one or more anchors, each anchor has an attribute aType whose value is an anchor type class. For two anchors to be able to connect, their aType pair should be defined to be legit beforehand.

Anchor types are empty classes used as keys in some dictionary that contains all the legit connections. The reason that a class is chosen as the key over str, int or any other hashable object is that classes are inheritable, and this feature makes it elegant to define legit links. For example, if connections between ANCHOR_STRING and ANCHOR_SEQUENCE is defined to be legit, then connections between ANCHOR_STRING and ANCHOR_DNA, or ANCHOR_STRING and ANCHOR_PROTEIN are also legit automatically, given that ANCHOR_DNA and ANCHOR_PROTEIN are subclasses of ANCHOR_SEQUENCE.

Example

from labpype.widget import ANCHOR_REGULAR
class ANCHOR_SEQUENCE(ANCHOR_REGULAR): pass
class ANCHOR_DNA(ANCHOR_SEQUENCE): pass
class ANCHOR_PROTEIN(ANCHOR_SEQUENCE): pass

ANCHOR_REGULAR class

The base class for all user-defined anchor types.

ANCHOR_SPECIAL class

The base class for special anchor types (e.g., ANCHOR_ALL and ANCHOR_NONE). The connection between two special anchor types is considered not legit.

ANCHOR_ALL class

Anchors whose aType are ANCHOR_ALL can connect to any anchors whose aType are subclasses of ANCHOR_REGULAR

ANCHOR_NONE class

Anchors whose aType are ANCHOR_NONE cannot connect to anything.


Data fields

Instances of data fields are used as value of class attribute Widget.INTERNAL. They represent the type of input data from the widget's dialog. An argument key is passed when instantiate a data field. This key has the same meaning as the string you would use directly for Widget.INTERNAL. They are used as keys for accessing and assigning data to the widget. Although data field is optional, it has two advantages. First, it validates the value from the dialog, and only assigns the value to the widget if the value is valid. Second, with data fields, it is possible for the Dialog class to inspect the Widget for the types of data, and populate the the dialog with appropiate UI controls. Each data field has one or more associated dialog.AddXXX method used to construct the UI control. See below for the association and Dialog APIs for the associated method.

Example

from labpype.widget.field import *
from labpype.widget import widget

class DataFieldExample(Widget):
    NAME = "DataField Example"
    DIALOG = "V"  # Automatically generate dialog using vertical layout
    INTERNAL = \
        BooleanField("BOOLEAN", "BooleanField", "No", "Yes"), \
        LineField("LINE", "LineField"), \
        TextField("TEXT", "TextField"), \
        IntegerField("INTEGER", "IntegerField"), \
        FloatField("FLOAT", "FloatField"), \
        ChoiceField("CHOICE1", "ChoiceField", choices=list("ABC"), widget="C"), \
        ChoiceField("CHOICE2", "ChoiceField", choices=list("ABC"), widget="L"), \
        ChoiceField("CHOICE3", "ChoiceField", choices=list("ABC"), widget="B"), \
        FileField("FILE", "FileField")

The dialog of this widget:

BaseField class

BaseField(key, label, **kwargs)
  • The base class of all data fields. You should not directly use this class.
  • key - the key for accessing and assigning associated data to the widget.
  • label - the label of this field that displays on the dialog. Use "" for no label.
  • **kwargs - keyword arguments to be passed to the associated dialog.AddXXX method.

BooleanField class

BooleanField(key, label, tag1, tag2, **kwargs)
  • Associated with dialog.AddButtonToggle.
  • Represent a Boolean value. The value is True if the button is toggled, otherwise False.
  • No validation.
  • tag1 - text displayed on the button when it is untoggled.
  • tag2 - text displayed on the button when it is toggled.

LineField class

LineField(key, label, maxLength=None, minLength=None, **kwargs)
  • Associated with dialog.AddLineCtrl.
  • Represent a single line of text (str with no line break).
  • If maxLength or minLength is not None, validate the length accordingly.
  • maxLength - maximum acceptable length of the string.
  • minLength - minimum acceptable length of the string.

TextField class

TextField(key, label, maxLine=None, minLine=None,
          maxLength=None, minLength=None, **kwargs)
  • Associated with dialog.AddTextCtrl.
  • Represent a str.
  • If maxLine or minLine is not None, validate the number of lines accordingly.
  • If maxLength or minLength is not None, validate the length accordingly.
  • maxLine - maximum acceptable number of lines.
  • minLine - minimum acceptable number of lines.
  • maxLength - maximum acceptable length of the string.
  • minLength - minimum acceptable length of the string.

IntegerField class

IntegerField(key, label, maxValue=None, minValue=None, **kwargs)
  • Associated with dialog.AddLineCtrl.
  • Represent an int.
  • Validate if the text in the line control can be converted to an int.
  • Then, if maxValue or minValue is not None, validate the value accordingly.
  • maxValue - maximum acceptable value.
  • minValue - minimum acceptable value.

FloatField class

FloatField(key, label, maxValue=None, minValue=None, **kwargs)
  • Associated with dialog.AddLineCtrl.
  • Represent a float.
  • Validate if the text in the line control can be converted to a float.
  • Then, if maxValue or minValue is not None, validate the value accordingly.
  • maxValue - maximum acceptable value.
  • minValue - minimum acceptable value.

ChoiceField class

ChoiceField(key, label, choices=(), widget="C", **kwargs)
  • Associated with dialog.AddPickerValue by default.
  • Represent a chosen value from a tuple of strs.
  • Validate that a selection has been made.
  • choices - a tuple of strs to be selected from.
  • widget - the UI control associated. "C" for dialog.AddPickerValue, "L" for dialog.AddListBox, "B" for dialog.AddButtonBundle.

FileField class

FileField(key, label, **kwargs)
  • Associated with dialog.AddPickerFile.
  • Represent a str of the path to a file.
  • No validation.
Clone this wiki locally