home *** CD-ROM | disk | FTP | other *** search
/ Dan Appleman's Visual Bas…s Guide to the Win32 API / Dan.Applmans.Visual.Basic.5.0.Programmers.Guide.To.The.Win32.API.1997.Ziff-Davis.Press.CD / VB5PG32.mdf / articles / vbpj / source / stindex.frm (.txt) < prev    next >
Encoding:
Visual Basic Form  |  1996-01-29  |  25.9 KB  |  650 lines

  1. VERSION 4.00
  2. Begin VB.Form Indexer 
  3.    Appearance      =   0  'Flat
  4.    BackColor       =   &H00C0C0C0&
  5.    Caption         =   "Stock Indexer"
  6.    ClientHeight    =   4905
  7.    ClientLeft      =   1095
  8.    ClientTop       =   1785
  9.    ClientWidth     =   8565
  10.    BeginProperty Font 
  11.       name            =   "MS Sans Serif"
  12.       charset         =   0
  13.       weight          =   700
  14.       size            =   8.25
  15.       underline       =   0   'False
  16.       italic          =   0   'False
  17.       strikethrough   =   0   'False
  18.    EndProperty
  19.    ForeColor       =   &H80000008&
  20.    Height          =   5595
  21.    Left            =   1035
  22.    LinkTopic       =   "Form1"
  23.    ScaleHeight     =   4905
  24.    ScaleWidth      =   8565
  25.    Top             =   1155
  26.    Width           =   8685
  27.    Begin VB.Timer tmr_Background 
  28.       Enabled         =   0   'False
  29.       Interval        =   2
  30.       Left            =   8040
  31.       Top             =   2640
  32.    End
  33.    Begin VB.CommandButton cmd_Draw 
  34.       Appearance      =   0  'Flat
  35.       BackColor       =   &H80000005&
  36.       Caption         =   "Draw"
  37.       Height          =   435
  38.       Left            =   6780
  39.       TabIndex        =   14
  40.       Top             =   2640
  41.       Width           =   1035
  42.    End
  43.    Begin VB.Frame Frame1 
  44.       Appearance      =   0  'Flat
  45.       BackColor       =   &H00FFFF00&
  46.       Caption         =   "Display Characteristic"
  47.       ForeColor       =   &H80000008&
  48.       Height          =   1635
  49.       Left            =   4740
  50.       TabIndex        =   11
  51.       Top             =   3240
  52.       Width           =   3735
  53.       Begin VB.Label lbl_DisplayState 
  54.          Appearance      =   0  'Flat
  55.          BackColor       =   &H80000005&
  56.          BackStyle       =   0  'Transparent
  57.          Caption         =   "State Machine Off"
  58.          ForeColor       =   &H80000008&
  59.          Height          =   615
  60.          Left            =   60
  61.          TabIndex        =   13
  62.          Top             =   960
  63.          Width           =   3615
  64.       End
  65.       Begin VB.Label lbl_DisplayChar 
  66.          Appearance      =   0  'Flat
  67.          BackColor       =   &H00FFFF00&
  68.          ForeColor       =   &H80000008&
  69.          Height          =   555
  70.          Left            =   60
  71.          TabIndex        =   12
  72.          Top             =   300
  73.          Width           =   3615
  74.       End
  75.    End
  76.    Begin VB.ListBox lst_Companies 
  77.       Appearance      =   0  'Flat
  78.       Height          =   2370
  79.       Left            =   6240
  80.       MultiSelect     =   2  'Extended
  81.       TabIndex        =   10
  82.       Top             =   180
  83.       Width           =   2115
  84.    End
  85.    Begin VB.OptionButton opt_CurIndex 
  86.       Appearance      =   0  'Flat
  87.       BackColor       =   &H00C0C0C0&
  88.       Caption         =   "Index8"
  89.       ForeColor       =   &H00FFFFFF&
  90.       Height          =   315
  91.       Index           =   7
  92.       Left            =   4740
  93.       TabIndex        =   2
  94.       Top             =   2700
  95.       Width           =   1335
  96.    End
  97.    Begin VB.OptionButton opt_CurIndex 
  98.       Appearance      =   0  'Flat
  99.       BackColor       =   &H00C0C0C0&
  100.       Caption         =   "Index7"
  101.       ForeColor       =   &H00FFFFFF&
  102.       Height          =   315
  103.       Index           =   6
  104.       Left            =   4740
  105.       TabIndex        =   9
  106.       Top             =   2340
  107.       Width           =   1335
  108.    End
  109.    Begin VB.OptionButton opt_CurIndex 
  110.       Appearance      =   0  'Flat
  111.       BackColor       =   &H00C0C0C0&
  112.       Caption         =   "Index6"
  113.       ForeColor       =   &H00FFFFFF&
  114.       Height          =   315
  115.       Index           =   5
  116.       Left            =   4740
  117.       TabIndex        =   8
  118.       Top             =   1980
  119.       Width           =   1335
  120.    End
  121.    Begin VB.OptionButton opt_CurIndex 
  122.       Appearance      =   0  'Flat
  123.       BackColor       =   &H00C0C0C0&
  124.       Caption         =   "Index5"
  125.       ForeColor       =   &H00FFFFFF&
  126.       Height          =   315
  127.       Index           =   4
  128.       Left            =   4740
  129.       TabIndex        =   7
  130.       Top             =   1620
  131.       Width           =   1335
  132.    End
  133.    Begin VB.OptionButton opt_CurIndex 
  134.       Appearance      =   0  'Flat
  135.       BackColor       =   &H00C0C0C0&
  136.       Caption         =   "Index4"
  137.       ForeColor       =   &H00FFFFFF&
  138.       Height          =   315
  139.       Index           =   3
  140.       Left            =   4740
  141.       TabIndex        =   6
  142.       Top             =   1260
  143.       Width           =   1335
  144.    End
  145.    Begin VB.OptionButton opt_CurIndex 
  146.       Appearance      =   0  'Flat
  147.       BackColor       =   &H00C0C0C0&
  148.       Caption         =   "Index3"
  149.       ForeColor       =   &H00FFFFFF&
  150.       Height          =   315
  151.       Index           =   2
  152.       Left            =   4740
  153.       TabIndex        =   5
  154.       Top             =   900
  155.       Width           =   1335
  156.    End
  157.    Begin VB.OptionButton opt_CurIndex 
  158.       Appearance      =   0  'Flat
  159.       BackColor       =   &H00C0C0C0&
  160.       Caption         =   "Index2"
  161.       ForeColor       =   &H00FFFFFF&
  162.       Height          =   315
  163.       Index           =   1
  164.       Left            =   4740
  165.       TabIndex        =   4
  166.       Top             =   540
  167.       Width           =   1335
  168.    End
  169.    Begin VB.OptionButton opt_CurIndex 
  170.       Appearance      =   0  'Flat
  171.       BackColor       =   &H00C0C0C0&
  172.       Caption         =   "Index1"
  173.       ForeColor       =   &H00FFFFFF&
  174.       Height          =   315
  175.       Index           =   0
  176.       Left            =   4740
  177.       TabIndex        =   3
  178.       Top             =   180
  179.       Value           =   -1  'True
  180.       Width           =   1335
  181.    End
  182.    Begin VB.PictureBox pic_Display 
  183.       Appearance      =   0  'Flat
  184.       BackColor       =   &H80000005&
  185.       ForeColor       =   &H80000008&
  186.       Height          =   4515
  187.       Left            =   60
  188.       ScaleHeight     =   4485
  189.       ScaleMode       =   0  'User
  190.       ScaleWidth      =   4485
  191.       TabIndex        =   0
  192.       Top             =   360
  193.       Width           =   4515
  194.    End
  195.    Begin VB.Label Label1 
  196.       Appearance      =   0  'Flat
  197.       BackColor       =   &H80000005&
  198.       BackStyle       =   0  'Transparent
  199.       Caption         =   "Historical Data"
  200.       ForeColor       =   &H80000008&
  201.       Height          =   195
  202.       Left            =   60
  203.       TabIndex        =   1
  204.       Top             =   60
  205.       Width           =   2475
  206.    End
  207.    Begin VB.Menu mnu_Behave 
  208.       Caption         =   "Category"
  209.       Begin VB.Menu mnu_Category 
  210.          Caption         =   "Non-Interruptable"
  211.          Checked         =   -1  'True
  212.          Index           =   0
  213.       End
  214.       Begin VB.Menu mnu_Category 
  215.          Caption         =   "Background Display Only"
  216.          Index           =   1
  217.       End
  218.       Begin VB.Menu mnu_Category 
  219.          Caption         =   "Background Display and Scaling"
  220.          Index           =   2
  221.       End
  222.    End
  223. Attribute VB_Name = "Indexer"
  224. Attribute VB_Creatable = False
  225. Attribute VB_Exposed = False
  226. Option Explicit
  227. Dim CurrentStateMachine%   ' Indicates which state machine is currently selected.
  228.                         ' 0 = Non-interruptable
  229.                         ' 1 = Background display
  230.                         ' 2 = Background display and scaling
  231. Dim CurrentSelectedIndex%   ' Index that is currently selected for editing.
  232. Dim Sheet As Object     ' Object will refer to Excel sheet
  233.                         ' containing stock prices.
  234. Dim Companies As Object ' Object refers to an Excel range
  235.                         ' containing the list of companies.
  236. Dim period As Object    ' Object refers to an Excel range
  237.                         ' containing the periods for which
  238.                         ' we have data.
  239. Dim HighRange As Object, LowRange As Object ' Range information
  240. Dim DataTable As Object ' Object refers to an Excel range
  241.                         ' containing all of the data for all
  242.                         ' of the companies.
  243. Dim IndexList$()    ' Brute force array of companies in
  244.                         ' each index.
  245. ' Used for fast listbox update
  246. Const WM_USER = &H400
  247. #If Win32 Then
  248. Private Const LB_FINDSTRINGEXACT = &H1A2
  249. Private Const LB_SELITEMRANGE = &H19B
  250. Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
  251. Private Declare Function SendMessageBynum Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  252. Private Declare Function SendMessageByString Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
  253. #Else
  254. Const LB_FINDSTRINGEXACT = (WM_USER + 35)
  255. Const LB_SELITEMRANGE = (WM_USER + 28)
  256. Private Declare Function SendMessage& Lib "User" (ByVal hwnd%, ByVal wMsg%, ByVal wParam%, lParam As Any)
  257. Private Declare Function SendMessageBynum& Lib "User" Alias "SendMessage" (ByVal hwnd%, ByVal wMsg%, ByVal wParam%, ByVal lParam&)
  258. Private Declare Function SendMessageByString& Lib "User" Alias "SendMessage" (ByVal hwnd%, ByVal wMsg%, ByVal wParam%, ByVal lParam$)
  259. #End If
  260. Private Sub cmd_Draw_Click()
  261.     Dim i%, di%
  262.     pic_Display.Cls
  263.     LoadIndexFromList CurrentSelectedIndex
  264.     For i% = 0 To 7
  265.         di% = DrawIndex(i%, True)
  266.     Next i%
  267. End Sub
  268. ' This function draws the historical chart of an entire index.
  269. ' restart% is set to True to clear the current operation
  270. ' Returns True if the operation is completed, 0 if the function
  271. ' needs to be called again.
  272. ' See article text for additional information on this function
  273. Private Function DrawIndex%(IndexNum%, restart%)
  274.     Dim CurEntry%
  275.     Dim IVal#
  276.     Dim PrevVal#
  277.     Static StateCurEntry%(7)
  278.     Static StatePrevVal#(7)
  279.     If restart% Then
  280.         StateCurEntry%(IndexNum%) = 1
  281.         If CurrentStateMachine% <> 0 Then
  282.             ' We defined the function to always return
  283.             ' immediately on reset.
  284.             DrawIndex = False
  285.             Exit Function
  286.         End If
  287.     End If
  288.     If IndexList$(IndexNum%, 0) = "" Then
  289.         ' Exit if no entries for this index
  290.         DrawIndex% = True
  291.         Exit Function
  292.     End If
  293.     Select Case CurrentStateMachine%
  294.         Case 0 ' - Non interruptable - VERY SLOW
  295.             For CurEntry% = 1 To period.Columns.Count
  296.                 IVal# = GetIndexVal(IndexNum%, CurEntry%)
  297.                 ' Don't draw the first entry
  298.                 If CurEntry% <> 1 Then pic_Display.Line (CurEntry% - 1, PrevVal#)-(CurEntry%, IVal#), opt_CurIndex(IndexNum%).BackColor
  299.                 PrevVal# = IVal#
  300.             Next CurEntry%
  301.             DrawIndex% = True
  302.         Case 1 To 2 ' Interruptable
  303.             If StateCurEntry%(IndexNum%) > period.Columns.Count Then
  304.                 DrawIndex% = True
  305.                 Exit Function
  306.             End If
  307.             IVal# = GetIndexVal(IndexNum%, StateCurEntry%(IndexNum%))
  308.             ' Don't draw the first entry
  309.             If StateCurEntry%(IndexNum%) <> 1 Then pic_Display.Line (StateCurEntry%(IndexNum%) - 1, StatePrevVal#(IndexNum%))-(StateCurEntry%(IndexNum%), IVal#), opt_CurIndex(IndexNum%).BackColor
  310.             StatePrevVal#(IndexNum%) = IVal#
  311.             StateCurEntry%(IndexNum%) = StateCurEntry%(IndexNum%) + 1
  312.             DrawIndex% = False
  313.     End Select
  314. End Function
  315. Private Sub Form_Load()
  316.     Dim col%, usecol&
  317.     Dim rcount%
  318.     Dim di%
  319.     Screen.MousePointer = 11
  320.     ' Initialize the background colors to indicate which
  321.     ' option button corresponds to each index.
  322.     For col% = 0 To 7
  323.         Select Case col%
  324.             Case 0 To 6
  325.                 usecol& = QBColor(col%)
  326.             Case 7  ' We're drawing on a white background
  327.                 usecol& = QBColor(8)
  328.         End Select
  329.         opt_CurIndex(col%).BackColor = usecol&
  330.     Next col%
  331.     mnu_Category_Click (0)  ' Initialize menu
  332.     ' Initialize OLE Automation objects
  333.     Set Sheet = GetObject(App.Path & "\Stocks.XLS")
  334.     Set Companies = Sheet.Range("companies")
  335.     Set period = Sheet.Range("period")
  336.     Set HighRange = Sheet.Range("highprice")
  337.     Set LowRange = Sheet.Range("lowprice")
  338.     Set DataTable = Sheet.Range("StockData")
  339.     ' Now load listbox lst_Companies with a list of all
  340.     ' available companies.  Note that this particular stock
  341.     ' database is entirely ficitional.
  342.     For rcount% = 1 To Companies.Rows.Count
  343.         lst_Companies.AddItem Companies.Cells(rcount%, 1).Text
  344.     Next rcount%
  345.     ' Redimension list to hold all companies if necessary
  346.     ReDim IndexList$(8, Companies.Rows.Count - 1)
  347.     CurrentSelectedIndex% = 0   ' Track current index
  348.     Screen.MousePointer = 0
  349.     StateMachineInput "FormLoaded"
  350. End Sub
  351. ' Retreives the value of an index. It searches through all
  352. ' of the companies that comprise the index and takes the
  353. ' average of their prices (Note that real stock indexes
  354. ' often use different formulas).
  355. Private Function GetIndexVal#(ByVal IndexNum%, Entrynum%)
  356.     Dim CurVal%
  357.     Dim Comp$
  358.     Dim dl&
  359.     Dim TotalPrice#
  360.     Do
  361.         Comp$ = IndexList$(IndexNum%, CurVal%)
  362.         If Comp$ <> "" Then
  363.             ' Find the offset to the company
  364.             dl& = SendMessageByString(lst_Companies.hwnd, LB_FINDSTRINGEXACT, -1, Comp$)
  365.             If dl& < 0 Then Exit Do ' Should never happen
  366.         
  367.             ' Now get the data for the specified entry
  368.             TotalPrice# = TotalPrice# + DataTable.Value(dl& + 1, Entrynum%)
  369.             CurVal% = CurVal% + 1
  370.         End If
  371.     Loop While Comp$ <> ""
  372.     If CurVal% > 0 Then GetIndexVal# = TotalPrice# / CurVal%
  373. End Function
  374. ' Retrieves the low and high range for a particular company
  375. Private Sub GetPeriodLimit(ByVal Company$, LowPrice#, HighPrice#)
  376.     Dim quote As Object
  377.     Dim dl&
  378.     dl& = SendMessageByString(lst_Companies.hwnd, LB_FINDSTRINGEXACT, -1, Company$)
  379.     If dl& >= 0 Then ' We found it, now select it
  380.         HighPrice# = HighRange.Value(dl& + 1)
  381.         LowPrice# = LowRange.Value(dl& + 1)
  382.     End If
  383. End Sub
  384. ' Loads the company list for an index from the list box
  385. Private Sub LoadIndexFromList(idxnum%)
  386.     Dim c%, CurEntry%
  387.     For c% = 0 To lst_Companies.ListCount - 1
  388.         If lst_Companies.Selected(c%) Then
  389.             IndexList$(idxnum%, CurEntry%) = lst_Companies.List(c%)
  390.             CurEntry% = CurEntry% + 1
  391.         End If
  392.     Next c%
  393.     ' Clear the rest of the entries
  394.     While CurEntry% < UBound(IndexList$, 1)
  395.         IndexList$(idxnum%, CurEntry%) = ""
  396.         CurEntry% = CurEntry% + 1
  397.     Wend
  398.         
  399. End Sub
  400. ' Loads the company list box from an index list
  401. Private Sub LoadListFromIndex(idxnum%)
  402.     Dim dl&
  403.     Dim c%
  404.     Dim rng&
  405.     ' First clear all existing selections
  406.     rng& = lst_Companies.ListCount - 1
  407.     rng& = rng * &H10000    ' Shift to high word
  408.     dl& = SendMessageBynum(lst_Companies.hwnd, LB_SELITEMRANGE, 0, rng)
  409.     ' Now loop through the list
  410.     For c% = 0 To UBound(IndexList, 1)
  411.         If IndexList$(idxnum%, c%) = "" Then Exit For ' We're done
  412.         dl& = SendMessageByString(lst_Companies.hwnd, LB_FINDSTRINGEXACT, -1, IndexList(idxnum%, c%))
  413.         If dl& >= 0 Then ' We found it, now select it
  414.             lst_Companies.Selected(dl&) = True
  415.         End If
  416.     Next c%
  417. End Sub
  418. Private Sub lst_Companies_Click()
  419.     StateMachineInput "ListClicked"
  420. End Sub
  421. Private Sub mnu_Category_Click(Index As Integer)
  422.     Dim lbl$
  423.     Dim midx%
  424.     For midx% = 0 To 1  ' Uncheck the other categories
  425.         If midx% <> Index Then mnu_Category(midx%).Checked = False Else mnu_Category(midx%).Checked = True
  426.     Next midx%
  427.     Select Case Index
  428.         Case 0  ' Display is non-interruptable
  429.                 ' This represents the category of task that
  430.                 ' must not allow any user interaction or changes
  431.                 ' by other applications.  It also represents
  432.                 ' non-event driven design.
  433.                 lbl$ = "Non-interruptable: Characteristic of non-event driven design."
  434.                 ' We need a command button to provide any
  435.                 ' sort of decent performance
  436.                 cmd_Draw.Visible = True
  437.         Case 1  ' Display takes place in the background
  438.                 ' Display is retriggered on click on option button
  439.                 cmd_Draw.Visible = False
  440.                 lbl$ = "Background display: Reset on option click"
  441.                 CurrentStateMachine% = 1
  442.         Case 2
  443.                 cmd_Draw.Visible = False
  444.                 lbl$ = "Background display and scale: Reset on option click"
  445.                 CurrentStateMachine% = 2
  446.     End Select
  447.     lbl_DisplayChar = lbl$
  448.     StateMachineInput "MenuClick"
  449. End Sub
  450. Private Sub opt_CurIndex_Click(Index As Integer)
  451.     ' Exit if no change to index
  452.     If CurrentSelectedIndex% = Index Then Exit Sub
  453.     ' Save previous index information
  454.     LoadIndexFromList CurrentSelectedIndex
  455.     LoadListFromIndex Index
  456.     CurrentSelectedIndex% = Index
  457.     ' Now trigger any background operations that
  458.     ' may be necessary
  459.     StateMachineInput "OptionClicked"
  460. End Sub
  461. ' Sets the scale of the display area to match the period
  462. ' range and the low and high price
  463. ' restart% is set to True to reset the operation
  464. ' Returns -1 if the operation was completed, 0 if the
  465. ' function needs to be called again.
  466. Private Function SetDisplayScales%(restart%)
  467.     Dim LowPrice#, HighPrice#
  468.     Dim LowestPrice#, HighestPrice#
  469.     Static StateLowestPrice#, StateHighestPrice#
  470.     Static StateC%
  471.     ' The period width is easy: We'll use a coordinate
  472.     ' system corresponding to the number of periods
  473.     ' The vertical ($) axis is scaled from the lowest
  474.     ' price to the highest.  How we do this depends on
  475.     ' the selected Category
  476.     Select Case CurrentStateMachine%
  477.         ' - Non interruptable - VERY SLOW!!!
  478.         Case 0, 1 ' Machine # 1 does this non-interruptable also
  479.             Dim c%
  480.             For c% = 0 To lst_Companies.ListCount - 1
  481.                 GetPeriodLimit ByVal lst_Companies.List(c%), LowPrice#, HighPrice#
  482.                 If c% = 0 Then
  483.                     LowestPrice# = LowPrice#
  484.                     HighestPrice# = HighPrice#
  485.                 Else
  486.                     If LowPrice# < LowestPrice# Then LowestPrice# = LowPrice#
  487.                     If HighPrice# > HighestPrice# Then HighestPrice# = HighPrice#
  488.                 End If
  489.             Next c%
  490.             pic_Display.Scale (0, HighestPrice#)-(period.Columns.Count, LowestPrice#)
  491.             ' Using this algorithm we are always done
  492.             SetDisplayScales% = True
  493.         Case 2 ' Machine # 2 does this interruptable also
  494.             If restart% Then
  495.                 StateC% = 0
  496.                 SetDisplayScales% = False
  497.                 Exit Function
  498.             End If
  499.             If StateC% > lst_Companies.ListCount - 1 Then
  500.                 pic_Display.Scale (0, StateHighestPrice#)-(period.Columns.Count, StateLowestPrice#)
  501.                 ' Using this algorithm we are always done
  502.                 SetDisplayScales% = True
  503.                 Exit Function
  504.             End If
  505.                 
  506.             GetPeriodLimit ByVal lst_Companies.List(StateC%), LowPrice#, HighPrice#
  507.             If StateC% = 0 Then
  508.                 StateLowestPrice# = LowPrice#
  509.                 StateHighestPrice# = HighPrice#
  510.             Else
  511.                 If LowPrice# < StateLowestPrice# Then StateLowestPrice# = LowPrice#
  512.                 If HighPrice# > StateHighestPrice# Then StateHighestPrice# = HighPrice#
  513.             End If
  514.             StateC% = StateC% + 1
  515.             
  516.     End Select
  517. End Function
  518. ' This is the control function that decides what should
  519. ' be happening at any given time.
  520. ' We're using a string to describe the event for illustration
  521. ' purposes.  A real program would use an integer for efficiency.
  522. ' This is the state machine function that is the heart
  523. ' of the background processing capability.
  524. Private Sub StateMachineInput(OutsideEvent$)
  525.     Static InternalState%   ' Indicates the current state
  526.     ' 0 - State machine off
  527.     ' 1 - Machine is idle
  528.     ' 2 - State machine is ready to start drawing
  529.     ' 3 - State machine is drawing index InternalIndex%
  530.     ' 4 - State machine is setting scale mode
  531.     Static InternalIndex%   ' Current index being drawn (Machine 1)
  532.     Dim result%
  533.     ' Each of these cases defines a different state
  534.     ' machine.
  535.     Select Case CurrentStateMachine%
  536.         Case 0 ' Non-interruptable.  This is not really
  537.                 ' a state machine - it just performs
  538.                 ' the specified operation immediately
  539.             Select Case OutsideEvent$
  540.                 Case "FormLoaded"
  541.                         result% = SetDisplayScales(True)
  542.                 Case "MenuClicked"
  543.                         ' Turn off the state machine
  544.                         tmr_Background.Enabled = False
  545.                         cmd_Draw_Click
  546.                         InternalState% = 0
  547.                         lbl_DisplayState.Caption = "State Machine Off"
  548.                         pic_Display.Cls
  549.             End Select
  550.         Case 1  ' Background display only (No state 4)
  551.             If OutsideEvent$ = "FormLoaded" Then
  552.                 ' We're not handling display as part of
  553.                 ' the machine at this point
  554.                 result% = SetDisplayScales(True)
  555.             End If
  556.             Select Case InternalState%
  557.                 Case 0  ' Always turn on the machine
  558.                         tmr_Background.Enabled = True
  559.                         InternalState% = 2
  560.                         lbl_DisplayState.Caption = "Start Drawing"
  561.                         pic_Display.Cls
  562.                 Case 1  ' Idle
  563.                     Select Case OutsideEvent$
  564.                         Case "OptionClicked"
  565.                             InternalState% = 2
  566.                             lbl_DisplayState.Caption = "Start Drawing"
  567.                     End Select
  568.                 Case 2  ' Start drawing here
  569.                     InternalIndex% = 0
  570.                     pic_Display.Cls
  571.                     result% = DrawIndex(InternalIndex%, True)
  572.                     InternalState% = 3
  573.                     lbl_DisplayState.Caption = "Drawing in Progress"
  574.                 Case 3
  575.                     Select Case OutsideEvent$
  576.                         Case "OptionClicked" ' Restart
  577.                             InternalState% = 2
  578.                             lbl_DisplayState.Caption = "Start Drawing"
  579.                         Case "Timer"
  580.                             result% = DrawIndex(InternalIndex%, False)
  581.                             If result% Then ' End of index
  582.                                 If InternalIndex% >= 7 Then
  583.                                     InternalState% = 1 ' Goto idle
  584.                                     lbl_DisplayState.Caption = "Idle"
  585.                                 Else
  586.                                     InternalIndex% = InternalIndex + 1
  587.                                     result% = DrawIndex(InternalIndex%, True)
  588.                                 End If
  589.                             End If
  590.                     End Select
  591.             End Select
  592.         Case 2  ' Background display and Scale Mode
  593.             Select Case InternalState%
  594.                 Case 0  ' Always turn on the machine
  595.                         tmr_Background.Enabled = True
  596.                         InternalState% = 4
  597.                         result% = SetDisplayScales(True)
  598.                         lbl_DisplayState.Caption = "Setting Display Scale"
  599.                         pic_Display.Cls
  600.                 Case 1  ' Idle
  601.                     Select Case OutsideEvent$
  602.                         Case "OptionClicked"
  603.                             InternalState% = 2
  604.                             lbl_DisplayState.Caption = "Start Drawing"
  605.                     End Select
  606.                 Case 2  ' Start drawing here
  607.                     InternalIndex% = 0
  608.                     pic_Display.Cls
  609.                     ' We've also changed the drawing algorithm
  610.                     For InternalIndex% = 0 To 7
  611.                         result% = DrawIndex(InternalIndex%, True)
  612.                     Next InternalIndex%
  613.                     InternalState% = 3
  614.                     lbl_DisplayState.Caption = "Drawing in Progress"
  615.                 Case 3
  616.                     Select Case OutsideEvent$
  617.                         Case "OptionClicked" ' Restart
  618.                             InternalState% = 2
  619.                             lbl_DisplayState.Caption = "Start Drawing"
  620.                         Case "Timer"
  621.                             result% = True
  622.                             For InternalIndex% = 0 To 7
  623.                                 ' Look for all of them to finish
  624.                                 result% = result% And DrawIndex(InternalIndex%, False)
  625.                             Next InternalIndex%
  626.                             If result% Then ' End of index
  627.                                 InternalState% = 1 ' Goto idle
  628.                                 lbl_DisplayState.Caption = "Idle"
  629.                             End If
  630.                     End Select
  631.                 Case 4
  632.                     ' Note that the only way to exit this state is
  633.                     ' through completion, or if you change state machines
  634.                     ' using the menu
  635.                     result% = SetDisplayScales(False)
  636.                     
  637.                     If result% Then
  638.                         ' Lets start a drawing operation
  639.                         InternalState% = 2
  640.                         lbl_DisplayState.Caption = "Start Drawing"
  641.                         tmr_Background.Interval = 2
  642.                     End If
  643.             End Select
  644.             
  645.     End Select
  646. End Sub
  647. Private Sub tmr_Background_Timer()
  648.     StateMachineInput "Timer"
  649. End Sub
  650.