Module dbExtFrm.pkg
1//************************************************************************
2// Confidential Trade Secret.
3// Copyright (c) 1997 Data Access Corporation, Miami Florida
4// as an unpublished work. All rights reserved.
5// DataFlex is a registered trademark of Data Access Corporation.
6//
7//************************************************************************
8//************************************************************************
9//
10// $File name : dbExtFrm.pkg
11// $File title : dbFormExternalControl
12// Notice :
13// $Author(s) : John Tuohy
14//
15// $Rev History
16//
17// 9/8/97 JJT - File created
18//************************************************************************
19
20//This creates an class that can be used for creating single item data-entry
21//classes based around a custom windows control(or any DLL). This class is used
22//for sub-classing only. This contains all the "basic" behaviors required
23//to create a DEO class. In a sub-class you must add the needed logic to
24//talk to a custom control and the needed logic to coordinate the DF class and
25//the windows control. Normally this is done as follows:
26//
27//1. Create a mixin class that contains all of the logic and interface to
28// support a custom control. Normally, this class will define an external
29// control (Set External_Class_Name 'DFTrackBar' To "msctls_trackbar32")
30// and map windows messages to DF messages (Set External_Message WM_HSCROLL
31// To Private_SliderNotification). Normally this mixin class will itself
32// contain a mixin class named External_Class_Mixin (DFExtClM.pkg) which
33// contains logic that will be common to all external control mixin classes.
34// In particular this creates two messages External_SetFocus and
35// External_KillFocus were created to handle focus changes events. Those
36// messages must be mapped to windows messages and will most likely be:
37// Set External_Message WM_SETFOCUS To External_SetFocus
38// Set External_Message WM_KILLFOCUS To External_KillFocus
39//
40//2. When creating this mixin class you need to identify three message types:
41// A. The message(s) that is (are) sent when the control's data value is
42// changed. Whenever the windows control changes we want to notify the DF
43// side of this change so that Get Value is always up to date. This is very
44// important for DDs since they must be updated anytime a DEO's data value
45// changes. We will augment each of these messages and force it to send
46// the message ControlValueChanged. This will force the DF side to stay
47// synchronized with the control.
48// B. The message that gets the current data value of the windows control. This
49// is used to get this value and set the DF side's value accordingly.
50// C. The message that sets the current data value of the windows control. This is
51// used to set the control value to its DF value. Often B and C will be a
52// GET/SET message of the same name.
53//
54// For the sake of example lets assume that messages A, B, and C were defined in
55// the mixin as:
56// A. Procedure onHeyControlChanged
57// B. Function MyCustomControlDataValue returns String
58// C. Procedure Set MyCustomControlDataVale String sVal
59//
60//3. You will create your sub-class as follows:
61//
62//Class dbMyCustomFormClass is a dbFormExternalControl
63//
64// import_class_protocol MyCustomControl_Mixin
65//
66// Procedure Construct_Object
67// Forward Send Construct_Object
68// Send Define_MyCustomControl_Mixin
69// End_Procedure // Construct_Object
70//
71// // we must identify all events that result in a changed
72// // value in the control and notify the DF side about this
73// // change. We notify DF by sending ControlValueChanged. If multiple
74// // events cause changes, multiple messages must be created all sending
75// // ControlValueChanged
76// Procedure OnHeyControlChanged
77// Send ControlValueChanged
78// End_Procedure
79//
80// // The class expects a message named Set ControlValue. It is passed a string
81// // and should be used to change the value of the windows control. This
82// // is the message "C" from above.
83// Procedure Set ControlValue string sVal
84// Set MyCustomControlDataValue to sVal
85// End_Procedure
86//
87// // The class expects a messsage named get controlValue. It will return
88// // the control's data value.
89// Function ControlValue Returns String
90// string sVal
91// Get MyCustomControlDataValue to sVal
92// Function_return sVal
93// End_Function
94//
95//End_Class
96//
97
98
99use dfentry.pkg
100
101{ ClassType=Abstract }
102{ HelpTopic=dbFormExternalControl }
103Class dbFormExternalControl is a dbForm
104
105 Procedure Construct_Object
106 Forward Send Construct_Object
107 // This is used to prevent recursion. When a control notifies
108 // DF that a value has changed, DF will attempt to notify the
109 // control. We must stop that circularity
110 { Visibility=Private }
111 Property integer Private.ControlChangingState false
112
113 // set true when making a local (externally triggered) change. This is
114 // set when a Set Value of Set Local_Value change is made
115 { Visibility=Private }
116 property integer LocalChangingState false
117 Set Prompt_Button_Mode to PB_PromptOff // add next revision
118 End_Procedure // Construct_Object
119
120 //
121 // When the DF side changes we must notify the control about the change.
122 // If DD are in use we must use set Local_Value, if no DD we use set value
123 //
124 { MethodType=Property NoDoc=True }
125 Procedure set Value integer iItem string sVal
126 forward set value item iItem to sVal
127 If (Extended_deo_State(self)=0 AND ;
128 Private.ControlChangingState(self)=0 ) ;
129 Send RefreshControl sVal
130 End_Procedure
131
132 { Visibility=Private MethodType=Property }
133 Procedure set Local_Value integer iItem string sVal
134 forward set Local_value item iItem to sVal
135 If not (Private.ControlChangingState(self)) ;
136 send RefreshControl sval
137 End_Procedure
138
139 // It is expected that the sub-class (or more likely another
140 // mixin included with the sub-class will provide functionality
141 // for these messages. This gets and sets the value of the actual
142 // window control. These should only be used to synchronize the window
143 // control and the DF side. Do not use for any other purpose.
144 //
145 { Visibility=Private MethodType=Property }
146 Procedure Set ControlValue string sVal
147 End_Procedure
148
149 { MethodType=Property Visibility=Private }
150 Function ControlValue Returns String
151 End_Function
152
153 // refresh control without triggering a DD changed condition.
154 { Visibility=Private }
155 Procedure RefreshControl string sVal
156 integer bOld
157 Get LocalChangingState to bOld
158 Set LocalChangingState to True
159 set ControlValue to sval
160 Set LocalChangingState to bOld
161 End_Procedure
162
163 { Visibility=Private }
164 Procedure ControlValueChanged
165 integer bOld
166 String sval
167 If (LocalChangingState(self)) Procedure_return
168 Get Private.ControlChangingState to bOld
169 Set Private.ControlChangingState to True
170 Get ControlValue to sVal
171 Set Changed_Value item 0 to sVal
172 Set Private.ControlChangingState to bOld
173 End_Procedure
174
175End_Class
176