Difference between revisions of "Lazarus For Delphi Users/es"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting; deleted category included in page template)
 
(12 intermediate revisions by 3 users not shown)
Line 5: Line 5:
  
 
== Delphi -> Lazarus ==
 
== Delphi -> Lazarus ==
   Lazarus es una herramienta de desarrollo rápido de aplicaciones, al igual que Delphi. Esto significa que dispone de una biblioteca de componentes visuales y de un entorno de desarrollo integrado (IDE). La librería de componentes de Lazarus (LCL) es muy similar a la VCL de Delphi. Muchas unidades, clases y propiedades tienen el mismo nombre e idéntica funcionalidad. Esto hace que el paso de uno o otro sea fácil. Pero Lazarus '''no''' es un ''clon Delphi'' de fuentes libres. So don't expect 100% compatibility.
+
   Lazarus es una herramienta de desarrollo rápido de aplicaciones, al igual que Delphi. Esto significa que dispone de una biblioteca de componentes visuales y de un entorno de desarrollo integrado (IDE). La librería de componentes de Lazarus (LCL) es muy similar a la VCL de Delphi. Muchas unidades, clases y propiedades tienen el mismo nombre e idéntica funcionalidad. Esto hace que el paso de uno o otro sea fácil. Pero Lazarus '''no''' es un ''clon Delphi'' de fuentes libres. No esperes por tanto una compatibilidad total.
  
 
=== La mayor diferencia ===
 
=== La mayor diferencia ===
Line 14: Line 14:
 
=== Lo primero que hay que hacer al convertir un proyecto de Delphi ===
 
