reynosa - delphi technologies mexico
Declarar variable global pública en Delphi (3)
el ejemplo muestra Form1 (principal) y Form2 (otro) que tiene un mejor uso para la organización;
Declaración de interfaz FORM1 solamente;
se puede leer de todas las formas;
interface
procedure oncreate(Sender: TObject);
implementation
uses Form2;
procedure TForm1.oncreate(Sender: TObject);
begin
Form2.test1;
//{Form2.test2} are not visible to Form1;
end;
FORM2 interfaz y declaraciones de implementación;
la declaración de implementación es local a la unidad; no se puede leer de todas las formas;
interface
procedure test1;
implementation
procedure test2; //declared under implementation;
procedure TForm2.test1;
begin
ShowMessage(''form2 test1 message'');
end;
procedure TForm2.test2;
begin
ShowMessage(''form2 test2 message'');
end;
cualquier procedimiento , función , tipo , variable puede ser local para la unidad en implementación;
también hace que intellisense (Ctrl + Space) se limpie de declaraciones usadas solo para la unidad;
Digamos que tengo dos formas en un proyecto delphi, quiero poder acceder a las variables de Form1 desde form2. ¿Hay alguien para declarar, digamos una variable ''pública'' en form1 que se puede leer de todas las formas?
He intentado poner una variable en la declaración pública
{ private declarations }
public
{ public declarations }
test: integer;
end;
y en la forma 2 tengo
unit Unit2;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, unit1;
type
{ TForm2 }
TForm2 = class(TForm)
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.lfm}
{ TForm2 }
procedure TForm2.FormCreate(Sender: TObject);
begin
form1 //<---------- DOES NOT GET RECOGNIZED
end;
end.
Luego coloco ''Unit1'' en la sección de usos en Form2, pero parece que no puedo hacer eso debido a una referencia circular. Me gustaría evitar el uso de punteros si es posible.
En primer lugar, si debe usar globales (probablemente sea mejor no usar globales, como ha señalado sabiamente Craig), debe poner los globales que desea compartir en SharedGlobals.pas:
unit SharedGlobals;
interface
var
{variables here}
Something:Integer;
implementation
{ nothing here?}
Ahora usa esa unidad, de las dos unidades en las que quieras compartir el acceso a esa variable. Alternativamente, haz referencia a otro objeto, que se llama algo sensible, y haz que ese objeto sea diseñado como el titular de estado (valores variables) que esas dos instancias (formularios o clases, o lo que sea) deben compartir.
Segunda idea , dado que sus dos unidades ya tienen dependencias entre sí, también podría sortear su dependencia circular utilizando la unidad que crearía una dependencia circular, desde la sección de implementación en lugar de la interfaz:
unit Unit2;
interface
/// stuff
implementation
uses Unit1;
...
unit Unit1;
interface
/// stuff
implementation
uses Unit2;
Primero , es mejor pretender que los globales no existen en absoluto . Si comienzas a programar con la muleta de variables globales, evitarás aprender las técnicas más simples que te permiten prescindir de ellas. Te preocupa utilizar punteros (lo que en realidad no ayudaría en absoluto a tu problema), pero no te preocupa usar globos globales que en realidad sean más peligrosos.
Globales son peligrosos porque:
- Proporcionan un enlace entre las unidades que los comparten (un concepto llamado acoplamiento cerrado )
- Este enlace está oculto en el sentido de que no es obvia la naturaleza exacta del enlace sin examinar los detalles del código.
- Su código estará lleno de efectos secundarios , lo que quiere decir que cuando hace algo en un método, también suceden otras cosas inesperadas. Esto aumenta la posibilidad y complejidad de errores sutiles.
- El efecto acumulativo de los puntos anteriores es que incluso si divide un proyecto en 20 unidades, su cerebro todavía tiene que pensar en las 20 unidades al mismo tiempo, como si solo fueran 1 unidad. Esto derrota el propósito de dividir su proyecto en unidades manejables más pequeñas en primer lugar.
- Descubrirá rápidamente que incluso los proyectos de tamaño mediano comienzan a ser muy difíciles de mantener.
Referencias circulares
Por favor, eche un vistazo a mi respuesta a una pregunta anterior para obtener ideas sobre el tratamiento de referencias circulares en general.
En su caso, simplemente necesita mover la Unit1
de los usos de la interface
a los usos de implementation
.
var
Form2: TForm2;
implementation
uses
Unit1;
{$R *.lfm}
{ TForm2 }
procedure TForm2.FormCreate(Sender: TObject);
begin
Form1.test; //Is now accessible, but remember: it will cause a runtime error if Form1 hasn''t been created or has already been destroyed.
end;
Compartir datos sin globales
Notarás que técnicamente sigues usando globales; aunque creados por Delphi y no los tuyos. Aquí hay una técnica que puede usar para compartir datos de una manera más controlada.
unit Unit3;
interface
type
TSharedData = class(TObject)
public
Test1: Integer;
Test2: Integer;
end;
Luego en Form1
agregas lo siguiente:
implementation
uses
...
Unit3;
type
TForm1 = class(TForm)
...
public
SharedData: TSharedData;
end;
//Inside either the constructor or OnCreate event add the following line:
SharedData := TSharedData.Create;
//Inside either the destructor or OnDestroyevent add the following line:
SharedData.Free;
Luego, en Form2
haces algo ligeramente diferente porque quieres usar los datos compartidos de Form1, no sus propios "datos compartidos".
implementation
uses
...
Unit3;
type
TForm2 = class(TForm)
...
public
Form1SharedData: TSharedData;
end;
//Nothing added to constructor/destructor or OnCreate/OnDestroy events
Finalmente, después de crear ambos formularios, le da a Form2
una referencia a los datos compartidos de Form1
:
procedure RunApplicationWithoutFormGlobals;
var
LForm1: TForm1;
LForm2: TForm2;
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, LForm1);
Application.CreateForm(TForm2, LForm2);
LForm2.Form1SharedData := LForm1.SharedData;
Application.Run;
end;
Lo anterior ilustra cuán fácilmente puede deshacerse incluso de las variables globales de Delphi.
Descargo de responsabilidad: Parte del código se aplica a principios de encapsulación generalmente aceptados, pero solo con fines ilustrativos.