DLL 2 - Ayuda para Crear Eventos - Delphi Snippet - RowObject Comunidad ...
DLL 2 - Ayuda para Crear Eventos - Delphi Snippet - RowObject Comunidad ...
ENE 26
Publicado por El monstruo de Caerbannog
Como si me tratase del doctor Frankenstein
(http://www.youtube.com/watch?v=muTcYb1lCbU) perseguido por
mi creación, decido abandonar mi retiro para afrontar a la bestia a
la que un día aciago, jugando a ser programador, di
vida: RowObject.pas
Sí, varias han sido las llamadas que hemos recibido últimamente de
desarrolladores que se quejaban de fallos en un código que, en
ciertos casos, hemos proporcionado como ejemplo de cómo manipular de manera fácil unas
matrices de variants en delphi usadas en algunos eventos de a3ERP. Para evitar tener que aplicar la
medicina de la escupidera de bronce a alguno (se evita leyendo algunos artículos de este blog),
publicaré aquí la versión más reciente de dicha unidad.
Bien, el fragmento de código que publico a continuación contiene tres clases principalmente que nos
evitarán tener que trabajar con las engorrosas matrices de matrices de variants (las matrices
unidimensionales son muy fáciles de manipular, con un caramelo basta).
TDatasetObject
Esta clase encapsula lo que en el artículo en el que se describían los tipos usados en los eventos
a3ERP (http://comunidadnexus.com/2009/03/26/yo-y-nexus-la-consumacion/) denominé “Conjunto
de datos”. Se encarga de, dado un variant que contiene un “Conjunto de datos”, o sea una lista de
“Registros”, crear una lista de objetos (TRowObject) para cada uno de los registros. Permite, de esta
manera, un acceso indexado a los registros. Adicionalmente permite devolver los cambios que se
hayan producido en los registros al variant original.
TRowObject
Esta otra encapsula lo que en el enlace del punto anterior se denominó “Registro”. Su
responsabilidad es mantener la lista de campos definidos en el registro encapsulado así como
proveer de algunas facilidades para localizarlos, ya sea por índice o nombre. Además es capaz de
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 1/10
23/09/12 Ayuda para crear eventos: Delphi snippet – RowObject « Comunidad a3ERP
TFieldObject
La última de las tres clases simplemente permite algunas facilidades extra para manipular los
valores de cada uno de los campos, al estilo de los TField, del tipo denominado “Registro”, ya
encapsulado por la clase anterior.
El código: RowObject.pas
Que menos que decir que se entrega como está, con sus bugs y demás atrocidades que se puedan
encontrar. La mayor versión de Delphi con la que se ha compilado es la 2006. La última vez que lo
intenté, compiló. Con versiones superiores es muy posible que de problemas por el soporte
UNICODE.
001 unit RowObject;
002
003 interface
004
005 uses
006 SysUtils, Classes, Contnrs;
007
008 type
009 ERowObjectException = class(Exception);
010 EInvalidFieldnameException = class(ERowObjectException);
011 EInvalidGetFieldsParameter = class(ERowObjectException);
012
013 TDatasetObject = class;
014
015 TRowObject = class;
016 TFieldObject = class
017 private
018 FIndex: Integer;
019 FValue,
020 FOldValue: Variant;
021 FRow: TRowObject;
022 FModified: Boolean;
023 FFieldname: string;
024 protected
025 procedure SetAsBoolean(const AValue: Boolean);
026 procedure SetAsCurrency(const AValue: Currency);
027 procedure SetAsFloat(const AValue: Double);
028 procedure SetAsInteger(const AValue: Integer);
029 procedure SetAsString(const AValue: string);
030 function GetAsCurrency: Currency;
031 function GetAsInteger: Integer;
032 function GetAsString : string;
033 function GetAsBoolean: Boolean;
034 function GetAsFloat: Double;
035 procedure SetValue(const Value: Variant);
036 procedure ApplyTo(var Line: Variant);
037 public
038 constructor Create(const AIndex: Integer; ARow: TRowObject);
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 2/10
23/09/12 Ayuda para crear eventos: Delphi snippet – RowObject « Comunidad a3ERP
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 3/10
23/09/12 Ayuda para crear eventos: Delphi snippet – RowObject « Comunidad a3ERP
109
110 { TRowObject }
111
112 constructor TRowObject.Create(const Line: Variant; ADatasetObject: TDatasetObject = nil);
113 begin
114 inherited Create;
115 FData := Line;
116 FFields := TObjectList.Create(True);
117 FFieldNameIndex := TStringList.Create;
118 TStringList(FFieldNameIndex).Sorted := True;
119 FDataset := ADatasetObject;
120 BuildFields;
121 end;
122
123 procedure TRowObject.BuildFields;
124 var
125 Idx, Max: Integer;
126 Field: TFieldObject;
127 begin
128 FFields.Clear;
129 FFieldNameIndex.Clear;
130 Max := GetBufferFieldCount - 1;
131 for Idx := 0 to Max do begin
132 Field := TFieldObject.Create(Idx, Self);
133 FFields.Add(Field);
134 FFieldNameIndex.AddObject(Field.Fieldname, Field);
135 end;
136 end;
137
138 destructor TRowObject.Destroy;
139 begin
140 FFieldNameIndex.Free;
141 FFields.Free;
142 inherited;
143 end;
144
145 function TRowObject.GetBufferFieldCount: Integer;
146 begin
147 Result := FData[0];
148 end;
149
150 procedure TRowObject.CheckIndex(const AIndex: Integer);
151 begin
152 if (AIndex > GetFieldCount) then
153 raise ERangeError.CreateFmt('Índice [%d] fuera de rango [%d, %d]', [AIndex, 0, GetFieldCount - 1]);
154 end;
155
156 function TRowObject.GetBufferFieldValue(const Index: Integer): Variant;
157 begin
158 CheckIndex(Index);
159 Result := FData[Index + 1][1];
160 end;
161
162 function TRowObject.GetBufferFieldName(const Index: Integer): string;
163 begin
164 CheckIndex(Index);
165 Result := FData[Index + 1][0];
166 end;
167
168 procedure TRowObject.ApplyTo(var Line: Variant);
169 var
170 Idx: Integer;
171 begin
172 for Idx := 0 to FieldCount - 1 do
173 Fields[Idx].ApplyTo(Line);
174 end;
175
176 procedure TRowObject.CancelChanges;
177 var
178 Idx: Integer;
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 4/10
23/09/12 Ayuda para crear eventos: Delphi snippet – RowObject « Comunidad a3ERP
179 begin
180 for Idx := 0 to FieldCount - 1 do
181 Fields[Idx].CancelChange;
182 end;
183
184 function TRowObject.GetModified: Boolean;
185 var
186 Idx: Integer;
187 begin
188 for Idx := 0 to FieldCount - 1 do begin
189 Result := Fields[Idx].Modified;
190 if Result then Exit;
191 end;
192 Result := False;
193 end;
194
195 function TRowObject.FieldByName(const AFieldname: string): TFieldObject;
196 begin
197 Result := FindField(AFieldname);
198 if not Assigned(Result) then
199 raise EInvalidFieldnameException.CreateFmt('No se encontró campo [%s]', [AFieldname]);
200 end;
201
202 function TRowObject.FindField(const AFieldname: string): TFieldObject;
203 var
204 Idx: Integer;
205 begin
206 Idx := FFieldNameIndex.IndexOf(UpperCase(AFieldname));
207 if Idx = -1 then
208 Result := nil
209 else
210 Result := TFieldObject(FFieldNameIndex.Objects[Idx]);
211 end;
212
213 function TRowObject.GetFieldCount: Integer;
214 begin
215 Result := FFields.Count;
216 end;
217
218 function TRowObject.GetFields(const FieldNameOrIndex: Variant): TFieldObject;
219 begin
220 if VarIsOrdinal(FieldNameOrIndex) then
221 Result := TFieldObject(FFields[FieldNameOrIndex])
222 else if VarIsStr(FieldNameOrIndex) then
223 Result := FieldByName(FieldNameOrIndex)
224 else
225 raise EInvalidGetFieldsParameter.Create('Parametro FieldNameOrIndex de tipo incorrecto');
226 end;
227
228 { TDatasetObject }
229
230 constructor TDatasetObject.Create(const Lines: Variant);
231 var
232 Idx, Max: Integer;
233 begin
234 Create;
235 Max := Lines[0];
236 for Idx := 1 to Max do
237 AddRow(TRowObject.Create(Lines[Idx], Self));
238 end;
239
240 constructor TDatasetObject.Create;
241 begin
242 inherited Create;
243 FRows := TObjectList.Create;
244 end;
245
246 destructor TDatasetObject.Destroy;
247 begin
248 FreeAndNil(FRows);
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 5/10
23/09/12 Ayuda para crear eventos: Delphi snippet – RowObject « Comunidad a3ERP
249 inherited;
250 end;
251
252 procedure TDatasetObject.AddRow(ARow: TRowObject);
253 begin
254 FRows.Add(ARow);
255 end;
256
257 procedure TDatasetObject.ApplyTo(var Lines: Variant);
258 var
259 Idx: Integer;
260 Aux: Variant;
261 begin
262 for Idx := 1 to Count do begin
263 Aux := Lines[Idx];
264 Rows[Idx - 1].ApplyTo(Aux);
265 VarArrayPut(Lines, Aux, [Idx]);
266 end;
267 end;
268
269 function TDatasetObject.GetCount: Integer;
270 begin
271 Result := FRows.Count;
272 end;
273
274 function TDatasetObject.GetModified: Boolean;
275 var
276 Idx: Integer;
277 begin
278 for Idx := 0 to Count - 1 do begin
279 Result := Rows[Idx].Modified;
280 if Result then Exit;
281 end;
282 Result := False;
283 end;
284
285 function TDatasetObject.GetRows(const Index: Integer): TRowObject;
286 begin
287 Result := TRowObject(FRows[Index]);
288 end;
289
290 function TDatasetObject.RemoveRow(ARow: TRowObject): TRowObject;
291 begin
292 FRows.Remove(ARow);
293 Result := ARow;
294 end;
295
296 procedure TDatasetObject.Sort(Compare: TListSortCompare);
297 begin
298 FRows.Sort(Compare);
299 end;
300
301 { TFieldObject }
302
303 procedure TFieldObject.CancelChange;
304 begin
305 if not FModified then Exit;
306 FValue := FOldValue;
307 end;
308
309 constructor TFieldObject.Create(const AIndex: Integer; ARow: TRowObject);
310 begin
311 inherited Create;
312 FValue := ARow.GetBufferFieldValue(AIndex);
313 FFieldname := ARow.GetBufferFieldName(AIndex);
314 FOldValue := FValue;;
315 FIndex := AIndex;
316 FRow := ARow;
317 end;
318
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 6/10
23/09/12 Ayuda para crear eventos: Delphi snippet – RowObject « Comunidad a3ERP
TRowObject
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 8/10
23/09/12 Ayuda para crear eventos: Delphi snippet – RowObject « Comunidad a3ERP
Mejoras posibles
Hay muchas. Por ejemplo soportar versiones de Delphi UNICODE trabajando contra a3ERP con
cadenas AnsiString, que no haga falta indicar el destino en los método ApplyTo (y por lo tanto
queden como Apply sin más). Que el TRowObject permita construir registros al vuelo, sin necesidad
de darle un variant origen, para así facilitar el devolver campos a modificar en los métodos
“AntesDeGuardarLinea”, etc…
ADVERTISEMENT
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 9/10
23/09/12 Ayuda para crear eventos: Delphi snippet – RowObject « Comunidad a3ERP
Dejar un comentario
comunidadnexus.com/2012/01/26/delphi-snippet-rowobject/ 10/10