=== Lo primero que hay que hacer al convertir un proyecto de Delphi ===
 
   Teniendo Lazarus en ejecución,  tienes que ir a '''Herramientas''' y después a '''Convertir proyecto Delphi a proyecto Lazarus'''. Esto no lo hace todo, pero te facilitará la conversión. Tenga en cuenta que las herramientas disponibles en el IDE son unidireccionales. Si se necesita conservar la compatibilidad, para poder compilar indistintamente en Delphi y en Lazarus, considera convertir tus archivos utilizando [http://wiki.lazarus.freepascal.org/XDev_Toolkit XDev Toolkit].
 
   Teniendo Lazarus en ejecución,  tienes que ir a '''Herramientas''' y después a '''Convertir proyecto Delphi a proyecto Lazarus'''. Esto no lo hace todo, pero te facilitará la conversión. Tenga en cuenta que las herramientas disponibles en el IDE son unidireccionales. Si se necesita conservar la compatibilidad, para poder compilar indistintamente en Delphi y en Lazarus, considera convertir tus archivos utilizando [http://wiki.lazarus.freepascal.org/XDev_Toolkit XDev Toolkit].
 +
 +
=== Soporte para Unicode ===
 +
 +
   Delphi, incluida la versión 2007, no da soporte para Unicode, utilizando la codificación ANSI de Windows. Delphi da soporte a Unicode utilizando codificación de cadenas en UTF-16 a partir de la versión 2009.
 +
 +
   Por su lado Lazarus ha comenzado a dar soporte a Unicode con anterioridad y utiliza codificación de cadenas UTF-8. Para más información ver [[LCL Unicode Support|Soporte LCL para Unicode]].
  
 
== Delphi IDE -> Lazarus IDE ==
 
== Delphi IDE -> Lazarus IDE ==
 
=== Proyectos ===
 
=== Proyectos ===
   El archivo de extensión .dpr es el principal de una aplicación Delphi. El archivo principal de un proyecto Lazarus es el de extensión  ''.lpi'' (Información de proyecto Lazarus). El archivo ''.dpr'' es también el arcivo principal de código y en el mismo el IDE almacena información sobre las opciones de compilación y las unidades que utiliza el proyecto. Una aplicación Lazarus también tiene un archivo ''.lpr'',  que es el archivo principal de código. El resto de la información se lamacena en el ''.lpi''. Por lo tanto el ''.lpi'' es el archivo más importante del proyecto.
+
   El archivo de extensión .dpr es el principal de una aplicación Delphi. El archivo principal de un proyecto Lazarus es el de extensión  ''.lpi'' (Información de proyecto Lazarus). El archivo ''.dpr'' es también el archivo principal de código y en el mismo el IDE almacena información sobre las opciones de compilación y las unidades que utiliza el proyecto. Una aplicación Lazarus también tiene un archivo ''.lpr'',  que es el archivo principal de código. El resto de la información se almacena en el ''.lpi''. Por lo tanto el ''.lpi'' es el archivo más importante del proyecto.
  
 
   Por ejemplo:
 
   Por ejemplo:
Line 23: Line 29:
 
   Delphi guarda las rutas a las unidades en el archivo ''.dpr''. Como esta, ''unidad1 in 'ruta/Unidad1.pas'''. El ''in'' es específico de Delphi  y no es entendido por Lazarus. No lo utilices, en su lugar usa las opciones de unidades y rutas de configuración del compilador.
 
   Delphi guarda las rutas a las unidades en el archivo ''.dpr''. Como esta, ''unidad1 in 'ruta/Unidad1.pas'''. El ''in'' es específico de Delphi  y no es entendido por Lazarus. No lo utilices, en su lugar usa las opciones de unidades y rutas de configuración del compilador.
  
   Delphi guarda las opciones del compilador en el archivo ''.dpr'', como {$APPTYPE CONSOLE}, que son ignoradas por Lazarus. No lo utilices, en su lugar usa las opciones del compilador.
+
   Delphi guarda las opciones del compilador, como {$APPTYPE CONSOLE}, en el archivo ''.dpr'', que son ignoradas por Lazarus. No lo utilices, en su lugar usa las opciones del compilador.
  
 
====Una cuestión importante: ''Siempre'' hay un proyecto. ====
 
====Una cuestión importante: ''Siempre'' hay un proyecto. ====
   La única forma de "cerrar" un proyecto es cerrando Lazarus o abriendo otro proyecto. ESto es así, porque un proyecto Lazarus es así mimso una "sesión". Esto significa que la configuración actual del IDE se guarda en el archivo ''.lpi'' y es restaurada al reabrir el proyecto. Por ejemplo: estás depurando una aplicación, pones una serie de puntos de parada y marcas. Puedes guardar el proyecto, cerrar Lazarus o abrir otro proyecto. Cuándo reabras el proyecto, incluso en otra máquina, todos los puntos de parada, marcadores, archivos abiertos en el editor, posición de los cursosres, hisoria de saltos, y demás, serán restaurados.
+
   La única forma de "cerrar" un proyecto es cerrando Lazarus o abriendo otro proyecto. Esto es así, porque un proyecto Lazarus es así mismo una "sesión". Esto significa que la configuración actual del IDE se guarda en el archivo ''.lpi'' y es restaurada al reabrir el proyecto. Por ejemplo: estás depurando una aplicación, pones una serie de puntos de parada y marcas. Puedes guardar el proyecto, cerrar Lazarus o abrir otro proyecto. Cuándo reabras el proyecto, incluso en otra máquina, todos los puntos de parada, marcadores, archivos abiertos en el editor, posición de los cursores, historia de saltos, y demás, serán restaurados.
  
 
=== Editor de Código ===
 
=== Editor de Código ===
Line 33: Line 39:
 
   El IDE de Lazarus tiene una gran cantidad de herramientas para trabajar con el código fuente. Muchas son parecidas y trabajan de forma similar a las de Delphi. Pero hay una diferencia importante, Lazarus no utiliza el compilador para obtener información del código, analiza el código fuente directamente. Esto tiene un montón de ventajas importantes:
 
   El IDE de Lazarus tiene una gran cantidad de herramientas para trabajar con el código fuente. Muchas son parecidas y trabajan de forma similar a las de Delphi. Pero hay una diferencia importante, Lazarus no utiliza el compilador para obtener información del código, analiza el código fuente directamente. Esto tiene un montón de ventajas importantes:
  
&nbsp;&nbsp;&nbsp;El editor trabaja con "comentarios". Para Delphi los comentarios son simplemente espacios entre el código. Ninguna  característica del código trabaja aquí y si se inserta automáticamente nuevo código, los comentarios se desplazan. Con Lazarus se puede encontrar una declaración de código incluso dentro de los comentarios. Aunque esto no es completamente fiable, normalmente funciona. Cuando se inserta nuevo código el IDE utiliza heurística para mantener los comentarios y el código juntos. Por ejemplo, no separará la línea: <delphi> letra: char; // comentario</delphi>
+
&nbsp;&nbsp;&nbsp;El editor trabaja con "comentarios". Para Delphi los comentarios son simplemente espacios entre el código. Ninguna  característica del código trabaja aquí y si se inserta automáticamente nuevo código, los comentarios se desplazan. Con Lazarus se puede encontrar una declaración de código incluso dentro de los comentarios. Aunque esto no es completamente fiable, normalmente funciona. Cuando se inserta nuevo código el IDE utiliza heurística para mantener los comentarios y el código juntos. Por ejemplo, no separará la línea: <syntaxhighlight lang=pascal> letra: char; // comentario</syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;La función de ''Completar código'' de Delphi (Ctrl+Space) se denomina ''Completar identificador'' (''Identifier Completion'') en Lazarus. El término Lazarus ''Completar código'' (''Code Completion'') es una funcionalidad que combina  ''Completar Clase automáticamente'' (''Automatic Class Completion'' igual que en Delphi), ''Completar variable local'' (''Local Variable Completion'') y  ''Completar asignación de evento'' (''Event Assignment Completion''. Todas ellas se activan mediante ''Ctrl+Shift+C'' y el IDE determina cuál ejecutaraá en función del código presente en la posición del cursor.
 
&nbsp;&nbsp;&nbsp;La función de ''Completar código'' de Delphi (Ctrl+Space) se denomina ''Completar identificador'' (''Identifier Completion'') en Lazarus. El término Lazarus ''Completar código'' (''Code Completion'') es una funcionalidad que combina  ''Completar Clase automáticamente'' (''Automatic Class Completion'' igual que en Delphi), ''Completar variable local'' (''Local Variable Completion'') y  ''Completar asignación de evento'' (''Event Assignment Completion''. Todas ellas se activan mediante ''Ctrl+Shift+C'' y el IDE determina cuál ejecutaraá en función del código presente en la posición del cursor.
Line 39: Line 45:
 
==== Ejemplo de ''Completar variable local'' ====
 
==== Ejemplo de ''Completar variable local'' ====
 
&nbsp;&nbsp;&nbsp;Supongamos que acabas de crear un nuevo método y escribes la sentencia "i:=3;"
 
&nbsp;&nbsp;&nbsp;Supongamos que acabas de crear un nuevo método y escribes la sentencia "i:=3;"
<delphi>  procedure TForm1.HacerAlgo;
+
<syntaxhighlight lang=pascal>  procedure TForm1.HacerAlgo;
 
   begin
 
   begin
 
   i := 3;
 
   i := 3;
   end; </delphi>
+
   end; </syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;Coloca el cursor justo de delante del identificador "i" y presiona Ctrl+Shift+C para obtener la declaración de la variable:
 
&nbsp;&nbsp;&nbsp;Coloca el cursor justo de delante del identificador "i" y presiona Ctrl+Shift+C para obtener la declaración de la variable:
  
<delphi>  procedure TForm1.HacerAlgo;
+
<syntaxhighlight lang=pascal>  procedure TForm1.HacerAlgo;
 
   var i: Integer;
 
   var i: Integer;
 
   begin
 
   begin
 
   i := 3;
 
   i := 3;
   end; </delphi>
+
   end; </syntaxhighlight>
  
 
==== Ejemplo ''Completar asignación de evento'' ====
 
==== Ejemplo ''Completar asignación de evento'' ====
Line 56: Line 62:
 
&nbsp;&nbsp;&nbsp;Por ejemplo:
 
&nbsp;&nbsp;&nbsp;Por ejemplo:
  
<delphi> btnCancelar.OnClick:=</delphi>
+
<syntaxhighlight lang=pascal> btnCancelar.OnClick:=</syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;Sitúa el cursor tras el operador de asignación ":=" y presiona Ctrl+Shift+C, y se generará el esqueleto de la función de respuesta al evento.
 
&nbsp;&nbsp;&nbsp;Sitúa el cursor tras el operador de asignación ":=" y presiona Ctrl+Shift+C, y se generará el esqueleto de la función de respuesta al evento.
  
<delphi>//...
+
<syntaxhighlight lang=pascal>//...
 
   btnCancelar.OnClick:=@btnCancelarClick;
 
   btnCancelar.OnClick:=@btnCancelarClick;
 
//...
 
//...
Line 67: Line 73:
 
   begin
 
   begin
  
   end;    </delphi>
+
   end;    </syntaxhighlight>
  
==== Ejemplo de ''Completar llamada a Procedimiento ====
+
==== Ejemplo de ''Completar llamada a Procedimiento'' ====
 
&nbsp;&nbsp;&nbsp;Supongamos que acabamos de escribir la sentencia "HacerAlgo(Ancho);" en este código
 
&nbsp;&nbsp;&nbsp;Supongamos que acabamos de escribir la sentencia "HacerAlgo(Ancho);" en este código
<delphi> procedure UnProcedimiento;
+
<syntaxhighlight lang=pascal> procedure UnProcedimiento;
 
   var
 
   var
 
   Ancho: integer;
 
   Ancho: integer;
Line 77: Line 83:
 
   Ancho:=3;
 
   Ancho:=3;
 
   HacerAlgo(Ancho);
 
   HacerAlgo(Ancho);
   end;</delphi>
+
   end;</syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;Sitúa el cursor sobre el identificador "HacerAlgo" y presiona las teclas Ctrl+Shift+C para obtener:
 
&nbsp;&nbsp;&nbsp;Sitúa el cursor sobre el identificador "HacerAlgo" y presiona las teclas Ctrl+Shift+C para obtener:
  
<delphi> procedure HacerAlgo(aAncho: LongInt);
+
<syntaxhighlight lang=pascal> procedure HacerAlgo(aAncho: LongInt);
 
   begin
 
   begin
  
Line 94: Line 100:
 
   Ancho:=3;
 
   Ancho:=3;
 
   HacerAlgo(Ancho);
 
   HacerAlgo(Ancho);
   end;</delphi>
+
   end;</syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;'''Nota''' del traductor: lo descrito más arriba no funciona (da un error: Ya fue definido el identificador UnProcedimiento); sin embargo si el cursor está dentro del  código de "UnProcedimiento", cómo en el ejemplo:
 
&nbsp;&nbsp;&nbsp;'''Nota''' del traductor: lo descrito más arriba no funciona (da un error: Ya fue definido el identificador UnProcedimiento); sin embargo si el cursor está dentro del  código de "UnProcedimiento", cómo en el ejemplo:
<delphi> type
+
<syntaxhighlight lang=pascal> type
 
     UnaClase = Class(TObject)
 
     UnaClase = Class(TObject)
 
     end;
 
     end;
Line 104: Line 110:
 
   begin
 
   begin
 
   //...
 
   //...
   end;</delphi>
+
   end;</syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;Al pulsar Ctrl+Shift+C obtendremos la definición de UnProcedimiento como miembro de la clase "UnaClase".
 
&nbsp;&nbsp;&nbsp;Al pulsar Ctrl+Shift+C obtendremos la definición de UnProcedimiento como miembro de la clase "UnaClase".
<delphi> type
+
<syntaxhighlight lang=pascal> type
 
     UnaClase = Class(TObject)
 
     UnaClase = Class(TObject)
 
     private
 
     private
Line 113: Line 119:
 
     end;
 
     end;
 
//...
 
//...
  procedure UnaClase.UnProcedimiento;</delphi>
+
  procedure UnaClase.UnProcedimiento;</syntaxhighlight>
  
 
==== "Completar palabras" Ctrl+W ====
 
==== "Completar palabras" Ctrl+W ====
Line 149: Line 155:
 
&nbsp;&nbsp;&nbsp;Sí, para ello:
 
&nbsp;&nbsp;&nbsp;Sí, para ello:
  
&nbsp;&nbsp;&nbsp;Crea un nuevo paquete, guárdalo en el direcorio donde residen los archivos fuente (normalmente el mismo directorio del archivo ''.dpk''), añade la LCL cómo pauete necesario y finalmente los archivos ''.pas''.
+
&nbsp;&nbsp;&nbsp;Crea un nuevo paquete, guárdalo en el direcorio donde residen los archivos fuente (normalmente el mismo directorio del archivo ''.dpk''), añade la LCL cómo paquete necesario y finalmente los archivos ''.pas''.
 
Ya puedes instalarlo o utilizarlo en tus proyectos.
 
Ya puedes instalarlo o utilizarlo en tus proyectos.
 
Hay algunas diferencias entre los paquetes de Lazarus y Delphi, leete el archivo docs/Packages.txt que se encuentra en el directorio de fuentes de Lazarus.
 
Hay algunas diferencias entre los paquetes de Lazarus y Delphi, leete el archivo docs/Packages.txt que se encuentra en el directorio de fuentes de Lazarus.
Line 175: Line 181:
  
 
&nbsp;&nbsp;&nbsp;Esto significa actualmente que ningún control hereda/utiliza las funciones, procedimientos, propiedades o eventos de TControl siguientes:
 
&nbsp;&nbsp;&nbsp;Esto significa actualmente que ningún control hereda/utiliza las funciones, procedimientos, propiedades o eventos de TControl siguientes:
<delphi> Protected
+
<syntaxhighlight lang=pascal> Protected
 
     function GetDockEdge(MousePos: TPoint): TAlign;
 
     function GetDockEdge(MousePos: TPoint): TAlign;
 
     function GetDragImages: TDragImageList;
 
     function GetDragImages: TDragImageList;
Line 221: Line 227:
 
     property TBDockHeight: Integer;
 
     property TBDockHeight: Integer;
 
     property UndockHeight: Integer;
 
     property UndockHeight: Integer;
     property UndockWidth: Integer; </delphi>
+
     property UndockWidth: Integer; </syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;que las clases siguientes no existen/o no son utilizables
 
&nbsp;&nbsp;&nbsp;que las clases siguientes no existen/o no son utilizables
  
<delphi> TDragImageList = class(TCustomImageList)
+
<syntaxhighlight lang=pascal> TDragImageList = class(TCustomImageList)
 
  TDockZone = class
 
  TDockZone = class
 
  TDockTree = class(TInterfacedObject, IDockManager)
 
  TDockTree = class(TInterfacedObject, IDockManager)
Line 231: Line 237:
 
  TBaseDragControlObject = class(TDragObject)
 
  TBaseDragControlObject = class(TDragObject)
 
  TDragControlObject = class(TBaseDragControlObject)
 
  TDragControlObject = class(TBaseDragControlObject)
  TDragDockObject = class(TBaseDragControlObject) </delphi>
+
  TDragDockObject = class(TBaseDragControlObject) </syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;y que las siguientes funciones no son utilizables o son incompablibles
 
&nbsp;&nbsp;&nbsp;y que las siguientes funciones no son utilizables o son incompablibles
  
<delphi> function FindDragTarget(const Pos: TPoint;
+
<syntaxhighlight lang=pascal> function FindDragTarget(const Pos: TPoint;
 
                         AllowDisabled: Boolean) : TControl;
 
                         AllowDisabled: Boolean) : TControl;
 
  procedure CancelDrag;
 
  procedure CancelDrag;
  function IsDragObject(sender: TObject): Boolean; </delphi>
+
  function IsDragObject(sender: TObject): Boolean; </syntaxhighlight>
  
 
&nbsp;&nbsp;&nbsp;El inicio del controlador de ajuste se describe aquí: [[Anchor Docking]]
 
&nbsp;&nbsp;&nbsp;El inicio del controlador de ajuste se describe aquí: [[Anchor Docking]]
  
 
==== TEdit/TCustomEdit ====
 
==== TEdit/TCustomEdit ====
&nbsp;&nbsp;&nbsp;Los controles Edit, funcionan esencialmente de la misma forma en la LCL y en la VCL, aunque tienen algunas cuestiones  de las que ser conscientes a la hora de convertir.
+
&nbsp;&nbsp;&nbsp;Los controles ''Edit'', funcionan esencialmente de la misma forma en la LCL y en la VCL, aunque tienen algunas cuestiones  de las que ser conscientes a la hora de convertir.
# Debido a restricciones en los interfaces, TEdit.PasswordChar no trabaja en todos los interfaces (con el tiempo puede que sí), en su lugar se puede utilizar emPassword de TCustomEdit.EchoMode para el texto  que necesite ser ocultado.
+
# Debido a restricciones en los interfaces, ''TEdit.PasswordChar'' no trabaja en todos los interfaces (con el tiempo puede que sí), en su lugar se puede utilizar emPassword de ''TCustomEdit.EchoMode'' para el texto  que necesite ser ocultado.
# Los eventos Drag/Dock no están implementados. Para más información ver la sección [[#Arrastre y colocación de controles|Arrastre y colocación de controles]].
+
# Los eventos ''Drag/Dock ''no están implementados. Para más información ver la sección [[#Arrastre y colocación de controles|Arrastre y colocación de controles]].
 
# Las propiedades de Font son normalmente ignoradas para consistencia del interfaz, para una explicación detallada ver la sección [[#TControl.Font/TControl.ParentFont | TControl.Font/TControl.ParentFont]]
 
# Las propiedades de Font son normalmente ignoradas para consistencia del interfaz, para una explicación detallada ver la sección [[#TControl.Font/TControl.ParentFont | TControl.Font/TControl.ParentFont]]
  
Line 251: Line 257:
 
'''Mejórame, por favor'''
 
'''Mejórame, por favor'''
  
&nbsp;&nbsp;&nbsp;Ya existe un control TSplitter en la LCL, por lo que no es necesaria la conversión. Sin embargo, si usted quiere hacerlo, aquí se explica cómo:
+
&nbsp;&nbsp;&nbsp;Ya existe un control ''TSplitter'' en la LCL, por lo que no es necesaria la conversión. Sin embargo, si usted quiere hacerlo, aquí se explica cómo:
  
 
&nbsp;&nbsp;&nbsp;Lo que sigue se basa libremente en preguntas de [[User:Vincent|Vincent Snijders]] en la lista de correo, y en las respuestas de [http://lazarus-ccr.sourceforge.net/index.php?wiki=AndrewJohnson Andrew Johnson]:
 
&nbsp;&nbsp;&nbsp;Lo que sigue se basa libremente en preguntas de [[User:Vincent|Vincent Snijders]] en la lista de correo, y en las respuestas de [http://lazarus-ccr.sourceforge.net/index.php?wiki=AndrewJohnson Andrew Johnson]:
  
&nbsp;&nbsp;&nbsp;En la VCL el control "divisores", que es como un [http://buscon.rae.es/draeI/SrvltGUIBusUsual?TIPO_HTML=2&TIPO_BUS=3&LEMA=tirador tirador] que se coloca entre dos componentes para distrbuir el espacio entre ambos,  está representado por TSplitter. Esto se ve a menudo, por ejemplo en el IDE de Delphi entre el explorador del código y el visor de código fuente.
+
&nbsp;&nbsp;&nbsp;En la VCL el control "repartidor", que es como un [http://buscon.rae.es/draeI/SrvltGUIBusUsual?TIPO_HTML=2&TIPO_BUS=3&LEMA=tirador tirador] que se coloca entre dos componentes para distribuir el espacio entre ambos,  está representado por ''TSplitter''. Esto se ve a menudo, por ejemplo en el IDE de Delphi entre el explorador del código y el visor de código fuente.
  
&nbsp;&nbsp;&nbsp;La LCL proporciona su propio control llamado TPairSplitter, que sirve para el mismo propósito, no obstante no es compatible, será necesario "reparar"  el código  de los DFM de Delphi convertidos, aunque gran parte es compartido entre los dos.
+
&nbsp;&nbsp;&nbsp;La LCL proporciona su propio control llamado ''TPairSplitter'', que sirve para el mismo propósito, no obstante no es compatible, será necesario "reparar"  el código  de los DFM de Delphi convertidos, aunque gran parte es compartido entre los dos.
  
&nbsp;&nbsp;&nbsp;'''¿Cúales son exactamente las direfencias?'''
+
&nbsp;&nbsp;&nbsp;'''¿Cuales son exactamente las diferencias?'''
  
&nbsp;&nbsp;&nbsp;La mayor diferencia es que el TSplitter de la VCL no tiene ''hijos'', en vez de ello se coloca entre los dos controles alineados apropiadamente y los redimensiona en tiempo de ejecución. Es necesario tener dos controles alineados para cualquier cosa. Un ejemplo sencillo es un formulario con un Panel alineado a la izquierda (Aling := alLeft), un Splitter alineado a la izquierda y un segundo panel alineado al área cliente (Aling := alClient). Durante la ejecución puede ajustar el espacio entre los dos paneles arrastrando el tirador que provee el control Splitter.
+
&nbsp;&nbsp;&nbsp;La mayor diferencia es que el ''TSplitter'' de la VCL no tiene ''hijos'', en vez de ello se coloca entre los dos controles alineados apropiadamente y modifica sus dimensiones en tiempo de ejecución. Es necesario tener dos controles alineados para cualquier cosa. Un ejemplo sencillo es un formulario con un Panel alineado a la izquierda (''Aling := alLeft''), un ''Splitter'' alineado a la izquierda y un segundo panel alineado al área cliente (''Aling := alClient''). Durante la ejecución puede ajustar el espacio entre los dos paneles arrastrando el tirador que provee el control ''Splitter''.
  
&nbsp;&nbsp;&nbsp;En la LCL, por su parte, un TPairSplitter es un tipo especial de control con dos paneles, y aunque es útil únicamente si los controles que se reparten el espacio están en ellos, realiza su cometido estando vacios. Siguiendo con el ejemplo anterior, tendríamos un formulario con un TPairSplitter alineado al área cliente (Aling := alClient) y sendos paneles, igualmente alineados  al área cliente (Aling := alClient) a los lados.
+
&nbsp;&nbsp;&nbsp;En la LCL, por su parte, un ''TPairSplitter'' es un tipo especial de control con dos paneles, y aunque es útil únicamente si los controles que se reparten el espacio están en ellos, realiza su cometido estando vacios. Siguiendo con el ejemplo anterior, tendríamos un formulario con un TPairSplitter alineado al área cliente (Aling := alClient) y sendos paneles, igualmente alineados  al área cliente (Aling := alClient) a los lados.
  
&nbsp;&nbsp;&nbsp;La otra diferencia importante es que en la VCL, puesto que el TSplitter es su propio TControl, la posición se guarda relativa a los otros controles al redimensionar, así que en cierto momento un panel del cliente crecerá mientras que los otros paneles no, así la posición de la ''frontera'' es relativa alineación de los controles participantes.
+
&nbsp;&nbsp;&nbsp;La otra diferencia importante es que en la VCL, puesto que el ''TSplitter'' es su propio ''TControl'', la posición se guarda relativa a los otros controles al hacer el reparto, así que en cierto momento un panel del cliente crecerá mientras que los otros paneles no, así la posición de la ''frontera'' es relativa a la alineación de los controles participantes.
  
&nbsp;&nbsp;&nbsp;En la LCL puesto que los paneles laterales estan separados el control TPairSplitter tiene su propiedad de posición es aboluta, y al realizar la redimensión no cambia su posición según el contenido, por lo que hay que hacer una ''retrollamada'' para asegurar que se mantiene el ratio, en caso de ser importante.
+
&nbsp;&nbsp;&nbsp;En la LCL puesto que los paneles laterales están separados el control ''TPairSplitter'' tiene su propiedad de posición es absoluta, y al realizar la redistribución no cambia su posición según el contenido, por lo que hay que hacer una ''retrollamada'' para asegurar que se mantiene el ratio, en caso de ser importante.
  
&nbsp;&nbsp;&nbsp;Por ejemplo, si el lado derecho de una distribución vertical necesita comportase como si estuviera ''alineado al cliente'' será necesario añadir al evento resize del formulario código cómo este:
+
&nbsp;&nbsp;&nbsp;Por ejemplo, si el lado derecho de una distribución vertical necesita comportase como si estuviera ''alineado al cliente'' será necesario añadir al evento ''OnResize'' del formulario código cómo este:
<delphi> PairSplitter.Position := PairSplitter.Width - PairSplitter.Position; </delphi>
+
<syntaxhighlight lang=pascal> PairSplitter.Position := PairSplitter.Width - PairSplitter.Position; </syntaxhighlight>
  
 
;&nbsp;&nbsp;&nbsp;¿Cómo puedo convertir código existente que utiliza TSplitter a TPairSplitter?
 
;&nbsp;&nbsp;&nbsp;¿Cómo puedo convertir código existente que utiliza TSplitter a TPairSplitter?
  
&nbsp;&nbsp;&nbsp;Si el redimensionador y los controles se crean dentro de una función (como OnCreate del  formulario), la conversión será más difícil, reorganiza primero el código para crear los controles en orden según la nueva jerarquía y para fijar a los padres de los controles ''hijo'' a redimensionar de izquierda/arriba y a la derecha/abajo del PairSplitter. Un ejemplo de los cambios necesarios:
+
&nbsp;&nbsp;&nbsp;Si el repartidor y los controles se crean dentro de una función (como ''OnCreate'' del  formulario), la conversión será más difícil, se reorganiza primero el código para crear los controles en el orden adecuado según la nueva jerarquía y para fijar a los padres de los controles ''hijo'' a repartir de izquierda/arriba y a la derecha/abajo del ''PairSplitter''. Un ejemplo de los cambios necesarios:
  
 
{| class="code"
 
{| class="code"
Line 281: Line 287:
 
|- class="code"
 
|- class="code"
 
| class="code" |
 
| class="code" |
<delphi> var  
+
<syntaxhighlight lang=pascal> var  
 
   BottomPanel: TPanel;
 
   BottomPanel: TPanel;
 
   VerticalSplitter: TSplitter;
 
   VerticalSplitter: TSplitter;
Line 326: Line 332:
 
     Caption:= 'Hello';
 
     Caption:= 'Hello';
 
   end;
 
   end;
end; </delphi>
+
end; </syntaxhighlight>
 
| class="code" |  
 
| class="code" |  
<delphi> var
+
<syntaxhighlight lang=pascal> var
 
   BottomPanel: TPanel;
 
   BottomPanel: TPanel;
 
   VerticalSplitter: TPairSplitter;
 
   VerticalSplitter: TPairSplitter;
Line 381: Line 387:
 
     Align:= alClient;
 
     Align:= alClient;
 
   end;
 
   end;
end; </delphi>
+
end; </syntaxhighlight>
 
|}
 
|}
  
Hay que ser consistente con la jerarquía de los controles. Y si se está familiarizado con  los DFM' s, los cambios necesarios para la conversión DFM->LFM serán obvios cómo los anteriores, pues son del mismo tipo para las propiedades Parent/Owner, etc. El ejemplo sería algo así:
+
Hay que ser consistente con la jerarquía de los controles. Y si se está familiarizado con  los DFM' s, los cambios necesarios para la conversión DFM->LFM serán obvios cómo los anteriores, pues son del mismo tipo para las propiedades P''arent/Owner'', etc. El ejemplo sería algo así:
  
 
{| class="code"
 
{| class="code"
 
|-  
 
|-  
| class="header" | '''Delphi DFM''' <div style="font-weight: normal">'''(extraneous values removed)'''
+
| class="header" | '''Delphi DFM''' <div style="font-weight: normal">'''(valores ajenos elliminados)'''
| class="header" | '''Lazarus LFM''' <div style="font-weight: normal">'''(most width, height, etc. removed)'''
+
| class="header" | '''Lazarus LFM''' <div style="font-weight: normal">'''(algunos ''width'', ''height'', etc. eliminados)'''
 
|- class="code"
 
|- class="code"
 
| class="code" |
 
| class="code" |
<delphi> object VerticalSplitter: TSplitter
+
<syntaxhighlight lang=pascal> object RepartidorVertical: TSplitter
  Height = 3
+
  Height = 3
  Cursor = crVSplit
+
  Cursor = crVSplit
  Align = alBottom
+
  Align = alBottom
end
+
end
object HorizontalSplitter: TSplitter
+
object RepartidorHorizontal: TSplitter
  Width = 3
+
  Width = 3
  Align = alLeft
+
  Align = alLeft
end
+
end
object BottomPanel: TPanel
+
object Panel_Inferior: TPanel
  Height = 75
+
  Height = 75
  Align = alBottom
+
  Align = alBottom
end
+
end
object LeftPanel: TPanel
+
object Panel_Izquierdo: TPanel
  Width = 125
+
  Width = 125
  Align = alLeft
+
  Align = alLeft
end
+
end
object MainPanel: TPanel
+
object Panel_Principal: TPanel
  Align = alClient
+
  Align = alClient
end  </delphi>
+
end  </syntaxhighlight>
 
| class="code" |
 
| class="code" |
<delphi> object VerticalSplitter: TPairSplitter
+
<syntaxhighlight lang=pascal>
  Align = alClient
+
  object RepartidorVertical: TPairSplitter
  SplitterType = pstVertical
+
    Height = 154
  Position = 225
+
    Width = 362
  Height = 300
+
    Position = 45
  Width = 400
+
    SplitterType = pstVertical
  object Pairsplitterside1: TPairSplitterIde
+
    object Panel_Superior: TPairSplitterSide
     object HorizontalSplitter: TPairSplitter
+
      Height = 45
       Align = alClient
+
      Width = 362
       Position = 125
+
    end
       object Pairsplitterside3: TPairSplitterIde
+
     object Panel_Inferior: TPairSplitterSide
         Width = 125
+
      Height = 103
         object LeftPanel: TPanel
+
      Width = 362
           Align = alClient
+
       ClientWidth = 362
           Width = 125
+
       ClientHeight = 103
 +
       object PairSplitter1: TPairSplitter
 +
        Height = 103
 +
         Width = 362
 +
        Align = alClient
 +
        Position = 45
 +
         object Panel_Izquierdo: TPairSplitterSide
 +
           Height = 103
 +
           Width = 45
 
         end
 
         end
      end
+
        object Panel_Derecho: TPairSplitterSide
      object Pairsplitterside4: TPairSplitterIde
+
          Height = 103
        object MainPanel: TPanel
+
           Width = 311
           Align = alClient
 
 
         end
 
         end
 
       end
 
       end
 
     end
 
     end
   end
+
   end </syntaxhighlight>
  object Pairsplitterside2: TPairSplitterIde
 
    object BottomPanel: TPanel
 
      Align = alClient
 
      Height = 75
 
    end
 
  end
 
end </delphi>
 
 
|}
 
|}
  
 
=== TCustomTreeView/TTreeView ===
 
=== TCustomTreeView/TTreeView ===
&nbsp;&nbsp;&nbsp;Tanto la VCL como la LCL disponen de un componente TCustomTreeView/TTreeView, utilizados para mostrar listas en forma de árboles estrcuturados con múltiples nodos, selección avanzada y lista de imágenes; y aunque las funcionalidades don comparables, no todas las propiedades son completamente compatibles. Las principales diferencias son estas:
+
&nbsp;&nbsp;&nbsp;Tanto la VCL como la LCL disponen de un componente ''TCustomTreeView/TTreeView'', utilizados para mostrar listas en forma de árboles estructurados con múltiples nodos, selección avanzada y lista de imágenes; y aunque las funcionalidades don comparables, no todas las propiedades son completamente compatibles. Las principales diferencias son estas:
  
'''La lista no está completa, es necesario actualizar para incluir las funciones TCustomTreeView Mark y los métodos protegridos'''
+
'''La lista no está completa, es necesario actualizar para incluir las funciones ''TCustomTreeView Mark ''y los métodos protegridos'''
  
 
#  La LCL provee ''TCustomTreeView.Options'', un conjunto de opciones con cuyos valores podemos cambiar el comportamiento y la apariencia del control. Estas opciones son:
 
#  La LCL provee ''TCustomTreeView.Options'', un conjunto de opciones con cuyos valores podemos cambiar el comportamiento y la apariencia del control. Estas opciones son:
#* tvoAllowMultiselect - habilita el modo de selección múltiple, equivalente a TCustomTreeView.MultiSelect en VCL de D6.
+
#* ''tvoAllowMultiselect''- habilita el modo de selección múltiple, equivalente a ''TCustomTreeView.MultiSelect ''en VCL de D6.
#* tvoAutoExpand - Expandir nodos automáticamente, equivalente a TCustomTreeView.AutoExpand.
+
#* ''tvoAutoExpand'' - Expandir nodos automáticamente, equivalente a ''TCustomTreeView.AutoExpand''.
#* tvoAutoInsertMark - Actualizar la vista de arrastre al mover el ratón.
+
#* ''tvoAutoInsertMark'' - Actualizar la vista de arrastre al mover el ratón.
#* tvoAutoItemHeight - Ajustar la altura de los elementos automáticamente.
+
#* ''tvoAutoItemHeight'' - Ajustar la altura de los elementos automáticamente.
#* tvoHideSelection - No marcar el elemento seleccionado.
+
#* tvoHideSelection'' - No marcar el elemento seleccionado.
#* tvoHotTrack - usar ''Hot Tracking'', equivalente a TCustomTreeview.HotTrack
+
#* "tvoHotTrack'' - usar ''Hot Tracking'', equivalente a ''TCustomTreeview.HotTrack''
#* tvoKeepCollapsedNodes - Mantener los nodos hijos al cerrar o abrir.
+
#* "tvoKeepCollapsedNodes'' - Mantener los nodos hijos al cerrar o abrir.
#* tvoReadOnly - Poner el componente en modo sólo lectura, equivalente a TCustomTreeview.ReadOnly
+
#* "tvoReadOnly'' - Poner el componente en modo sólo lectura, equivalente a ''TCustomTreeview.ReadOnly''
#* tvoRightClickSelect - habilitar la selección de nodos con el botón derecho del ratón, equivalente a TCustomTreeView.RightClickSelect.
+
#* "tvoRightClickSelect'' - habilitar la selección de nodos con el botón derecho del ratón, equivalente a ''TCustomTreeView.RightClickSelect''.
#* tvoRowSelect - habilitar la selección de columnas, equivalente a TCustomTreeView.RowSelect.
+
#* "tvoRowSelect '' - habilitar la selección de columnas, equivalente a ''TCustomTreeView.RowSelect.''
#* tvoShowButtons - mostrar botones, equivalente a TCustomTreeView.ShowButtons.
+
#* "tvoShowButtons '' - mostrar botones, equivalente a ''TCustomTreeView.ShowButtons''.
#* tvoShowLines - mostrar líneas de nodos, equivalente a TCustomTreeView.ShowLines.
+
#* "tvoShowLines'' - mostrar líneas de nodos, equivalente a ''TCustomTreeView.ShowLines''.
#* tvoShowRoot - mostrar nodo raíz, equivalente a TCustomTreeView.ShowRoot.
+
#* "tvoShowRoot '' - mostrar nodo raíz, equivalente a ''TCustomTreeView.ShowRoot''.
#* tvoShowSeparators - mostrar separadores.
+
#* "tvoShowSeparators '' - mostrar separadores.
#* tvoToolTips - mostrar ayudas para nodos individuales.
+
#* "tvoToolTips'' - mostrar ayudas para nodos individuales.
 
# La LCL provee propiedades adicionales:
 
# La LCL provee propiedades adicionales:
#* Evento TCustomTreeView.OnSelectionChange.
+
#* Evento ''TCustomTreeView.OnSelectionChange''.
#* TCustomTreeView.DefaultItems, para el número de elementos predeterminados.
+
#* "tCustomTreeView.DefaultItems'', para el número de elementos predeterminados.
#* TCustomTreeView.ExpandSignType para elegir el signo utilizado para indicar los nodos expandibles o contraibles.
+
#* "tCustomTreeView.ExpandSignType'' para elegir el signo utilizado para indicar los nodos expandibles o contraibles.
# La mayor parte de los eventos de Arrastrar y soltar (Drag/Dock) están disponibles en la LCL, aunque no funcionan.PAra más información ver la sección precedente sobre [[#Arrastre y colocación de controles|Arrastre y colocación de controles]].
+
# La mayor parte de los eventos de Arrastrar y soltar (''Drag/Dock'') están disponibles en la LCL, aunque no funcionan. Para más información ver la sección precedente sobre [[#Arrastre y colocación de controles|Arrastre y colocación de controles]].
  
 
=== Mensajes y Eventos ===
 
=== Mensajes y Eventos ===
  
&nbsp;&nbsp;&nbsp;El orden y la frecuencia de los mensajes y eventos (OnShow, OnActivate, OnEnter, ...) de la LCL son diferentes de los de la VCL y dependen de la interfaz utilizada.
+
&nbsp;&nbsp;&nbsp;El orden y la frecuencia de los mensajes y eventos (''OnShow'', ''OnActivate'', ''OnEnter'', ...) de la LCL son diferentes de los de la VCL y dependen de la interfaz utilizada.
  
&nbsp;&nbsp;&nbsp;La LCL dispone de un subconjunto de mensajes similares a los de winAPI para hacer la migración desde Delphi sencilla, pero muchos mensajes de la LCL operan de forma diferente a sus pares de la VCL/winAPI. La mayor parte del código de Delphi utiliza mensajes winAPI,porque el VCL carece de esa característica o por razones de velocidad. Este tipo de código ráramente funcionará igual tcon la LCL, así que debe ser comprobado manualmente. Esto es así, ya que los mensajes de LCL se llaman por ejemplo LM_SIZE en vez de WM_SIZE (unidad lmessages).
+
&nbsp;&nbsp;&nbsp;La LCL dispone de un subconjunto de mensajes similares a los de winAPI para hacer la migración desde Delphi sencilla, pero muchos mensajes de la LCL operan de forma diferente a sus pares de la VCL/winAPI. La mayor parte del código de Delphi utiliza mensajes winAPI,porque el VCL carece de esa característica o por razones de velocidad. Este tipo de código ráramente funcionará igual con la LCL, así que debe ser comprobado manualmente. Esto es así, ya que los mensajes de LCL se llaman por ejemplo ''LM_SIZE'' en vez de ''WM_SIZE'' (unidad lmessages).
  
 
== Colaboradores originales y cambios ==
 
== Colaboradores originales y cambios ==
Line 494: Line 500:
  
 
==Ver también==
 
==Ver también==
[[Code Conversion Guide| Guía de conversión de código (desde Delphi y Kylix)]]
+
[[Code Conversion Guide/es| Guía de conversión de código (desde Delphi y Kylix)]]
  
 
[[Compile With Delphi|Compilar con Delphi]]
 
[[Compile With Delphi|Compilar con Delphi]]

Latest revision as of 23:52, 18 February 2020

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) 한국어 (ko) português (pt) русский (ru) slovenčina (sk)

Este escrito está dirigido a usuarios interesados en Lazarus que conocen Delphi, ya que describe las diferencias entre ambos.

Delphi -> Lazarus

   Lazarus es una herramienta de desarrollo rápido de aplicaciones, al igual que Delphi. Esto significa que dispone de una biblioteca de componentes visuales y de un entorno de desarrollo integrado (IDE). La librería de componentes de Lazarus (LCL) es muy similar a la VCL de Delphi. Muchas unidades, clases y propiedades tienen el mismo nombre e idéntica funcionalidad. Esto hace que el paso de uno o otro sea fácil. Pero Lazarus no es un clon Delphi de fuentes libres. No esperes por tanto una compatibilidad total.

La mayor diferencia

   Lazarus es completamente libre, está escrito para ser independiente de la plataforma y utiliza el potente compilador Free Pascal (FPC). FPC está disponible para más de 15 plataformas. No obstante lo anterior, no todas las librerías y paquetes están disponibles en todas ellas, Lazarus a día de hoy funciona en Linux (i386, x86_64), FreeBSD (i386), MacOSX (powerpc, i386) y Windows (i386, x86_64).

   Lazarus no está terminado del todo, y del mismo modo, tampoco este texto. Se buscan nuevos programadores, escritores de paquetes, traductores, escritores de documentación, ...

Lo primero que hay que hacer al convertir un proyecto de Delphi

   Teniendo Lazarus en ejecución, tienes que ir a Herramientas y después a Convertir proyecto Delphi a proyecto Lazarus. Esto no lo hace todo, pero te facilitará la conversión. Tenga en cuenta que las herramientas disponibles en el IDE son unidireccionales. Si se necesita conservar la compatibilidad, para poder compilar indistintamente en Delphi y en Lazarus, considera convertir tus archivos utilizando XDev Toolkit.

Soporte para Unicode

   Delphi, incluida la versión 2007, no da soporte para Unicode, utilizando la codificación ANSI de Windows. Delphi da soporte a Unicode utilizando codificación de cadenas en UTF-16 a partir de la versión 2009.

   Por su lado Lazarus ha comenzado a dar soporte a Unicode con anterioridad y utiliza codificación de cadenas UTF-8. Para más información ver Soporte LCL para Unicode.

Delphi IDE -> Lazarus IDE

Proyectos

   El archivo de extensión .dpr es el principal de una aplicación Delphi. El archivo principal de un proyecto Lazarus es el de extensión .lpi (Información de proyecto Lazarus). El archivo .dpr es también el archivo principal de código y en el mismo el IDE almacena información sobre las opciones de compilación y las unidades que utiliza el proyecto. Una aplicación Lazarus también tiene un archivo .lpr, que es el archivo principal de código. El resto de la información se almacena en el .lpi. Por lo tanto el .lpi es el archivo más importante del proyecto.

   Por ejemplo:

   Delphi guarda las rutas a las unidades en el archivo .dpr. Como esta, unidad1 in 'ruta/Unidad1.pas'. El in es específico de Delphi y no es entendido por Lazarus. No lo utilices, en su lugar usa las opciones de unidades y rutas de configuración del compilador.

   Delphi guarda las opciones del compilador, como {$APPTYPE CONSOLE}, en el archivo .dpr, que son ignoradas por Lazarus. No lo utilices, en su lugar usa las opciones del compilador.

Una cuestión importante: Siempre hay un proyecto.

   La única forma de "cerrar" un proyecto es cerrando Lazarus o abriendo otro proyecto. Esto es así, porque un proyecto Lazarus es así mismo una "sesión". Esto significa que la configuración actual del IDE se guarda en el archivo .lpi y es restaurada al reabrir el proyecto. Por ejemplo: estás depurando una aplicación, pones una serie de puntos de parada y marcas. Puedes guardar el proyecto, cerrar Lazarus o abrir otro proyecto. Cuándo reabras el proyecto, incluso en otra máquina, todos los puntos de parada, marcadores, archivos abiertos en el editor, posición de los cursores, historia de saltos, y demás, serán restaurados.

Editor de Código

   Casi todas las funciones asignadas a teclas y los accesos directos se puede definir en Entorno -> Opciones del editor -> Accesos rápidos.

   El IDE de Lazarus tiene una gran cantidad de herramientas para trabajar con el código fuente. Muchas son parecidas y trabajan de forma similar a las de Delphi. Pero hay una diferencia importante, Lazarus no utiliza el compilador para obtener información del código, analiza el código fuente directamente. Esto tiene un montón de ventajas importantes:

   El editor trabaja con "comentarios". Para Delphi los comentarios son simplemente espacios entre el código. Ninguna característica del código trabaja aquí y si se inserta automáticamente nuevo código, los comentarios se desplazan. Con Lazarus se puede encontrar una declaración de código incluso dentro de los comentarios. Aunque esto no es completamente fiable, normalmente funciona. Cuando se inserta nuevo código el IDE utiliza heurística para mantener los comentarios y el código juntos. Por ejemplo, no separará la línea:

 letra: char; // comentario

   La función de Completar código de Delphi (Ctrl+Space) se denomina Completar identificador (Identifier Completion) en Lazarus. El término Lazarus Completar código (Code Completion) es una funcionalidad que combina Completar Clase automáticamente (Automatic Class Completion igual que en Delphi), Completar variable local (Local Variable Completion) y Completar asignación de evento (Event Assignment Completion. Todas ellas se activan mediante Ctrl+Shift+C y el IDE determina cuál ejecutaraá en función del código presente en la posición del cursor.

Ejemplo de Completar variable local

   Supongamos que acabas de crear un nuevo método y escribes la sentencia "i:=3;"

  procedure TForm1.HacerAlgo;
  begin
   i := 3;
  end;

   Coloca el cursor justo de delante del identificador "i" y presiona Ctrl+Shift+C para obtener la declaración de la variable:

  procedure TForm1.HacerAlgo;
  var i: Integer;
  begin
   i := 3;
  end;

Ejemplo Completar asignación de evento

   Una buena característica del inspector de objetos es crear métodos automáticamente. Se puede hacer lo mismo en el editor de código.
   Por ejemplo:

 btnCancelar.OnClick:=

   Sitúa el cursor tras el operador de asignación ":=" y presiona Ctrl+Shift+C, y se generará el esqueleto de la función de respuesta al evento.

//...
  btnCancelar.OnClick:=@btnCancelarClick;
//...

 procedure Form1.btnCancelarClick(Sender : TObject);
  begin

  end;

Ejemplo de Completar llamada a Procedimiento

   Supongamos que acabamos de escribir la sentencia "HacerAlgo(Ancho);" en este código

 procedure UnProcedimiento;
  var
   Ancho: integer;
  begin
   Ancho:=3;
   HacerAlgo(Ancho);
  end;

   Sitúa el cursor sobre el identificador "HacerAlgo" y presiona las teclas Ctrl+Shift+C para obtener:

 procedure HacerAlgo(aAncho: LongInt);
  begin

  end;

//...

 procedure UnProcedimiento;
  var
   Ancho: integer;
  begin
   Ancho:=3;
   HacerAlgo(Ancho);
  end;

   Nota del traductor: lo descrito más arriba no funciona (da un error: Ya fue definido el identificador UnProcedimiento); sin embargo si el cursor está dentro del código de "UnProcedimiento", cómo en el ejemplo:

 type
    UnaClase = Class(TObject)
    end;
//...
 procedure UnaClase.UnProcedimiento;
  begin
  //...
  end;

   Al pulsar Ctrl+Shift+C obtendremos la definición de UnProcedimiento como miembro de la clase "UnaClase".

 type
    UnaClase = Class(TObject)
     private
      procedure  UnProcedimiento;
     end;
//...
 procedure UnaClase.UnProcedimiento;

"Completar palabras" Ctrl+W

   Trabaja de forma parecida a Completar identificador, sólo que no trabaja con identificadores pascal, sino con cualquier palabra. Busca en los ficheros abiertos todas las palabras que comienzan con las letras precedentes.

Borrar hasta el final de la línea: Ctrl+T

Borrar la línea completa: Ctrl+Y

Acceder a las plantillas de código: Ctrl+J

Permite archivos de inclusión (include)

    Mediante la directiva {$i acrchivo.inc}. Delphi también permite usarlos (comprobado en D3 y D7, en D/ además se utiliza), aunque que probablemente no has creado muchos archivos de inclusión. Estos archivos tienen una gran ventaja: permiten escribir código (in)dependiente de la plataforma sin llenar el código de directivas IFDEF. Por ejemplo: Saltar al procedimiento (procedure jump), Completar clase, buscar declaración, ... funcionan con los archivos de inclusión.

   Hay otras muchas opciones para trabajar con el código.

Diseñador

  • Directrices

Inspector de Objetos

   En Delphi y Lazarus el Inspector de Objetos se utiliza para editar las propiedades de los componentes y la asignación de los eventos. Estas son lagunas de las pequeñas diferencias que hay entre ambos:

  1. Con Delphi 5 apareció una vista jerarquizada en árbol de los componentes (Object Treeview), que se podía usar para moverse por los objetos y seleccionarlos, además de la tradicional lista desplegable del Inspector. En Lazarus esta vista de árbol está integrada en el Inspector y se utiliza en sustitución de la lista desplegable. Se puede activar o desactivar su utilización mediante la opción Mostrar Árbol de componentes del menú contextual del Inspector .
  2. En Delphi haciendo doble clic en un evento vacío se crea este y se abre el Editor con el cursos en el mismo, en Lazarus, además de lo anterior, existe un botón al lado de la lista desplegable que hace lo mismo.
  3. En Delphi se puede borrar manualmente el nombre de un evento para deshacer el enlace, en Lazarus, además podemos seleccionar (none) en la lista desplegable.
  4. De forma similar, con doble clic en propiedades corrientes, cómo un lógico cambia su valor, además podemos seleccionarlo con la lista desplegable. Si la propiedad requiere de editor especializado, aparecerá este, al igual que si usamos el botón con los puntos suspensivos.

Paquetes

   ¿Se pueden instalar y usar paquetes Delphi en Lazarus?

   No de forma directa, porque necesitan la magia del compilador de Delphi.

   ¿Necesitamos entonces paquetes específicos para Lazarus ?

   Sí, para ello:

   Crea un nuevo paquete, guárdalo en el direcorio donde residen los archivos fuente (normalmente el mismo directorio del archivo .dpk), añade la LCL cómo paquete necesario y finalmente los archivos .pas. Ya puedes instalarlo o utilizarlo en tus proyectos. Hay algunas diferencias entre los paquetes de Lazarus y Delphi, leete el archivo docs/Packages.txt que se encuentra en el directorio de fuentes de Lazarus.

   Ver tambien la Guía de conversión de código entre Delphi y Lazarus

VCL -> LCL

   Aunque laVCL y la LCL sirven en gran parte para el mismo propósito, una jerarquía de componentes orientada a objetos enfocada especialmente hacia el desarrollo rápido de aplicaciones, no son idénticas. Por ejemplo mientras que la VCL proporciona muchos componentes no visuales, el LCL procura proveer solamente componentes visuales, mientras que la mayoría de los componentes no visuales (tales como el acceso a BD) son proporcionados por la FCL, incluida con Free Pascal.

   Así mismo la LCL no tiene de algunos controles disponibles en la VCL o al contrario, o cuándo tiene el mismo control estos no son idénticos, y por tanto hay que realizar cambios en aplicaciones, componentes y controles al migrar.

   Lo que sigue es una tentativa de proporcionar descripciones bastante completas de la diferencias principales o de incompatibilidades entre los dos para el usuario de Delphi. Se cubren las diferencias primordialmente con la VCL de D4, aunque ocasionalmente también con las de D5, D6, o D7 ; y con la LCL actual, tal como está en el CVS. No podemos asegurar la coincidencia con la LCL de que cada uno dispone, ni cuál es la versión de Delphi de la que cada uno viene, por lo que si se ven discrepancias se es libre de añadir o modificar lo que sea necesario con el fin de mantener este documento tan comprensible como sea posible para todo el mundo.

TControl.Font/TControl.ParentFont

   En la VCL es muy común y normal utilizar un tipo de letra y propiedades de fuente, como negrita y cursiva para los controles y se espera que este valor sea usado siempre. Más adelante se proporciona la característica de TControl.ParentFont que se asegura de que un control siga siempre la fuente de su padre. Otra vez se asume que estos valores serán seguidos siempre, incluso ignorando los ajustes de en la apariencia de Windows.

   Esto no es siempre cierto en la LCL, ni lo puede ser. La LCL que es por naturaleza múltiplataforma-multiinterfaz prefiere hacer una acercamiento equilibrado, y en su lugar intentará siempre utilizar los ajustes nativos de la apariencia del escritorio y el tema utilizado en los controles. Por ejemplo si usa un interfaz de GTK, y el tema del gtk dispone una fuente específica para los botones, los botones de la LCL procurarán siempre utilizar esta fuente.

   Esto significa que la mayoría de los controles de LCL no tienen el mismo nivel de ajuste del diseño que se espera a menudo en el VCL, solamente los controles personalizados que sean dibujados en el lienzo (canvas) y no creados por la interfaz pueden modificar consistentemente este interfaz asignado, sin importar cual sea el interfaz usado.

Arrastre y colocación de controles

   En la VCL muchos (win)controles tienen métodos y funciones de retrollamada para habilitar el arrastre y colocación de los mismos, v.g. arrastrar un control desde un panel y colocarlo en otro panel en tiempo de ejecución.

   Esta funcionalidad no está implementada y está inacabada normalmente en la LCL,aunque está actualmente en las etapas iniciales de estudio, y debe aportar un cierto nivel de compatibilidad para este tipo de comportamiento, aunque no exactamente de la misma manera.

   Esto significa actualmente que ningún control hereda/utiliza las funciones, procedimientos, propiedades o eventos de TControl siguientes:

 Protected
    function GetDockEdge(MousePos: TPoint): TAlign;
    function GetDragImages: TDragImageList;
    function GetFloating: Boolean;
    function GetFloatingDockSiteClass: TWinControlClass;
    procedure DoEndDrag(Target:TObject); X, Y: Integer);
    procedure DockTrackNoTarget(Source: TDragDockObject; X, Y: Integer);
    procedure DoEndDock(Target: TObject; X, Y: Integer);
    procedure DoDock(NewDockSite: TWinControl; var ARect: TRect);
    procedure DoStartDock(var DragObject: TDragObject);
    procedure DragCanceled;
    procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState;
                    var Accept: Boolean);
    procedure DoEndDrag(Target: TObject; X, Y: Integer);
    procedure DoStartDrag(var DragObject: TDragObject);
    procedure DrawDragDockImage(DragDockObject: TDragDockObject);
    procedure EraseDragDockImage(DragDockObject: TDragDockObject);
    procedure PositionDockRect(DragDockObject: TDragDockObject);
    procedure SetDragMode(Value: TDragMode);
    property DragKind: TDragKind;
    property DragCursor: TCursor;
    property DragMode: TDragMode;
    property OnDragDrop: TDragDropEvent;
    property OnDragOver: TDragOverEvent;
    property OnEndDock: TEndDragEvent;
    property OnEndDrag: TEndDragEvent;
    property OnStartDock: TStartDockEvent;
    property OnStartDrag: TStartDragEvent;
 public
    function Dragging: Boolean;
    function ManualDock(NewDockSite: TWinControl; DropControl: TControl;
                     ControlSide: TAlign): Boolean;
    function ManualFloat(ScreenPos: TRect): Boolean;
    function ReplaceDockedControl(Control: TControl; NewDockSite: TWinControl;
                      DropControl: TControl; ControlSide: TAlign): Boolean;
    procedure BeginDrag(Immediate: Boolean; Threshold: Integer);
    procedure Dock(NewDockSite: TWinControl; ARect: TRect);
    procedure DragDrop(Source: TObject; X, Y: Integer);
    procedure EndDrag(Drop: Boolean);
    property DockOrientation: TDockOrientation;
    property Floating: Boolean;
    property FloatingDockSiteClass: TWinControlClass;
    property HostDockSite: TWinControl;
    property LRDockWidth: Integer;
    property TBDockHeight: Integer;
    property UndockHeight: Integer;
    property UndockWidth: Integer;

   que las clases siguientes no existen/o no son utilizables

 TDragImageList = class(TCustomImageList)
 TDockZone = class
 TDockTree = class(TInterfacedObject, IDockManager)
 TDragObject = class(TObject)
 TBaseDragControlObject = class(TDragObject)
 TDragControlObject = class(TBaseDragControlObject)
 TDragDockObject = class(TBaseDragControlObject)

   y que las siguientes funciones no son utilizables o son incompablibles

 function FindDragTarget(const Pos: TPoint;
                         AllowDisabled: Boolean) : TControl;
 procedure CancelDrag;
 function IsDragObject(sender: TObject): Boolean;

   El inicio del controlador de ajuste se describe aquí: Anchor Docking

TEdit/TCustomEdit

   Los controles Edit, funcionan esencialmente de la misma forma en la LCL y en la VCL, aunque tienen algunas cuestiones de las que ser conscientes a la hora de convertir.

  1. Debido a restricciones en los interfaces, TEdit.PasswordChar no trabaja en todos los interfaces (con el tiempo puede que sí), en su lugar se puede utilizar emPassword de TCustomEdit.EchoMode para el texto que necesite ser ocultado.
  2. Los eventos Drag/Dock no están implementados. Para más información ver la sección Arrastre y colocación de controles.
  3. Las propiedades de Font son normalmente ignoradas para consistencia del interfaz, para una explicación detallada ver la sección TControl.Font/TControl.ParentFont

(optional) TSplitter -> TPairSplitter

Mejórame, por favor

   Ya existe un control TSplitter en la LCL, por lo que no es necesaria la conversión. Sin embargo, si usted quiere hacerlo, aquí se explica cómo:

   Lo que sigue se basa libremente en preguntas de Vincent Snijders en la lista de correo, y en las respuestas de Andrew Johnson:

   En la VCL el control "repartidor", que es como un tirador que se coloca entre dos componentes para distribuir el espacio entre ambos, está representado por TSplitter. Esto se ve a menudo, por ejemplo en el IDE de Delphi entre el explorador del código y el visor de código fuente.

   La LCL proporciona su propio control llamado TPairSplitter, que sirve para el mismo propósito, no obstante no es compatible, será necesario "reparar" el código de los DFM de Delphi convertidos, aunque gran parte es compartido entre los dos.

   ¿Cuales son exactamente las diferencias?

   La mayor diferencia es que el TSplitter de la VCL no tiene hijos, en vez de ello se coloca entre los dos controles alineados apropiadamente y modifica sus dimensiones en tiempo de ejecución. Es necesario tener dos controles alineados para cualquier cosa. Un ejemplo sencillo es un formulario con un Panel alineado a la izquierda (Aling := alLeft), un Splitter alineado a la izquierda y un segundo panel alineado al área cliente (Aling := alClient). Durante la ejecución puede ajustar el espacio entre los dos paneles arrastrando el tirador que provee el control Splitter.

   En la LCL, por su parte, un TPairSplitter es un tipo especial de control con dos paneles, y aunque es útil únicamente si los controles que se reparten el espacio están en ellos, realiza su cometido estando vacios. Siguiendo con el ejemplo anterior, tendríamos un formulario con un TPairSplitter alineado al área cliente (Aling := alClient) y sendos paneles, igualmente alineados al área cliente (Aling := alClient) a los lados.

   La otra diferencia importante es que en la VCL, puesto que el TSplitter es su propio TControl, la posición se guarda relativa a los otros controles al hacer el reparto, así que en cierto momento un panel del cliente crecerá mientras que los otros paneles no, así la posición de la frontera es relativa a la alineación de los controles participantes.

   En la LCL puesto que los paneles laterales están separados el control TPairSplitter tiene su propiedad de posición es absoluta, y al realizar la redistribución no cambia su posición según el contenido, por lo que hay que hacer una retrollamada para asegurar que se mantiene el ratio, en caso de ser importante.

   Por ejemplo, si el lado derecho de una distribución vertical necesita comportase como si estuviera alineado al cliente será necesario añadir al evento OnResize del formulario código cómo este:

 PairSplitter.Position := PairSplitter.Width - PairSplitter.Position;
   ¿Cómo puedo convertir código existente que utiliza TSplitter a TPairSplitter?

   Si el repartidor y los controles se crean dentro de una función (como OnCreate del formulario), la conversión será más difícil, se reorganiza primero el código para crear los controles en el orden adecuado según la nueva jerarquía y para fijar a los padres de los controles hijo a repartir de izquierda/arriba y a la derecha/abajo del PairSplitter. Un ejemplo de los cambios necesarios:

VCL LCL
 var 
  BottomPanel: TPanel;
  VerticalSplitter: TSplitter;
  LeftPanel: TPanel;
  HorizontalSplitter: TSplitter;
  MainPanel: TPanel;

begin
  BottomPanel:= TPanel.Create(Self);
  with (BottomPanel) do
  begin
    Parent:= Self;
    Height:= 75;
    Align:= alBottom;
  end;

  VerticalSplitter:= TSplitter.Create(Self);
  with (VerticalSplitter) do
  begin
    Parent:= Self;
    Align:= alBottom;
  end;

  HorizontalSplitter:= TSplitter.Create(Self);
  with (HorizontalSplitter) do
  begin
    Parent:= Self;
    align:= alLeft;
  end;

  LeftPanel:= TPanel.Create(Self);
  with (LeftPanel) do
  begin
    Parent:= Self;
    Width:= 125;
    Align:= alLeft;
  end;

  MainPanel:= TPanel.Create(Self);
  with (MainPanel) do
  begin
    Parent:= Self;
    Align:= alClient;
    Caption:= 'Hello';
  end;
end;
 var
  BottomPanel: TPanel;
  VerticalSplitter: TPairSplitter;
  LeftPanel: TPanel;
  HorizontalSplitter: TPairSplitter;
  MainPanel: TPanel;

begin
  VerticalSplitter:= TPairSplitter.Create(Self);
  with (VerticalSplitter) do
  begin
    Parent:= Self;
    Align:= alClient;
    Width:= Self.Width;
    Height:= Self.Height;
    SplitterType:= pstVertical;
    Position:= Height - 75;
    Sides[0].Width:= Width;
    Sides[0].Height:= Position;
  end;

  HorizontalSplitter:= TPairSplitter.Create(Self);
  with (HorizontalSplitter) do
  begin
    Parent:= VerticalSplitter.Sides[0];
    Width:= Self.Width;
    Height:= VerticalSplitter.Position;
    align:= alClient;
    SplitterType:= pstHorizontal;
    Position:= 125;
  end;

  LeftPanel:= TPanel.Create(Self);
  with (LeftPanel) do
  begin
    Parent:= HorizontalSplitter.Sides[0];
    Align:= alClient;
  end;

  MainPanel:= TPanel.Create(Self);
  with (MainPanel) do
  begin
    Parent:= HorizontalSplitter.Sides[1];
    Align:= alClient;
    Caption:= 'Hello';
  end;

  BottomPanel:= TPanel.Create(Self);
  with (BottomPanel) do
  begin
    Parent:= VerticalSplitter.Sides[1];
    Align:= alClient;
  end;
end;

Hay que ser consistente con la jerarquía de los controles. Y si se está familiarizado con los DFM' s, los cambios necesarios para la conversión DFM->LFM serán obvios cómo los anteriores, pues son del mismo tipo para las propiedades Parent/Owner, etc. El ejemplo sería algo así:

Delphi DFM
(valores ajenos elliminados)
Lazarus LFM
(algunos width, height, etc. eliminados)
 object RepartidorVertical: TSplitter
   Height = 3
   Cursor = crVSplit
   Align = alBottom
 end
 object RepartidorHorizontal: TSplitter
   Width = 3
   Align = alLeft
 end
 object Panel_Inferior: TPanel
   Height = 75
   Align = alBottom
 end
 object Panel_Izquierdo: TPanel
   Width = 125
   Align = alLeft
 end
 object Panel_Principal: TPanel
   Align = alClient
 end
   object RepartidorVertical: TPairSplitter
    Height = 154
    Width = 362
    Position = 45
    SplitterType = pstVertical
    object Panel_Superior: TPairSplitterSide
      Height = 45
      Width = 362
    end
    object Panel_Inferior: TPairSplitterSide
      Height = 103
      Width = 362
      ClientWidth = 362
      ClientHeight = 103
      object PairSplitter1: TPairSplitter
        Height = 103
        Width = 362
        Align = alClient
        Position = 45
        object Panel_Izquierdo: TPairSplitterSide
          Height = 103
          Width = 45
        end
        object Panel_Derecho: TPairSplitterSide
          Height = 103
          Width = 311
        end
      end
    end
  end

TCustomTreeView/TTreeView

   Tanto la VCL como la LCL disponen de un componente TCustomTreeView/TTreeView, utilizados para mostrar listas en forma de árboles estructurados con múltiples nodos, selección avanzada y lista de imágenes; y aunque las funcionalidades don comparables, no todas las propiedades son completamente compatibles. Las principales diferencias son estas:

La lista no está completa, es necesario actualizar para incluir las funciones TCustomTreeView Mark y los métodos protegridos

  1. La LCL provee TCustomTreeView.Options, un conjunto de opciones con cuyos valores podemos cambiar el comportamiento y la apariencia del control. Estas opciones son:
    • tvoAllowMultiselect- habilita el modo de selección múltiple, equivalente a TCustomTreeView.MultiSelect en VCL de D6.
    • tvoAutoExpand - Expandir nodos automáticamente, equivalente a TCustomTreeView.AutoExpand.
    • tvoAutoInsertMark - Actualizar la vista de arrastre al mover el ratón.
    • tvoAutoItemHeight - Ajustar la altura de los elementos automáticamente.
    • tvoHideSelection - No marcar el elemento seleccionado.
    • "tvoHotTrack - usar Hot Tracking, equivalente a TCustomTreeview.HotTrack
    • "tvoKeepCollapsedNodes - Mantener los nodos hijos al cerrar o abrir.
    • "tvoReadOnly - Poner el componente en modo sólo lectura, equivalente a TCustomTreeview.ReadOnly
    • "tvoRightClickSelect - habilitar la selección de nodos con el botón derecho del ratón, equivalente a TCustomTreeView.RightClickSelect.
    • "tvoRowSelect - habilitar la selección de columnas, equivalente a TCustomTreeView.RowSelect.
    • "tvoShowButtons - mostrar botones, equivalente a TCustomTreeView.ShowButtons.
    • "tvoShowLines - mostrar líneas de nodos, equivalente a TCustomTreeView.ShowLines.
    • "tvoShowRoot - mostrar nodo raíz, equivalente a TCustomTreeView.ShowRoot.
    • "tvoShowSeparators - mostrar separadores.
    • "tvoToolTips - mostrar ayudas para nodos individuales.
  2. La LCL provee propiedades adicionales:
    • Evento TCustomTreeView.OnSelectionChange.
    • "tCustomTreeView.DefaultItems, para el número de elementos predeterminados.
    • "tCustomTreeView.ExpandSignType para elegir el signo utilizado para indicar los nodos expandibles o contraibles.
  3. La mayor parte de los eventos de Arrastrar y soltar (Drag/Dock) están disponibles en la LCL, aunque no funcionan. Para más información ver la sección precedente sobre Arrastre y colocación de controles.

Mensajes y Eventos

   El orden y la frecuencia de los mensajes y eventos (OnShow, OnActivate, OnEnter, ...) de la LCL son diferentes de los de la VCL y dependen de la interfaz utilizada.

   La LCL dispone de un subconjunto de mensajes similares a los de winAPI para hacer la migración desde Delphi sencilla, pero muchos mensajes de la LCL operan de forma diferente a sus pares de la VCL/winAPI. La mayor parte del código de Delphi utiliza mensajes winAPI,porque el VCL carece de esa característica o por razones de velocidad. Este tipo de código ráramente funcionará igual con la LCL, así que debe ser comprobado manualmente. Esto es así, ya que los mensajes de LCL se llaman por ejemplo LM_SIZE en vez de WM_SIZE (unidad lmessages).

Colaboradores originales y cambios

   Esta página a sido convertida desde la versión de la epikwiki.

Ver también

Guía de conversión de código (desde Delphi y Kylix)

Compilar con Delphi