AUTO DIALOG - A layer for automatic creation of Tkinter dialogs to examine class members or lists

The module auto_dialog.py is built on (that is it inherits behaviour) from module control dialog and is designed to allow the programmer to examine complex data structures. Matlab, Netbeans and Visual Studio environments all have tools for examining class structures so there is bound to be similar tools for python. This module just seemed to be a natural extension of the control dialog module.

The module control_dialog.py is the simplest layer above Tkinter and should be examined first if the user wishes to extend the auto_dialog module in any way.

For data editing applications, the modules tkfront(for menu management) and managed_dialog (built on control_dialog) are designed to simplify menu and dialog creation.

This is one of the three layers which can be called from a menu item using the tkfront module.


Contents


A Simple Example

from auto_dialog import *

def main():

  def apply_callback(dialog):
    print "Apply callback"

  class test_class:
    def __init__(self,name):
      self.name = name
      self.v = 4
      self.v2 = 5.5

  test_object = test_class("TeaCup")
  test_list =[True,3,5.5,"Help",test_object]

  #import sys

  root = Tk()

  test_auto_dialog = AutoDialog(root,test_list,"Test List",apply_callback)
  test_auto_dialog.update()
  test_auto_dialog.lift()

  frame = 0
  while  not test_auto_dialog.exit_request:
    test_auto_dialog.update()
    #sys.stdout.flush()
    frame += 1
  test_auto_dialog.destroy()    # not required but good practise

if __name__ == '__main__': main()

Running this should bring up an empty application window and a dialog:

This dialog both provides graphical access to each of the elements of the test list.

Clicking on the teacup button will create a sub-dialog that accesses the 4th item of the list which is a class object with the name TeaCup:

The only information that has been supplied to the autoDialog class is a reference to the variable test_list. Since autoDialog has no way of knowing what name is being used for this list, a title should be supplied as well. The complete call is:

test_auto_dialog = AutoDialog(root,test_list,"Test List",apply_callback)

The name for the class object TeaCup was found by looking for a class member called name. if a class has no member called name then it will use the label "class test_class".

On the page for the menu creation module,tkfront,we will see the a simple menu item can give the programmer access to the full depth of any complex OOP database.


A More Complex Example

In this example a multi layered class is examined using auto_dialog while a normal control dialog examines one element of that class,

from auto_dialog import *

def main():

  def apply_callback(dialog):
    print "Apply callback"
    int_value = dialog.getValue('IntValue')
    print "Value:",int_value
    if dialog == test_dialog:
      test_auto_dialog.set('IntValue',int_value)
    else:
      test_dialog.set('IntValue',int_value)

  # value callbacks - may be called immediatly on change (stage = 0), at validation (state = 1) or
  # if and only if a change occurred from the original value at apply stage (return key or apply button)

  def int_fn(name="",value = None, stage = 0):
    if stage == 1:
      return False
    print "int is ", value," at stage:", stage

  class test_subclass:
    def __init__(self,name):
      self.name = name
      self.v = 4
      self.v2 = 5.5

  class test_subclass2:
    def __init__(self):
      self.v = 9
      self.v2 = 8.5

  sub_objs = []
  sub_objs2 = []
  for i in range(3):
    sub_objs.append(test_subclass("SubClass"+str(i)))
    sub_objs2.append(test_subclass2())

  class test_class:

    test_int_max_value = 7
    test_int_min_value = 3
    test_season_values = ("Spring","Summer","Winter")

    def __init__(self):
      self.test_bool = False
      self.IntValue = 4
      self.test_float = 5.5
      self.test_string = "Hello"
      self.test_season = "Summer"
      self.sub_object = test_subclass("OneSubClass")
      self.sub = sub_objs[0]
      self.sub_values = sub_objs  # this one doesn't get dialoged
      self.class_tuple = ("1st","2nd","3rd")
      self.class_list = [True,3,5.5,"Help"]
      self.sub2 = sub_objs2[0]
      self.sub2_values = sub_objs2

  #import sys

  root = Tk()
  test_object = test_class()

  var_list = (("IntValue",test_object.IntValue,int_fn),)
  test_dialog = ControlDialog(root,var_list,"Control Dialog Test",apply_callback,None,False)
  test_dialog.update()
  test_dialog.lift()

  test_auto_dialog = AutoDialog(root,test_object,None,apply_callback)
  test_auto_dialog.update()
  test_auto_dialog.lift()

  frame = 0
  while not test_dialog.exit_request and not test_auto_dialog.exit_request:
    test_dialog.update()
    test_auto_dialog.update()
    #sys.stdout.flush()
    frame += 1
  test_dialog.destroy()              # not required but good practise
  test_auto_dialog.destroy()    # not required but good practise

if __name__ == '__main__': main()

Running this should bring up an empty application window and a dialog:

Since we are examining a class this time, auto_dialog has access to the member names which are used as the labels for each field.

The instance of test_class that we are examining has 3 references to class objects:


      self.sub_object = test_subclass("OneSubClass")
      self.sub = sub_objs[0]
      self.sub2 = sub_objs2[0]

Where sub_objs is a list of instances of a class with name members and sub_obj2 is a list of instances of class which have no name member. Notice the different ways the instances are named in the selector box. The reason that the member sub_object only gets a button, while sub and sub2 get selectors is that for the latter a member name_values was found being:


      self.sub_values = sub_objs  # this one doesn't get dialoged
      self.sub2_values = sub_objs2

The sub_value member provides a list of options for what values might be selected for the sub member. The *_value member is itself ignored as the selector box effectively provides access to both.

The class_tuple and class_list members demonstrate that at tuples are treated differently to lists - tuples can only be viewed not changed. Both are given a button which, when pressed opens a new auto_dialog. While the content of tuples cannot be changed, members of lists and class instances can be so these are given buttons in the new dialog to further sub dialogs to open.

The apply_callback(dialog) in this example demonstrates the use of dialog.getValue(label) to recover the values set in the dialog and also to demonstrate the use of dialog.set(label,value) to change the displayed value in an open dialog.

In this examples, the two dialogs initially opened both have fields pointing to the same integer value. Changing one will only change the other after pressing Enter or by clicking on the apply button.

This requirement to fetch the dialog values through callbacks is rather tedious, so the managed_dialog has been created to address this.


Installation

First off grab the module auto_dialog.py here or the complete tkfront suite of modules as a zip file here. Test programs used on these webpages can also be downloaded here.

Installation is similar to control dialog except that both the auto_dialog.py and control_dialog.py modules must be in the path of your application.

Documentation can be generated by running python help("auto_dialog").


In case you didn't notice them, please heed the warnings on the microde page.


Copyright Robert Parker November 2009