<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="es">
	<id>https://clarionwiki.com.ar/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jorge+Brugger</id>
	<title>ClarionWiki - Contribuciones del usuario [es]</title>
	<link rel="self" type="application/atom+xml" href="https://clarionwiki.com.ar/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jorge+Brugger"/>
	<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php/Especial:Contribuciones/Jorge_Brugger"/>
	<updated>2026-05-23T20:54:05Z</updated>
	<subtitle>Contribuciones del usuario</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=97</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=97"/>
		<updated>2017-11-15T11:31:38Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento gratuitas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
[news://news.softvelocity.com/softvelocity.clarion.intl.spanish Grupo de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Skype Chat Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[https://join.skype.com/w0yUGoFhHyA2 Chat Clarioneros]&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
=== Webinarios Clarioneros en Español ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.net www.clarioneros.net]&lt;br /&gt;
&lt;br /&gt;
=== Clarionhub (en inglés) ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionhub.com www.clarionhub.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Sitio web de soporte de Nettalk de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ ClarionLive (Webinars y tutoriales muy útiles)]&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/download/ Manuales y Howto&#039;s de Clarion Templates (en español)]&lt;br /&gt;
&lt;br /&gt;
[http://www.litreum.com/Categories ClarionFoundry]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://http://templatesclarion.com.ar/downloads/ Templates Clarion - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Guia_de_las_mejores_pr%C3%A1cticas_de_Clarion&amp;diff=96</id>
		<title>Guia de las mejores prácticas de Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Guia_de_las_mejores_pr%C3%A1cticas_de_Clarion&amp;diff=96"/>
		<updated>2017-08-25T11:26:35Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;(Por Cristian Olsen)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tipos de Campos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Acordarse siempre que lo que define el almacenamiento es la opción&lt;br /&gt;
Characters, la opción Picture es solo como se va a mostrar&lt;br /&gt;
&lt;br /&gt;
Clarion	Que se puede almacenar&lt;br /&gt;
*Byte		(de 1 a 99)&lt;br /&gt;
*Short		(de 1 a 9,999)&lt;br /&gt;
*Long		(de 1 a 999,999,999)&lt;br /&gt;
*Decimal	(de 1 a 9,999,999,999,999,999,999,999,999,999,999)&lt;br /&gt;
*String	(de 1 a 4 Mega-Bytes)&lt;br /&gt;
&lt;br /&gt;
Para guardar hasta 99,999.99 se define un campo del tipo Decimal con un character de 7 decimal 2 picture @N9.2&lt;br /&gt;
&lt;br /&gt;
Para campos alfanuméricos grandes se puede usar CSTRING pero en characters hay que poner uno más del que se quiere almacenar&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pictures para Fecha y Hora&#039;&#039;&#039;&lt;br /&gt;
*@D6	DD/MM/YYYY&lt;br /&gt;
*@D17  Fecha corta según formato Windows&lt;br /&gt;
*@D18  Fecha larga según formato Windows&lt;br /&gt;
*@T1	HH:MM&lt;br /&gt;
*@T4	HH:MM:SS&lt;br /&gt;
*@T7	Hora corta según formato de Windows&lt;br /&gt;
*@T8	Hora larga según formato de Windows&lt;br /&gt;
&lt;br /&gt;
Para todos los pictures si se especifica B esto hará que cuando el campo es cero se muestre blanco (@D6B), otros ejemplos comunes son&lt;br /&gt;
&lt;br /&gt;
*@N10	&amp;lt;&amp;lt;,&amp;lt;&amp;lt;&amp;lt;,&amp;lt;&amp;lt;&amp;lt;#		Ejemplo de CUIT &lt;br /&gt;
*@N_10	 &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;#		Decimal 11 Picture @P##-########-#P&lt;br /&gt;
*@N010	 ##########		los guiones nunca son almacenados&lt;br /&gt;
&lt;br /&gt;
Para el ingreso de datos la forma mas sencilla es la siguiente&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
!Campos&lt;br /&gt;
!Entry Mode&lt;br /&gt;
|- &lt;br /&gt;
|Numéricos&lt;br /&gt;
|Insert&lt;br /&gt;
|- &lt;br /&gt;
|Fecha&lt;br /&gt;
|Overwrite&lt;br /&gt;
|- &lt;br /&gt;
|String&lt;br /&gt;
|Overwrite&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Relación tipos de campos entre Clarion y MS-SQL Server&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
!CLARION&lt;br /&gt;
!MS-SQL SERVER&lt;br /&gt;
|- &lt;br /&gt;
|Byte&lt;br /&gt;
|Bit (de 0 a 1)&lt;br /&gt;
|- &lt;br /&gt;
|Byte&lt;br /&gt;
|Tinyint (de 1 a 99)		&lt;br /&gt;
|- &lt;br /&gt;
|Short&lt;br /&gt;
|SmallInt (de 1 a 9,999)&lt;br /&gt;
|- &lt;br /&gt;
|Long&lt;br /&gt;
|Int (de 1 a 999,999,999)&lt;br /&gt;
|- &lt;br /&gt;
|Decimal&lt;br /&gt;
|Decimal (999.99 se define como: (pres 5 esc 2)&lt;br /&gt;
|- &lt;br /&gt;
|String&lt;br /&gt;
|Char&lt;br /&gt;
|- &lt;br /&gt;
|CString&lt;br /&gt;
|VarChar&lt;br /&gt;
|- &lt;br /&gt;
|Date&lt;br /&gt;
|DateTime (Fecha y Hora)&lt;br /&gt;
|- &lt;br /&gt;
|Time&lt;br /&gt;
|DateTime (Fecha y Hora)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Para un buen funcionamiento de las aplicaciones todos los índices deben ser Únicos y los campos se deben definir sin el atributo NULL&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;&#039;Manejo de Tablas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Acceso a un registro&lt;br /&gt;
  CLEAR(TBL:RECORD)&lt;br /&gt;
  TBL:CAMPO = XXXXX&lt;br /&gt;
  IF Access:TABLA.Fetch(TBL:CLAVE) = LEVEL:BENIGN&lt;br /&gt;
     !El registro existe&lt;br /&gt;
  ELSE&lt;br /&gt;
     !El registro no existe&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
Insertar un registro&lt;br /&gt;
  CLEAR(TBL:RECORD)&lt;br /&gt;
  TBL:CAMPO = XXXXX&lt;br /&gt;
  IF Access:TABLA.Insert() &amp;lt;&amp;gt; LEVEL:BENIGN&lt;br /&gt;
     ! Error al crear el registro&lt;br /&gt;
&lt;br /&gt;
Cambiar un registro&lt;br /&gt;
  CLEAR(TBL:RECORD)&lt;br /&gt;
  TBL:CAMPO = XXXXX&lt;br /&gt;
  IF Access:TABLA.Fetch(TBL:CLAVE) = LEVEL:BENIGN&lt;br /&gt;
     TBL:CAMPO = XXXXX&lt;br /&gt;
     IF Access:TABLA.Update() &amp;lt;&amp;gt; LEVEL:BENIGN&lt;br /&gt;
        !Error al actualizar el registro&lt;br /&gt;
     END&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
Borrar un registro&lt;br /&gt;
  CLEAR(TBL:RECORD)&lt;br /&gt;
  TBL:CAMPO = XXXXX&lt;br /&gt;
  IF Access:TABLA.Fetch(TBL:CLAVE) = LEVEL:BENIGN&lt;br /&gt;
     Access:TABLA.DeleteRecord() !Alternativa 1&lt;br /&gt;
     Relate:TABLA.Delete(0) !Alternativa 2&lt;br /&gt;
     Delete(TABLA) !Alternativa 3&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
Lectura secuencial&lt;br /&gt;
  CLEAR(TBL:RECORD)&lt;br /&gt;
  TBL:CAMPO = XXXXX&lt;br /&gt;
  SET(TBL:CLAVE,TBL:CLAVE)&lt;br /&gt;
  LOOP Until Access:TABLA.Next() OR TBL:CAMPO &amp;lt;&amp;gt; XXXXX&lt;br /&gt;
     !!!!&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Igualar los registros de dos tablas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   TB1:RECORD :=: TB2:RECORD  :=: es una igualación en profundidad&lt;br /&gt;
   Esta instrucción iguala solo los campos que se llamen igual en ambas tablas independientemente de la posición de cada uno de ellos&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Antes de abrir la ventana como saber si en el Form estoy en modo ADD-CHANGE-DELETE-VIEW&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Window Manager - Init - Open the window (PR-8000)&lt;br /&gt;
&lt;br /&gt;
  IF SELF.Request = InsertRecord&lt;br /&gt;
  IF SELF.Request = ChangeRecord&lt;br /&gt;
  IF SELF.Request = ViewRecord&lt;br /&gt;
  IF SELF.Request = DeleteRecord&lt;br /&gt;
  La última instrucción solo es valida siempre que el Form muestre el registro a borrar &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Agregar código antes que el Form realice el ADD-CHANGE-DELETE&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Window Manager - TakeCompleted (PR-5000)&lt;br /&gt;
&lt;br /&gt;
  IF SELF.Request = InsertRecord&lt;br /&gt;
  IF SELF.Request = ChangeRecord&lt;br /&gt;
  IF SELF.Request = DeleteRecord &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Agregar código después que el Form realizo el ADD-CHANGE-DELETE exitosamente&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Window Manager - TakeCompleted (PR-5001)&lt;br /&gt;
&lt;br /&gt;
  IF ReturnValue = Level:Benign&lt;br /&gt;
     IF SELF.Request = InsertRecord&lt;br /&gt;
     IF SELF.Request = ChangeRecord&lt;br /&gt;
     IF SELF.Request = DeleteRecord &lt;br /&gt;
  La última instrucción solo es valida siempre que el Form muestre el registro a borrar&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como salir un procedimiento antes de abrir la window&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  RETURN Level:Fatal&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Donde colocar código para hacer una validación en un campo en un procedimiento del tipo Form&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Control Events – Accepted – Generated Code (PR-7000)&lt;br /&gt;
&lt;br /&gt;
  IF Condicion&lt;br /&gt;
     BEEP	&lt;br /&gt;
     MESSAGE(&#039;Texto del Error&#039;,&#039;Texto de la Ventana’,&amp;amp;|&lt;br /&gt;
           ICON:Exclamation,BUTTON:Cancel,BUTTON:Cancel,1)&lt;br /&gt;
     SELECT(?)&lt;br /&gt;
     CYCLE&lt;br /&gt;
  END   &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Si quiero tomar control de los botones del cuadro de mensajes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  CASE MESSAGE(&#039;Texto del mensaje’,’Texto de la Ventana’,&amp;amp;|&lt;br /&gt;
              ICON:Question,BUTTON:Yes+BUTTON:No,BUTTON:No,1)&lt;br /&gt;
     OF BUTTON:No&lt;br /&gt;
        SELECT(?)&lt;br /&gt;
        CYCLE&lt;br /&gt;
     OF BUTTON:Yes&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como forzar la validación de un campo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Control Events – Selected – Generated Code (PR-4000)&lt;br /&gt;
&lt;br /&gt;
  ?CAMPO{PROP:Touched} = TRUE&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como saber en la validación de un campo si se esta pasando cuando se presiono el botón OK&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  IF NOT ThisWindow{PROP:AcceptAll} o &lt;br /&gt;
  IF NOT (Nombre de Ventana){PROP:AcceptAll}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como saber si luego de que un control del tipo Field LookUp que accedió a un browse para validar se le dio Select&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  IF GlobalResponse = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como colocar código en un Browse para cada registro leído&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Local Objects – Browse on Tabla – SetQueueRecord (PR-2500)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como filtrar un Browse antes de mostrarlo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Se puede hacer por record filter &lt;br /&gt;
Si es mas complejo se puede hacer en &lt;br /&gt;
&lt;br /&gt;
Local Object – Browse on Table – InitSort (PR-10000)&lt;br /&gt;
&lt;br /&gt;
  IF Condicion = 1&lt;br /&gt;
     BRW1.SetFilter(&#039;(TCON:CVP_B &amp;lt;&amp;gt; 0)&#039;)&lt;br /&gt;
     BRW1.ApplyFilter()&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como filtrar un registro en un Browse o Reporte antes que se muestre&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Local Objects – Browse on Tabla – ValidateRecord (PR-4500)&lt;br /&gt;
&lt;br /&gt;
  IF Condition THEN RETURN Record:Filtered;END&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como controlar desde un Browse justo antes de llamar a un Form&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Local Object – Browse on Table – Ask(Byte Request) (PR-4999)&lt;br /&gt;
&lt;br /&gt;
  IF Request = InsertRecord&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como abrir una tabla en modo exclusivo&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Colocar la tabla en OTHER TABLE&lt;br /&gt;
&lt;br /&gt;
Window Manager - Init – Open Files (PR-7501)&lt;br /&gt;
&lt;br /&gt;
  Relate:TABLA.Close&lt;br /&gt;
  Access:TABLA.SetOpenMode(12h);Relate:TABLA.Open&lt;br /&gt;
  Relate:TABLA.Close&lt;br /&gt;
&lt;br /&gt;
O También abrir la tabla en modo exclusivo&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como ordenar una tabla para luego imprimirla en ese orden en un reporte&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
OpenReport – Code (PR-5000)&lt;br /&gt;
&lt;br /&gt;
  ThisReport.SetOrder(&#039;TBL:CAMPO1&#039;,TBL:CAMPO2’,’-TBL:CAMPO3’)&lt;br /&gt;
  ThisReport.ApplyOrder()&lt;br /&gt;
&lt;br /&gt;
CAMPO1 Y 2 en orden ascendente CAMPO3 en orden descendente&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como filtrar una tabla para luego imprimirla sin esos registros en un reporte&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
OpenReport – Code (PR-5000)&lt;br /&gt;
&lt;br /&gt;
  ThisReport.SetFilter(&#039;TBL:CAMPO1 = XXXX’)&lt;br /&gt;
  ThisReport.ApplyFilter()&lt;br /&gt;
&lt;br /&gt;
Tanto para el Order como para el Filter los campos a utilizar si no están pintados en el reporte tienen que estar definidos como HOT FIELDS&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como manejar un Browse con una clave compuesta por más de un campo e ir refrescándolo por cada cambio en esos campos&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Clave de la Tabla&lt;br /&gt;
*Empresa&lt;br /&gt;
*Cliente&lt;br /&gt;
*Fecha&lt;br /&gt;
&lt;br /&gt;
Colocar en Range Limit siempre el último campo de la clave que se quiere limitar, en este caso Cliente&lt;br /&gt;
&lt;br /&gt;
Si se cambia la Empresa colocar&lt;br /&gt;
  TBL:Empresa = GLO:Empresa&lt;br /&gt;
  BRW1.AddRange(TBL:Empresa)&lt;br /&gt;
  BRW1.ApplyRange()&lt;br /&gt;
  ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Si se cambia el Cliente colocar&lt;br /&gt;
  TBL:Cliente = GLO:Cliente&lt;br /&gt;
  BRW1.AddRange(TBL:Cliente)&lt;br /&gt;
  BRW1.ApplyRange()&lt;br /&gt;
  ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como refrescar un Browse&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  SETCURSOR(CURSOR:WAIT)&lt;br /&gt;
  BRW1.ResetFromFile()&lt;br /&gt;
  BRW1.ResetFromBuffer()&lt;br /&gt;
  ThisWindow.Reset(True)&lt;br /&gt;
  SETCURSOR&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como ordenar un Browse antes de abrir la ventana&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Local Objects – Browse on Tabla – InitSort (PR-10000)&lt;br /&gt;
&lt;br /&gt;
  BRW1.SetOrder(&#039;TBL:CAMPO&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como agregar otro ítem al PopUp menú de ABM del browse&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Agregar un botón debajo de los estándar ADD-CHANGE-DELETE con atributo Hide&lt;br /&gt;
&lt;br /&gt;
Window Manager - Init – Prepare Alert Key (PR-9001)&lt;br /&gt;
&lt;br /&gt;
  BRW1.PopUp.AddItemMimic(&#039;Texto&#039;,?Boton)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como borro un boton de update en ABM del browse&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Window Manager - Init – Open the Window (PR-8000)&lt;br /&gt;
&lt;br /&gt;
  BRW4.DeleteControl = 0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Como pararse en un browse de entrada en distintas partes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Window Manager - Init - (PR-9000)&lt;br /&gt;
&lt;br /&gt;
  POST(Event:ScrollUp,?Browse)		! subir un registro&lt;br /&gt;
  POST(Event:ScrollDown,?Browse)	! descer un registro&lt;br /&gt;
  POST(EVENT:ScrollTop,?Browse)		! primer registro&lt;br /&gt;
  POST(EVENT:ScrollBottom,?Browse)	! ultimo registro&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Para apretar un botón desde la lógica&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  POST(EVENT:ACCEPTED,?Boton)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Colas en memoria (Queue)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Para recorrer toda una cola&lt;br /&gt;
&lt;br /&gt;
  LOOP Q# = 1 TO RECORDS(COLA) BY 1;GET(COLA,Q#)&lt;br /&gt;
    !Codigo&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
  GET(COLA,CAMPO)	Busca un registro (El campo a buscar tiene que ser de la cola previamente igualado)&lt;br /&gt;
  ADD(COLA)		Inserta un registro&lt;br /&gt;
  PUT(COLA)		Modifica un registro&lt;br /&gt;
  DELETE(COLA)	Borra un registro&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bloquear una Tabla&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  AUX:TABLA_UseLogOut = Relate:A_STOPRO.UseLogOut&lt;br /&gt;
  Relate:TABLA.UseLogout = FALSE&lt;br /&gt;
  LOOP;LOGOUT(1,TABLA);UNTIL ERRORCODE() = 0&lt;br /&gt;
    !Mi código&lt;br /&gt;
  COMMIT&lt;br /&gt;
  Relate:TABLA.UseLogOut = AUX:TABLA_UseLogOut&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Validación de campos en Browse EIP&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Local Object – EIP Manager for browse using ?Browse:1 – Take Completed (BYTE Force) (PR-4999)&lt;br /&gt;
&lt;br /&gt;
  IF BRW1.Q.TBL:CAMPO &amp;lt;&amp;gt; 1&lt;br /&gt;
     Return&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Poner disable un campo del EIP por una condición&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Local Object – EIP Manager for browse using ?Browse:1 – GetEdit (PR-5001)&lt;br /&gt;
&lt;br /&gt;
  IF SELF.Req = ChangeRecord AND Self.Column = 1 AND TBL:MARCA &amp;lt;&amp;gt; &#039;E&#039;&lt;br /&gt;
     ReturnValue = FALSE&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Agregar código antes que el EIP realice el ADD-CHANGE-DELETE&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Local Object – EIP Manager for browse using ?Browse:1 – TakeCompleted Force (PR-4999)&lt;br /&gt;
&lt;br /&gt;
   IF SELF.Request = InsertRecord&lt;br /&gt;
   IF SELF.Request = ChangeRecord&lt;br /&gt;
   IF SELF.Request = DeleteRecord&lt;br /&gt;
      BRW1.Q.COU:DESCRIPTION = CLIP(UPPER(BRW1.Q.COU:DESCRIPTION))&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Agregar código después que el EIP realice el ADD-CHANGE-DELETE&#039;&#039;&#039;&lt;br /&gt;
Local Object – EIP Manager for browse using ?Browse:1 – TakeCompleted (PR-5001)&lt;br /&gt;
&lt;br /&gt;
IF ReturnValue = Level:Benign&lt;br /&gt;
   IF SELF.Request = InsertRecord&lt;br /&gt;
   IF SELF.Request = ChangeRecord&lt;br /&gt;
   IF SELF.Request = DeleteRecord&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=91</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=91"/>
		<updated>2016-08-09T17:59:35Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Repositorios de archivos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
[news://news.softvelocity.com/softvelocity.clarion.intl.spanish Grupo de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
=== Clarionhub (en inglés) ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionhub.com www.clarionhub.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Sitio web de soporte de Nettalk de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ ClarionLive (Webinars y tutoriales muy útiles)]&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/download/ Manuales y Howto&#039;s de Clarion Templates (en español)]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://http://templatesclarion.com.ar/downloads/ Templates Clarion - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=90</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=90"/>
		<updated>2016-08-09T17:58:13Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento gratuitas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
[news://news.softvelocity.com/softvelocity.clarion.intl.spanish Grupo de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
=== Clarionhub (en inglés) ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionhub.com www.clarionhub.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Sitio web de soporte de Nettalk de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ ClarionLive (Webinars y tutoriales muy útiles)]&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/download/ Manuales y Howto&#039;s de Clarion Templates (en español)]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://http://templatesclarion.com.ar/downloads/ Templates Clarion - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=89</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=89"/>
		<updated>2016-08-09T17:56:23Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento gratuitas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
[news://news.softvelocity.com/softvelocity.clarion.intl.spanish Grupo de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
=== Clarionhub (en inglés) ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionhub.com www.clarionhub.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://faq.clarionmag.com ClarionFAQ en Clarion Magazine]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Sitio web de soporte de Nettalk de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ ClarionLive (Webinars y tutoriales muy útiles)]&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/download/ Manuales y Howto&#039;s de Clarion Templates (en español)]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://http://templatesclarion.com.ar/downloads/ Templates Clarion - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Recomendaciones&amp;diff=84</id>
		<title>Recomendaciones</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Recomendaciones&amp;diff=84"/>
		<updated>2015-03-08T20:06:46Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Video tutoriales acerca de Clarion */ Videos ya no están disponibles&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Recomendaciones y Trucos que nos pueden evitar dolores de cabeza&#039;&#039;&#039;&lt;br /&gt;
= Versión Demo (básica) =&lt;br /&gt;
Poner este embed global en un par de tablas importantes&lt;br /&gt;
 Global Embeds&lt;br /&gt;
    Abc Objects&lt;br /&gt;
        File Managers&lt;br /&gt;
            File Manager for YourFile&lt;br /&gt;
                Insert - Before Parent Call&lt;br /&gt;
 IF RECORDS(SELF.FILE)&amp;gt; 10&lt;br /&gt;
  MESSAGE(&#039;Demo Version&#039;)&lt;br /&gt;
  RETURN LEVEL:FATAL&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Obtener un total general (al final) en un Reporte =&lt;br /&gt;
 Lo mas facil es armar un break group sobre una variable que no cambie nunca,&lt;br /&gt;
 (puede ser cualquier variable global, por ejemplo)&lt;br /&gt;
 Luego pones los totales en un group footer de este break y listo.&lt;br /&gt;
 Como la variable nunca cambia (puede ser una global por ejemplo) solo se&lt;br /&gt;
 imprime el group footer al final del reporte.&lt;br /&gt;
 Tambien podria usarse el Group Header de ese break como &amp;quot;caratula&amp;quot; del reporte&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Usar DLLs no creadas en Clarion =&lt;br /&gt;
Para Usar DLLs no creadas en Clarion, hay que seguir los siguientes pasos:&lt;br /&gt;
 - Crear los prototipos equivalentes en Clarion&lt;br /&gt;
 para esto hay que averiguar cuales son los prototipos originales (en c, por ej.)&lt;br /&gt;
 y ver la equivalencia de tipos entre Clarion, C y  o C++&lt;br /&gt;
 - Usar el Libmaker para la creacion de una Clarion Library (.LIB File) para la DLL&lt;br /&gt;
 - Incluir el .LIB File al proyecto&lt;br /&gt;
&lt;br /&gt;
Para mas detalles, ver .\docs\FAQsTips&amp;amp;Tricks.pdf el tema &amp;quot;How to Use Windows DLLs NOT Created in Clarion&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Modificar código en múltiples embeds, o varias tablas del DCT =&lt;br /&gt;
Se puede exportar la aplicación o el DCT a Texto (app.TXA) modificar el texto con un buen editor (yo recomiendo el textpad) y luego importar de nuevo.&lt;br /&gt;
&lt;br /&gt;
Obviamente, hacer un backup primero porque esto es una opración &amp;quot;peligrosa&amp;quot;&lt;br /&gt;
&lt;br /&gt;
En la sección de [http://www.templatesclarion/download/ Downloads] el documento de migración de TPS a SQL se basa en esta técnica para modificar el DCT.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Deshabilitar el PopUp en un control TEXT =&lt;br /&gt;
Simplemente asignar la Key MouseRight al control TEXT&lt;br /&gt;
&lt;br /&gt;
= Desplegar una opción de menú desde un botón =&lt;br /&gt;
Pónle un hotkey al menu, por ejemplo:&lt;br /&gt;
 Menu Text: &amp;amp;Browse&lt;br /&gt;
Luego en el botón&lt;br /&gt;
 PRESSKEY(AltB)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Obtener los diferentes elementos del path =&lt;br /&gt;
Global Embeds - Inside Global Map&lt;br /&gt;
 Include(&#039;clib.clw&#039;)&lt;br /&gt;
&lt;br /&gt;
En el embed:&lt;br /&gt;
 X# = FnSplit(LOC:Path,LOC:Drive,LOC:Dir,LOC:File,LOC:Ext)&lt;br /&gt;
 DISPLAY&lt;br /&gt;
&lt;br /&gt;
Las variables locales son todas CSTRING(256)&lt;br /&gt;
Por ejemplo para saber solo el nombre del archivo se usaria LOC:File &amp;amp; LOC:Ext&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Conversión de Archivos =&lt;br /&gt;
1) Tenés que tener un diccionario aparte, en principio vacio. Yo lo llamo &lt;br /&gt;
conversiones.dct.&lt;br /&gt;
&lt;br /&gt;
2) Abrís ambos DCT. Te parás en la definición que querés convertir y &lt;br /&gt;
apretás &amp;quot;copiar&amp;quot;. Te parás en el conversiones.dct y apretás &amp;quot;pegar&amp;quot;. A &lt;br /&gt;
este archivo pegado lo renombrás con la fecha (por ejemplo, si mi archivo &lt;br /&gt;
a convertir se llama CLIENTES, en conversiones lo pego como CLIENTES_&lt;br /&gt;
050328).&lt;br /&gt;
&lt;br /&gt;
3) Hacés todos los cambios que necesites en la definición de tu archivos &lt;br /&gt;
CLIENTES. Acá ya podés recompilar todo tu sistema.&lt;br /&gt;
&lt;br /&gt;
4) Cerrá tu diccionario, dejá abierto Conversiones.dct. Seleccioná &lt;br /&gt;
&amp;quot;convert&amp;quot; el archivo, te pide el path al archivo y primero te hace un &lt;br /&gt;
&amp;quot;browse&amp;quot; sobre el mismo, de ahí seleccionás el menú &amp;quot;File&amp;quot;, &amp;quot;Convert &lt;br /&gt;
File&amp;quot; y te abre una ventanita.&lt;br /&gt;
&lt;br /&gt;
5) Acá, en target dictionary elegís tu DCT, el que tiene la definición &lt;br /&gt;
ahora modificada (Acordate que estás en el conversiones.dct).&lt;br /&gt;
&lt;br /&gt;
6) En target structure, buscás en tu DCT el nombre del archivo &lt;br /&gt;
convertido.&lt;br /&gt;
&lt;br /&gt;
7) En Generated source, tipeá algo que tenga sentido: yo voy numerando &lt;br /&gt;
mis programas conversores, así que voy poniendo algo como CONV0001, &lt;br /&gt;
CONV0002, etc. Fijate bien el path donde lo metés.&lt;br /&gt;
&lt;br /&gt;
8) Si no salió solo, salí del browser, cerrá todos los DCT.&lt;br /&gt;
&lt;br /&gt;
9) Andá por &amp;quot;File&amp;quot;, &amp;quot;Change directory&amp;quot; y cambiate al directorio donde &lt;br /&gt;
grabaste el fuente del conversor. Yo uso un subdirectorio &amp;quot;pasa&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
10) Andá a &amp;quot;File&amp;quot;, &amp;quot;Open&amp;quot;, elegí &amp;quot;Clarion source&amp;quot;, y abrí el programa &lt;br /&gt;
conversor.&lt;br /&gt;
&lt;br /&gt;
11) Andá a &amp;quot;Project&amp;quot;, &amp;quot;Set&amp;quot; y seleccioná el archivo de proyecto que tiene &lt;br /&gt;
el mismo nombre que el fuente del conversor.&lt;br /&gt;
&lt;br /&gt;
12) Editale lo que quieras al programa conversor. Acá por ejemplo a veces &lt;br /&gt;
cambio el directorio de salida, o ajusto la ventana de display, le pongo &lt;br /&gt;
mensajes o hago cualquier asignación que sea necesaria.&lt;br /&gt;
&lt;br /&gt;
13) Compilá, correlo y listo. Te queda un ejecutable autónomo que podés &lt;br /&gt;
correr en el cliente llamándolo a mano, desde un instalador o desde tu &lt;br /&gt;
propia aplicación.&lt;br /&gt;
&lt;br /&gt;
14) Ventaja adicional: Si tu cliente guarda backups de los archivos, y &lt;br /&gt;
por la circunstancia que sea tiene que reprocesar información de un &lt;br /&gt;
archivo viejo, se pueden correr todos los programas de conversión que &lt;br /&gt;
corresponden a ese archivo, en secuencia, para llevar su formato al &lt;br /&gt;
actual.&lt;br /&gt;
&lt;br /&gt;
15) Otra ventaja: este método sirve para cualquier base ISAM, para SQL &lt;br /&gt;
hay que hacer algunos pasos más pero básicamente se puede hacer lo mismo.&lt;br /&gt;
&lt;br /&gt;
Finalmente, te digo que esto lleva muchísimo más tiempo explicarlo y &lt;br /&gt;
aprenderlo que hacerlo. Cuando te digo que todo esto lleva 1 minuto, es &lt;br /&gt;
en serio, es lo que lleva cuando ya sabés cómo hacerlo de memoria.&lt;br /&gt;
&lt;br /&gt;
Una acotación, con este método te van quedando en el conversiones.dct &lt;br /&gt;
todas las definiciones históricas de tus archivos, algo que puede llegar &lt;br /&gt;
a ser muy últil, mientras que en tu dct de &amp;quot;trabajo&amp;quot; sólo está la &lt;br /&gt;
definición &amp;quot;actual&amp;quot; y no hay nada que haga ruido.&lt;br /&gt;
&lt;br /&gt;
Saludos,&lt;br /&gt;
Jorge A. Lavera&lt;br /&gt;
&lt;br /&gt;
= Encriptación de TPS =&lt;br /&gt;
Sobre el Owner Name y su seguridad o capacidad de encriptación&lt;br /&gt;
depende mas que nada del  planeamiento que a la herramienta en sí&lt;br /&gt;
misma&lt;br /&gt;
&lt;br /&gt;
Caso 1 :  Owner Name : &amp;quot; Tu palabra clave &amp;quot;&lt;br /&gt;
&lt;br /&gt;
Este caso es el mas vulnerable de todos no se demora mas de &lt;br /&gt;
una hora en buscarlo y encontrarlo a simple vista , con la tecnología &lt;br /&gt;
adecuada son solo minutos.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Caso 2 :  Owner Name : &amp;quot; ©}êô?Ñé? &amp;quot; ( Carcateres ALT + xxxx)&lt;br /&gt;
&lt;br /&gt;
Este caso ya comienza a complicar el nivel de búsqueda dentro &lt;br /&gt;
del exe porque no se encuentra relación y lleva a la confusión con &lt;br /&gt;
los otros caracteres dentro del exe y todos los hexadecimales, pero es &lt;br /&gt;
vulnerable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Caso 3 :  Owner Name : &amp;quot; VGLO:xxxxxxxxxxxxxxx&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Aca el valor del Owler Name está dentro de una variable &lt;br /&gt;
global, esa variable global  puede traer la informacion desde otro lado , &lt;br /&gt;
archivo , otra variable,etc. Este método es el mas complicado de todos para aquel que &lt;br /&gt;
quiera romper el TPS.&lt;br /&gt;
&lt;br /&gt;
Para mi el mejor caso de seguridad en TPS&#039;s es el 3, por el nivel de &lt;br /&gt;
dificultad que presenta y ante un intento de vulnerabilidad por fuerza bruta siempre devuelve un &lt;br /&gt;
valor 0.&lt;br /&gt;
Es muy importante tener bien documentado lo realizado utilizando el caso 3 &lt;br /&gt;
porque de perder la información, el diseño, etc. el mismo desarrollador puede quedar &lt;br /&gt;
preso y victima de su propia seguridad&lt;br /&gt;
&lt;br /&gt;
Estos son lo niveles que se pueden manejar desde el IDE de desarrollo de &lt;br /&gt;
Clarion, pero tambien se le pueden agregar elementos externos.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo utilizando el  Caso 3 + algún compactador de exes ( ASPACK ) &lt;br /&gt;
realmente se hace casi imposible encontrar las cabeceras de definición de las tablas , &lt;br /&gt;
etc.etc. .&lt;br /&gt;
&lt;br /&gt;
Remarco de lo CASI , porque se puede vulnerar, pero ahi ya comienzan a medir &lt;br /&gt;
otros parámetros como ser el costo/beneficio de invertirle horas y horas o días y &lt;br /&gt;
días  a ese intento de poder vulnerar el archivo , etc, etc, etc. el cual también está &lt;br /&gt;
relacionado al hardware y su capacidad de procesamiento , etc.&lt;br /&gt;
&lt;br /&gt;
Espero que les sirva.&lt;br /&gt;
&lt;br /&gt;
Ing. Fabian Coria&lt;br /&gt;
&lt;br /&gt;
Consultor Seguridad Informatica, Capital Soft&lt;br /&gt;
&lt;br /&gt;
= Diferir la carga de un browse ABC =&lt;br /&gt;
&lt;br /&gt;
Los browse ABC se cargan automáticamente al abrir la ventana. Pero muchas veces se desea controlar el momento de la carga porque se utilizan filtros que deben ser ingresados por el usuario (por ejemplo, un rango de fechas).  Es un tema particularmente importante cuando se trata de browses “file loaded”, o cuando se trabaja sobre MySQL (al utilizar este motor todos los browse son “file loaded”).&lt;br /&gt;
&lt;br /&gt;
Para diferir la carga de un browse ABC hay dos posiblidades.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A. Mediante &#039;&#039;BrowseClass.ActiveInvisible&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Esta técnica consiste en “esconder” el ListBox mediante HIDE y apagar la propiedad &#039;&#039;BrowseClass.ActiveInvisible&#039;&#039;. Cuando se quiere cargar el browse se quita la propiedad HIDE al ListBox.&lt;br /&gt;
&lt;br /&gt;
Los pasos a seguir son los siguientes:&lt;br /&gt;
&lt;br /&gt;
1. En el Window Formatter encender la propiedad HIDE (o utilizar el comando HIDE en el código del procedimiento) para el control correspondiente al ListBox del browse.&lt;br /&gt;
&lt;br /&gt;
2. En &#039;&#039;WindowManager.Init&#039;&#039;, con prioridad 8150, agregar el siguiente código:&lt;br /&gt;
 BRW1.ActiveInvisible = False	!BRW1 es el nombre del objeto Browse&lt;br /&gt;
&lt;br /&gt;
3. Cuando se quiera cargar y mostrar el browse, agregar el siguiente código:&lt;br /&gt;
 ?Browse:1{PROP:Hide} = False	!?Browse:1 es el control del ListBox&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;B. Derivando la BrowseClass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Esta técnica tiene la ventaja de que no es necesario que el ListBox esté oculto.  Consiste en agregar una nueva propiedad a la clase BrowseClass que controle cuándo se desea cargar el browse. Según el estado de esta propiedad se omite o se ejecuta el método &#039;&#039;BrowseClass.ResetQueue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Los pasos a seguir son los siguientes:&lt;br /&gt;
&lt;br /&gt;
1. En BrowseBoxBehavior, en la solapa Classes, encender la opción “Derive?”&lt;br /&gt;
&lt;br /&gt;
2. En New Class Properties agregar una propiedad de tipo BYTE. Para seguir con la nomenclatura en inglés del resto de la clase, la llamaremos “WaitToFill”&lt;br /&gt;
 Property Name: 	WaitToFill&lt;br /&gt;
 Property Type: 	BYTE&lt;br /&gt;
&lt;br /&gt;
3. En &#039;&#039;WindowManager.Init&#039;&#039;, con prioridad 8150, agregar el siguiente código:&lt;br /&gt;
 BRW1.WaitToFill = True	!BRW1 es el nombre del objeto Browse&lt;br /&gt;
&lt;br /&gt;
4. En &#039;&#039;BrowseClass.ResetQueue&#039;&#039;, con prioridad 2500 (antes del ParentCall), agregar el siguiente código:&lt;br /&gt;
 IF SELF.WaitToFill&lt;br /&gt;
    RETURN&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
5. Cuando se quiera cargar y mostrar el browse, agregar el siguiente código:&lt;br /&gt;
 BRW1.WaitToFill = False	!BRW1 es el nombre del objeto browse&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Si bien esto mismo se podría lograr con una variable, con una nueva propiedad se puede administrar más de un browse en el mismo procedimiento, aunque tengan diferente comportamiento.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Otras posibilidades&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Como solución elemental esta técnica es suficiente. Una solución más completa sería derivar directamente la clase &#039;&#039;BrowseClass&#039;&#039; y utilizar la clase derivada en lugar de la clase original. El método &#039;&#039;ResetQueue&#039;&#039; de la nueva clase haría su propia omisión en base al valor de la propiedad &#039;&#039;WaitToFill&#039;&#039;. También se podría agregar un método para encender y apagar la propiedad &#039;&#039;WaitToFill&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
La solución final consistiría en escribir un template que se encargue de implementar la técnica.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
Daniel Ruzo [http://www.amazingGUI.com (amazingGUI)]&lt;br /&gt;
&lt;br /&gt;
= Identificación ÚNICA =&lt;br /&gt;
En ocasiones el campo de identificación de nuestros archivos no son suficiente con que éste sea autonumerado de forma secuencial.&lt;br /&gt;
Por ejemplo tener un pedido en un archivo y los productos del pedido en otro archivo, podría ocurrir que ambos archivos sean reemplazados por backups de diferentes fechas (ej. pedidos mas viejo que item) asi cuando abrimos un nuevo pedido éste ya poseerá productos. Otro ejemplo es que tengamos varias bases distribuidas en diferentes máquinas (no en red) y éstas se vuelcan sobre un solo grupo de archivos via internet (o cualquier otro medio) si son autonumeradas existirán mas de una ID con el mismo número.&lt;br /&gt;
Para solucionar esto pruebe lo siguiente:&lt;br /&gt;
 En el Campo del archivo que sirve de Identificación Ej. ClienteNumero&lt;br /&gt;
 colocar en INITIAL VALUE colocar la función &#039;&#039;GeneraID()&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Crear la función GeneraID&lt;br /&gt;
  loc:IDU   STRING(20)&lt;br /&gt;
  CODE&lt;br /&gt;
  !Identificación Única&lt;br /&gt;
  loc:IDU = FORMAT(TODAY(),@d11) &amp;amp; FORMAT(CLOCK(),@t5) &amp;amp; FORMAT(RANDOM(0,999),@n03)&lt;br /&gt;
  RETURN loc:IDU&lt;br /&gt;
&lt;br /&gt;
un saludo &lt;br /&gt;
DIPS&lt;br /&gt;
&lt;br /&gt;
= Parámetros en procedimientos llamados en threads nuevos =&lt;br /&gt;
Si quiero mandar parámetros a un procedimiento llamado con START (es decir, en un thread nuevo), puedo mandar solo hasta 3 parámetros y todos deben estar definidos como string en el prototipo del procedimiento. Internamente puedo convertir esos parámetros al tipo que necesito en variables locales al procedimiento.&lt;br /&gt;
&lt;br /&gt;
= Meses, días, botones en Español =&lt;br /&gt;
En el main, en el embed &amp;quot;Initialize the procedure&amp;quot; colocar:&lt;br /&gt;
 LOCALE(&#039;CLAMONTH&#039;,&#039;Enero,Febrero,Marzo,Abril,Mayo,Junio,Julio,Agosto,Septiembre,Octubre,Noviembre,Diciembre&#039;)&lt;br /&gt;
 LOCALE(&#039;CLAMON&#039;,&#039;Ene,Feb,Mar,Abr,May,Jun,Jul,Ago,Sep,Oct,Nov,Dic&#039;)&lt;br /&gt;
 LOCALE(&#039;CLACOLSEQ&#039;,&#039;AÁÄÅÆaàáâäåæBbCÇcçDdEÉeèéêëFfGgHhIÍiìíîïJjKkLlMmNnÑñOÓÖoòóôöPpQqRrSsßTtUÚÜuùúûüVvWwXxYyÿZz&#039;)&lt;br /&gt;
 LOCALE(&#039;CLABUTTON&#039;,&#039;Aceptar,&amp;amp;Sí,&amp;amp;No,&amp;amp;Abortar,&amp;amp;Reintentar,&amp;amp;Ignorar,Cancelar,&amp;amp;Ayuda&#039;)&lt;br /&gt;
 LOCALE(&#039;CLACASE&#039;,&#039;ÄÁÅÆÇÉÍÑÓÖÚÜ,äáåæçéíñóöúü&#039;)&lt;br /&gt;
 LOCALE(&#039;CLAAMPM&#039;,&#039;a.m.,p.m.&#039;)&lt;br /&gt;
&lt;br /&gt;
= Consultas SQL que en el Motor corren rapido pero en Clarion NO =&lt;br /&gt;
Un truco fácil pero funcional (sólo válido para SQL Server).&lt;br /&gt;
&lt;br /&gt;
Suponiendo que la instrucción original sea:&lt;br /&gt;
&lt;br /&gt;
  Select P.Codigo, P.Descripcion, K.Entradas, K.Salidas, K.Valor_Entradas, K.Valor_Salidas&lt;br /&gt;
  From Productos P&lt;br /&gt;
  Inner Join Kardex K On P.Id_Producto = K.Id_Producto&lt;br /&gt;
  Where P.Codigo = &#039;AAA001&#039; And K.Fecha = &#039;01-10-2006&#039;&lt;br /&gt;
  Order By K.Fecha, P.Codigo&lt;br /&gt;
&lt;br /&gt;
Como &#039;&#039;&#039;CLARION&#039;&#039;&#039; genera un cursor puede que en ocaciones dicho query sea muy pesado y el cursor tarde mucho en resolverlo, para ello simplemente agrega lo siguiente:&lt;br /&gt;
&lt;br /&gt;
  Select P.Codigo, P.Descripcion, K.Entradas, K.Salidas, K.Valor_Entradas, K.Valor_Salidas&lt;br /&gt;
  &#039;&#039;&#039;Into #TempTable&#039;&#039;&#039;&lt;br /&gt;
  From Productos P&lt;br /&gt;
  Inner Join Kardex K On P.Id_Producto = K.Id_Producto&lt;br /&gt;
  Where P.Codigo = &#039;AAA001&#039; And K.Fecha = &#039;01-10-2006&#039;&lt;br /&gt;
  Order By K.Fecha, P.Codigo&lt;br /&gt;
  &#039;&#039;&#039;Select * From #TempTable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
De esta manera todo se realiza en el servidor y solo va a devolver los datos ya procesados en el #TempTable&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Este truco se lo agradezco a mi amigo Juan Manuel Medina.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Javier A. Junca Barreto. [http://www.sicya.com (SICyA Software Ltda.)]&lt;br /&gt;
&lt;br /&gt;
= Exportar fechas a Excel =&lt;br /&gt;
&lt;br /&gt;
Para exportar campos fecha a Excel hay que mandarlos con format(campo, @d01b), de lo contrario Excel interpreta aleatoriamente meses como días, días como meses, etc.&lt;br /&gt;
&lt;br /&gt;
De todas maneras, que el mecanismo comentado arriba funcione depende de la configuración de Excel. Otra opción es usar la función “date” de Excel, y enviar por separado año, mes y día. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
  MSExcel1.ExecFunction(&#039;A1&#039;, &#039;=date(&#039; &amp;amp; year(FechaClarion) &amp;amp; &#039;,&#039; &amp;amp; month(FechaClarion) &amp;amp; &#039;,&#039; &amp;amp; day(FechaClarion) &amp;amp; &#039;)&#039;)&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Recomendaciones&amp;diff=83</id>
		<title>Recomendaciones</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Recomendaciones&amp;diff=83"/>
		<updated>2015-03-08T00:36:22Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Recomendaciones y Trucos que nos pueden evitar dolores de cabeza&#039;&#039;&#039;&lt;br /&gt;
= Versión Demo (básica) =&lt;br /&gt;
Poner este embed global en un par de tablas importantes&lt;br /&gt;
 Global Embeds&lt;br /&gt;
    Abc Objects&lt;br /&gt;
        File Managers&lt;br /&gt;
            File Manager for YourFile&lt;br /&gt;
                Insert - Before Parent Call&lt;br /&gt;
 IF RECORDS(SELF.FILE)&amp;gt; 10&lt;br /&gt;
  MESSAGE(&#039;Demo Version&#039;)&lt;br /&gt;
  RETURN LEVEL:FATAL&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Obtener un total general (al final) en un Reporte =&lt;br /&gt;
 Lo mas facil es armar un break group sobre una variable que no cambie nunca,&lt;br /&gt;
 (puede ser cualquier variable global, por ejemplo)&lt;br /&gt;
 Luego pones los totales en un group footer de este break y listo.&lt;br /&gt;
 Como la variable nunca cambia (puede ser una global por ejemplo) solo se&lt;br /&gt;
 imprime el group footer al final del reporte.&lt;br /&gt;
 Tambien podria usarse el Group Header de ese break como &amp;quot;caratula&amp;quot; del reporte&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Usar DLLs no creadas en Clarion =&lt;br /&gt;
Para Usar DLLs no creadas en Clarion, hay que seguir los siguientes pasos:&lt;br /&gt;
 - Crear los prototipos equivalentes en Clarion&lt;br /&gt;
 para esto hay que averiguar cuales son los prototipos originales (en c, por ej.)&lt;br /&gt;
 y ver la equivalencia de tipos entre Clarion, C y  o C++&lt;br /&gt;
 - Usar el Libmaker para la creacion de una Clarion Library (.LIB File) para la DLL&lt;br /&gt;
 - Incluir el .LIB File al proyecto&lt;br /&gt;
&lt;br /&gt;
Para mas detalles, ver .\docs\FAQsTips&amp;amp;Tricks.pdf el tema &amp;quot;How to Use Windows DLLs NOT Created in Clarion&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Modificar código en múltiples embeds, o varias tablas del DCT =&lt;br /&gt;
Se puede exportar la aplicación o el DCT a Texto (app.TXA) modificar el texto con un buen editor (yo recomiendo el textpad) y luego importar de nuevo.&lt;br /&gt;
&lt;br /&gt;
Obviamente, hacer un backup primero porque esto es una opración &amp;quot;peligrosa&amp;quot;&lt;br /&gt;
&lt;br /&gt;
En la sección de [http://www.templatesclarion/download/ Downloads] el documento de migración de TPS a SQL se basa en esta técnica para modificar el DCT.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Deshabilitar el PopUp en un control TEXT =&lt;br /&gt;
Simplemente asignar la Key MouseRight al control TEXT&lt;br /&gt;
&lt;br /&gt;
= Desplegar una opción de menú desde un botón =&lt;br /&gt;
Pónle un hotkey al menu, por ejemplo:&lt;br /&gt;
 Menu Text: &amp;amp;Browse&lt;br /&gt;
Luego en el botón&lt;br /&gt;
 PRESSKEY(AltB)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Obtener los diferentes elementos del path =&lt;br /&gt;
Global Embeds - Inside Global Map&lt;br /&gt;
 Include(&#039;clib.clw&#039;)&lt;br /&gt;
&lt;br /&gt;
En el embed:&lt;br /&gt;
 X# = FnSplit(LOC:Path,LOC:Drive,LOC:Dir,LOC:File,LOC:Ext)&lt;br /&gt;
 DISPLAY&lt;br /&gt;
&lt;br /&gt;
Las variables locales son todas CSTRING(256)&lt;br /&gt;
Por ejemplo para saber solo el nombre del archivo se usaria LOC:File &amp;amp; LOC:Ext&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
= Conversión de Archivos =&lt;br /&gt;
1) Tenés que tener un diccionario aparte, en principio vacio. Yo lo llamo &lt;br /&gt;
conversiones.dct.&lt;br /&gt;
&lt;br /&gt;
2) Abrís ambos DCT. Te parás en la definición que querés convertir y &lt;br /&gt;
apretás &amp;quot;copiar&amp;quot;. Te parás en el conversiones.dct y apretás &amp;quot;pegar&amp;quot;. A &lt;br /&gt;
este archivo pegado lo renombrás con la fecha (por ejemplo, si mi archivo &lt;br /&gt;
a convertir se llama CLIENTES, en conversiones lo pego como CLIENTES_&lt;br /&gt;
050328).&lt;br /&gt;
&lt;br /&gt;
3) Hacés todos los cambios que necesites en la definición de tu archivos &lt;br /&gt;
CLIENTES. Acá ya podés recompilar todo tu sistema.&lt;br /&gt;
&lt;br /&gt;
4) Cerrá tu diccionario, dejá abierto Conversiones.dct. Seleccioná &lt;br /&gt;
&amp;quot;convert&amp;quot; el archivo, te pide el path al archivo y primero te hace un &lt;br /&gt;
&amp;quot;browse&amp;quot; sobre el mismo, de ahí seleccionás el menú &amp;quot;File&amp;quot;, &amp;quot;Convert &lt;br /&gt;
File&amp;quot; y te abre una ventanita.&lt;br /&gt;
&lt;br /&gt;
5) Acá, en target dictionary elegís tu DCT, el que tiene la definición &lt;br /&gt;
ahora modificada (Acordate que estás en el conversiones.dct).&lt;br /&gt;
&lt;br /&gt;
6) En target structure, buscás en tu DCT el nombre del archivo &lt;br /&gt;
convertido.&lt;br /&gt;
&lt;br /&gt;
7) En Generated source, tipeá algo que tenga sentido: yo voy numerando &lt;br /&gt;
mis programas conversores, así que voy poniendo algo como CONV0001, &lt;br /&gt;
CONV0002, etc. Fijate bien el path donde lo metés.&lt;br /&gt;
&lt;br /&gt;
8) Si no salió solo, salí del browser, cerrá todos los DCT.&lt;br /&gt;
&lt;br /&gt;
9) Andá por &amp;quot;File&amp;quot;, &amp;quot;Change directory&amp;quot; y cambiate al directorio donde &lt;br /&gt;
grabaste el fuente del conversor. Yo uso un subdirectorio &amp;quot;pasa&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
10) Andá a &amp;quot;File&amp;quot;, &amp;quot;Open&amp;quot;, elegí &amp;quot;Clarion source&amp;quot;, y abrí el programa &lt;br /&gt;
conversor.&lt;br /&gt;
&lt;br /&gt;
11) Andá a &amp;quot;Project&amp;quot;, &amp;quot;Set&amp;quot; y seleccioná el archivo de proyecto que tiene &lt;br /&gt;
el mismo nombre que el fuente del conversor.&lt;br /&gt;
&lt;br /&gt;
12) Editale lo que quieras al programa conversor. Acá por ejemplo a veces &lt;br /&gt;
cambio el directorio de salida, o ajusto la ventana de display, le pongo &lt;br /&gt;
mensajes o hago cualquier asignación que sea necesaria.&lt;br /&gt;
&lt;br /&gt;
13) Compilá, correlo y listo. Te queda un ejecutable autónomo que podés &lt;br /&gt;
correr en el cliente llamándolo a mano, desde un instalador o desde tu &lt;br /&gt;
propia aplicación.&lt;br /&gt;
&lt;br /&gt;
14) Ventaja adicional: Si tu cliente guarda backups de los archivos, y &lt;br /&gt;
por la circunstancia que sea tiene que reprocesar información de un &lt;br /&gt;
archivo viejo, se pueden correr todos los programas de conversión que &lt;br /&gt;
corresponden a ese archivo, en secuencia, para llevar su formato al &lt;br /&gt;
actual.&lt;br /&gt;
&lt;br /&gt;
15) Otra ventaja: este método sirve para cualquier base ISAM, para SQL &lt;br /&gt;
hay que hacer algunos pasos más pero básicamente se puede hacer lo mismo.&lt;br /&gt;
&lt;br /&gt;
Finalmente, te digo que esto lleva muchísimo más tiempo explicarlo y &lt;br /&gt;
aprenderlo que hacerlo. Cuando te digo que todo esto lleva 1 minuto, es &lt;br /&gt;
en serio, es lo que lleva cuando ya sabés cómo hacerlo de memoria.&lt;br /&gt;
&lt;br /&gt;
Una acotación, con este método te van quedando en el conversiones.dct &lt;br /&gt;
todas las definiciones históricas de tus archivos, algo que puede llegar &lt;br /&gt;
a ser muy últil, mientras que en tu dct de &amp;quot;trabajo&amp;quot; sólo está la &lt;br /&gt;
definición &amp;quot;actual&amp;quot; y no hay nada que haga ruido.&lt;br /&gt;
&lt;br /&gt;
Saludos,&lt;br /&gt;
Jorge A. Lavera&lt;br /&gt;
&lt;br /&gt;
= Encriptación de TPS =&lt;br /&gt;
Sobre el Owner Name y su seguridad o capacidad de encriptación&lt;br /&gt;
depende mas que nada del  planeamiento que a la herramienta en sí&lt;br /&gt;
misma&lt;br /&gt;
&lt;br /&gt;
Caso 1 :  Owner Name : &amp;quot; Tu palabra clave &amp;quot;&lt;br /&gt;
&lt;br /&gt;
Este caso es el mas vulnerable de todos no se demora mas de &lt;br /&gt;
una hora en buscarlo y encontrarlo a simple vista , con la tecnología &lt;br /&gt;
adecuada son solo minutos.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Caso 2 :  Owner Name : &amp;quot; ©}êô?Ñé? &amp;quot; ( Carcateres ALT + xxxx)&lt;br /&gt;
&lt;br /&gt;
Este caso ya comienza a complicar el nivel de búsqueda dentro &lt;br /&gt;
del exe porque no se encuentra relación y lleva a la confusión con &lt;br /&gt;
los otros caracteres dentro del exe y todos los hexadecimales, pero es &lt;br /&gt;
vulnerable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Caso 3 :  Owner Name : &amp;quot; VGLO:xxxxxxxxxxxxxxx&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Aca el valor del Owler Name está dentro de una variable &lt;br /&gt;
global, esa variable global  puede traer la informacion desde otro lado , &lt;br /&gt;
archivo , otra variable,etc. Este método es el mas complicado de todos para aquel que &lt;br /&gt;
quiera romper el TPS.&lt;br /&gt;
&lt;br /&gt;
Para mi el mejor caso de seguridad en TPS&#039;s es el 3, por el nivel de &lt;br /&gt;
dificultad que presenta y ante un intento de vulnerabilidad por fuerza bruta siempre devuelve un &lt;br /&gt;
valor 0.&lt;br /&gt;
Es muy importante tener bien documentado lo realizado utilizando el caso 3 &lt;br /&gt;
porque de perder la información, el diseño, etc. el mismo desarrollador puede quedar &lt;br /&gt;
preso y victima de su propia seguridad&lt;br /&gt;
&lt;br /&gt;
Estos son lo niveles que se pueden manejar desde el IDE de desarrollo de &lt;br /&gt;
Clarion, pero tambien se le pueden agregar elementos externos.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo utilizando el  Caso 3 + algún compactador de exes ( ASPACK ) &lt;br /&gt;
realmente se hace casi imposible encontrar las cabeceras de definición de las tablas , &lt;br /&gt;
etc.etc. .&lt;br /&gt;
&lt;br /&gt;
Remarco de lo CASI , porque se puede vulnerar, pero ahi ya comienzan a medir &lt;br /&gt;
otros parámetros como ser el costo/beneficio de invertirle horas y horas o días y &lt;br /&gt;
días  a ese intento de poder vulnerar el archivo , etc, etc, etc. el cual también está &lt;br /&gt;
relacionado al hardware y su capacidad de procesamiento , etc.&lt;br /&gt;
&lt;br /&gt;
Espero que les sirva.&lt;br /&gt;
&lt;br /&gt;
Ing. Fabian Coria&lt;br /&gt;
&lt;br /&gt;
Consultor Seguridad Informatica, Capital Soft&lt;br /&gt;
&lt;br /&gt;
= Diferir la carga de un browse ABC =&lt;br /&gt;
&lt;br /&gt;
Los browse ABC se cargan automáticamente al abrir la ventana. Pero muchas veces se desea controlar el momento de la carga porque se utilizan filtros que deben ser ingresados por el usuario (por ejemplo, un rango de fechas).  Es un tema particularmente importante cuando se trata de browses “file loaded”, o cuando se trabaja sobre MySQL (al utilizar este motor todos los browse son “file loaded”).&lt;br /&gt;
&lt;br /&gt;
Para diferir la carga de un browse ABC hay dos posiblidades.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A. Mediante &#039;&#039;BrowseClass.ActiveInvisible&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Esta técnica consiste en “esconder” el ListBox mediante HIDE y apagar la propiedad &#039;&#039;BrowseClass.ActiveInvisible&#039;&#039;. Cuando se quiere cargar el browse se quita la propiedad HIDE al ListBox.&lt;br /&gt;
&lt;br /&gt;
Los pasos a seguir son los siguientes:&lt;br /&gt;
&lt;br /&gt;
1. En el Window Formatter encender la propiedad HIDE (o utilizar el comando HIDE en el código del procedimiento) para el control correspondiente al ListBox del browse.&lt;br /&gt;
&lt;br /&gt;
2. En &#039;&#039;WindowManager.Init&#039;&#039;, con prioridad 8150, agregar el siguiente código:&lt;br /&gt;
 BRW1.ActiveInvisible = False	!BRW1 es el nombre del objeto Browse&lt;br /&gt;
&lt;br /&gt;
3. Cuando se quiera cargar y mostrar el browse, agregar el siguiente código:&lt;br /&gt;
 ?Browse:1{PROP:Hide} = False	!?Browse:1 es el control del ListBox&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;B. Derivando la BrowseClass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Esta técnica tiene la ventaja de que no es necesario que el ListBox esté oculto.  Consiste en agregar una nueva propiedad a la clase BrowseClass que controle cuándo se desea cargar el browse. Según el estado de esta propiedad se omite o se ejecuta el método &#039;&#039;BrowseClass.ResetQueue&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Los pasos a seguir son los siguientes:&lt;br /&gt;
&lt;br /&gt;
1. En BrowseBoxBehavior, en la solapa Classes, encender la opción “Derive?”&lt;br /&gt;
&lt;br /&gt;
2. En New Class Properties agregar una propiedad de tipo BYTE. Para seguir con la nomenclatura en inglés del resto de la clase, la llamaremos “WaitToFill”&lt;br /&gt;
 Property Name: 	WaitToFill&lt;br /&gt;
 Property Type: 	BYTE&lt;br /&gt;
&lt;br /&gt;
3. En &#039;&#039;WindowManager.Init&#039;&#039;, con prioridad 8150, agregar el siguiente código:&lt;br /&gt;
 BRW1.WaitToFill = True	!BRW1 es el nombre del objeto Browse&lt;br /&gt;
&lt;br /&gt;
4. En &#039;&#039;BrowseClass.ResetQueue&#039;&#039;, con prioridad 2500 (antes del ParentCall), agregar el siguiente código:&lt;br /&gt;
 IF SELF.WaitToFill&lt;br /&gt;
    RETURN&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
5. Cuando se quiera cargar y mostrar el browse, agregar el siguiente código:&lt;br /&gt;
 BRW1.WaitToFill = False	!BRW1 es el nombre del objeto browse&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Si bien esto mismo se podría lograr con una variable, con una nueva propiedad se puede administrar más de un browse en el mismo procedimiento, aunque tengan diferente comportamiento.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Otras posibilidades&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Como solución elemental esta técnica es suficiente. Una solución más completa sería derivar directamente la clase &#039;&#039;BrowseClass&#039;&#039; y utilizar la clase derivada en lugar de la clase original. El método &#039;&#039;ResetQueue&#039;&#039; de la nueva clase haría su propia omisión en base al valor de la propiedad &#039;&#039;WaitToFill&#039;&#039;. También se podría agregar un método para encender y apagar la propiedad &#039;&#039;WaitToFill&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
La solución final consistiría en escribir un template que se encargue de implementar la técnica.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
Daniel Ruzo [http://www.amazingGUI.com (amazingGUI)]&lt;br /&gt;
&lt;br /&gt;
= Identificación ÚNICA =&lt;br /&gt;
En ocasiones el campo de identificación de nuestros archivos no son suficiente con que éste sea autonumerado de forma secuencial.&lt;br /&gt;
Por ejemplo tener un pedido en un archivo y los productos del pedido en otro archivo, podría ocurrir que ambos archivos sean reemplazados por backups de diferentes fechas (ej. pedidos mas viejo que item) asi cuando abrimos un nuevo pedido éste ya poseerá productos. Otro ejemplo es que tengamos varias bases distribuidas en diferentes máquinas (no en red) y éstas se vuelcan sobre un solo grupo de archivos via internet (o cualquier otro medio) si son autonumeradas existirán mas de una ID con el mismo número.&lt;br /&gt;
Para solucionar esto pruebe lo siguiente:&lt;br /&gt;
 En el Campo del archivo que sirve de Identificación Ej. ClienteNumero&lt;br /&gt;
 colocar en INITIAL VALUE colocar la función &#039;&#039;GeneraID()&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Crear la función GeneraID&lt;br /&gt;
  loc:IDU   STRING(20)&lt;br /&gt;
  CODE&lt;br /&gt;
  !Identificación Única&lt;br /&gt;
  loc:IDU = FORMAT(TODAY(),@d11) &amp;amp; FORMAT(CLOCK(),@t5) &amp;amp; FORMAT(RANDOM(0,999),@n03)&lt;br /&gt;
  RETURN loc:IDU&lt;br /&gt;
&lt;br /&gt;
un saludo &lt;br /&gt;
DIPS&lt;br /&gt;
&lt;br /&gt;
= Parámetros en procedimientos llamados en threads nuevos =&lt;br /&gt;
Si quiero mandar parámetros a un procedimiento llamado con START (es decir, en un thread nuevo), puedo mandar solo hasta 3 parámetros y todos deben estar definidos como string en el prototipo del procedimiento. Internamente puedo convertir esos parámetros al tipo que necesito en variables locales al procedimiento.&lt;br /&gt;
&lt;br /&gt;
= Meses, días, botones en Español =&lt;br /&gt;
En el main, en el embed &amp;quot;Initialize the procedure&amp;quot; colocar:&lt;br /&gt;
 LOCALE(&#039;CLAMONTH&#039;,&#039;Enero,Febrero,Marzo,Abril,Mayo,Junio,Julio,Agosto,Septiembre,Octubre,Noviembre,Diciembre&#039;)&lt;br /&gt;
 LOCALE(&#039;CLAMON&#039;,&#039;Ene,Feb,Mar,Abr,May,Jun,Jul,Ago,Sep,Oct,Nov,Dic&#039;)&lt;br /&gt;
 LOCALE(&#039;CLACOLSEQ&#039;,&#039;AÁÄÅÆaàáâäåæBbCÇcçDdEÉeèéêëFfGgHhIÍiìíîïJjKkLlMmNnÑñOÓÖoòóôöPpQqRrSsßTtUÚÜuùúûüVvWwXxYyÿZz&#039;)&lt;br /&gt;
 LOCALE(&#039;CLABUTTON&#039;,&#039;Aceptar,&amp;amp;Sí,&amp;amp;No,&amp;amp;Abortar,&amp;amp;Reintentar,&amp;amp;Ignorar,Cancelar,&amp;amp;Ayuda&#039;)&lt;br /&gt;
 LOCALE(&#039;CLACASE&#039;,&#039;ÄÁÅÆÇÉÍÑÓÖÚÜ,äáåæçéíñóöúü&#039;)&lt;br /&gt;
 LOCALE(&#039;CLAAMPM&#039;,&#039;a.m.,p.m.&#039;)&lt;br /&gt;
&lt;br /&gt;
= Consultas SQL que en el Motor corren rapido pero en Clarion NO =&lt;br /&gt;
Un truco fácil pero funcional (sólo válido para SQL Server).&lt;br /&gt;
&lt;br /&gt;
Suponiendo que la instrucción original sea:&lt;br /&gt;
&lt;br /&gt;
  Select P.Codigo, P.Descripcion, K.Entradas, K.Salidas, K.Valor_Entradas, K.Valor_Salidas&lt;br /&gt;
  From Productos P&lt;br /&gt;
  Inner Join Kardex K On P.Id_Producto = K.Id_Producto&lt;br /&gt;
  Where P.Codigo = &#039;AAA001&#039; And K.Fecha = &#039;01-10-2006&#039;&lt;br /&gt;
  Order By K.Fecha, P.Codigo&lt;br /&gt;
&lt;br /&gt;
Como &#039;&#039;&#039;CLARION&#039;&#039;&#039; genera un cursor puede que en ocaciones dicho query sea muy pesado y el cursor tarde mucho en resolverlo, para ello simplemente agrega lo siguiente:&lt;br /&gt;
&lt;br /&gt;
  Select P.Codigo, P.Descripcion, K.Entradas, K.Salidas, K.Valor_Entradas, K.Valor_Salidas&lt;br /&gt;
  &#039;&#039;&#039;Into #TempTable&#039;&#039;&#039;&lt;br /&gt;
  From Productos P&lt;br /&gt;
  Inner Join Kardex K On P.Id_Producto = K.Id_Producto&lt;br /&gt;
  Where P.Codigo = &#039;AAA001&#039; And K.Fecha = &#039;01-10-2006&#039;&lt;br /&gt;
  Order By K.Fecha, P.Codigo&lt;br /&gt;
  &#039;&#039;&#039;Select * From #TempTable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
De esta manera todo se realiza en el servidor y solo va a devolver los datos ya procesados en el #TempTable&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Este truco se lo agradezco a mi amigo Juan Manuel Medina.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Javier A. Junca Barreto. [http://www.sicya.com (SICyA Software Ltda.)]&lt;br /&gt;
&lt;br /&gt;
= Exportar fechas a Excel =&lt;br /&gt;
&lt;br /&gt;
Para exportar campos fecha a Excel hay que mandarlos con format(campo, @d01b), de lo contrario Excel interpreta aleatoriamente meses como días, días como meses, etc.&lt;br /&gt;
&lt;br /&gt;
De todas maneras, que el mecanismo comentado arriba funcione depende de la configuración de Excel. Otra opción es usar la función “date” de Excel, y enviar por separado año, mes y día. Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
  MSExcel1.ExecFunction(&#039;A1&#039;, &#039;=date(&#039; &amp;amp; year(FechaClarion) &amp;amp; &#039;,&#039; &amp;amp; month(FechaClarion) &amp;amp; &#039;,&#039; &amp;amp; day(FechaClarion) &amp;amp; &#039;)&#039;)&lt;br /&gt;
&lt;br /&gt;
= Video tutoriales acerca de Clarion =&lt;br /&gt;
&lt;br /&gt;
Serie de videos publicados en YouTube. &lt;br /&gt;
&lt;br /&gt;
Autor: Eberto Barrios Romo&lt;br /&gt;
&lt;br /&gt;
Efecto &#039;GreenBar&#039;&lt;br /&gt;
&lt;br /&gt;
http://www.youtube.com/watch?v=QgOylZBHbVs&lt;br /&gt;
&lt;br /&gt;
Uso de &amp;quot;List Format&amp;quot; en un Browse&lt;br /&gt;
&lt;br /&gt;
http://www.youtube.com/watch?v=hO2mfSz7VHc&lt;br /&gt;
&lt;br /&gt;
Imprimiendo el resultado de una consulta&lt;br /&gt;
&lt;br /&gt;
http://www.youtube.com/watch?v=QgOylZBHbVs&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Codigo_Util&amp;diff=82</id>
		<title>Codigo Util</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Codigo_Util&amp;diff=82"/>
		<updated>2015-03-08T00:34:37Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;En esta sección se incluyen rutinas de código que nos resultaron útiles en más de una ocasión.&lt;br /&gt;
&lt;br /&gt;
== PDF con cualquier versión de Clarion ==&lt;br /&gt;
Después de mucho rebuscar algo gratis que haga esto, hoy pude componer algo:&lt;br /&gt;
1º) Aporte de Fernando Cerini para &amp;quot;capturar&amp;quot; los .wmf de los reportes de Clarion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En el embed PrintPreview.Open, despues de Parent call&lt;br /&gt;
 &lt;br /&gt;
 get(SELF.ImageQueue,POINTER(SELF.ImageQueue))&lt;br /&gt;
 LOOP a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
          get(SELF.ImageQueue,a#)&lt;br /&gt;
          COPY(SELF.ImageQueue, &#039;c:\temp\Pagina&#039; &amp;amp; a# &amp;amp;&#039;.WMF&#039;)&lt;br /&gt;
          IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
En mi caso, con Clarion 5.0 ABC el embed point fue Previewer.Open, después del Parent call&lt;br /&gt;
&lt;br /&gt;
2º) Instalar OpenOffice y seguir las instrucciones de&lt;br /&gt;
http://www.xml.com/pub/a/2006/01/11/from-microsoft-to-openoffice.html&lt;br /&gt;
para crear la macro.&lt;br /&gt;
La verdad, no pude cambiar el nombre de Module1 a Conversiones o algo así, pero no importó mucho.&lt;br /&gt;
&lt;br /&gt;
3º) Cree un batch con la línea&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;C:\Archivos de Programa\OpenOffice.org 2.3\program\soffice&amp;quot; -invisible macro:///Standard.Module1.SaveAsPDF(c:\temp\pagina8.wmf)&lt;br /&gt;
&lt;br /&gt;
Es lo que dice el instructivo mencionado en el punto 2º) acomodado a mi instalación de OpenOffice, lo corrí y funcionó a la primera prueba.&lt;br /&gt;
&lt;br /&gt;
4º) Sólo queda hacer la llamada mediante RUN en el código de Clarion y santo remedio.&lt;br /&gt;
&lt;br /&gt;
Espero sea de ayuda para alguien.&lt;br /&gt;
Saludos&lt;br /&gt;
Ezequiel&lt;br /&gt;
&lt;br /&gt;
== Como filtrar un Tree ==&lt;br /&gt;
Una tecnica de Saul Perez Quezada para filtrar Arboles (generados con el template Relacion Tree), con filtros en runtime que son complejos, y que no podemos hacer con un simple SetFilter().&lt;br /&gt;
&lt;br /&gt;
Alguien ha posteado una pregunta sobre como Filtrar arboles, yo en lo personal he dejado de usar arboles, por que son bastante lentos y deficientes, pero en algunas aplicaciones es bastante util, de manera que comparto la experiencia y les subo una pequeña explicacion de como filtrar Arboles (generados con el template Relacion Tree), con filtros en runtime que son complejos, y que no podemos hacer con un simple SetFilter(), ya que no existe esto en la propiedad.&lt;br /&gt;
 &lt;br /&gt;
Saludos y espero les sirva.&lt;br /&gt;
 &lt;br /&gt;
Como filtrar un Tree con solamente tablas:&lt;br /&gt;
 &lt;br /&gt;
Dentro del Template para armar los arboles, tiene dentro de Primary y Secondary files la opcion de filtrar, agregando un filtro, pero muchas veces dicho filtro no es tan simple de armar, o necesitamos estarlo cambiando en runtime.&lt;br /&gt;
 &lt;br /&gt;
Aqui les presento un caso y como su solucion, esperando que les sirva...&lt;br /&gt;
 &lt;br /&gt;
Tengo tres tablas:&lt;br /&gt;
 &lt;br /&gt;
Abuelos&lt;br /&gt;
Padres&lt;br /&gt;
Hijos&lt;br /&gt;
 &lt;br /&gt;
Y en la tabla hijos, tengo un campo que define en que nivel de escuela en que va cada hijo: Pre-escolar, Primaria, Secundaria, Bachillerato, Universidad, PostGrado, Maestria y Doctorado.&lt;br /&gt;
 &lt;br /&gt;
En la ventana requiero que el usuario pueda filtrar por el nivel escolar, pero con las siguientes condiciones:&lt;br /&gt;
 &lt;br /&gt;
1.- El usuario puede seleccionar si quiere ver cualquier combinacion de estudios, es decir, que pueda ver los de primaria y universidad solamente o todos, o ninguno...&lt;br /&gt;
2.- Si selecciona un filtro donde resulte que un abuelo o padre no tiene hijos que cumplan la condicion, entonces no debe mostrarnos a esos abuelos y padres...&lt;br /&gt;
 &lt;br /&gt;
Considerando que el Tree template, muestra siempre los niveles de acuerdo al filtro que se arma, pues podria convertirse algo engorroso, estar cambiando el filtro, ya que no es una propiedad del relacion tree, tal como sucede con el browse class, sino que el tree filtra a base de If&#039;s interpuestos al llenar el queue...&lt;br /&gt;
 &lt;br /&gt;
Usando el template y solo poniendo los filtros de NIVELESCOLAR = LOC:MINIVEL, solo mostraria los hijos de un nivel, asi que este metodo no nos servira...&lt;br /&gt;
 &lt;br /&gt;
La idea seria entonces que como filtro usaremos una condicion matematica, si la condicion es Verdadera, entonces mostrara el hijo, de lo contrario no lo mostrara.&lt;br /&gt;
 &lt;br /&gt;
Asi que con el comando EVALUATE, evaluaremos un filtro, dentro del secondary files, opcion filter, si el filtro es bueno (igual a 1), entonces nos mostrara la info de lo contrario no...&lt;br /&gt;
 &lt;br /&gt;
Por ejemplo:&lt;br /&gt;
 &lt;br /&gt;
En el secondary files en buscamos la tabla de Hijos y le escribimos en el filtro:&lt;br /&gt;
 &lt;br /&gt;
0&amp;lt;EVALUATE(Filtro) ! Si el filtro es valido, entonces nos mostrara el resultado, de lo contrario no...&lt;br /&gt;
 &lt;br /&gt;
Declaramos un check box por cada cada condicion, con su respectiva variable: Preescolar, Primaria, Secundaria, etc... que sea tipo byte, con valor true = 1 y valor false = 0&lt;br /&gt;
 &lt;br /&gt;
! En el acepted del check box Preescolar... y cada condicion...&lt;br /&gt;
Do Filtrar&lt;br /&gt;
Display&lt;br /&gt;
 &lt;br /&gt;
! En procedure routines&lt;br /&gt;
Filtrar Routine&lt;br /&gt;
  Clear(Filtro) ! Variable para filtrar&lt;br /&gt;
 &lt;br /&gt;
  If Preescolar Then Filtro = &#039;HIJ:NIVELESCOLAR=&#039;&#039;Preescolar&#039;&#039;&#039; ..&lt;br /&gt;
  &lt;br /&gt;
  If Filtro And Primaria&lt;br /&gt;
    Filtro = Clip(Filtro) &amp;amp; &#039; And HIJ:NIVELESCOLAR=&#039;&#039;Primaria&#039;&#039;&#039;&lt;br /&gt;
  ElsIf Filtro And Primaria&lt;br /&gt;
    Filtro = &#039;HIJ:NIVELESCOLAR=&#039;&#039;Primaria&#039;&#039;&#039;&lt;br /&gt;
  End&lt;br /&gt;
  ! Esto se repite con todas las condiciones...&lt;br /&gt;
  ...&lt;br /&gt;
  ...&lt;br /&gt;
  &lt;br /&gt;
  ! Despues de armar el filtro, refrescar el browse...&lt;br /&gt;
 &lt;br /&gt;
  DO REL4::RefreshTree ! Esta rutina la genera el template, se debe buscar en los modulos su nombre correcto.&lt;br /&gt;
  POST(EVENT:NewSelection,?RelTree)&lt;br /&gt;
 &lt;br /&gt;
 Exit  &lt;br /&gt;
 &lt;br /&gt;
Hasta ahora, lo que se ha logrado es que cuando el usuario seleccione un tipo nivel escolar, nos mostrara o no los hijos, pero resulta, que ahora lo que necesito es que solo me muestre los abuelos que tienen nietos, y los padres que tienen hijos, es entonces por que no tiene caso que el arbol se llene con Mil abuelos, si solo 30 de ellos tienen nietos...&lt;br /&gt;
 &lt;br /&gt;
Para hacer debemos entender como se llena el queue del tree, basicamente, el tree, tantas vueltas como combinaciones de nuestra estructura tengamos, es decir, suponiendo que tenemos 3 abuelos, 3 padres, con 3 hijos cada uno, lo que hace el template es:&lt;br /&gt;
 &lt;br /&gt;
Por cada Abuelo Barre (con Loop) la tabla Padres por completo 1 vez y selecciono los que me corresponden y por cada padre barro la tabla hijos (con Loop) por completo y selecciono los que me corresponden...&lt;br /&gt;
 &lt;br /&gt;
Entonces esta estructura daria 3 x 3 x 3 = 27 vueltas. (Ahora imaginen lo que tarda en entre tablas de 10000 registros...)&lt;br /&gt;
 &lt;br /&gt;
Bueno, siguiendo esta idea, entonces lo que necesitamos, es interceptar cada vuelta en el punto donde no queremos que se ingrese al queue y hacer un break.&lt;br /&gt;
 &lt;br /&gt;
Conociendo esto buscamos en nuestros embeds, embedido llamado:&lt;br /&gt;
 &lt;br /&gt;
RelacionTree After Next Primary File y RelationTree After Next Secondary File...&lt;br /&gt;
 &lt;br /&gt;
Aqui buscamos el archivo que requerimos excluir en algunos casos, que es Padres e Hijos, le escribimos en el caso de Padres:&lt;br /&gt;
 &lt;br /&gt;
PAD:AbueloId = ABU:AbueloId&lt;br /&gt;
If Access:Padres.Fetch(FK AbueloId)  ! Si no existen padres que sean dependientes de este abuelo&lt;br /&gt;
  Break          ! hacer el break al Loop del armado del tree...&lt;br /&gt;
End&lt;br /&gt;
 &lt;br /&gt;
Y el caso de los hijos repetimos la condicion:&lt;br /&gt;
 &lt;br /&gt;
HIJ:PadreId = PAD:PadreId&lt;br /&gt;
If Access:Hijos.Fetch(FK PadreId)  ! Si no existen hijos que sean dependientes de este abuelo&lt;br /&gt;
  Break          ! hacer el break al Loop del armado del tree...&lt;br /&gt;
End&lt;br /&gt;
 &lt;br /&gt;
El efecto sera que no nos mostrara aquellos padres y abuelos que no tengan hijos.&lt;br /&gt;
 &lt;br /&gt;
Si requerimos algo mas complejo podemos usar una vista, en vez de una Fetch a una tabla, pero obviamente se alentara esto cada vez mas y mas al llenar el Arbol.&lt;br /&gt;
 &lt;br /&gt;
Nota&lt;br /&gt;
Si usamos un motor de SQL, una alternativa mucho mas eficiente es declarar un Vista en nuestro motor y diccionario que sirva de base para llenar el Arbol, con esto aumentaria considerablemente la velocidad.&lt;br /&gt;
&lt;br /&gt;
== Reemplazar caracteres en un string ==&lt;br /&gt;
Una rutina generica para reemplazar todas las instancias de un string dentro de otro&lt;br /&gt;
&lt;br /&gt;
 Replace       PROCEDURE(string find,string replace,*cstring into)&lt;br /&gt;
 Locate LONG,AUTO&lt;br /&gt;
  CODE&lt;br /&gt;
    IF UPPER(find)&amp;lt;&amp;gt;UPPER(replace)&lt;br /&gt;
       LOOP&lt;br /&gt;
         Locate = INSTRING(UPPER(find),UPPER(into),1,1)&lt;br /&gt;
         IF ~Locate THEN RETURN .&lt;br /&gt;
         into = SUB(into,1,Locate-1) &amp;amp; replace &amp;amp;SUB(into,Locate+LEN(find),LEN(into))&lt;br /&gt;
       END&lt;br /&gt;
    END&lt;br /&gt;
&lt;br /&gt;
Para llamarlo:&lt;br /&gt;
&lt;br /&gt;
Replace(&#039;Busacr&#039;,&#039;Reemplazar&#039;,Loc:miString)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contar los threads abiertos ==&lt;br /&gt;
Este código fue posteado por Jeff Slarve&lt;br /&gt;
 ChildThreadCount Procedure!,Long&lt;br /&gt;
 Ndx   Long&lt;br /&gt;
 Count Long&lt;br /&gt;
 T     &amp;amp;Window&lt;br /&gt;
 W     &amp;amp;Window&lt;br /&gt;
  Code&lt;br /&gt;
&lt;br /&gt;
  Count = 0&lt;br /&gt;
  SetTarget&lt;br /&gt;
  T &amp;amp;= System{PROP:Target}&lt;br /&gt;
  Loop Ndx = 1 to MaxThreads&lt;br /&gt;
     SetTarget(,Ndx)&lt;br /&gt;
     W &amp;amp;= System{PROP:Target}&lt;br /&gt;
     If NOT W &amp;amp;= T&lt;br /&gt;
       Count += 1&lt;br /&gt;
     end&lt;br /&gt;
  end&lt;br /&gt;
  SetTarget&lt;br /&gt;
  Return Count&lt;br /&gt;
&lt;br /&gt;
== Permitir solo una instancia del EXE en ejecucion ==&lt;br /&gt;
En Inside the global map:&lt;br /&gt;
&lt;br /&gt;
 INCLUDE(&#039;CWUTIL.INC&#039;),ONCE&lt;br /&gt;
&lt;br /&gt;
En Global Program Setup:&lt;br /&gt;
&lt;br /&gt;
 IF NOT BeginUnique(&#039;MiAPP.exe&#039;)&lt;br /&gt;
    BEEP(BEEP:SystemExclamation)&lt;br /&gt;
    YIELD()&lt;br /&gt;
    CASE MESSAGE(&#039;El programa ya esta ejecutando..&#039;,&#039;Ho, ho...&#039;,ICON:Asterisk,BUTTON:OK,BUTTON:OK,0)&lt;br /&gt;
    OF BUTTON:OK&lt;br /&gt;
       HALT()&lt;br /&gt;
    END&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Cambiar los atributos de un archivo ==&lt;br /&gt;
(Del FAQ de SoftVelocity)&lt;br /&gt;
1. En Global Embeds&lt;br /&gt;
&lt;br /&gt;
A. Before Global Includes:&lt;br /&gt;
&lt;br /&gt;
 LPCSTR EQUATE(CSTRING)&lt;br /&gt;
 DWORD EQUATE(ULONG)&lt;br /&gt;
&lt;br /&gt;
B. Global Data: Equates de los artributos&lt;br /&gt;
&lt;br /&gt;
 FILE_ATTRIBUTE_READONLY EQUATE(00000001h)&lt;br /&gt;
 FILE_ATTRIBUTE_HIDDEN EQUATE(00000002h)&lt;br /&gt;
 FILE_ATTRIBUTE_SYSTEM EQUATE(00000004h)&lt;br /&gt;
 FILE_ATTRIBUTE_ARCHIVE EQUATE(00000020h)&lt;br /&gt;
 FILE_ATTRIBUTE_NORMAL EQUATE(00000080h)&lt;br /&gt;
 FILE_ATTRIBUTE_TEMPORARY EQUATE(00000100h)&lt;br /&gt;
&lt;br /&gt;
C. Inside Global Map:&lt;br /&gt;
&lt;br /&gt;
 Module(&#039;Win32.lib&#039;)&lt;br /&gt;
 SetFileAttributes(*CSTRING, ULONG), BOOL, RAW, PASCAL, NAME(&#039;SetFileAttributesA&#039;)&lt;br /&gt;
 GetFileAttributes(*CSTRING), ULONG, RAW, PASCAL, NAME(&#039;GetFileAttributesA&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
2. En el codigo:&lt;br /&gt;
&lt;br /&gt;
 filename CSTRING(50)&lt;br /&gt;
&lt;br /&gt;
 filename = &#039;test.txt&#039;&lt;br /&gt;
 y# = GetFileAttributes(filename) ! Leer atributos&lt;br /&gt;
 y# = SetFileAttributes(filename, FILE_ATTRIBUTE_READONLY)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Crear directorios ==&lt;br /&gt;
Hay 2 opciones:&lt;br /&gt;
&lt;br /&gt;
1- Con Clarion (no sé si estarán estas funciones en versiones anteriores de Clarion)&lt;br /&gt;
&lt;br /&gt;
En &amp;quot;Inside the Global map&amp;quot;&lt;br /&gt;
 Include(&#039;clib.clw&#039;)&lt;br /&gt;
&lt;br /&gt;
En Local Data&lt;br /&gt;
 MiDir Cstring(256)&lt;br /&gt;
 Ret     Long&lt;br /&gt;
&lt;br /&gt;
En tu embed&lt;br /&gt;
 MiDir = &#039;Dirtest&#039;&lt;br /&gt;
 Ret = MkDir(MiDir)&lt;br /&gt;
&lt;br /&gt;
2- Con API&lt;br /&gt;
En Global Embeds - inside global map:&lt;br /&gt;
&lt;br /&gt;
 MODULE(&#039;&#039;)&lt;br /&gt;
  DirAccess(*CSTRING,SHORT=0),SHORT,RAW,NAME(&#039;_access&#039;),PROC&lt;br /&gt;
  MkDir(*CSTRING),SHORT,RAW,NAME(&#039;_mkdir&#039;),PROC&lt;br /&gt;
  DirRename(*CSTRING, *CSTRING), SHORT, RAW, NAME(&#039;_rename&#039;),PROC&lt;br /&gt;
  RmDir(*CSTRING),SHORT,RAW,NAME(&#039;_rmdir&#039;),PROC&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Y en tu embebido podés poner lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 Var=&#039;O:\test&#039;      ! Ojo tiene que ser Cstring&lt;br /&gt;
 IF DirAccess(Var)&amp;lt;&amp;gt;0        !Si no existe&lt;br /&gt;
          MkDir(Var)                    !Crearlo&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
También se puede usar DirRename y RmDir para renombrar o borrar&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Modificar la posicion de un informe ==&lt;br /&gt;
&lt;br /&gt;
Este código permite modificar la posición inicial vertical y horizontal de un informe. Es útil cuando trabajamos con un formulario preimpreso o una hoja membretada y necesitamos desplazar la impresión sin necesidad de reconfigurar el programa.&lt;br /&gt;
&lt;br /&gt;
El punto embebido donde se ubica es After Open the Report.&lt;br /&gt;
&lt;br /&gt;
 !=====================================================&lt;br /&gt;
 ! MODIFICAR LA POSICION DEL INFORME&lt;br /&gt;
 ! El pie de página modificarlo sólo si se usa: &lt;br /&gt;
 ! Por ejemplo se pone ahí el Nro de página o algo así.&lt;br /&gt;
 ! No es necesario cambiar los atributos de las bandas &lt;br /&gt;
 ! de detalle adicionales que se usan en el informe.&lt;br /&gt;
 !-----------------------------------------------------&lt;br /&gt;
 DesplazamientoX =  getini(&#039;Parametros&#039;,|&lt;br /&gt;
                    &#039;DesplazamientoX&#039;,&#039;&#039;,&#039;.\prog.ini&#039;)&lt;br /&gt;
 DesplazamientoY = getini(&#039;Parametros&#039;,|&lt;br /&gt;
                    &#039;DesplazamientoY&#039;,&#039;&#039;,&#039;.\prog.ini&#039;)&lt;br /&gt;
 &lt;br /&gt;
 if DesplazamientoX or DesplazamientoY then&lt;br /&gt;
    SETTARGET(Report)&lt;br /&gt;
    x# = report{prop:Xpos}&lt;br /&gt;
    y# = report{prop:Ypos}&lt;br /&gt;
    x# += DesplazamientoX&lt;br /&gt;
    y# += DesplazamientoY&lt;br /&gt;
    target{prop:Xpos} = x#&lt;br /&gt;
    target{prop:Ypos} = y#&lt;br /&gt;
    settarget&lt;br /&gt;
 &lt;br /&gt;
    SETTARGET(Report,?Encabezado)&lt;br /&gt;
    x# = ?Encabezado{prop:Xpos}&lt;br /&gt;
    y# = ?Encabezado{prop:Ypos}&lt;br /&gt;
    x# += DesplazamientoX&lt;br /&gt;
    y# += DesplazamientoY&lt;br /&gt;
    ?Encabezado{prop:Xpos} = x#&lt;br /&gt;
    ?Encabezado{prop:Ypos} = y#&lt;br /&gt;
    settarget&lt;br /&gt;
 &lt;br /&gt;
    SETTARGET(Report,?PiePagina)&lt;br /&gt;
    x# = ?PiePagina{prop:Xpos}&lt;br /&gt;
    y# = ?PiePagina{prop:Ypos}&lt;br /&gt;
    x# += DesplazamientoX&lt;br /&gt;
    y# += DesplazamientoY&lt;br /&gt;
    ?PiePagina{prop:Xpos} = x#&lt;br /&gt;
    ?PiePagina{prop:Ypos} = y#&lt;br /&gt;
    SETTARGET&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
== Generar un informe a partir de una cola en memoria ==&lt;br /&gt;
&lt;br /&gt;
(Sin pasar por el template)&lt;br /&gt;
&lt;br /&gt;
Se puede definir en el módulo en la parte de DATA el reporte necesario y mandarlo a imprimir.&lt;br /&gt;
&lt;br /&gt;
En DATA SECTION&lt;br /&gt;
&lt;br /&gt;
 WMFQue        QUEUE&lt;br /&gt;
 PageImage       STRING(64)&lt;br /&gt;
               END&lt;br /&gt;
 ReportRunDate LONG&lt;br /&gt;
 ReportRunTime LONG&lt;br /&gt;
 !!&amp;gt; Report (portrait) &lt;br /&gt;
 Report  REPORT,AT(1000,2000,6000,7000),THOUS,PRE(RPT),FONT(&#039;Arial&#039;,10)&lt;br /&gt;
         HEADER,AT(1000,1000,6000,1000)&lt;br /&gt;
         END&lt;br /&gt;
 Detail   DETAIL&lt;br /&gt;
         END&lt;br /&gt;
         FOOTER,AT(1000,9000,6000,1000)&lt;br /&gt;
         END&lt;br /&gt;
         FORM,AT(1000,1000,6000,9000)&lt;br /&gt;
         END&lt;br /&gt;
       END&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
Luego, en el botón que imprime,  poner el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 ReportRunDate = today()&lt;br /&gt;
 ReportRunDate = today()&lt;br /&gt;
 ReportRunTime = clock()&lt;br /&gt;
 OPEN(Report)&lt;br /&gt;
 LOOP x# = 1 to records(ColaError)&lt;br /&gt;
    get(ColaError,x#)&lt;br /&gt;
    PRINT(rpt:DetalleUno)&lt;br /&gt;
 END&lt;br /&gt;
 ENDPAGE(Report)&lt;br /&gt;
 ReportPreview(WMFQue)&lt;br /&gt;
 IF GlobalResponse = RequestCompleted&lt;br /&gt;
    Report{PROP:FlushPreview} = True&lt;br /&gt;
 END&lt;br /&gt;
 CLOSE(Report)&lt;br /&gt;
 FREE(WMFQue)&lt;br /&gt;
&lt;br /&gt;
Este proceso usa el Print Preview de Clarion para visualizar el informe, por consiguiente, la apariencia es totalmente normal para el usuario&lt;br /&gt;
&lt;br /&gt;
== Proceso BATCH que funcione sincronizado con el TIMER de la ventana. ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En un proceso BATCH hecho a mano se puede operar en forma similar al report o al proccess, para eso hay que definir una pantalla que tenga el atributo TIMER (un valor de 1 es suficiente). El código fuente quedaría de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
 open(PantaTrabaja)&lt;br /&gt;
 Accept&lt;br /&gt;
 case event()&lt;br /&gt;
   of event:openwindow&lt;br /&gt;
      Display()&lt;br /&gt;
      ! Abrir pantalla, Abrir archivos, hacer el set &lt;br /&gt;
      ! Inicial&lt;br /&gt;
   of event:timer&lt;br /&gt;
      ?Mensaje{prop:text} = &#039;Procesando...&#039;&lt;br /&gt;
      display(?Mensaje)&lt;br /&gt;
      loop 2 times&lt;br /&gt;
         next(archivo)&lt;br /&gt;
         if errorcode() then &lt;br /&gt;
            FinArchivo = true&lt;br /&gt;
            Break&lt;br /&gt;
         end&lt;br /&gt;
         ! HACER AQUÍ ALGÚN PROCESO..&lt;br /&gt;
      end&lt;br /&gt;
   of event:closewindow&lt;br /&gt;
      Setcursor()&lt;br /&gt;
      Close(PantaTrabaja)&lt;br /&gt;
      Break&lt;br /&gt;
   End!case&lt;br /&gt;
 &lt;br /&gt;
 case field()&lt;br /&gt;
   of ?BotonCancelar&lt;br /&gt;
      if event() = event:accepted then&lt;br /&gt;
         message(&#039;Proceso cancelado por el usuario.&#039;)&lt;br /&gt;
         post(event:closewindow)&lt;br /&gt;
      end&lt;br /&gt;
   End&lt;br /&gt;
 end!accept&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Drop Combo a mano, con opción a todos y recuerdo de último elegido ==&lt;br /&gt;
&lt;br /&gt;
En muchos de mis informes, cuando pido parámetros asumo lo siguiente, por ejemplo: Si el código de cliente es igual a 0 (cero) se imprimen todos los clientes, sino, se imprime uno solo. Este código permite armar lo mismo con un DropCombo, agregando la opción TODOS LOS XXXX (código Cero).&lt;br /&gt;
&lt;br /&gt;
1. Definir una cola con la siguiente estructura ( por ejemplo ):&lt;br /&gt;
&lt;br /&gt;
 Cola     QUEUE,PRE(col)&lt;br /&gt;
 descri     STRING(20)&lt;br /&gt;
 codigo     SHORT&lt;br /&gt;
          END&lt;br /&gt;
	&lt;br /&gt;
2. Definir una variable local llamada por ejemplo&lt;br /&gt;
&lt;br /&gt;
 Combo1     STRING(20)&lt;br /&gt;
	&lt;br /&gt;
3.	En la pantalla definir una drop combo a mano, en el campo FROM poner el nombre de la COLA, y en el USE poner Combo1 ( no poner ?Combo1 )&lt;br /&gt;
	&lt;br /&gt;
4.	Cargar la cola según corresponda después de abrir archivos, poniendo como último dato el código 0 y el texto &#039;TODOS LOS REGISTROS&#039; y hacer un ADD(Cola,1) para que quede al principio.&lt;br /&gt;
	&lt;br /&gt;
5.	Definir una variable global ( o local estática) que va a guardar el resultado elegido:&lt;br /&gt;
&lt;br /&gt;
 Glo:codigo    short     &lt;br /&gt;
	&lt;br /&gt;
6.	En el evento open window, ANTES de abrir la ventana va el siguiente código&lt;br /&gt;
&lt;br /&gt;
 loop x# = 1 to records(Cola)&lt;br /&gt;
   get(Cola,x#)&lt;br /&gt;
   if col:codigo = glo:codigo then break.&lt;br /&gt;
 end&lt;br /&gt;
 Combo1 = col:descri&lt;br /&gt;
 ?Combo1{prop:selected} = x#&lt;br /&gt;
	&lt;br /&gt;
7.	Al hacer esto, el combo se abre posicionado en el último elemento elegido o en TODOS LOS REGISTROS  si es la primera vez.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== En un report, poner los totales en otra página ==&lt;br /&gt;
&lt;br /&gt;
En algún informe, se puede solicitar como parámetro la opción de imprimir los totales correspondientes en una página nueva. Para ello, después de abrir el report:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 if glo:totpag then&lt;br /&gt;
    settarget(report)&lt;br /&gt;
    ?TituloTotalCategoria{prop:pagebefore} = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
== En un report, cambiar el color de un campo según alguna condición ==&lt;br /&gt;
&lt;br /&gt;
Si durante la impresión de un informe se desea cambiar algún atributo (tal como el color) de un campo puede hacer lo siguiente (antes de imprimir el detalle):&lt;br /&gt;
&lt;br /&gt;
 if cl:impotota &amp;lt;&amp;gt; cl:totacalc&lt;br /&gt;
    settarget(report)&lt;br /&gt;
    ?ARC:importe{PROP:FONTCOLOR} = COLOR:RED&lt;br /&gt;
    settarget(ProgressWindow)&lt;br /&gt;
 else&lt;br /&gt;
    settarget(report)&lt;br /&gt;
    ?ARC:importe{PROP:FONTCOLOR} = COLOR:NONE&lt;br /&gt;
    settarget(ProgressWindow)&lt;br /&gt;
 end&lt;br /&gt;
 print(rpt:Detalle)  ! Imprimir la línea de detalle&lt;br /&gt;
&lt;br /&gt;
== Cerrar todas las ventanas abiertas ==&lt;br /&gt;
 LOOP Thrd# = 2 TO 64 !1 es el Frame&lt;br /&gt;
     POST(Event:CloseWindow,,Thrd#)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Abrir cualquier archivo con ShellExecute ==&lt;br /&gt;
Hay varios templates gratis que implementan Shellexecute, por ejemplo:&lt;br /&gt;
http://www.sterlingdata.com/shellex.htm&lt;br /&gt;
&lt;br /&gt;
Para hacerlo con codigo:&lt;br /&gt;
&lt;br /&gt;
En Global-embed &#039;Inside the Global Map&#039;:&lt;br /&gt;
 Module(&#039;Win32.lib&#039;)&lt;br /&gt;
 ShellExecute(Long,*CString,*CString,*CString,*CString,Short),UShort,PASCAL,RAW,NAME(&#039;ShellExecuteA&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
En Local Data&lt;br /&gt;
 LOC:Handle LONG&lt;br /&gt;
 LOC:Op     CSTRING (255)&lt;br /&gt;
 LOC:File   CSTRING (255)&lt;br /&gt;
 LOC:Path   CSTRING (255)&lt;br /&gt;
 LOC:Param  CSTRING (255)&lt;br /&gt;
 LOC:Show   LONG&lt;br /&gt;
 LOC:RetHandle LONG&lt;br /&gt;
&lt;br /&gt;
En el embed&lt;br /&gt;
 LOC:Handle = 0{PROP:Handle}&lt;br /&gt;
 LOC:Op     = &#039;Open&#039;&lt;br /&gt;
 LOC:File   = &#039;C:\TEST.TXT&#039;&lt;br /&gt;
 LOC:Path   = PATH()&lt;br /&gt;
 LOC:Param  = &#039; &#039;&lt;br /&gt;
 LOC:Show   = 1&lt;br /&gt;
 LOC:RetHandle =  ShellExecute(LOC:Handle,LOC:Op,LOC:File,LOC:Param,LOC:Path,LOC:Show)&lt;br /&gt;
 If LOC:Rethandle &amp;lt;&amp;gt; 0 Then&lt;br /&gt;
   Message(&#039;Error&#039;,&#039;Error&#039;,Icon:Exclamation)&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Abrir una pagina WEB con ShellExecute ==&lt;br /&gt;
(Ver declaraciones del API y variables en el ejemplo anterior)&lt;br /&gt;
&lt;br /&gt;
En el embed&lt;br /&gt;
 LOC:Handle = 0{PROP:Handle}&lt;br /&gt;
 LOC:Op     = &#039;Open&#039;&lt;br /&gt;
 LOC:File   = &#039;http://www.templatesclarion.com.ar&#039;&lt;br /&gt;
 LOC:Path   = &#039; &#039;&lt;br /&gt;
 LOC:Param  = &#039; &#039;&lt;br /&gt;
 LOC:Show   = 1&lt;br /&gt;
 LOC:RetHandle = ShellExecute(LOC:Handle,LOC:Op,LOC:File,LOC:Param,LOC:Path,LOC:Show)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Convertir un LONG a un String Binario ==&lt;br /&gt;
 binario=&#039;&#039; !binario es CSTRING&lt;br /&gt;
 LOOP F# = 1 TO 32&lt;br /&gt;
    IF BAND(abinario, 1) !abinario es LONG&lt;br /&gt;
        binario =  &#039;1&#039; &amp;amp; binario&lt;br /&gt;
    ELSE&lt;br /&gt;
        binario = &#039;0&#039; &amp;amp; binario&lt;br /&gt;
    END&lt;br /&gt;
    abinario = abinario / 2&lt;br /&gt;
    if abinario = 0 then break.&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Convertir un string binario a LONG ==&lt;br /&gt;
Para volver del CSTRING al LONG seria simplemente&lt;br /&gt;
 X# = EVALUATE (binario &amp;amp; &#039;b&#039;)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Copiar la QUEUE (solo lo que se esta viendo) de un browse a Excel ==&lt;br /&gt;
 Copiar=&#039;&#039; !Cstring de 4.000.000&lt;br /&gt;
 LOOP C#= 1 TO BRW1.View{Prop:Fields}&lt;br /&gt;
 !Primero una fila con los titulos&lt;br /&gt;
     Copiar= Copiar &amp;amp; ?Browse:1{PropList:Header,C#} &amp;amp; &#039;&amp;lt;9&amp;gt;&#039;&lt;br /&gt;
 END&lt;br /&gt;
 Copiar= Copiar &amp;amp;&#039;&amp;lt;13,10&amp;gt;&#039;&lt;br /&gt;
&lt;br /&gt;
 LOOP F# = 1 TO RECORDS(BRW1.Q)&lt;br /&gt;
    LOOP C#= 1 TO BRW1.View{Prop:Fields}&lt;br /&gt;
        GET(BRW1.Q, F#)&lt;br /&gt;
        Copiar= Copiar &amp;amp; FORMAT(WHAT(BRW1.Q, C#), ?Browse:1{PropList:Picture,C#}) &amp;amp; &#039;&amp;lt;9&amp;gt;&#039;&lt;br /&gt;
    END&lt;br /&gt;
    Copiar= Copiar &amp;amp;&#039;&amp;lt;13,10&amp;gt;&#039;&lt;br /&gt;
 END&lt;br /&gt;
 SETCLIPBOARD(Copiar)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Copiar el VIEW (cuidado: se lee todo) de un browse a Excel ==&lt;br /&gt;
 Copiar=&#039;&#039; !CSTRNG de 4.000.000&lt;br /&gt;
 LOOP C#= 1 TO BRW1.View{Prop:Fields}&lt;br /&gt;
     Copiar= Copiar &amp;amp; ?Browse:1{PropList:Header,C#} &amp;amp; &#039;&amp;lt;9&amp;gt;&#039;&lt;br /&gt;
 END&lt;br /&gt;
 Copiar= Copiar &amp;amp;&#039;&amp;lt;13,10&amp;gt;&#039;&lt;br /&gt;
 &lt;br /&gt;
 SET (BRW1.View)&lt;br /&gt;
 LOOP&lt;br /&gt;
    NEXT(BRW1.View)&lt;br /&gt;
    IF ERRORCODE() THEN BREAK.&lt;br /&gt;
    BRW1.SetQueueRecord&lt;br /&gt;
    LOOP C#= 1 TO BRW1.View{Prop:Fields}&lt;br /&gt;
        Copiar= Copiar &amp;amp; FORMAT(WHAT(BRW1.Q, C#), ?Browse:1{PropList:Picture,C#}) &amp;amp; &#039;&amp;lt;9&amp;gt;&#039;&lt;br /&gt;
    END&lt;br /&gt;
    Copiar= Copiar &amp;amp;&#039;&amp;lt;13,10&amp;gt;&#039;&lt;br /&gt;
 END&lt;br /&gt;
 SETCLIPBOARD(Copiar)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Para que no lea todo el contenido del archivo, sino que procese estrictamente lo mismo que muestra el browse, basta con agregar la antes del BRW1.SetQueueRecord el llamado a BRW1.ValidateRecord().&lt;br /&gt;
  ...&lt;br /&gt;
  LOOP&lt;br /&gt;
    NEXT(BRW1.View)&lt;br /&gt;
    IF ERRORCODE() THEN BREAK.&lt;br /&gt;
    IF BRW1.ValidateRecord() THEN CYCLE.&lt;br /&gt;
    BRW1.SetQueueRecrod&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
Daniel Ruzo&lt;br /&gt;
&lt;br /&gt;
== Mostrar iconos en un listbox desde una queue ==&lt;br /&gt;
Ejemplo: marcar en una cola de memoria si un empleado tiene entrada y/o salida&lt;br /&gt;
&lt;br /&gt;
Primero agregar los iconos al Project&lt;br /&gt;
&lt;br /&gt;
En el Codigo:&lt;br /&gt;
&lt;br /&gt;
 cola_empleados    queue, pre(que)&lt;br /&gt;
 nombre        string(30)&lt;br /&gt;
 entro          long&lt;br /&gt;
 entro_ico    long&lt;br /&gt;
 salio          long&lt;br /&gt;
 salio_ico    long&lt;br /&gt;
                         end&lt;br /&gt;
&lt;br /&gt;
En el list:&lt;br /&gt;
&lt;br /&gt;
primer campo: nombre&lt;br /&gt;
&lt;br /&gt;
segundo campo: entro, picture @p p, iconized, transparente&lt;br /&gt;
&lt;br /&gt;
tercer campo: salio, picture @p p, iconized, transparente&lt;br /&gt;
&lt;br /&gt;
En el init de la pantalla:&lt;br /&gt;
&lt;br /&gt;
 ?list{prop:iconlist,1} = &#039;~no.ico&#039;&lt;br /&gt;
 ?list{prop:iconlist,2} = &#039;~si.ico&#039;&lt;br /&gt;
&lt;br /&gt;
Donde cargo la cola y la muestro:&lt;br /&gt;
&lt;br /&gt;
 if condicion  (si NO hay entrada)&lt;br /&gt;
     que:entro_ico = 1    ! icono de no&lt;br /&gt;
 else&lt;br /&gt;
     que:entro_ico = 2    !icono de si&lt;br /&gt;
 end&lt;br /&gt;
 if condicion  (si NO hay salida)&lt;br /&gt;
     que:salio_ico = 1    ! icono de no&lt;br /&gt;
 else&lt;br /&gt;
     que:salio_ico = 2    !icono de si&lt;br /&gt;
 end&lt;br /&gt;
 ! otras asignaciones&lt;br /&gt;
 add(cola_empleados)&lt;br /&gt;
 !&lt;br /&gt;
 display(?list)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Calcular Días Hábiles ==&lt;br /&gt;
&lt;br /&gt;
Ante todo necesitas una tabla de feriados, con al menos un campo llamado,&lt;br /&gt;
por ej., diaferiado y una clave por dicho campo.&lt;br /&gt;
&lt;br /&gt;
Luego podés hacer lo siguiente&lt;br /&gt;
&lt;br /&gt;
 habiles# = 0&lt;br /&gt;
 loop dia# = FechaInicial to FechaFinal&lt;br /&gt;
  if (Dia# % 7) = 0 then cycle. ! porque es domingo&lt;br /&gt;
  if (Dia# % 7) = 6 then cycle. ! porque es sabado&lt;br /&gt;
  !&lt;br /&gt;
  ! busco si es feriado&lt;br /&gt;
  !&lt;br /&gt;
  clear(feriado:record)&lt;br /&gt;
  feriado:diaferiado = dia#&lt;br /&gt;
  if access:feriado.fetch(Feriado:PorDia) = level:benign then cycle. !porque es feriado&lt;br /&gt;
  !&lt;br /&gt;
  habiles# += 1&lt;br /&gt;
 end!loop&lt;br /&gt;
 corridos# = fechafinal - fechainicial&lt;br /&gt;
&lt;br /&gt;
Si los cálculos que vas a realizar son muchos y continuos, sería conveniente&lt;br /&gt;
que la tabla de feriados la cargues en una queue y realices las búsquedas&lt;br /&gt;
sobre ella.&lt;br /&gt;
&lt;br /&gt;
Adrian Gallegos - Mega Sistemas S.R.L.&lt;br /&gt;
&lt;br /&gt;
Otra opción: Días Hábiles del mes - Rutina que quita los días sábados y domingos del mes&lt;br /&gt;
&lt;br /&gt;
CONTAR_DIAS ROUTINE&lt;br /&gt;
    LOC:DIAS = 0&lt;br /&gt;
    tope# = 1&lt;br /&gt;
    LOOP UNTIL DAY(LOC:FECHA) = tope#&lt;br /&gt;
    CASE  LOC:FECHA % 7&lt;br /&gt;
      of  0   ! Domingo&lt;br /&gt;
       LOC:FECHA = LOC:FECHA - 1&lt;br /&gt;
       CYCLE&lt;br /&gt;
      of  6    ! sabado&lt;br /&gt;
       LOC:FECHA = LOC:FECHA - 1&lt;br /&gt;
       CYCLE&lt;br /&gt;
      ELSE&lt;br /&gt;
       LOC:DIAS += 1&lt;br /&gt;
       LOC:FECHA = LOC:FECHA - 1&lt;br /&gt;
     END !CASE&lt;br /&gt;
   END !LOOP&lt;br /&gt;
   IF  LOC:FECHA % 7 = 0 or  LOC:FECHA % 7 = 6 THEN  !si el primero es feriado&lt;br /&gt;
         ! nada&lt;br /&gt;
          else&lt;br /&gt;
         LOC:DIAS  += 1&lt;br /&gt;
   END !IF&lt;br /&gt;
&lt;br /&gt;
Julio César Britez&lt;br /&gt;
&lt;br /&gt;
== Último día del mes y cantidad de días (Lunes, Martes, etc) entre 2 Fechas ==&lt;br /&gt;
Incluye el truco de saber el último día del mes: en la parte &amp;quot; Date(4,1,2005)-1 &amp;quot; significa que le resto 1 al primer día del mes siguiente, lo cual es una forma de obtener el último día del mes actual...&lt;br /&gt;
&lt;br /&gt;
 Loop Fecha# = Date(3,1,2005) TO (Date(4,1,2005)-1)&lt;br /&gt;
    EXECUTE (Fecha# % 7) + 1&lt;br /&gt;
          Domingo# +=1&lt;br /&gt;
          Lunes# +=1&lt;br /&gt;
          Martes# +=1&lt;br /&gt;
          Miercoles# +=1&lt;br /&gt;
          Jueves# +=1&lt;br /&gt;
          Viernes# +=1&lt;br /&gt;
          Sabado# +=1&lt;br /&gt;
    END&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Fecha en Español (por ejemplo en el Frame)==&lt;br /&gt;
Si quieres que funcione independientemente de como este configurado windows,&lt;br /&gt;
lo mejor es poner este embed, al final de WindowManager.Init&lt;br /&gt;
&lt;br /&gt;
 EXECUTE (TODAY() % 7) + 1&lt;br /&gt;
 Dia&amp;quot;= &#039;Domingo&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Lunes&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Martes&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Miercoles&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Jueves&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Viernes&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Sabado&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
 EXECUTE (MONTH(TODAY()))&lt;br /&gt;
 Mes&amp;quot; = &#039;Enero&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Febrero&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Marzo&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Abril&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Mayo&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Junio&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Julio&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Agosto&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Septiembre&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Octubre&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Noviembre&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Diciembre&#039;&lt;br /&gt;
 END&lt;br /&gt;
 AppFrame{Prop:StatusText,1} = CLIP(Dia&amp;quot;) &amp;amp; &#039; &#039; &amp;amp; DAY(TODAY()) &amp;amp; &#039; de &#039; &amp;amp;&lt;br /&gt;
 CLIP(Mes&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
 Dia&amp;quot; = Choose(((TODAY() % 7) + 1),&#039;Domingo&#039;,&#039;Lunes&#039;,&#039;Martes&#039;,&#039;Miercoles&#039;,&#039;Jueves&#039;,&#039;Viernes&#039;,&#039;Sabado&#039;)&lt;br /&gt;
&lt;br /&gt;
Javier A. Junca Barreto [http://www.sicya.com (SICyA Software - Colombia)]&lt;br /&gt;
&lt;br /&gt;
== Obtener la fecha del server ==&lt;br /&gt;
Este código lee la fecha del servidor, usando el truco de crear un archivo en el servidor y leer la fecha y hora de los atributos:&lt;br /&gt;
&lt;br /&gt;
 !Data&lt;br /&gt;
 LOC:TMP STRING(254),STATIC&lt;br /&gt;
 TMP FILE,DRIVER(&#039;Ascii&#039;),CREATE,NAME(LOC:TMP)&lt;br /&gt;
 RECORD  RECORD&lt;br /&gt;
 LIN STRING(1)&lt;br /&gt;
    .&lt;br /&gt;
    .&lt;br /&gt;
 FILS   QUEUE(File:queue),PRE(FIL)&lt;br /&gt;
       END&lt;br /&gt;
&lt;br /&gt;
 CODE&lt;br /&gt;
  LOC:TMP = PATH()&amp;amp;&#039;\TMP&#039;&amp;amp;RANDOM(10000,99999)&amp;amp;&#039;.TMP&#039;&lt;br /&gt;
  CREATE(TMP)&lt;br /&gt;
  IF NOT ERRORCODE()&lt;br /&gt;
    DIRECTORY(FILS,LOC:TMP,0)&lt;br /&gt;
    REMOVE(TMP)&lt;br /&gt;
    GET(FILS,1)&lt;br /&gt;
    IF TODAY() &amp;lt;&amp;gt; FIL:DATE OR ABS(CLOCK()-FIL:TIME) &amp;gt; 100&lt;br /&gt;
 !FECHA DIFERENTE O 1 SEGUNDO DE DESFASE&lt;br /&gt;
      SETTODAY(FIL:DATE)&lt;br /&gt;
      SETCLOCK(FIL:TIME)&lt;br /&gt;
    END&lt;br /&gt;
  ELSE&lt;br /&gt;
    REMOVE(TMP)&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
Carlos Gutierrez&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Con SQL&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La sugerencia de Carlos es muy buena. Si estás usando SQL o drivers ODBC, la otra opción es preguntarle la fecha al motor de base de datos.&lt;br /&gt;
&lt;br /&gt;
La forma genérica de hacerlo es:&lt;br /&gt;
 temp{prop:sql}=&#039;SELECT {fn curdate() }&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Con NET TIME&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Posteado por Diego Sánchez al foro.&lt;br /&gt;
 Run(&#039;NET TIME \\Server_Name /SET /Y&#039;)&lt;br /&gt;
Reemplazar  &amp;quot;Server_Name&amp;quot;  por el nombre del servidor o equipo del cual se desea obtener la hora&lt;br /&gt;
Fue posteado originalmente por un NICOLAS VEILLEUX nveilleux@nbautomation.com, en el foro comp.lang.clarion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Llamar a un Stored Procedure ==&lt;br /&gt;
El código sería mas o menos asi:&lt;br /&gt;
 L:Query = &#039;CALL NombreDelStored (&#039;&#039;&#039; &amp;amp; FORMAT(ParamFecha,@D12) &amp;amp; &#039;&#039;&#039;, &#039;&#039;&#039; &amp;amp;&lt;br /&gt;
 FORMAT(OtraFecha,@D12) &amp;amp; &#039;&#039;&#039;, &#039; &amp;amp; OtroParam1 &amp;amp;&#039;, &#039; &amp;amp; OtroParam2 &amp;amp;&#039;, &#039; &amp;amp;&lt;br /&gt;
 OtroParam3 &amp;amp;&#039;  )&#039;&lt;br /&gt;
&lt;br /&gt;
 ResSQL{prop:sql} = L:Query&lt;br /&gt;
 Loop Until Access:ResSql.Next()&lt;br /&gt;
    MiVariable = R:Campo1&lt;br /&gt;
    etc     = R:Campo2&lt;br /&gt;
 ....&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
En la tabla auxiliar ResSQL obtienes el resultado del último SELECT que&lt;br /&gt;
tenga el Stored Procedure.&lt;br /&gt;
&lt;br /&gt;
Para mas detalles ver el documento sobre SQL Embebido [http://templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
También recomiendo leer el help &amp;quot;MSSQL Accelerator Calling a Stored&lt;br /&gt;
Procedure&amp;quot;. Ahi está explicado además el uso de valores de retorno y parámetros de salida.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Encriptación básica ==&lt;br /&gt;
Encriptación / desencriptación básica de un campo usando el metodo XOR.&lt;br /&gt;
 !la primera vez encripta&lt;br /&gt;
 !al volver a aplicar el algoritmo con la misma&lt;br /&gt;
 !Clave de encriptado: desencripta&lt;br /&gt;
 X# = 1&lt;br /&gt;
 loop Y# = 1 to Len(Campo)&lt;br /&gt;
   Campo [Y#] = chr(bxor(val(Campo[Y#]), val(ClaveEncriptado[X#])))&lt;br /&gt;
   X# += 1&lt;br /&gt;
   if X# &amp;gt; len (ClaveEncriptado) then X# = 1.&lt;br /&gt;
 end&lt;br /&gt;
 display&lt;br /&gt;
&lt;br /&gt;
 !Campo y ClaveEncriptado son campos CString&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Generar un archivo de Texto a máxima velocidad==&lt;br /&gt;
Estas son las APIs para generar un archivo de texto sin necesidad de declararlo en el Diccionario.&lt;br /&gt;
&lt;br /&gt;
Además es muy rápido, ideal para exportaciones.&lt;br /&gt;
&lt;br /&gt;
En Global - Inside Global map:&lt;br /&gt;
&lt;br /&gt;
 MODULE(&#039;Windows API&#039;)&lt;br /&gt;
  _lcreat(*CSTRING,SIGNED),SIGNED,PASCAL,RAW&lt;br /&gt;
  _hwrite(SIGNED,*CSTRING,LONG),LONG,PASCAL,RAW&lt;br /&gt;
  _lclose(SIGNED),SIGNED,PASCAL&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para guardar el contenido de un control Text&lt;br /&gt;
&lt;br /&gt;
 IF NOT FILEDIALOG(&#039;Guardar como&#039;,FileName,&#039;Text|*.TXT|Source|*.CLW&#039;,FILE:Save + FILE:LongName)&lt;br /&gt;
    CYCLE&lt;br /&gt;
 END&lt;br /&gt;
 F# = _lcreat(FileName,0)&lt;br /&gt;
 X# = _hwrite(F#,Texto,LEN(Texto))&lt;br /&gt;
 X# = _lclose(F#)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Efecto BLINK en un campo ==&lt;br /&gt;
Tienes que crear un timer en la ventana, para eso ponle cada cuanto se va a&lt;br /&gt;
ejecutar en la propiedad timer de la ventana. Son centesimas de seg, asi que&lt;br /&gt;
si le pones 50 por ejemplo tu campo va a titilar 2 veces por segundo.&lt;br /&gt;
&lt;br /&gt;
Luego cierra la ventana, vuelve a entrar y vas a encontrar un evento timer&lt;br /&gt;
de la ventana en los embeds.&lt;br /&gt;
&lt;br /&gt;
Window Events --&amp;gt; Timer&lt;br /&gt;
 if ?campo{prop:background} = COLOR:WHITE&lt;br /&gt;
    ?campo{prop:background} = COLOR:SILVER&lt;br /&gt;
 else&lt;br /&gt;
    ?campo{prop:background} = COLOR:WHITE&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Función para calcular dígito verificador en CUIT ==&lt;br /&gt;
- La siguiente función devuelve el numero de CUIT con el dígito verificador&lt;br /&gt;
correcto.&lt;br /&gt;
- El parámetro que recibe es el numero de CUIT a revisar incluyendo el&lt;br /&gt;
dígito verificador.&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  CuitCliente=&#039;20-15433984-6&#039;&lt;br /&gt;
  IF Cuit(CuitCliente)=CuitCliente THEN&lt;br /&gt;
    MESSAGE(&#039;Digito verificador correcto&#039;)&lt;br /&gt;
  ELSE&lt;br /&gt;
    MESSAGE(&#039;Digito verificador incorrecto&#039;)&lt;br /&gt;
  END&lt;br /&gt;
  ...&lt;br /&gt;
 &lt;br /&gt;
 Cuit         PROCEDURE(cuit1)&lt;br /&gt;
 cuit2        STRING(255)&lt;br /&gt;
 digver       LONG&lt;br /&gt;
 lon          LONG&lt;br /&gt;
 fac          LONG&lt;br /&gt;
 car          STRING(1)&lt;br /&gt;
   &lt;br /&gt;
  CODE&lt;br /&gt;
  cuit2=cuit1&lt;br /&gt;
  digver=0&lt;br /&gt;
  fac=2&lt;br /&gt;
  lon=LEN(CLIP(cuit2))&lt;br /&gt;
  LOOP i#=lon-1 TO 1 BY -1&lt;br /&gt;
    car=SUB(cuit2,i#,1)&lt;br /&gt;
    IF car&amp;lt;&#039;0&#039; OR car&amp;gt;&#039;9&#039; THEN&lt;br /&gt;
      CYCLE&lt;br /&gt;
    .&lt;br /&gt;
    digver=digver+(car*fac)&lt;br /&gt;
    fac+=1&lt;br /&gt;
    IF fac&amp;gt;7 THEN&lt;br /&gt;
      fac=2&lt;br /&gt;
    .&lt;br /&gt;
  .&lt;br /&gt;
  digver=11-(digver%11)&lt;br /&gt;
  IF digver&amp;gt;9 THEN&lt;br /&gt;
    digver=0&lt;br /&gt;
  .&lt;br /&gt;
  cuit2=SUB(cuit2,1,lon-1) &amp;amp; FORMAT(digver,@n01)&lt;br /&gt;
  RETURN(cuit2)&lt;br /&gt;
&lt;br /&gt;
Este codigo esta en la documentacion del template de Impresoras Fiscales&lt;br /&gt;
(BIGSYS TEMPLATES) del amigo Juan Carlos Rodríguez&lt;br /&gt;
&lt;br /&gt;
== Validar Email ==&lt;br /&gt;
Puedes hacerlo con MATCH, el cual devuelve 1 o 0 si el mail no es valido.&lt;br /&gt;
Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# =  MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Restar Horas==&lt;br /&gt;
Para sacar la diferencia entre horas es simplemente:&lt;br /&gt;
 resultado = hora2  - hora + 1&lt;br /&gt;
&lt;br /&gt;
El +1 es porque sino que faltaria un segundo cuando muestres el resultado (en formato @T6, por ej)&lt;br /&gt;
&lt;br /&gt;
Si Hora2 es del dia siguiente, la cuenta seria:&lt;br /&gt;
 resultado = (hora2 +(100*60*60*24)) - hora + 1&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Digito Verificador para 5 digitos ==&lt;br /&gt;
&lt;br /&gt;
Si tenes un numero de 5 digitos y deses verificar que el mismo es ingresado correctamente podes usar este codigo que genera un digito verificador&lt;br /&gt;
&lt;br /&gt;
Crea una funcion que tenga un parametro (numero a verificar) y retorne el digito verificador correspondiente ejem: DigitoV5(LONG xNumero),BYTE&lt;br /&gt;
&lt;br /&gt;
  loc:Numero = xNumero&lt;br /&gt;
 &lt;br /&gt;
  loc:Valor = (loc:Numero[1]*5) + |&lt;br /&gt;
              (loc:Numero[2]*4) + |&lt;br /&gt;
              (loc:Numero[3]*3) + |&lt;br /&gt;
              (loc:Numero[4]*2) + |&lt;br /&gt;
              (loc:Numero[5]*7)&lt;br /&gt;
 &lt;br /&gt;
  IF (loc:Valor%5) + 1 = 0 OR (loc:Valor%5) + 1 = 1&lt;br /&gt;
    loc:Digito = 0&lt;br /&gt;
  ELSE&lt;br /&gt;
    loc:Digito = 6 - ((loc:Valor%5) + 1)&lt;br /&gt;
  END&lt;br /&gt;
 &lt;br /&gt;
  RETURN loc:Digito&lt;br /&gt;
&lt;br /&gt;
Ruben Garcia [http://www.dipsarg.com (DiPS)]&lt;br /&gt;
&lt;br /&gt;
== Digito Verificador para Cualquier Longitud ==&lt;br /&gt;
&lt;br /&gt;
Si no sabes que longitud puede tener el numero a verificar podes probar verificarla con este codigo&lt;br /&gt;
&lt;br /&gt;
Crea una funcion cuyo parametro es el numero a verificar y retorne el digito verificador. Ej. DigitoV(STRING xNumero),BYTE&lt;br /&gt;
&lt;br /&gt;
  !Inicializa&lt;br /&gt;
  loc:Numero   = xNumero&lt;br /&gt;
  loc:Valor    = 0&lt;br /&gt;
  loc:Multiplo = 1&lt;br /&gt;
 &lt;br /&gt;
  !Barrido y calculo&lt;br /&gt;
  LOOP loc:Posicion = LEN(CLIP(loc:Numero)) TO 1 BY -1&lt;br /&gt;
    loc:Multiplo += 1&lt;br /&gt;
    IF loc:Multiplo &amp;gt; 7&lt;br /&gt;
      loc:Multiplo = 2&lt;br /&gt;
    END&lt;br /&gt;
    loc:Valor += loc:Numero[loc:Posicion] * loc:Multiplo&lt;br /&gt;
  END&lt;br /&gt;
 &lt;br /&gt;
  loc:Digito = loc:Valor % 11&lt;br /&gt;
 &lt;br /&gt;
  IF loc:Digito = 10&lt;br /&gt;
    loc:Digito = 0&lt;br /&gt;
  END&lt;br /&gt;
 &lt;br /&gt;
  RETURN loc:Digito&lt;br /&gt;
&lt;br /&gt;
Ruben Garcia [http://www.dipsarg.com (DiPS)]&lt;br /&gt;
&lt;br /&gt;
== Autoincremento Manual == &lt;br /&gt;
&lt;br /&gt;
Esto se utiliza cuando tenemos una tabla en la cual queremos manejar la clave de auto incremento &lt;br /&gt;
&lt;br /&gt;
 CLEAR(MASTER)&lt;br /&gt;
 SET(MAS:ClavePorID, MAS:ClavePorID)&lt;br /&gt;
 ACCES:MASTER.Previous()&lt;br /&gt;
 IF MAS:Id = 0 THEN &lt;br /&gt;
     MAS:Id = 1&lt;br /&gt;
 ELSE &lt;br /&gt;
     MAS:Id = MAS:Id +1 &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
!!!MAS:Id TENDRÍA EL VALOR DEL PROXIMO NUMERO.- &lt;br /&gt;
&lt;br /&gt;
Gracias [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Nota: El mecanismo descrito es &amp;quot;confiable&amp;quot; sólo para aplicaciones que usan TPS y en modo single-user. Para Multiusuario y SQL hay que tener cuidado con las lecturas simultáneas del último valor. &lt;br /&gt;
También puede simplificarse el &amp;quot;if ... then ... else ...&amp;quot; como &amp;quot;MAS:Id = MAS:Id +1&amp;quot; (si es cero, será 1, no hace falta chequearlo)&lt;br /&gt;
&lt;br /&gt;
== Desabilitar menu desde cualquier procedimiento ==&lt;br /&gt;
Una opcion seria usando NOTIFY.&lt;br /&gt;
En el Frame&lt;br /&gt;
 Window Events&lt;br /&gt;
    Notify&lt;br /&gt;
        DISABLE = VariableGlobal&lt;br /&gt;
&lt;br /&gt;
En cualquier procedimiento que se necesite deshabilitar un menu&lt;br /&gt;
&lt;br /&gt;
 VariableGlobal = Nro de Use del Menu&lt;br /&gt;
 NOTIFY (999, 1)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que no estoy usando ese parametro.&lt;br /&gt;
(bueno, en realidad podria usar ese parametro en lugar de la global...)&lt;br /&gt;
1 es el Tread del Frame&lt;br /&gt;
&lt;br /&gt;
Como desde los otros procedimientos no existen los use del los items de menu&lt;br /&gt;
(o sea ?menuitem) lo que hay que hacer es ponerles un numero a cada uno.&lt;br /&gt;
Esto se logra poniendolos de esta manera ?use, numero en la definicion del&lt;br /&gt;
menu.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
==Formatear fechas en SQL ==&lt;br /&gt;
Les paso una función que utilizo para trabajar con las fechas en el SQL parecido al format de clarion. Es muy útil.&lt;br /&gt;
  &lt;br /&gt;
  CREATE FUNCTION dbo.FormatDateTime&lt;br /&gt;
  (&lt;br /&gt;
      @dt DATETIME,&lt;br /&gt;
      @format VARCHAR(16)&lt;br /&gt;
  )&lt;br /&gt;
  RETURNS VARCHAR(64)&lt;br /&gt;
  AS&lt;br /&gt;
  BEGIN&lt;br /&gt;
      DECLARE @dtVC VARCHAR(64)&lt;br /&gt;
      SELECT @dtVC = CASE @format&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;LONGDATE&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          DATENAME(dw, @dt)&lt;br /&gt;
          + &#039;,&#039; + SPACE(1) + DATENAME(m, @dt)&lt;br /&gt;
          + SPACE(1) + CAST(DAY(@dt) AS VARCHAR(2))&lt;br /&gt;
          + &#039;,&#039; + SPACE(1) + CAST(YEAR(@dt) AS CHAR(4))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;LONGDATEANDTIME&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          DATENAME(dw, @dt)&lt;br /&gt;
          + &#039;,&#039; + SPACE(1) + DATENAME(m, @dt)&lt;br /&gt;
          + SPACE(1) + CAST(DAY(@dt) AS VARCHAR(2))&lt;br /&gt;
          + &#039;,&#039; + SPACE(1) + CAST(YEAR(@dt) AS CHAR(4))&lt;br /&gt;
          + SPACE(1) + RIGHT(CONVERT(CHAR(20),&lt;br /&gt;
          @dt - CONVERT(DATETIME, CONVERT(CHAR(8),&lt;br /&gt;
          @dt, 112)), 22), 11)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;SHORTDATE&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          LEFT(CONVERT(CHAR(19), @dt, 0), 11)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;SHORTDATEANDTIME&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          REPLACE(REPLACE(CONVERT(CHAR(19), @dt, 0),&lt;br /&gt;
              &#039;AM&#039;, &#039; AM&#039;), &#039;PM&#039;, &#039; PM&#039;)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;UNIXTIMESTAMP&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CAST(DATEDIFF(SECOND, &#039;19700101&#039;, @dt)&lt;br /&gt;
          AS VARCHAR(64))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;YYYYMMDD&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 112)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;YYYY-MM-DD&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(10), @dt, 23)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;YYMMDD&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(VARCHAR(8), @dt, 12)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;YY-MM-DD&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          STUFF(STUFF(CONVERT(VARCHAR(8), @dt, 12),&lt;br /&gt;
          5, 0, &#039;-&#039;), 3, 0, &#039;-&#039;)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;MMDDYY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          REPLACE(CONVERT(CHAR(8), @dt, 10), &#039;-&#039;, SPACE(0))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;MM-DD-YY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 10)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;MM/DD/YY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 1)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;MM/DD/YYYY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(10), @dt, 101)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;DDMMYY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          REPLACE(CONVERT(CHAR(8), @dt, 3), &#039;/&#039;, SPACE(0))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;DD-MM-YY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          REPLACE(CONVERT(CHAR(8), @dt, 3), &#039;/&#039;, &#039;-&#039;)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;DD/MM/YY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 3)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;DD/MM/YYYY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(10), @dt, 103)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;HH:MM:SS 24&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 8)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;HH:MM 24&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          LEFT(CONVERT(VARCHAR(8), @dt, 8), 5)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;HH:MM:SS 12&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          LTRIM(RIGHT(CONVERT(VARCHAR(20), @dt, 22), 11))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;HH:MM 12&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          LTRIM(SUBSTRING(CONVERT(&lt;br /&gt;
          VARCHAR(20), @dt, 22), 10, 5)&lt;br /&gt;
          + RIGHT(CONVERT(VARCHAR(20), @dt, 22), 3))&lt;br /&gt;
  &lt;br /&gt;
      ELSE&lt;br /&gt;
  &lt;br /&gt;
          &#039;Invalid format specified&#039;&lt;br /&gt;
  &lt;br /&gt;
      END&lt;br /&gt;
      RETURN @dtVC&lt;br /&gt;
  END&lt;br /&gt;
  GO&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  Ejemplos:&lt;br /&gt;
  &lt;br /&gt;
  DECLARE @now DATETIME&lt;br /&gt;
  SET @now = GETDATE()&lt;br /&gt;
  &lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;LONGDATE&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;LONGDATEANDTIME&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;SHORTDATE&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;SHORTDATEANDTIME&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;UNIXTIMESTAMP&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;YYYYMMDD&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;YYYY-MM-DD&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;YYMMDD&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;YY-MM-DD&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;MMDDYY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;MM-DD-YY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;MM/DD/YY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;MM/DD/YYYY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;DDMMYY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;DD-MM-YY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;DD/MM/YY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;DD/MM/YYYY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;HH:MM:SS 24&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;HH:MM 24&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;HH:MM:SS 12&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;HH:MM 12&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;goofy&#039;) &lt;br /&gt;
  &lt;br /&gt;
Posteado al foro por Omar Squiabro&lt;br /&gt;
&lt;br /&gt;
== Anular Tecla Escape ==&lt;br /&gt;
&lt;br /&gt;
Hay veces que se necesita que el usuario salga de una FORM o de una ventana solo cuando pulse un determinado boton o se halla completado alguna condicion. Y en estos casos puede suceder que si el usuario pulsa la tecla ESC cause algun problema&lt;br /&gt;
&lt;br /&gt;
Primero hay que activar la alerta de la tecla esc en el INIT de la ventana&lt;br /&gt;
&lt;br /&gt;
  ALERT(EscKey)&lt;br /&gt;
&lt;br /&gt;
Despues en el evento alertkey&lt;br /&gt;
&lt;br /&gt;
  IF KEYCODE() = EscKey&lt;br /&gt;
    SELECT(?UnDeterminadoCampo)  !1= al primero&lt;br /&gt;
    RETURN Level:Notify          &lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
Si el codigo embebido es puesto despues del codigo generado por clarion reemplazar el RETURN por CYCLE&lt;br /&gt;
&lt;br /&gt;
Ruben Garcia [http://www.programaya.com (DiPS)]&lt;br /&gt;
&lt;br /&gt;
== Convertir Número Hexadecimal a Binario ==&lt;br /&gt;
A veces, y sobre todo al trabajar con estados de puertos de comunicaciones, necesitamos convertir numeros hexadecimales a binario para establecer errores o tratar envios y recepciones.&lt;br /&gt;
Esta función hace justamente esto de forma sencilla.&lt;br /&gt;
&lt;br /&gt;
 HexaABinario         PROCEDURE(PAR:Nhexa)   ! (String),String&lt;br /&gt;
 HBinario   String(4),dim(16) !Equivalencias&lt;br /&gt;
 RetuBina   String(100)       !Variable Retorno&lt;br /&gt;
&lt;br /&gt;
  CODE&lt;br /&gt;
   HBinario[01] = &#039;0000&#039; !     0h&lt;br /&gt;
   HBinario[02] = &#039;0001&#039; !     1h&lt;br /&gt;
   HBinario[03] = &#039;0010&#039; !     2h&lt;br /&gt;
   HBinario[04] = &#039;0011&#039; !     3h&lt;br /&gt;
   HBinario[05] = &#039;0100&#039; !     4h&lt;br /&gt;
   HBinario[06] = &#039;0101&#039; !     5h &lt;br /&gt;
   HBinario[07] = &#039;0110&#039; !     6h&lt;br /&gt;
   HBinario[08] = &#039;0111&#039; !     7h&lt;br /&gt;
   HBinario[09] = &#039;1000&#039; !     8h &lt;br /&gt;
   HBinario[10] = &#039;1001&#039; !     9h&lt;br /&gt;
   HBinario[11] = &#039;1010&#039; !     Ah  65&lt;br /&gt;
   HBinario[12] = &#039;1011&#039; !     Bh  66&lt;br /&gt;
   HBinario[13] = &#039;1100&#039; !     Ch  67&lt;br /&gt;
   HBinario[14] = &#039;1101&#039; !     Dh  68&lt;br /&gt;
   HBinario[15] = &#039;1110&#039; !     Eh  69&lt;br /&gt;
   HBinario[16] = &#039;1111&#039; !     Fh  70&lt;br /&gt;
   CLEAR(RetuBina)&lt;br /&gt;
   PAR:NHexa = UPPER(PAR:NHexa) !Aseguro letras en mayusculas&lt;br /&gt;
   LOOP I# = 1 to LEN(CLIP(PAR:NHexa))&lt;br /&gt;
     IF NUMERIC(PAR:NHexa[I#]) THEN  !Si es numero es &amp;lt;= 9&lt;br /&gt;
        !Asigno equivalente&lt;br /&gt;
        RetuBina = CLIP(RetuBina) &amp;amp; HBinario[PAR:NHexa[I#]+1]&lt;br /&gt;
     ELSE&lt;br /&gt;
       !Asigno equivalente tomando,por ejemplo, 65 - 54 = 11 para &amp;quot;A&amp;quot;&lt;br /&gt;
        RetuBina = CLIP(RetuBina) &amp;amp; HBinario[VAL(PAR:NHexa[I#])-54]&lt;br /&gt;
     END&lt;br /&gt;
   END&lt;br /&gt;
   !Retorno la cadena binaria sin ceros a la izquierda&lt;br /&gt;
   RETURN(SUB(RetuBina, INSTRING(&#039;1&#039;,RetuBina), LEN(CLIP(RetuBina)))) &lt;br /&gt;
&lt;br /&gt;
Bueno, espero les sea de utilidad!&lt;br /&gt;
&lt;br /&gt;
Mario A. Wojcik&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=81</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=81"/>
		<updated>2015-03-08T00:03:08Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento gratuitas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
[news://news.softvelocity.com/softvelocity.clarion.intl.spanish Grupo de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
=== Clarionhub (en inglés) ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionhub.com www.clarionhub.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://faq.clarionmag.com ClarionFAQ en Clarion Magazine]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Sitio web de soporte de Nettalk de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ ClarionLive (Webinars y tutoriales muy útiles)]&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/download/ Manuales y Howto&#039;s de Clarion Templates (en español)]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://http://templatesclarion.com.ar/downloads/ Templates Clarion - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=77</id>
		<title>Puntos Embebidos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=77"/>
		<updated>2015-03-07T23:06:17Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Cuando se produce el borrado sin abrir el Form */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los puntos embebidos son la pesadilla de todo principiante de Clarion. Son extremadamente útiles, pero son muy difíciles de aprender. Para colmo, la abstracción que implementa la clase ABC hace más difícil todavía conocerlos y aprovecharlos. Por eso esta sección es de vital importancia.&lt;br /&gt;
&lt;br /&gt;
== FORMULARIOS ==&lt;br /&gt;
=== ¿Qué procedimiento llamó al Form? ===&lt;br /&gt;
Al principio del WindowManager.Init del Form (primer prioridad disponible)&lt;br /&gt;
&lt;br /&gt;
 GlobalErrors.GetProcedureName()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones complejas ===&lt;br /&gt;
Por ejemplo validar un Email:&lt;br /&gt;
En el accepted del campo&lt;br /&gt;
Puedes hacerlo con MATCH, ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# = MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
Devuelve 1 o 0 si el mail no es válido.&lt;br /&gt;
El MATCH puede usarse con expresiones regulares para validar casi cualquier cosa...&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se Abre/inicializa el Form ===&lt;br /&gt;
ThisWindow.Init&lt;br /&gt;
 !Es interesante entrar por el botón source a este embed para entender bien todas sus prioridades&lt;br /&gt;
 !GlobalRequest (pasada por el browse) se guarda en la propiedad ThisWindow.Request&lt;br /&gt;
 !Se puede preguntar por SELF.Request para saber para qué se lo llamó al form: &lt;br /&gt;
 !InsertRecord EQUATE (1)&lt;br /&gt;
 !ChangeRecord EQUATE (2)&lt;br /&gt;
 !DeleteRecord EQUATE (3)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar el Form a &amp;quot;Solo lectura&amp;quot; ante una condición===&lt;br /&gt;
 ThisWindow.Init&lt;br /&gt;
 ! [Priority 4950] La prioridad es importante!&lt;br /&gt;
 IF FAC:facturado = 1 THEN SELF.Request = ViewRecord.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Truco: Llamar al form para insertar desde el menú ===&lt;br /&gt;
Podríamos asumir que si la GlobalRequest está en blanco es que se lo&lt;br /&gt;
llamó para insertar, evitaríamos asi el paso por un Browse&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !If GlobalRequest = 0 Then GlobalRequest = InsertRecord.&lt;br /&gt;
&lt;br /&gt;
Si la tabla tiene una clave Autonumber, se complica un poco mas, sería asi:&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !Por ej prioridad 300&lt;br /&gt;
 If GlobalRequest = 0&lt;br /&gt;
     GlobalRequest = InsertRecord&lt;br /&gt;
     DesdeMenu# = True&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
 !Después de Open Files:&lt;br /&gt;
 !Por ej prioridad 7800&lt;br /&gt;
 If DesdeMenu# = True&lt;br /&gt;
 Access:People.PrimeAutoinc()&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Llamar a un form para editar una tabla con un solo registro ===&lt;br /&gt;
Típicamente una tabla de parametros, obviamente no queremos pasar por un browse&lt;br /&gt;
 WindowManager.Init,&lt;br /&gt;
 !al principio&lt;br /&gt;
 GlobalRequest = ChangeRecord&lt;br /&gt;
&lt;br /&gt;
 !Luego de Open files&lt;br /&gt;
 Set(Tabla)&lt;br /&gt;
 access:Tabla.Next()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se confirma un Form ===&lt;br /&gt;
ThisWindow.TakeCompleted&lt;br /&gt;
 ! [Priority 2800]&lt;br /&gt;
 !ANTES DE QUE SE CONFIRME LA GRABACION&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 ReturnValue = PARENT.TakeCompleted()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 !YA SE GRABÓ EL REGISTRO.&lt;br /&gt;
 !VERIFICAR SI SELF.Response=RequestCompleted A VER SI SE GRABÓ OK.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se cierra un Form ===&lt;br /&gt;
ThisWindow.Kill&lt;br /&gt;
 !VERIFICAR LOS valores de SELF.Request y SELF.Response&lt;br /&gt;
 !Para decidir que acciones tomar&lt;br /&gt;
 !Este punto ya es &amp;quot;demasiado tarde&amp;quot; para hacer algo antes de que se grabe el registro&lt;br /&gt;
 !Para eso usar TakeCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se produce el borrado sin abrir el Form ===&lt;br /&gt;
Si tenemos un form para actualizar una tabla, y definimos que el borrado sea Confirmando (Standard Warning) o Automático (Automatic Delete), y necesitamos ejecutar un código en el form cuando se efectúe el borrado, usamos:&lt;br /&gt;
&lt;br /&gt;
ThisWindow.PrimeUpdate, después del Parent Call&lt;br /&gt;
&lt;br /&gt;
 if self.request = DeleteRecord and self.Response = RequestCompleted&lt;br /&gt;
 !lo que quiero hacer&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que el borrado de un registro no pasa por el TakeCompleted, excepto cuando se usa la ventana del form (Display Form).&lt;br /&gt;
&lt;br /&gt;
Aporte de Gustavo Olmedo [http://templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó cualquier campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
En el TakeCompleted ponemos el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF NOT SELF.Primary.Me.EqualBuffer(SELF.Saved)&lt;br /&gt;
 ! message(&#039;Cambio&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Aporte de Pablo Guarnieri y Gustavo Olmendo&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó un campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
 IF CLI:Campo &amp;lt;&amp;gt; history::CLI:Record.Campo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Forzar grabación del form === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para grabar el form inclusive cuando el usuario lo cancele&lt;br /&gt;
&lt;br /&gt;
TakeCloseEvent PROCEDURE(),BYTE,VIRTUAL&lt;br /&gt;
 IF loc:condicion &lt;br /&gt;
    SELF.CancelAction = Cancel:Save !immediate save (no confirmation)&lt;br /&gt;
 END&lt;br /&gt;
 &lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar un Drop Combo === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para filtrar un drop combo utilizando pro:sqlfilter, suponemos que en &lt;br /&gt;
la variable loc:filtro se arma el filtro ha enviar, algo asi como: &#039;a.idtercero = &amp;lt;39&amp;gt;90909090&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
FDCB14 es el nombre del objeto el cual se puede verificar en propiedades --&amp;gt; clases.&lt;br /&gt;
&lt;br /&gt;
ApplyFilter PROCEDURE,VIRTUAL&lt;br /&gt;
 FDCB14::View:FileDropCombo{PROP:SQLFILTER} =  &amp;lt;39&amp;gt;&#039;&amp;amp;clip(loc:filtro)&amp;amp;&#039;&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
 IF FILEERRORCODE()&lt;br /&gt;
    FDCB14::View:FileDropCombo{PROP:SQLFILTER} = &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Obtener el número autogenerado por SQL Server en tablas con identity === &lt;br /&gt;
Después del Parent Call, en el TakeCompleted del Form:&lt;br /&gt;
 IF Self.Response=RequestCompleted AND Self.Request = InsertRecord&lt;br /&gt;
    Tabla{prop:Sql}= &#039;SELECT @@IDENTITY&#039; !busco el número que se asignó&lt;br /&gt;
    IF not Access:Tabla.Next()&lt;br /&gt;
       !en el primer campo de Tabla viene cargado el número autogenerado&lt;br /&gt;
    else&lt;br /&gt;
       message(&#039;Error&#039;)&lt;br /&gt;
    end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Tomado de una respuesta de Fernando Cerini en el foro.&lt;br /&gt;
&lt;br /&gt;
== REPORTES Y PROCESOS ==&lt;br /&gt;
=== Ocultar un campo del detalle según condición ===&lt;br /&gt;
 !En TakeRecord, antes del Print (Process Manager)&lt;br /&gt;
 IF &amp;lt;CONDICION&amp;gt;&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=True&lt;br /&gt;
 ELSE&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=False !si la condición no se cumple, vuelvo a hacer visible el control&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Saber si un proceso se completó ===&lt;br /&gt;
O sea que no se salió por el botón de cancelar&lt;br /&gt;
 !En el WindowManager.Kill&lt;br /&gt;
 IF Self.Response = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
 &lt;br /&gt;
=== Inicializar el número de página ===&lt;br /&gt;
 !WindowManager.OpenReport, despues del Parent Call&lt;br /&gt;
 IF ReturnValue = Level:Benign&lt;br /&gt;
  Report{PROP:NextPageNo} = xxx&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar la impresión ===&lt;br /&gt;
 !Local Objects, Abc Objects, Previewer, Display, After ParentCall.&lt;br /&gt;
 !impresión prohibida&lt;br /&gt;
 ReturnValue = False&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
 If ReturnValue and DemoVersion&lt;br /&gt;
   ReturnValue = False&lt;br /&gt;
   Message(&amp;quot;Está utilizando una versión del demo, no puede imprimir este documento !&amp;quot;)&lt;br /&gt;
 End&lt;br /&gt;
Aporte de Olivier Cretey&lt;br /&gt;
&lt;br /&gt;
Otra opción, en Previewer.TakeAccepted, antes del Parent Call&lt;br /&gt;
 IF CLIP(ACCEPTED(){PROP:TIP}) = &#039;Print this report&#039; THEN RETURN LEVEL:BENIGN.&lt;br /&gt;
&lt;br /&gt;
O sea pregunto por el Tool Tip del botón que se ha presionado. Ojo, si lo tienes traducido tienes que cambiar el &#039;Print this report&#039; por tu Tool Tip.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un Proceso ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt; Validate Records --&amp;gt;&amp;gt; [Priority 5600] &lt;br /&gt;
 If &amp;lt;Condición de Filtro&amp;gt;&lt;br /&gt;
     Return Record:Filtered &lt;br /&gt;
 Else &lt;br /&gt;
     Return Record:OK &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
 &lt;br /&gt;
=== Habilitar o deshabilitar el Print Preview ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 Self.SkipPreview = Loc:Preview &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Cantidad de Páginas generadas ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 ENDPAGE(SELF.Report) &lt;br /&gt;
 Loc:Paginas = RECORDS(SELF.PreviewQueue) &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un Transporte ===&lt;br /&gt;
Necesitas crear 3 details.&lt;br /&gt;
DetailDatos&lt;br /&gt;
DetailTransporte: aca van las variables locales con los totales&lt;br /&gt;
DetailSalto: este detail es vacío y con la propiedad PageAfter&lt;br /&gt;
&lt;br /&gt;
En el embed TakeRecord (antes de los PRINTs) habría que hacer algo asi&lt;br /&gt;
 LOC:Fila += 1&lt;br /&gt;
 If LOC:Fila % 28 = 0 !28 líneas por página...&lt;br /&gt;
     PRINT(RPT:DetailSalto)&lt;br /&gt;
     PRINT(RPT:DetailTransporte)&lt;br /&gt;
     LOC:Fila = 1&lt;br /&gt;
 End&lt;br /&gt;
 LOC:Total += LIBRO:Total&lt;br /&gt;
 PRINT (RPT:Detalle)&lt;br /&gt;
 RETURN LEVEL:Benign&lt;br /&gt;
&lt;br /&gt;
Marcelo Martínez&lt;br /&gt;
y [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Acelerar las actualizaciones ===&lt;br /&gt;
Para que los procesos que agreguen registros funcionen mas rápido hay que agregar un Logout o Stream en Init y un Commit o Flush en el kill.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Se imprime o se Cancela? ===&lt;br /&gt;
Los embeds son&lt;br /&gt;
 ABC Objectd&lt;br /&gt;
 --WindowManager(ReportManager)&lt;br /&gt;
 --CancelPrintReport&lt;br /&gt;
 -Se Cancela&lt;br /&gt;
&lt;br /&gt;
 --PrintReport&lt;br /&gt;
 -Se imprime&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Recorrer la cola de las páginas ===&lt;br /&gt;
Cada página del reporte genera una imagen .WMF, la cual se guarda en el directorio temporal.&lt;br /&gt;
Con este ejemplo se puede recorrer la cola donde se guardan los nombres de estos archivos. Ésto es lo que usa por ejemplo el  [http://templatesclarion.com.ar/downloads/ EC_Mail Template] para enviar estas páginas por mail.&lt;br /&gt;
 Previewer.Open PROCEDURE&lt;br /&gt;
 ....&lt;br /&gt;
 loop a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
     get(SELF.ImageQueue,a#)&lt;br /&gt;
     message(SELF.ImageQueue)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir una Queue ===&lt;br /&gt;
La mejor forma de hacerlo en Clarion6 es en Report Properties - General -&lt;br /&gt;
Datasource: Queue.&lt;br /&gt;
&lt;br /&gt;
Yo generalmente pongo los parametros en la ventana y cargo la queue en el&lt;br /&gt;
evento accepted del PauseButton.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un SQL ===&lt;br /&gt;
Lo que yo hago es poner todos los parámetros en la ventana del reporte.&lt;br /&gt;
En el accepted del boton de pausa cargo la cola de memoria con:&lt;br /&gt;
&lt;br /&gt;
 SQL{PROP:SQL} = !aca armo el string SQL&lt;br /&gt;
 IF ERRORCODE() THEN STOP( FILEERROR()).&lt;br /&gt;
 FREE(ColaMemoria)&lt;br /&gt;
 LOOP&lt;br /&gt;
     NEXT(SQL) !O ABC, como prefieras...&lt;br /&gt;
     IF ERRORCODE() THEN BREAK.&lt;br /&gt;
     ColaMemoria :=: SQL:Record&lt;br /&gt;
     ADD(ColaMemoria)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
El reporte lo configuro para trabajar con la cola (data source) y en el&lt;br /&gt;
Detail del reporte pongo los campos de la cola de memoria.&lt;br /&gt;
Lo ideal es tener una cola de memoria global con el atributo thread y usar&lt;br /&gt;
siempre la misma para todo.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar o hacer cortes de control manuales en reportes ===&lt;br /&gt;
En TakeRecord, antes del Print.&lt;br /&gt;
 &lt;br /&gt;
!Actualizar contadores&lt;br /&gt;
&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; CampoCorte&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; 0 !para evitar la primera vez&lt;br /&gt;
 !Inicializar los contadores&lt;br /&gt;
 END&lt;br /&gt;
 AUX=CAMPO&lt;br /&gt;
 !SE VIENE EL CORTE&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Este método TakeRecord se usa también para actualizar cualquier variable calculada antes de la impresión de la banda de detalle.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo BLOB ===&lt;br /&gt;
Este código va en el método TakeRecord, antes del PRINT&lt;br /&gt;
&lt;br /&gt;
 Report$?Image1{PROP:NoWidth} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:NoHeight} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:ImageBlob} = STU:Photograph{PROP:Handle}&lt;br /&gt;
 IF Report$?Image1{PROP:Height} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Width}/Report$?Image1{PROP:Height}&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
 IF Report$?Image1{PROP:Width} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Height}/Report$?Image1{PROP:Width}&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo CSTRING ===&lt;br /&gt;
Este caso es similar al anterior, pero en el campo se encuentra el path donde está la imagen&lt;br /&gt;
 !En el método TakeRecord, antes del PRINT&lt;br /&gt;
 Report$?Image1{PROP:Text} = PRO:Foto&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Evitar el cartel &amp;quot;No records to process&amp;quot; en un proceso ===&lt;br /&gt;
 !En el metodo TAKE NO RECORDS poner un RETURN antes del parent call.&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir el reporte en blanco, cuando no hay registros ===&lt;br /&gt;
En WindowManager. Next, antes del Parent Call con prioridad 500.&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 500] antes del Parent Call&lt;br /&gt;
 If Primera=0 !variable local byte&lt;br /&gt;
    Primera=1&lt;br /&gt;
    SELF.Process.RecordsProcessed = 1&lt;br /&gt;
    Return Level:Benign&lt;br /&gt;
 End&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Cuando hay filtros y rangos, esta solución suele duplicar el primer registro del detalle.&lt;br /&gt;
Para Solucionar esto en ProcessManager NextPROCEDURE(BYTE ProcessRecord) con prioridad 7500 se debe colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF ReturnValue = 0 AND LOC:Primera = 0 THEN !Si hay un registro&lt;br /&gt;
    LOC:Primera = 1        !Dejo al reporte seguir su curso normal&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Mario Wojcik&lt;br /&gt;
&lt;br /&gt;
=== Detectar el último registro en un process o Reporte (fin de archivo) ===&lt;br /&gt;
 ThisProcess.Next PROCEDURE(BYTE ProcessRecords=True)&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 !Fin del proceso&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
Esto por ejemplo es muy útil para cambiar etiquetas en los totales generales del reporte, en un page footer&lt;br /&gt;
 ThisReport.Next PROCEDURE(BYTE ProcessRecords)&lt;br /&gt;
 ....&lt;br /&gt;
 ! [Priority 5001] despues del Parent Call&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 REPORT$?LabelTotal{prop:text}= &#039;Total&#039;&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Reporte con múltiples detalles ===&lt;br /&gt;
Por Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 Viajes&lt;br /&gt;
 |--&amp;gt;pasajeros&lt;br /&gt;
 |--&amp;gt;comisiones&lt;br /&gt;
&lt;br /&gt;
Habría que poner solo la tabla viajes en el Table Schematic. Pasajeros y Comisiones en Other Tables&lt;br /&gt;
&lt;br /&gt;
En el reporte crear 3 details, uno para cada tabla.&lt;br /&gt;
&lt;br /&gt;
En ThisReport.TakeRecord, antes de los PRINTs&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 5500]&lt;br /&gt;
 PRINT(RPT:DetailViaje)&lt;br /&gt;
 CLEAR(PAS:RECORD)&lt;br /&gt;
 PAS:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(PAS:ClavePorViaje, PAS:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Pasajeros.Next() OR PAS:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailPasajeros)&lt;br /&gt;
 END&lt;br /&gt;
 !Y lo mismo para las comisiones&lt;br /&gt;
 CLEAR(COM:RECORD)&lt;br /&gt;
 COM:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(COM:ClavePorViaje, COM:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Comisiones.Next() OR COM:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailComisiones)&lt;br /&gt;
 END&lt;br /&gt;
 Return Level:Benign !ya imprimí todo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Otra alternativa podría ser utilizando el Template &#039;&#039;&#039;ReportChildFiles&#039;&#039;&#039; (desde version 6.X ?) ya que puede ser utilizado mas de una vez en un mismo reporte, apuntando cada instancia a un archivo &amp;quot;hijo&amp;quot; diferente.&lt;br /&gt;
Es fácil de configurar: Se debe seleccionar la tabla CHILD y la PARENT. En el reporte hay que definir el REPORT DETAIL (para el CHILD) y ponerle algún nombre en el label que luego debe ser configurado en el Template.&lt;br /&gt;
&lt;br /&gt;
Jose Sturniolo&lt;br /&gt;
&lt;br /&gt;
=== Imprimir exactamente lo que estamos viendo en el browse ===&lt;br /&gt;
En el browse pones un botón que llame al reporte y en parameters:&lt;br /&gt;
(Brw1.view{PROP:Filter}, Brw1.view{PROP:Order})&lt;br /&gt;
&lt;br /&gt;
En las propiedades del reporte o proceso:&lt;br /&gt;
Prototype: (STRING, STRING)&lt;br /&gt;
Parameters: (FILTRO, ORDEN)&lt;br /&gt;
&lt;br /&gt;
En WindowManager.Init, al final:&lt;br /&gt;
 ThisReport.SetFilter(FILTRO) ! o ThisProcess....&lt;br /&gt;
 ThisReport.SetOrder(ORDEN)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar tamaño de hoja en el reporte ===&lt;br /&gt;
En el embed WindowManager &#039;OpenReport&#039;, PRIORITY(7500)&lt;br /&gt;
&lt;br /&gt;
 IF ~ReturnValue&lt;br /&gt;
 SETTARGET(REPORT)&lt;br /&gt;
 CASE PRINTER{PROPPRINT:Paper}&lt;br /&gt;
 OF PAPER:LETTER&lt;br /&gt;
     REPORT{PROP:height} = 8500&lt;br /&gt;
     ?Footer{PROP:Ypos} = 9000&lt;br /&gt;
 OF PAPER:LEGAL&lt;br /&gt;
     REPORT{PROP:height} = 11000&lt;br /&gt;
     ?Footer{PROP:Ypos} = 11500&lt;br /&gt;
 etc.&lt;br /&gt;
 END&lt;br /&gt;
 SETTARGET()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
etc. con los tamaños de papel que quieras.&lt;br /&gt;
Esto acomoda el contenido del reporte en run-time, haciéndolo ocupar más &lt;br /&gt;
o menos hoja según sea el largo de la misma. Chiche, ¿no?.&lt;br /&gt;
Ajustá los valores a tus necesidades.&lt;br /&gt;
Para tener en cuenta: el usuario tiene que elegir el tamaño del papel &lt;br /&gt;
ANTES de generar el reporte. Si ya está en la vista previa, el reporte ya &lt;br /&gt;
está generado, por lo tanto si cambia el largo de hoja ahí, no se lo va a &lt;br /&gt;
tomar.&lt;br /&gt;
&lt;br /&gt;
Jorge Lavera&lt;br /&gt;
&lt;br /&gt;
=== Cambiar Impresora ===&lt;br /&gt;
En Global Properties--&amp;gt;Embeds--&amp;gt;Before Global INCLUDEs&lt;br /&gt;
 INCLUDE(&#039;PRNPROP.CLW&#039;)&lt;br /&gt;
 !para poder acceder a las propiedades de las impresoras&lt;br /&gt;
&lt;br /&gt;
Luego en el Reporte en &lt;br /&gt;
 ThisReport.Open()&lt;br /&gt;
 !para guardar la impresora por defecto de Windows&lt;br /&gt;
 GLO:IMPRESORA = PRINTER{PROPPRINT:Device}&lt;br /&gt;
 !Seteo la impresora que quiero usar.&lt;br /&gt;
 !El string debe ser igual al que figura en IMPRESORAS&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = &#039;HP Deskjet 840&#039;&lt;br /&gt;
&lt;br /&gt;
y por último en&lt;br /&gt;
 ThisReport.Kill()&lt;br /&gt;
 !para devolver la impresora por defecto de windows&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = CLIP(GLO:IMPRESORA)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Guillermo Ondetti, Pragma Sistemas&lt;br /&gt;
&lt;br /&gt;
=== Detectar Salto de Página de Reporte ===&lt;br /&gt;
Este sería el codigo, siempre y cuando no tengas break groups (ahi se complica bastante)&lt;br /&gt;
El embebido es TakeRecord en ABC, o Before Print Detail en Legacy.&lt;br /&gt;
 VarLocal += REPORT$?Detail{PROP:height}&lt;br /&gt;
 IF VarLocal &amp;gt; REPORT{PROP:height}&lt;br /&gt;
     VarLocal = REPORT$?Detail{PROP:height}&lt;br /&gt;
     !En el siguiente PRINT Cambia la página...&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Aplicar Filtro sql en el reporte ===&lt;br /&gt;
Se arma el filtro si se quiere en una variable por ejemlo loc:sql&lt;br /&gt;
y se aplica en Local Objects --&amp;gt; Abc Objects -- &amp;gt; Process manager --&amp;gt; Apply Filter antes del parent call, asi:&lt;br /&gt;
&lt;br /&gt;
 Process:View{Prop:SqlFilter}=Loc:SQL&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez&lt;br /&gt;
&lt;br /&gt;
=== Imprimir mas de una Copia por Reporte  ===&lt;br /&gt;
Se tiene que poner en el Window Manager --&amp;gt; Open (Prioridad(5000))&lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=n  !! n = Cantidad de copias &lt;br /&gt;
&lt;br /&gt;
Luego es aconsejable poner en el Window Manager --&amp;gt; Kill &lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=1 &lt;br /&gt;
&lt;br /&gt;
ASC Sergio D. Caballero&lt;br /&gt;
&lt;br /&gt;
== BROWSES ==&lt;br /&gt;
=== Actualizar un campo al hacer click en una columna ===&lt;br /&gt;
Por ejemplo, en People.app&lt;br /&gt;
&lt;br /&gt;
En el evento Accepted del Control del browse.&lt;br /&gt;
 !Si se hizo click en el campo&lt;br /&gt;
 IF ?BROWSE:1{PropList:MouseDownField}= 4&lt;br /&gt;
    ACCESS:PEOPLE.Fetch(PEO:KeyId)&lt;br /&gt;
    PEO:Gender = &#039;X&#039;&lt;br /&gt;
    ACCESS:PEOPLE.Update()&lt;br /&gt;
    BRW1.ResetFromFile()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar con SQL===&lt;br /&gt;
A veces es muy útil aplicar un filtro SQL encima de todos los demas filtros que ya tenga el browse, por ejemplo para filtrar por usuario, por sucursal, etc.&lt;br /&gt;
Yo normalmente le pongo el filtro SQL en el método windowmanager.Reset, &lt;br /&gt;
prioridad 5000&lt;br /&gt;
 BRW1.View{PROP:SQLFILTER}=&#039;+ filtro sql&#039;&lt;br /&gt;
Luego se refresca normalmente, o manualmente con ThisWindow.Reset (1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Activar un Browse invisible, o sea que está en otro TAB ===&lt;br /&gt;
Esto es especialmente útil cuando necesitamos que se ejecuten totalizadores del browse aunque éste no esté visible en la pantalla.&lt;br /&gt;
!ABC Objects -&amp;gt; &lt;br /&gt;
Local Objects -&amp;gt;&lt;br /&gt;
Windows Manager-&amp;gt;&lt;br /&gt;
Init Priority[7500] &lt;br /&gt;
 BRW2.ActiveInvisible = True &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Copiar un Registro ===&lt;br /&gt;
&lt;br /&gt;
    !ABC Objects -&amp;gt; Browse on Clientes -&amp;gt; PrimeRecord Priority[4500] &lt;br /&gt;
    IF Loc:Copiar &lt;br /&gt;
     SuppressClear = True &lt;br /&gt;
     CLEAR(Loc:Copiar) &lt;br /&gt;
    END!IF &lt;br /&gt;
&lt;br /&gt;
    !Control Events --&amp;gt; Copiar -&amp;gt; Accepted -&amp;gt; Priority[5000] &lt;br /&gt;
    Loc:Copiar = True &lt;br /&gt;
    POST(EVENT:Accepted,?UseDelBotonAgregar) &lt;br /&gt;
&lt;br /&gt;
    !Notas: Crear Variable Local Loc:Copiar &lt;br /&gt;
    ! SuppressClear es un Parametro de BrowseClass.PrimeRecord&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar el Popup ===&lt;br /&gt;
 !ABC Objects -&amp;gt; Local Objects -&amp;gt; Windows Manager--&amp;gt;&amp;gt;Init Priority[9001] &lt;br /&gt;
 Brw1.Popup.KILL&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Ordenamiento Dinámico ===&lt;br /&gt;
En Clarion6 se puede hacer automáticamente con la opcion Sort Headers.&lt;br /&gt;
Si se quiere hacer desde código para ordenar por cualquier campo, se puede utilizar:&lt;br /&gt;
    Brw1.SetOrder(&#039;TAB:Campo&#039;) &lt;br /&gt;
    Brw1.ApplyOrder() &lt;br /&gt;
    ThisWindow.Reset(1) &lt;br /&gt;
Por ejemplo si quisiera emular un ordenamiento con el doble click sobre una columna, habría que alertar el doble click en al browse, y el código sería mas o menos asi.&lt;br /&gt;
 Control Event -&amp;gt; Browse:1 -&amp;gt;Alert Key [4500] &lt;br /&gt;
 ! Código usado para cambiar el Orden del Browse &lt;br /&gt;
 ! cuando se hace doble click en la columna &lt;br /&gt;
 IF KEYCODE()=MouseLeft2 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;Codigo&#039; &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;Nombre&#039; &lt;br /&gt;
     Loc:Columna = ?Browse:1{PropList:MouseDownField} &lt;br /&gt;
     CASE Loc:Columna &lt;br /&gt;
     OF 1 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;&amp;lt;&amp;lt;&amp;lt;CODIGO&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;LCA:LOCALIDAD&#039;) &lt;br /&gt;
     OF 2 &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;&amp;lt;&amp;lt;&amp;lt;NOMBRE&amp;gt;&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;UPPER(LCA:NOMBRE)&#039;) &lt;br /&gt;
     END!CASE &lt;br /&gt;
     Brw1.ApplyOrder() &lt;br /&gt;
     ThisWindow.Reset(1) &lt;br /&gt;
 END!IF &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Locator Múltiple ===&lt;br /&gt;
Por ejemplo, para posicionarme en un código de cuenta contable:&lt;br /&gt;
Lo que podrías hacer es poner una variable string sobre el browse y poner un&lt;br /&gt;
código mas o menos asi en su accepted del entry&lt;br /&gt;
&lt;br /&gt;
 !Asumiendo que cada código tiene cuatro dígitos&lt;br /&gt;
 !Revisar la sección String Slicing en el Help&lt;br /&gt;
 Cue:Cuenta = Loc:Cuenta[1:4]&lt;br /&gt;
 Cue:SubCuenta = Loc:Cuenta[5:8]&lt;br /&gt;
 Cue:SubSubCuenta = Loc:Cuenta[9:12]&lt;br /&gt;
 SET(Cue:PorCodigo,Cue:PorCodigo)&lt;br /&gt;
 Access:Cuentas.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Otro ejempo, en un browse de órdenes, posicionarse según el nombre del cliente&lt;br /&gt;
&lt;br /&gt;
 CLI:Nombre = LOC:Cliente&lt;br /&gt;
 SET(CLI:PorNombre, CLI:PorNombre)&lt;br /&gt;
 ACCESS:Clientes.Next()&lt;br /&gt;
&lt;br /&gt;
 ORD:CodCliente = CLI:CodCliente&lt;br /&gt;
 SET(ORD:PorCliente, ORD:PorCliente)&lt;br /&gt;
 ACCESS:Ordenes.Next()&lt;br /&gt;
&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Pintar un browse según un campo ===&lt;br /&gt;
Por ejemplo cuando vemos las facturas de un Cliente se repite el nombre, este código pinta diferente cada grupo de nombres.&lt;br /&gt;
Primero hay que ponerle el atributo color al campo que necesites pintar, desde list box format.&lt;br /&gt;
Luego va el siguiente código, en WindowManager.Reset antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 Aux = &#039;&#039;&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (BRW1.Q)&lt;br /&gt;
     GET(BRW1.Q, F#)&lt;br /&gt;
     IF Aux &amp;lt;&amp;gt; BRW1.Q.CLI:Nombre&lt;br /&gt;
         Col# = 1- Col#&lt;br /&gt;
         Aux = BRW1.Q.CLI:Nombre&lt;br /&gt;
     END&lt;br /&gt;
     If Col#&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:SILVER&lt;br /&gt;
     Else&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:WHITE&lt;br /&gt;
     End&lt;br /&gt;
     PUT(BRW1.Q)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Refrescar un browse desde otra ventana ===&lt;br /&gt;
Lo mas fácil sería usando NOTIFY.&lt;br /&gt;
En la Ventana 1 (la del browse a refrescar)&lt;br /&gt;
 WindowManager.Init&lt;br /&gt;
 GLO:THREAD = THREAD() !VARIABLE GLOBAL LONG&lt;br /&gt;
&lt;br /&gt;
 Window Events&lt;br /&gt;
 Notify&lt;br /&gt;
 BRW1.ResetfromBuffer() ! o ThisWindow.Reset(1)?&lt;br /&gt;
&lt;br /&gt;
En la ventana 2, cuando se necesite refrescar la 1&lt;br /&gt;
 NOTIFY (999, GLO:THREAD)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que en éste caso no estoy usando ese parámetro.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Iniciar el browse en un Tab determinado ===&lt;br /&gt;
En ThisWindow.Init, al final&lt;br /&gt;
 SELF.FirstField = ?Tab:4 !Use del tab&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Actualizar el resultado de un totaling del browse de detalle, en el Encabezado ===&lt;br /&gt;
En el Browse de abajo (el de detalle)&lt;br /&gt;
 ResetFromView, prioridad 4500 - La prioridad es importante&lt;br /&gt;
 GET(Encabezado, ENC:Por_Numero)&lt;br /&gt;
 ENC:Total = loc:total !ÉSTA ES LA VARIABLE DEL TOTALING&lt;br /&gt;
 PUT (Encabezado)&lt;br /&gt;
 IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtro Dinámico ===&lt;br /&gt;
Poner un control Text donde el usuario pueda escribir cualquier filtro&lt;br /&gt;
 X# = EVALUATE(Filtro)&lt;br /&gt;
 IF ERRORCODE()&lt;br /&gt;
     MESSAGE(&#039;ERROR DE SINTAXIS EN EL FILTRO: &#039; &amp;amp; ERROR(), &#039;ATENCION&#039;)&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.SetFilter(Filtro)&lt;br /&gt;
     ThisWindow.Reset(1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Rangos múltiples y dinámicos ===&lt;br /&gt;
Si tenemos una clave con varios componentes, en Actions del browse ponemos un rango por current value, elegimos el componente de la clave hasta el cual queremos hacer el rango.&lt;br /&gt;
El siguiente componente de la clave se puede usar como locator.&lt;br /&gt;
Por ejemplo si tenemos una clave con Tipo+Provincia+Localidad, hacemos un rango de current value por provincia y nos queda un locator por localidad.&lt;br /&gt;
&lt;br /&gt;
 BRW1.ApplyRange PROCEDURE&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 RAN:Tipo= loc:tipo&lt;br /&gt;
 RAN:Provincia=loc:provincia&lt;br /&gt;
 SELF.Order.Rangelist.AssignLeftToRight()&lt;br /&gt;
&lt;br /&gt;
En algun boton de aplicar rango&lt;br /&gt;
 BRW1.ApplyRange()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, deshabilitar condicionalmente la actualización de registros ===&lt;br /&gt;
 IF &amp;lt;Condición&amp;gt;&lt;br /&gt;
     !Deshabilitar Actualización&lt;br /&gt;
     BRW1.InsertControl=FALSE&lt;br /&gt;
     BRW1.ChangeControl=FALSE&lt;br /&gt;
     BRW1.DeleteControl=FALSE&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.InsertControl=?INSERT&lt;br /&gt;
     BRW1.ChangeControl=?CHANGE&lt;br /&gt;
     BRW1.DeleteControl=?DELETE&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar el cambio de registro seleccionado en un Browse ===&lt;br /&gt;
Ejemplo mostrar una foto del cliente al costado del browse&lt;br /&gt;
 BRW1.TakeNewSelection PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !EN CLI:FOTO ESTA EL PATH COMPLETO DE LA FOTO&lt;br /&gt;
 IF CLI:FOTO &amp;lt;&amp;gt; &#039;&#039;&lt;br /&gt;
     ?Foto{PROP:TEXT}= CLI:FOTO &lt;br /&gt;
 ELSE&lt;br /&gt;
     ?Foto{PROP:TEXT}= &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un browse ===&lt;br /&gt;
Ejemplo: Mostrar sólo los clientes que tengan alguna orden&lt;br /&gt;
&lt;br /&gt;
 BRW1.ValidateRecord PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !FILTROS COMPLEJOS&lt;br /&gt;
 !EJ: MOSTRAR SOLO LOS CLIENTES QUE TENGAN ALGUNA ORDEN&lt;br /&gt;
 CLEAR(ORD:RECORD)&lt;br /&gt;
 Ord:CodigoCliente=CLI:ID&lt;br /&gt;
 SET(Ord:FK_Ordenes_CLIENTES,Ord:FK_Ordenes_CLIENTES)&lt;br /&gt;
 NEXT(ORDENES)&lt;br /&gt;
 IF ERRORCODE() OR (Ord:CodigoCliente &amp;lt;&amp;gt; CLI:ID) THEN RETURN Record:Filtered.&lt;br /&gt;
 &lt;br /&gt;
 RETURN Record:OK&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Poner un campo &amp;quot;saldo&amp;quot; en un browse ===&lt;br /&gt;
ThisWindow.Reset, antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 S#=0&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (Queue:Browse:1)&lt;br /&gt;
     GET(Queue:Browse:1, F#)&lt;br /&gt;
     S# += Queue:Browse:1.ORD:Total_Impo&lt;br /&gt;
     Queue:Browse:1.Saldo = S#&lt;br /&gt;
     PUT(Queue:Browse:1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Resetear/inicializar un Locator ===&lt;br /&gt;
El método a ejecutar es&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
&lt;br /&gt;
Los nombres de las instancias de Locators por cada TAB se llaman:&lt;br /&gt;
 BRW1::Sort0:Locator.Set&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
 BRW1::Sort2:Locator.Set&lt;br /&gt;
 !etc..&lt;br /&gt;
&lt;br /&gt;
Luego sería bueno volver a poner el foco en el browse para que se pueda seguir usando el locator normalmente&lt;br /&gt;
 select (?Browse:1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, disparar un procedimiento después de generar un alta, modificación, etc. ===&lt;br /&gt;
&lt;br /&gt;
El proceso a disparar se hace desde el browse, la idea es saber si del Form volvió aceptando o canceló la actualización. El punto embebido es:&lt;br /&gt;
&lt;br /&gt;
 Local Objects&lt;br /&gt;
 BRW1 (o el objeto de tipo browse class que sea)&lt;br /&gt;
 ResetFromAsk (después del Parent.call)&lt;br /&gt;
 &lt;br /&gt;
 IF VCRRequest=VCR:None&lt;br /&gt;
 CASE Request&lt;br /&gt;
 OF InsertRecord&lt;br /&gt;
     IF Response = RequestCompleted&lt;br /&gt;
     !Hacer algún proceso&lt;br /&gt;
     END&lt;br /&gt;
 END&lt;br /&gt;
 END!&lt;br /&gt;
&lt;br /&gt;
=== Inserción continua refrescando el Browse ===&lt;br /&gt;
Este otro método es similar al anterior, también sirve para lo mismo.&lt;br /&gt;
Agrego un ejemplo para hacer inserción continua en el Form y además se vaya actualizando el browse&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Run PROCEDURE(USHORT Number,BYTE Request)&lt;br /&gt;
 ! Cuidado que existen dos ThisWindow.Run, seleccionar el correcto&lt;br /&gt;
 ! [Priority 8500]&lt;br /&gt;
 IF Request = InsertRecord And ReturnValue = RequestCompleted&lt;br /&gt;
     POST(EVENT:ACCEPTED, BRW1.InsertControl)&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Posicionar un browse en un registro seleccionado ===&lt;br /&gt;
&lt;br /&gt;
Al abrir un browse a veces necesitamos posicionar el selector en un registro determinado, tal como lo hacen los browses para selección.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para posicionar el browse en el registro más cercano al proporcionado por el usuario:&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Open PROCEDURE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 ! End of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 CODE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Executable Code Section&amp;quot;&lt;br /&gt;
 ! [Priority 500]&lt;br /&gt;
 CLI:cliente= LOC:Cliente&lt;br /&gt;
 ACCESS:Clientes.fetch(CLI:Kcodigo)&lt;br /&gt;
 BRW1.selecting=1&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 PARENT.Open()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 BRW1.selecting=0&lt;br /&gt;
&lt;br /&gt;
Otra idea, propuesta por Matías Flores:&lt;br /&gt;
Ubicarlo por el valor de los campos de la clave. Por ejemplo, si en un browse de clientes querés posicionarte en un cliente que tiene un código determinado (Loc:Codigo):&lt;br /&gt;
&lt;br /&gt;
 Cli:Codigo = Loc:Codigo&lt;br /&gt;
 SET(Cli:PorCodigo,Cli:PorCodigo)&lt;br /&gt;
 Access:Clientes.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
un ejemplo parecido al anterior, pero en legacy, sería:&lt;br /&gt;
 CLI:Codigo = LOC:Codigo&lt;br /&gt;
 BRW1::LocateMode = LocateOnValue&lt;br /&gt;
 DO BRW1::LocateRecord&lt;br /&gt;
&lt;br /&gt;
Una opción más es:&lt;br /&gt;
En el WindowManager.init, antes de Initialize browse y después de OpenFiles, colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 BRWx.StartAtCurrent = True&lt;br /&gt;
 TAB:Campo = Valor_Buscado&lt;br /&gt;
 get(Tabla, TAB:Key_que_ordena_por_Campo)&lt;br /&gt;
&lt;br /&gt;
=== En Legacy, activar un filtro sobre un browse abierto. ===&lt;br /&gt;
&lt;br /&gt;
Esto se pone en el punto embebido &amp;quot;Before opening VIEW&amp;quot;. Acordarse de BINDEAR todas las variables que se necesiten.&lt;br /&gt;
&lt;br /&gt;
 !---ANTES DE ABRIR EL VIEW--- &lt;br /&gt;
 if SoloPendientes then&lt;br /&gt;
 BRW2::View:Browse{Prop:Filter} = |&lt;br /&gt;
 &#039;MER:numertra = BRW2::Sort1:Reset:TRA:numertra AND MER:saldunid &amp;lt;&amp;gt; 0&#039;&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo cuando quieras presentar el nombre completo sin los espacios de un campo a otro. Pones en el browse una variable local.&lt;br /&gt;
En el SETQUEUERECORD (4500)&lt;br /&gt;
 &lt;br /&gt;
 Loc:ApellidoNombre = clip(CON:Apellido) &amp;amp; &#039; &#039; &amp;amp; CON:Nombre&lt;br /&gt;
&lt;br /&gt;
!(Tip de Alex B.)&lt;br /&gt;
&lt;br /&gt;
=== Código antes y después de una actualización DESDE UN BROWSE. ===&lt;br /&gt;
&lt;br /&gt;
- Antes de la llamada al Form de actualización&lt;br /&gt;
! ABC Objects -&amp;gt; Browse on Archvivo -&amp;gt;Ask Priority[4500]&lt;br /&gt;
 IF Request = InsertRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR ALTA &#039;,&#039;ALTA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = ChangeRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A ACTUALIZAR &#039;,&#039;CAMBIO&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = DeleteRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR DE BAJA &#039;,&#039;BAJA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
- Después de la actualización del registro&lt;br /&gt;
!ABC Objects -&amp;gt; Browse on Provincia -&amp;gt;Ask Priority[5500]&lt;br /&gt;
 IF ReturnValue =1&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCIÓN: SE ACTUALIZÓ EL REGISTRO&#039;,&#039;ACTUALIZÓ OK&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF ReturnValue =2&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;SE CANCELÓ LA ACTUALIZACIÓN DEL REGISTRO&#039;,&#039;ATENCIÓN&#039;,ICON:HAND)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar/esconder (cambiar a PROP:HIDE) un control si el browse está vacío - pe. un botón-. ===&lt;br /&gt;
&lt;br /&gt;
En el Browse.UpdateWindow(), última prioridad:&lt;br /&gt;
 ?TuBoton{PROP:Disable}=Choose(Self.Records()&amp;lt;&amp;gt;0,0,1)&lt;br /&gt;
&lt;br /&gt;
===Iniciar un browse con un orden &amp;quot;sort header&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Si queremos que al abrir un browse el mismo se encuentre ordenado como si hubiéramos hecho click en el sortheader, ponemos luego del generated code del evento openwindow lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 BRW1::SortHeader.SetSortFromString(&#039;TAB:Campo&#039;)&lt;br /&gt;
&lt;br /&gt;
donde TAB:Campo es uno de los campos de la tabla que estoy mostrando en el browse.&lt;br /&gt;
&lt;br /&gt;
== EDIT IN PLACE==&lt;br /&gt;
=== Edit in Place o Form, según condición ===&lt;br /&gt;
En BrowseClass, Ask, antes del Parent Call&lt;br /&gt;
 If ?browse:1{proplist:mousedownfield} = 5&lt;br /&gt;
     Self.AskProcedure = 0&lt;br /&gt;
 else&lt;br /&gt;
     Self.AskProcedure = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Puede usarse cualquier condición, en este caso si el usuario hace doble click en la 5a columna se usa edit in place, sino se usa el formulario&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Desactivar Edit in Place de un campo según condición ===&lt;br /&gt;
En las propiedades del EIP del campo admitir la edición del mismo.&lt;br /&gt;
&lt;br /&gt;
En el EIP Field Manager del campo, TakeEvent, antes del Parent Call&lt;br /&gt;
  if Queue:Browse:1.TAB:Campo_de_mi_Tabla &amp;gt; 0 &lt;br /&gt;
     Return EditAction:Cancel&lt;br /&gt;
     thiswindow.reset(true)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
En este ejemplo sólo permito que pueda editarse el campo si el valor actual del mismo es &amp;lt;= 0&lt;br /&gt;
&lt;br /&gt;
=== Inicializar campos al insertar registro ===&lt;br /&gt;
O sea lo que hace el Prime Fields en las formas&lt;br /&gt;
 ABC Objects&lt;br /&gt;
 BROWSE ON TABLA using ?LIST&lt;br /&gt;
 PrimeRecords&lt;br /&gt;
 Después del Parent Call&lt;br /&gt;
 TPS:TuCampo= valor inicial&lt;br /&gt;
&lt;br /&gt;
=== Poner Disable un campo===&lt;br /&gt;
 Local Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 Abc Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 EIP Field Manag...for Field NombreCampo&lt;br /&gt;
 --&amp;gt;&amp;gt;Init [Priority 5001]&lt;br /&gt;
 If SELF.FEQ then SELF.FEQ{Prop:Disable} = true.&lt;br /&gt;
También se pueden cambiar otras propiedades como por ejemplo UPPER (mayúsculas) o READ ONLY (sólo lectura)&lt;br /&gt;
 If SELF.FEQ &lt;br /&gt;
     SELF.FEQ{prop:readonly} = TRUE&lt;br /&gt;
     SELF.FEQ{prop:upr} = TRUE&lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo Modificar el total cuando cambia la cantidad.&lt;br /&gt;
Primero agregar el campo cantidad en Column Specific&lt;br /&gt;
 EditInPlace::DET:Cantidad.TakeEvent PROCEDURE(UNSIGNED Event)&lt;br /&gt;
 ....&lt;br /&gt;
 !Despues del Parent Call&lt;br /&gt;
&lt;br /&gt;
 CASE ReturnValue&lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel&lt;br /&gt;
 ELSE&lt;br /&gt;
     Update(Self.Feq)&lt;br /&gt;
     BRW1.Q.DET:Total = BRW1.Q.DET:Cantidad * BRW1.Q.DET:Importe&lt;br /&gt;
     !Etc... siempre haciendo referencia a los campos de la cola BRW1.Q.&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones ===&lt;br /&gt;
Por ejemplo una validación básica de un número requerido&lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:NroDocumento&lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 ! Validación del nro. de Documento &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     UPDATE(Self.Feq) &lt;br /&gt;
     IF NOT BRW1.Q.Cli:NroDocumento &lt;br /&gt;
         BEEP(BEEP:SystemExclamation) ; YIELD() &lt;br /&gt;
         MESSAGE(&#039;No se informó el número de Documento&#039;, | &lt;br /&gt;
         &#039;Atención!&#039;, ICON:Exclamation) &lt;br /&gt;
         ReturnValue = EditAction:NONE &lt;br /&gt;
         Return ReturnValue &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Validación con un lookup a una tabla &lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:Provincia &lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 !Valida Provincia &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     Update(Self.Feq) &lt;br /&gt;
     Pro:Codigo= BRW1.Q.Cli:Provincia &lt;br /&gt;
     IF Access:Provincia.Fetch(Pro:PorCodigo) &lt;br /&gt;
         GlobalRequest = SelectRecord &lt;br /&gt;
         SelectProvincia &lt;br /&gt;
         IF NOT Pro:Codigo &lt;br /&gt;
             ReturnValue = EditAction:NONE &lt;br /&gt;
             Return ReturnValue &lt;br /&gt;
         ELSE &lt;br /&gt;
             BRW1.Q.Cli:Provincia = Pro:Codigo &lt;br /&gt;
             BRW1.Q.Pro:NOMBRE = Pro:NOMBRE &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== GLOBALES ==&lt;br /&gt;
&lt;br /&gt;
=== Cambiar los mensajes de error del SQL === &lt;br /&gt;
Con cambiar los TRN no alcanza para ese tipo de errores. &lt;br /&gt;
 &lt;br /&gt;
Lo que se puede hacer es determinar el mensaje que viene desde el SQLServer &lt;br /&gt;
para mostrar un mensaje mas amigable. &lt;br /&gt;
 &lt;br /&gt;
El embebido es &lt;br /&gt;
Global Embeds: &lt;br /&gt;
 Global Objets &lt;br /&gt;
 Abc Objects &lt;br /&gt;
 Error Manager &lt;br /&gt;
 TakeNotify &lt;br /&gt;
 !Antes del Parent Call &lt;br /&gt;
 IF INSTRING(&#039;COLUMN REFERENCE&#039;, SELF.SubsString(),1,1) &lt;br /&gt;
 SELF.Msg(&#039;El registro no puede borrarse porque tiene datos de detalle &lt;br /&gt;
 que dependen de él. |Presione [OK] para una descripción detallada del &lt;br /&gt;
 error&#039;,SELF.GetErrorBufferTitle(),ICON:Exclamation,Button:OK,BUTTON:OK,0) &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Hay que armar un IF de estos por cada tipo de error... &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validación de campos (Edit in place o Form)=== &lt;br /&gt;
 &lt;br /&gt;
Para validar campos lo ideal es usar los Global Embeds &lt;br /&gt;
 Global Embeds &lt;br /&gt;
 Field Level Validation &lt;br /&gt;
 Tabla &lt;br /&gt;
 Campo &lt;br /&gt;
 IF &amp;lt;No cumple Condición&amp;gt; &lt;br /&gt;
 Message(&#039;error...&#039;) &lt;br /&gt;
 RETURN Level:Notify &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Esto te va a funcionar &amp;quot;para siempre&amp;quot; ya sea que uses Edit in place, un Form &lt;br /&gt;
o código embebido para actualizar la tabla. &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=76</id>
		<title>Puntos Embebidos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=76"/>
		<updated>2015-03-07T23:05:58Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los puntos embebidos son la pesadilla de todo principiante de Clarion. Son extremadamente útiles, pero son muy difíciles de aprender. Para colmo, la abstracción que implementa la clase ABC hace más difícil todavía conocerlos y aprovecharlos. Por eso esta sección es de vital importancia.&lt;br /&gt;
&lt;br /&gt;
== FORMULARIOS ==&lt;br /&gt;
=== ¿Qué procedimiento llamó al Form? ===&lt;br /&gt;
Al principio del WindowManager.Init del Form (primer prioridad disponible)&lt;br /&gt;
&lt;br /&gt;
 GlobalErrors.GetProcedureName()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones complejas ===&lt;br /&gt;
Por ejemplo validar un Email:&lt;br /&gt;
En el accepted del campo&lt;br /&gt;
Puedes hacerlo con MATCH, ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# = MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
Devuelve 1 o 0 si el mail no es válido.&lt;br /&gt;
El MATCH puede usarse con expresiones regulares para validar casi cualquier cosa...&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se Abre/inicializa el Form ===&lt;br /&gt;
ThisWindow.Init&lt;br /&gt;
 !Es interesante entrar por el botón source a este embed para entender bien todas sus prioridades&lt;br /&gt;
 !GlobalRequest (pasada por el browse) se guarda en la propiedad ThisWindow.Request&lt;br /&gt;
 !Se puede preguntar por SELF.Request para saber para qué se lo llamó al form: &lt;br /&gt;
 !InsertRecord EQUATE (1)&lt;br /&gt;
 !ChangeRecord EQUATE (2)&lt;br /&gt;
 !DeleteRecord EQUATE (3)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar el Form a &amp;quot;Solo lectura&amp;quot; ante una condición===&lt;br /&gt;
 ThisWindow.Init&lt;br /&gt;
 ! [Priority 4950] La prioridad es importante!&lt;br /&gt;
 IF FAC:facturado = 1 THEN SELF.Request = ViewRecord.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Truco: Llamar al form para insertar desde el menú ===&lt;br /&gt;
Podríamos asumir que si la GlobalRequest está en blanco es que se lo&lt;br /&gt;
llamó para insertar, evitaríamos asi el paso por un Browse&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !If GlobalRequest = 0 Then GlobalRequest = InsertRecord.&lt;br /&gt;
&lt;br /&gt;
Si la tabla tiene una clave Autonumber, se complica un poco mas, sería asi:&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !Por ej prioridad 300&lt;br /&gt;
 If GlobalRequest = 0&lt;br /&gt;
     GlobalRequest = InsertRecord&lt;br /&gt;
     DesdeMenu# = True&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
 !Después de Open Files:&lt;br /&gt;
 !Por ej prioridad 7800&lt;br /&gt;
 If DesdeMenu# = True&lt;br /&gt;
 Access:People.PrimeAutoinc()&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Llamar a un form para editar una tabla con un solo registro ===&lt;br /&gt;
Típicamente una tabla de parametros, obviamente no queremos pasar por un browse&lt;br /&gt;
 WindowManager.Init,&lt;br /&gt;
 !al principio&lt;br /&gt;
 GlobalRequest = ChangeRecord&lt;br /&gt;
&lt;br /&gt;
 !Luego de Open files&lt;br /&gt;
 Set(Tabla)&lt;br /&gt;
 access:Tabla.Next()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se confirma un Form ===&lt;br /&gt;
ThisWindow.TakeCompleted&lt;br /&gt;
 ! [Priority 2800]&lt;br /&gt;
 !ANTES DE QUE SE CONFIRME LA GRABACION&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 ReturnValue = PARENT.TakeCompleted()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 !YA SE GRABÓ EL REGISTRO.&lt;br /&gt;
 !VERIFICAR SI SELF.Response=RequestCompleted A VER SI SE GRABÓ OK.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se cierra un Form ===&lt;br /&gt;
ThisWindow.Kill&lt;br /&gt;
 !VERIFICAR LOS valores de SELF.Request y SELF.Response&lt;br /&gt;
 !Para decidir que acciones tomar&lt;br /&gt;
 !Este punto ya es &amp;quot;demasiado tarde&amp;quot; para hacer algo antes de que se grabe el registro&lt;br /&gt;
 !Para eso usar TakeCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se produce el borrado sin abrir el Form ===&lt;br /&gt;
Si tenemos un form para actualizar una tabla, y definimos que el borrado sea Confirmando (Standard Warning) o Automático (Automatic Delete), y necesitamos ejecutar un código en el form cuando se efectúe el borrado, usamos:&lt;br /&gt;
&lt;br /&gt;
ThisWindow.PrimeUpdate, después del Parent Call&lt;br /&gt;
&lt;br /&gt;
 if self.request = DeleteRecord and self.Response = RequestCompleted&lt;br /&gt;
 !lo que quiero hacer&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que el borrado de un registro no pasa por el TakeCompleted, excepto cuando se usa la ventana del form (Display Form).&lt;br /&gt;
&lt;br /&gt;
Aporte de Gustavo Olmedo [http://templatesclarion.com.ar/downloads/ (Templates Clarion)] (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó cualquier campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
En el TakeCompleted ponemos el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF NOT SELF.Primary.Me.EqualBuffer(SELF.Saved)&lt;br /&gt;
 ! message(&#039;Cambio&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Aporte de Pablo Guarnieri y Gustavo Olmendo&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó un campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
 IF CLI:Campo &amp;lt;&amp;gt; history::CLI:Record.Campo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Forzar grabación del form === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para grabar el form inclusive cuando el usuario lo cancele&lt;br /&gt;
&lt;br /&gt;
TakeCloseEvent PROCEDURE(),BYTE,VIRTUAL&lt;br /&gt;
 IF loc:condicion &lt;br /&gt;
    SELF.CancelAction = Cancel:Save !immediate save (no confirmation)&lt;br /&gt;
 END&lt;br /&gt;
 &lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar un Drop Combo === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para filtrar un drop combo utilizando pro:sqlfilter, suponemos que en &lt;br /&gt;
la variable loc:filtro se arma el filtro ha enviar, algo asi como: &#039;a.idtercero = &amp;lt;39&amp;gt;90909090&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
FDCB14 es el nombre del objeto el cual se puede verificar en propiedades --&amp;gt; clases.&lt;br /&gt;
&lt;br /&gt;
ApplyFilter PROCEDURE,VIRTUAL&lt;br /&gt;
 FDCB14::View:FileDropCombo{PROP:SQLFILTER} =  &amp;lt;39&amp;gt;&#039;&amp;amp;clip(loc:filtro)&amp;amp;&#039;&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
 IF FILEERRORCODE()&lt;br /&gt;
    FDCB14::View:FileDropCombo{PROP:SQLFILTER} = &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Obtener el número autogenerado por SQL Server en tablas con identity === &lt;br /&gt;
Después del Parent Call, en el TakeCompleted del Form:&lt;br /&gt;
 IF Self.Response=RequestCompleted AND Self.Request = InsertRecord&lt;br /&gt;
    Tabla{prop:Sql}= &#039;SELECT @@IDENTITY&#039; !busco el número que se asignó&lt;br /&gt;
    IF not Access:Tabla.Next()&lt;br /&gt;
       !en el primer campo de Tabla viene cargado el número autogenerado&lt;br /&gt;
    else&lt;br /&gt;
       message(&#039;Error&#039;)&lt;br /&gt;
    end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Tomado de una respuesta de Fernando Cerini en el foro.&lt;br /&gt;
&lt;br /&gt;
== REPORTES Y PROCESOS ==&lt;br /&gt;
=== Ocultar un campo del detalle según condición ===&lt;br /&gt;
 !En TakeRecord, antes del Print (Process Manager)&lt;br /&gt;
 IF &amp;lt;CONDICION&amp;gt;&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=True&lt;br /&gt;
 ELSE&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=False !si la condición no se cumple, vuelvo a hacer visible el control&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Saber si un proceso se completó ===&lt;br /&gt;
O sea que no se salió por el botón de cancelar&lt;br /&gt;
 !En el WindowManager.Kill&lt;br /&gt;
 IF Self.Response = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
 &lt;br /&gt;
=== Inicializar el número de página ===&lt;br /&gt;
 !WindowManager.OpenReport, despues del Parent Call&lt;br /&gt;
 IF ReturnValue = Level:Benign&lt;br /&gt;
  Report{PROP:NextPageNo} = xxx&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar la impresión ===&lt;br /&gt;
 !Local Objects, Abc Objects, Previewer, Display, After ParentCall.&lt;br /&gt;
 !impresión prohibida&lt;br /&gt;
 ReturnValue = False&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
 If ReturnValue and DemoVersion&lt;br /&gt;
   ReturnValue = False&lt;br /&gt;
   Message(&amp;quot;Está utilizando una versión del demo, no puede imprimir este documento !&amp;quot;)&lt;br /&gt;
 End&lt;br /&gt;
Aporte de Olivier Cretey&lt;br /&gt;
&lt;br /&gt;
Otra opción, en Previewer.TakeAccepted, antes del Parent Call&lt;br /&gt;
 IF CLIP(ACCEPTED(){PROP:TIP}) = &#039;Print this report&#039; THEN RETURN LEVEL:BENIGN.&lt;br /&gt;
&lt;br /&gt;
O sea pregunto por el Tool Tip del botón que se ha presionado. Ojo, si lo tienes traducido tienes que cambiar el &#039;Print this report&#039; por tu Tool Tip.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un Proceso ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt; Validate Records --&amp;gt;&amp;gt; [Priority 5600] &lt;br /&gt;
 If &amp;lt;Condición de Filtro&amp;gt;&lt;br /&gt;
     Return Record:Filtered &lt;br /&gt;
 Else &lt;br /&gt;
     Return Record:OK &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
 &lt;br /&gt;
=== Habilitar o deshabilitar el Print Preview ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 Self.SkipPreview = Loc:Preview &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Cantidad de Páginas generadas ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 ENDPAGE(SELF.Report) &lt;br /&gt;
 Loc:Paginas = RECORDS(SELF.PreviewQueue) &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un Transporte ===&lt;br /&gt;
Necesitas crear 3 details.&lt;br /&gt;
DetailDatos&lt;br /&gt;
DetailTransporte: aca van las variables locales con los totales&lt;br /&gt;
DetailSalto: este detail es vacío y con la propiedad PageAfter&lt;br /&gt;
&lt;br /&gt;
En el embed TakeRecord (antes de los PRINTs) habría que hacer algo asi&lt;br /&gt;
 LOC:Fila += 1&lt;br /&gt;
 If LOC:Fila % 28 = 0 !28 líneas por página...&lt;br /&gt;
     PRINT(RPT:DetailSalto)&lt;br /&gt;
     PRINT(RPT:DetailTransporte)&lt;br /&gt;
     LOC:Fila = 1&lt;br /&gt;
 End&lt;br /&gt;
 LOC:Total += LIBRO:Total&lt;br /&gt;
 PRINT (RPT:Detalle)&lt;br /&gt;
 RETURN LEVEL:Benign&lt;br /&gt;
&lt;br /&gt;
Marcelo Martínez&lt;br /&gt;
y [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Acelerar las actualizaciones ===&lt;br /&gt;
Para que los procesos que agreguen registros funcionen mas rápido hay que agregar un Logout o Stream en Init y un Commit o Flush en el kill.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Se imprime o se Cancela? ===&lt;br /&gt;
Los embeds son&lt;br /&gt;
 ABC Objectd&lt;br /&gt;
 --WindowManager(ReportManager)&lt;br /&gt;
 --CancelPrintReport&lt;br /&gt;
 -Se Cancela&lt;br /&gt;
&lt;br /&gt;
 --PrintReport&lt;br /&gt;
 -Se imprime&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Recorrer la cola de las páginas ===&lt;br /&gt;
Cada página del reporte genera una imagen .WMF, la cual se guarda en el directorio temporal.&lt;br /&gt;
Con este ejemplo se puede recorrer la cola donde se guardan los nombres de estos archivos. Ésto es lo que usa por ejemplo el  [http://templatesclarion.com.ar/downloads/ EC_Mail Template] para enviar estas páginas por mail.&lt;br /&gt;
 Previewer.Open PROCEDURE&lt;br /&gt;
 ....&lt;br /&gt;
 loop a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
     get(SELF.ImageQueue,a#)&lt;br /&gt;
     message(SELF.ImageQueue)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir una Queue ===&lt;br /&gt;
La mejor forma de hacerlo en Clarion6 es en Report Properties - General -&lt;br /&gt;
Datasource: Queue.&lt;br /&gt;
&lt;br /&gt;
Yo generalmente pongo los parametros en la ventana y cargo la queue en el&lt;br /&gt;
evento accepted del PauseButton.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un SQL ===&lt;br /&gt;
Lo que yo hago es poner todos los parámetros en la ventana del reporte.&lt;br /&gt;
En el accepted del boton de pausa cargo la cola de memoria con:&lt;br /&gt;
&lt;br /&gt;
 SQL{PROP:SQL} = !aca armo el string SQL&lt;br /&gt;
 IF ERRORCODE() THEN STOP( FILEERROR()).&lt;br /&gt;
 FREE(ColaMemoria)&lt;br /&gt;
 LOOP&lt;br /&gt;
     NEXT(SQL) !O ABC, como prefieras...&lt;br /&gt;
     IF ERRORCODE() THEN BREAK.&lt;br /&gt;
     ColaMemoria :=: SQL:Record&lt;br /&gt;
     ADD(ColaMemoria)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
El reporte lo configuro para trabajar con la cola (data source) y en el&lt;br /&gt;
Detail del reporte pongo los campos de la cola de memoria.&lt;br /&gt;
Lo ideal es tener una cola de memoria global con el atributo thread y usar&lt;br /&gt;
siempre la misma para todo.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar o hacer cortes de control manuales en reportes ===&lt;br /&gt;
En TakeRecord, antes del Print.&lt;br /&gt;
 &lt;br /&gt;
!Actualizar contadores&lt;br /&gt;
&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; CampoCorte&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; 0 !para evitar la primera vez&lt;br /&gt;
 !Inicializar los contadores&lt;br /&gt;
 END&lt;br /&gt;
 AUX=CAMPO&lt;br /&gt;
 !SE VIENE EL CORTE&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Este método TakeRecord se usa también para actualizar cualquier variable calculada antes de la impresión de la banda de detalle.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo BLOB ===&lt;br /&gt;
Este código va en el método TakeRecord, antes del PRINT&lt;br /&gt;
&lt;br /&gt;
 Report$?Image1{PROP:NoWidth} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:NoHeight} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:ImageBlob} = STU:Photograph{PROP:Handle}&lt;br /&gt;
 IF Report$?Image1{PROP:Height} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Width}/Report$?Image1{PROP:Height}&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
 IF Report$?Image1{PROP:Width} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Height}/Report$?Image1{PROP:Width}&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo CSTRING ===&lt;br /&gt;
Este caso es similar al anterior, pero en el campo se encuentra el path donde está la imagen&lt;br /&gt;
 !En el método TakeRecord, antes del PRINT&lt;br /&gt;
 Report$?Image1{PROP:Text} = PRO:Foto&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Evitar el cartel &amp;quot;No records to process&amp;quot; en un proceso ===&lt;br /&gt;
 !En el metodo TAKE NO RECORDS poner un RETURN antes del parent call.&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir el reporte en blanco, cuando no hay registros ===&lt;br /&gt;
En WindowManager. Next, antes del Parent Call con prioridad 500.&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 500] antes del Parent Call&lt;br /&gt;
 If Primera=0 !variable local byte&lt;br /&gt;
    Primera=1&lt;br /&gt;
    SELF.Process.RecordsProcessed = 1&lt;br /&gt;
    Return Level:Benign&lt;br /&gt;
 End&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Cuando hay filtros y rangos, esta solución suele duplicar el primer registro del detalle.&lt;br /&gt;
Para Solucionar esto en ProcessManager NextPROCEDURE(BYTE ProcessRecord) con prioridad 7500 se debe colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF ReturnValue = 0 AND LOC:Primera = 0 THEN !Si hay un registro&lt;br /&gt;
    LOC:Primera = 1        !Dejo al reporte seguir su curso normal&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Mario Wojcik&lt;br /&gt;
&lt;br /&gt;
=== Detectar el último registro en un process o Reporte (fin de archivo) ===&lt;br /&gt;
 ThisProcess.Next PROCEDURE(BYTE ProcessRecords=True)&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 !Fin del proceso&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
Esto por ejemplo es muy útil para cambiar etiquetas en los totales generales del reporte, en un page footer&lt;br /&gt;
 ThisReport.Next PROCEDURE(BYTE ProcessRecords)&lt;br /&gt;
 ....&lt;br /&gt;
 ! [Priority 5001] despues del Parent Call&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 REPORT$?LabelTotal{prop:text}= &#039;Total&#039;&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Reporte con múltiples detalles ===&lt;br /&gt;
Por Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 Viajes&lt;br /&gt;
 |--&amp;gt;pasajeros&lt;br /&gt;
 |--&amp;gt;comisiones&lt;br /&gt;
&lt;br /&gt;
Habría que poner solo la tabla viajes en el Table Schematic. Pasajeros y Comisiones en Other Tables&lt;br /&gt;
&lt;br /&gt;
En el reporte crear 3 details, uno para cada tabla.&lt;br /&gt;
&lt;br /&gt;
En ThisReport.TakeRecord, antes de los PRINTs&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 5500]&lt;br /&gt;
 PRINT(RPT:DetailViaje)&lt;br /&gt;
 CLEAR(PAS:RECORD)&lt;br /&gt;
 PAS:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(PAS:ClavePorViaje, PAS:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Pasajeros.Next() OR PAS:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailPasajeros)&lt;br /&gt;
 END&lt;br /&gt;
 !Y lo mismo para las comisiones&lt;br /&gt;
 CLEAR(COM:RECORD)&lt;br /&gt;
 COM:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(COM:ClavePorViaje, COM:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Comisiones.Next() OR COM:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailComisiones)&lt;br /&gt;
 END&lt;br /&gt;
 Return Level:Benign !ya imprimí todo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Otra alternativa podría ser utilizando el Template &#039;&#039;&#039;ReportChildFiles&#039;&#039;&#039; (desde version 6.X ?) ya que puede ser utilizado mas de una vez en un mismo reporte, apuntando cada instancia a un archivo &amp;quot;hijo&amp;quot; diferente.&lt;br /&gt;
Es fácil de configurar: Se debe seleccionar la tabla CHILD y la PARENT. En el reporte hay que definir el REPORT DETAIL (para el CHILD) y ponerle algún nombre en el label que luego debe ser configurado en el Template.&lt;br /&gt;
&lt;br /&gt;
Jose Sturniolo&lt;br /&gt;
&lt;br /&gt;
=== Imprimir exactamente lo que estamos viendo en el browse ===&lt;br /&gt;
En el browse pones un botón que llame al reporte y en parameters:&lt;br /&gt;
(Brw1.view{PROP:Filter}, Brw1.view{PROP:Order})&lt;br /&gt;
&lt;br /&gt;
En las propiedades del reporte o proceso:&lt;br /&gt;
Prototype: (STRING, STRING)&lt;br /&gt;
Parameters: (FILTRO, ORDEN)&lt;br /&gt;
&lt;br /&gt;
En WindowManager.Init, al final:&lt;br /&gt;
 ThisReport.SetFilter(FILTRO) ! o ThisProcess....&lt;br /&gt;
 ThisReport.SetOrder(ORDEN)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar tamaño de hoja en el reporte ===&lt;br /&gt;
En el embed WindowManager &#039;OpenReport&#039;, PRIORITY(7500)&lt;br /&gt;
&lt;br /&gt;
 IF ~ReturnValue&lt;br /&gt;
 SETTARGET(REPORT)&lt;br /&gt;
 CASE PRINTER{PROPPRINT:Paper}&lt;br /&gt;
 OF PAPER:LETTER&lt;br /&gt;
     REPORT{PROP:height} = 8500&lt;br /&gt;
     ?Footer{PROP:Ypos} = 9000&lt;br /&gt;
 OF PAPER:LEGAL&lt;br /&gt;
     REPORT{PROP:height} = 11000&lt;br /&gt;
     ?Footer{PROP:Ypos} = 11500&lt;br /&gt;
 etc.&lt;br /&gt;
 END&lt;br /&gt;
 SETTARGET()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
etc. con los tamaños de papel que quieras.&lt;br /&gt;
Esto acomoda el contenido del reporte en run-time, haciéndolo ocupar más &lt;br /&gt;
o menos hoja según sea el largo de la misma. Chiche, ¿no?.&lt;br /&gt;
Ajustá los valores a tus necesidades.&lt;br /&gt;
Para tener en cuenta: el usuario tiene que elegir el tamaño del papel &lt;br /&gt;
ANTES de generar el reporte. Si ya está en la vista previa, el reporte ya &lt;br /&gt;
está generado, por lo tanto si cambia el largo de hoja ahí, no se lo va a &lt;br /&gt;
tomar.&lt;br /&gt;
&lt;br /&gt;
Jorge Lavera&lt;br /&gt;
&lt;br /&gt;
=== Cambiar Impresora ===&lt;br /&gt;
En Global Properties--&amp;gt;Embeds--&amp;gt;Before Global INCLUDEs&lt;br /&gt;
 INCLUDE(&#039;PRNPROP.CLW&#039;)&lt;br /&gt;
 !para poder acceder a las propiedades de las impresoras&lt;br /&gt;
&lt;br /&gt;
Luego en el Reporte en &lt;br /&gt;
 ThisReport.Open()&lt;br /&gt;
 !para guardar la impresora por defecto de Windows&lt;br /&gt;
 GLO:IMPRESORA = PRINTER{PROPPRINT:Device}&lt;br /&gt;
 !Seteo la impresora que quiero usar.&lt;br /&gt;
 !El string debe ser igual al que figura en IMPRESORAS&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = &#039;HP Deskjet 840&#039;&lt;br /&gt;
&lt;br /&gt;
y por último en&lt;br /&gt;
 ThisReport.Kill()&lt;br /&gt;
 !para devolver la impresora por defecto de windows&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = CLIP(GLO:IMPRESORA)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Guillermo Ondetti, Pragma Sistemas&lt;br /&gt;
&lt;br /&gt;
=== Detectar Salto de Página de Reporte ===&lt;br /&gt;
Este sería el codigo, siempre y cuando no tengas break groups (ahi se complica bastante)&lt;br /&gt;
El embebido es TakeRecord en ABC, o Before Print Detail en Legacy.&lt;br /&gt;
 VarLocal += REPORT$?Detail{PROP:height}&lt;br /&gt;
 IF VarLocal &amp;gt; REPORT{PROP:height}&lt;br /&gt;
     VarLocal = REPORT$?Detail{PROP:height}&lt;br /&gt;
     !En el siguiente PRINT Cambia la página...&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Aplicar Filtro sql en el reporte ===&lt;br /&gt;
Se arma el filtro si se quiere en una variable por ejemlo loc:sql&lt;br /&gt;
y se aplica en Local Objects --&amp;gt; Abc Objects -- &amp;gt; Process manager --&amp;gt; Apply Filter antes del parent call, asi:&lt;br /&gt;
&lt;br /&gt;
 Process:View{Prop:SqlFilter}=Loc:SQL&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez&lt;br /&gt;
&lt;br /&gt;
=== Imprimir mas de una Copia por Reporte  ===&lt;br /&gt;
Se tiene que poner en el Window Manager --&amp;gt; Open (Prioridad(5000))&lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=n  !! n = Cantidad de copias &lt;br /&gt;
&lt;br /&gt;
Luego es aconsejable poner en el Window Manager --&amp;gt; Kill &lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=1 &lt;br /&gt;
&lt;br /&gt;
ASC Sergio D. Caballero&lt;br /&gt;
&lt;br /&gt;
== BROWSES ==&lt;br /&gt;
=== Actualizar un campo al hacer click en una columna ===&lt;br /&gt;
Por ejemplo, en People.app&lt;br /&gt;
&lt;br /&gt;
En el evento Accepted del Control del browse.&lt;br /&gt;
 !Si se hizo click en el campo&lt;br /&gt;
 IF ?BROWSE:1{PropList:MouseDownField}= 4&lt;br /&gt;
    ACCESS:PEOPLE.Fetch(PEO:KeyId)&lt;br /&gt;
    PEO:Gender = &#039;X&#039;&lt;br /&gt;
    ACCESS:PEOPLE.Update()&lt;br /&gt;
    BRW1.ResetFromFile()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar con SQL===&lt;br /&gt;
A veces es muy útil aplicar un filtro SQL encima de todos los demas filtros que ya tenga el browse, por ejemplo para filtrar por usuario, por sucursal, etc.&lt;br /&gt;
Yo normalmente le pongo el filtro SQL en el método windowmanager.Reset, &lt;br /&gt;
prioridad 5000&lt;br /&gt;
 BRW1.View{PROP:SQLFILTER}=&#039;+ filtro sql&#039;&lt;br /&gt;
Luego se refresca normalmente, o manualmente con ThisWindow.Reset (1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Activar un Browse invisible, o sea que está en otro TAB ===&lt;br /&gt;
Esto es especialmente útil cuando necesitamos que se ejecuten totalizadores del browse aunque éste no esté visible en la pantalla.&lt;br /&gt;
!ABC Objects -&amp;gt; &lt;br /&gt;
Local Objects -&amp;gt;&lt;br /&gt;
Windows Manager-&amp;gt;&lt;br /&gt;
Init Priority[7500] &lt;br /&gt;
 BRW2.ActiveInvisible = True &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Copiar un Registro ===&lt;br /&gt;
&lt;br /&gt;
    !ABC Objects -&amp;gt; Browse on Clientes -&amp;gt; PrimeRecord Priority[4500] &lt;br /&gt;
    IF Loc:Copiar &lt;br /&gt;
     SuppressClear = True &lt;br /&gt;
     CLEAR(Loc:Copiar) &lt;br /&gt;
    END!IF &lt;br /&gt;
&lt;br /&gt;
    !Control Events --&amp;gt; Copiar -&amp;gt; Accepted -&amp;gt; Priority[5000] &lt;br /&gt;
    Loc:Copiar = True &lt;br /&gt;
    POST(EVENT:Accepted,?UseDelBotonAgregar) &lt;br /&gt;
&lt;br /&gt;
    !Notas: Crear Variable Local Loc:Copiar &lt;br /&gt;
    ! SuppressClear es un Parametro de BrowseClass.PrimeRecord&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar el Popup ===&lt;br /&gt;
 !ABC Objects -&amp;gt; Local Objects -&amp;gt; Windows Manager--&amp;gt;&amp;gt;Init Priority[9001] &lt;br /&gt;
 Brw1.Popup.KILL&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Ordenamiento Dinámico ===&lt;br /&gt;
En Clarion6 se puede hacer automáticamente con la opcion Sort Headers.&lt;br /&gt;
Si se quiere hacer desde código para ordenar por cualquier campo, se puede utilizar:&lt;br /&gt;
    Brw1.SetOrder(&#039;TAB:Campo&#039;) &lt;br /&gt;
    Brw1.ApplyOrder() &lt;br /&gt;
    ThisWindow.Reset(1) &lt;br /&gt;
Por ejemplo si quisiera emular un ordenamiento con el doble click sobre una columna, habría que alertar el doble click en al browse, y el código sería mas o menos asi.&lt;br /&gt;
 Control Event -&amp;gt; Browse:1 -&amp;gt;Alert Key [4500] &lt;br /&gt;
 ! Código usado para cambiar el Orden del Browse &lt;br /&gt;
 ! cuando se hace doble click en la columna &lt;br /&gt;
 IF KEYCODE()=MouseLeft2 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;Codigo&#039; &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;Nombre&#039; &lt;br /&gt;
     Loc:Columna = ?Browse:1{PropList:MouseDownField} &lt;br /&gt;
     CASE Loc:Columna &lt;br /&gt;
     OF 1 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;&amp;lt;&amp;lt;&amp;lt;CODIGO&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;LCA:LOCALIDAD&#039;) &lt;br /&gt;
     OF 2 &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;&amp;lt;&amp;lt;&amp;lt;NOMBRE&amp;gt;&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;UPPER(LCA:NOMBRE)&#039;) &lt;br /&gt;
     END!CASE &lt;br /&gt;
     Brw1.ApplyOrder() &lt;br /&gt;
     ThisWindow.Reset(1) &lt;br /&gt;
 END!IF &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Locator Múltiple ===&lt;br /&gt;
Por ejemplo, para posicionarme en un código de cuenta contable:&lt;br /&gt;
Lo que podrías hacer es poner una variable string sobre el browse y poner un&lt;br /&gt;
código mas o menos asi en su accepted del entry&lt;br /&gt;
&lt;br /&gt;
 !Asumiendo que cada código tiene cuatro dígitos&lt;br /&gt;
 !Revisar la sección String Slicing en el Help&lt;br /&gt;
 Cue:Cuenta = Loc:Cuenta[1:4]&lt;br /&gt;
 Cue:SubCuenta = Loc:Cuenta[5:8]&lt;br /&gt;
 Cue:SubSubCuenta = Loc:Cuenta[9:12]&lt;br /&gt;
 SET(Cue:PorCodigo,Cue:PorCodigo)&lt;br /&gt;
 Access:Cuentas.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Otro ejempo, en un browse de órdenes, posicionarse según el nombre del cliente&lt;br /&gt;
&lt;br /&gt;
 CLI:Nombre = LOC:Cliente&lt;br /&gt;
 SET(CLI:PorNombre, CLI:PorNombre)&lt;br /&gt;
 ACCESS:Clientes.Next()&lt;br /&gt;
&lt;br /&gt;
 ORD:CodCliente = CLI:CodCliente&lt;br /&gt;
 SET(ORD:PorCliente, ORD:PorCliente)&lt;br /&gt;
 ACCESS:Ordenes.Next()&lt;br /&gt;
&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Pintar un browse según un campo ===&lt;br /&gt;
Por ejemplo cuando vemos las facturas de un Cliente se repite el nombre, este código pinta diferente cada grupo de nombres.&lt;br /&gt;
Primero hay que ponerle el atributo color al campo que necesites pintar, desde list box format.&lt;br /&gt;
Luego va el siguiente código, en WindowManager.Reset antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 Aux = &#039;&#039;&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (BRW1.Q)&lt;br /&gt;
     GET(BRW1.Q, F#)&lt;br /&gt;
     IF Aux &amp;lt;&amp;gt; BRW1.Q.CLI:Nombre&lt;br /&gt;
         Col# = 1- Col#&lt;br /&gt;
         Aux = BRW1.Q.CLI:Nombre&lt;br /&gt;
     END&lt;br /&gt;
     If Col#&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:SILVER&lt;br /&gt;
     Else&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:WHITE&lt;br /&gt;
     End&lt;br /&gt;
     PUT(BRW1.Q)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Refrescar un browse desde otra ventana ===&lt;br /&gt;
Lo mas fácil sería usando NOTIFY.&lt;br /&gt;
En la Ventana 1 (la del browse a refrescar)&lt;br /&gt;
 WindowManager.Init&lt;br /&gt;
 GLO:THREAD = THREAD() !VARIABLE GLOBAL LONG&lt;br /&gt;
&lt;br /&gt;
 Window Events&lt;br /&gt;
 Notify&lt;br /&gt;
 BRW1.ResetfromBuffer() ! o ThisWindow.Reset(1)?&lt;br /&gt;
&lt;br /&gt;
En la ventana 2, cuando se necesite refrescar la 1&lt;br /&gt;
 NOTIFY (999, GLO:THREAD)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que en éste caso no estoy usando ese parámetro.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Iniciar el browse en un Tab determinado ===&lt;br /&gt;
En ThisWindow.Init, al final&lt;br /&gt;
 SELF.FirstField = ?Tab:4 !Use del tab&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Actualizar el resultado de un totaling del browse de detalle, en el Encabezado ===&lt;br /&gt;
En el Browse de abajo (el de detalle)&lt;br /&gt;
 ResetFromView, prioridad 4500 - La prioridad es importante&lt;br /&gt;
 GET(Encabezado, ENC:Por_Numero)&lt;br /&gt;
 ENC:Total = loc:total !ÉSTA ES LA VARIABLE DEL TOTALING&lt;br /&gt;
 PUT (Encabezado)&lt;br /&gt;
 IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtro Dinámico ===&lt;br /&gt;
Poner un control Text donde el usuario pueda escribir cualquier filtro&lt;br /&gt;
 X# = EVALUATE(Filtro)&lt;br /&gt;
 IF ERRORCODE()&lt;br /&gt;
     MESSAGE(&#039;ERROR DE SINTAXIS EN EL FILTRO: &#039; &amp;amp; ERROR(), &#039;ATENCION&#039;)&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.SetFilter(Filtro)&lt;br /&gt;
     ThisWindow.Reset(1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Rangos múltiples y dinámicos ===&lt;br /&gt;
Si tenemos una clave con varios componentes, en Actions del browse ponemos un rango por current value, elegimos el componente de la clave hasta el cual queremos hacer el rango.&lt;br /&gt;
El siguiente componente de la clave se puede usar como locator.&lt;br /&gt;
Por ejemplo si tenemos una clave con Tipo+Provincia+Localidad, hacemos un rango de current value por provincia y nos queda un locator por localidad.&lt;br /&gt;
&lt;br /&gt;
 BRW1.ApplyRange PROCEDURE&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 RAN:Tipo= loc:tipo&lt;br /&gt;
 RAN:Provincia=loc:provincia&lt;br /&gt;
 SELF.Order.Rangelist.AssignLeftToRight()&lt;br /&gt;
&lt;br /&gt;
En algun boton de aplicar rango&lt;br /&gt;
 BRW1.ApplyRange()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, deshabilitar condicionalmente la actualización de registros ===&lt;br /&gt;
 IF &amp;lt;Condición&amp;gt;&lt;br /&gt;
     !Deshabilitar Actualización&lt;br /&gt;
     BRW1.InsertControl=FALSE&lt;br /&gt;
     BRW1.ChangeControl=FALSE&lt;br /&gt;
     BRW1.DeleteControl=FALSE&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.InsertControl=?INSERT&lt;br /&gt;
     BRW1.ChangeControl=?CHANGE&lt;br /&gt;
     BRW1.DeleteControl=?DELETE&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar el cambio de registro seleccionado en un Browse ===&lt;br /&gt;
Ejemplo mostrar una foto del cliente al costado del browse&lt;br /&gt;
 BRW1.TakeNewSelection PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !EN CLI:FOTO ESTA EL PATH COMPLETO DE LA FOTO&lt;br /&gt;
 IF CLI:FOTO &amp;lt;&amp;gt; &#039;&#039;&lt;br /&gt;
     ?Foto{PROP:TEXT}= CLI:FOTO &lt;br /&gt;
 ELSE&lt;br /&gt;
     ?Foto{PROP:TEXT}= &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un browse ===&lt;br /&gt;
Ejemplo: Mostrar sólo los clientes que tengan alguna orden&lt;br /&gt;
&lt;br /&gt;
 BRW1.ValidateRecord PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !FILTROS COMPLEJOS&lt;br /&gt;
 !EJ: MOSTRAR SOLO LOS CLIENTES QUE TENGAN ALGUNA ORDEN&lt;br /&gt;
 CLEAR(ORD:RECORD)&lt;br /&gt;
 Ord:CodigoCliente=CLI:ID&lt;br /&gt;
 SET(Ord:FK_Ordenes_CLIENTES,Ord:FK_Ordenes_CLIENTES)&lt;br /&gt;
 NEXT(ORDENES)&lt;br /&gt;
 IF ERRORCODE() OR (Ord:CodigoCliente &amp;lt;&amp;gt; CLI:ID) THEN RETURN Record:Filtered.&lt;br /&gt;
 &lt;br /&gt;
 RETURN Record:OK&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Poner un campo &amp;quot;saldo&amp;quot; en un browse ===&lt;br /&gt;
ThisWindow.Reset, antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 S#=0&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (Queue:Browse:1)&lt;br /&gt;
     GET(Queue:Browse:1, F#)&lt;br /&gt;
     S# += Queue:Browse:1.ORD:Total_Impo&lt;br /&gt;
     Queue:Browse:1.Saldo = S#&lt;br /&gt;
     PUT(Queue:Browse:1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Resetear/inicializar un Locator ===&lt;br /&gt;
El método a ejecutar es&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
&lt;br /&gt;
Los nombres de las instancias de Locators por cada TAB se llaman:&lt;br /&gt;
 BRW1::Sort0:Locator.Set&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
 BRW1::Sort2:Locator.Set&lt;br /&gt;
 !etc..&lt;br /&gt;
&lt;br /&gt;
Luego sería bueno volver a poner el foco en el browse para que se pueda seguir usando el locator normalmente&lt;br /&gt;
 select (?Browse:1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, disparar un procedimiento después de generar un alta, modificación, etc. ===&lt;br /&gt;
&lt;br /&gt;
El proceso a disparar se hace desde el browse, la idea es saber si del Form volvió aceptando o canceló la actualización. El punto embebido es:&lt;br /&gt;
&lt;br /&gt;
 Local Objects&lt;br /&gt;
 BRW1 (o el objeto de tipo browse class que sea)&lt;br /&gt;
 ResetFromAsk (después del Parent.call)&lt;br /&gt;
 &lt;br /&gt;
 IF VCRRequest=VCR:None&lt;br /&gt;
 CASE Request&lt;br /&gt;
 OF InsertRecord&lt;br /&gt;
     IF Response = RequestCompleted&lt;br /&gt;
     !Hacer algún proceso&lt;br /&gt;
     END&lt;br /&gt;
 END&lt;br /&gt;
 END!&lt;br /&gt;
&lt;br /&gt;
=== Inserción continua refrescando el Browse ===&lt;br /&gt;
Este otro método es similar al anterior, también sirve para lo mismo.&lt;br /&gt;
Agrego un ejemplo para hacer inserción continua en el Form y además se vaya actualizando el browse&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Run PROCEDURE(USHORT Number,BYTE Request)&lt;br /&gt;
 ! Cuidado que existen dos ThisWindow.Run, seleccionar el correcto&lt;br /&gt;
 ! [Priority 8500]&lt;br /&gt;
 IF Request = InsertRecord And ReturnValue = RequestCompleted&lt;br /&gt;
     POST(EVENT:ACCEPTED, BRW1.InsertControl)&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Posicionar un browse en un registro seleccionado ===&lt;br /&gt;
&lt;br /&gt;
Al abrir un browse a veces necesitamos posicionar el selector en un registro determinado, tal como lo hacen los browses para selección.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para posicionar el browse en el registro más cercano al proporcionado por el usuario:&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Open PROCEDURE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 ! End of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 CODE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Executable Code Section&amp;quot;&lt;br /&gt;
 ! [Priority 500]&lt;br /&gt;
 CLI:cliente= LOC:Cliente&lt;br /&gt;
 ACCESS:Clientes.fetch(CLI:Kcodigo)&lt;br /&gt;
 BRW1.selecting=1&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 PARENT.Open()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 BRW1.selecting=0&lt;br /&gt;
&lt;br /&gt;
Otra idea, propuesta por Matías Flores:&lt;br /&gt;
Ubicarlo por el valor de los campos de la clave. Por ejemplo, si en un browse de clientes querés posicionarte en un cliente que tiene un código determinado (Loc:Codigo):&lt;br /&gt;
&lt;br /&gt;
 Cli:Codigo = Loc:Codigo&lt;br /&gt;
 SET(Cli:PorCodigo,Cli:PorCodigo)&lt;br /&gt;
 Access:Clientes.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
un ejemplo parecido al anterior, pero en legacy, sería:&lt;br /&gt;
 CLI:Codigo = LOC:Codigo&lt;br /&gt;
 BRW1::LocateMode = LocateOnValue&lt;br /&gt;
 DO BRW1::LocateRecord&lt;br /&gt;
&lt;br /&gt;
Una opción más es:&lt;br /&gt;
En el WindowManager.init, antes de Initialize browse y después de OpenFiles, colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 BRWx.StartAtCurrent = True&lt;br /&gt;
 TAB:Campo = Valor_Buscado&lt;br /&gt;
 get(Tabla, TAB:Key_que_ordena_por_Campo)&lt;br /&gt;
&lt;br /&gt;
=== En Legacy, activar un filtro sobre un browse abierto. ===&lt;br /&gt;
&lt;br /&gt;
Esto se pone en el punto embebido &amp;quot;Before opening VIEW&amp;quot;. Acordarse de BINDEAR todas las variables que se necesiten.&lt;br /&gt;
&lt;br /&gt;
 !---ANTES DE ABRIR EL VIEW--- &lt;br /&gt;
 if SoloPendientes then&lt;br /&gt;
 BRW2::View:Browse{Prop:Filter} = |&lt;br /&gt;
 &#039;MER:numertra = BRW2::Sort1:Reset:TRA:numertra AND MER:saldunid &amp;lt;&amp;gt; 0&#039;&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo cuando quieras presentar el nombre completo sin los espacios de un campo a otro. Pones en el browse una variable local.&lt;br /&gt;
En el SETQUEUERECORD (4500)&lt;br /&gt;
 &lt;br /&gt;
 Loc:ApellidoNombre = clip(CON:Apellido) &amp;amp; &#039; &#039; &amp;amp; CON:Nombre&lt;br /&gt;
&lt;br /&gt;
!(Tip de Alex B.)&lt;br /&gt;
&lt;br /&gt;
=== Código antes y después de una actualización DESDE UN BROWSE. ===&lt;br /&gt;
&lt;br /&gt;
- Antes de la llamada al Form de actualización&lt;br /&gt;
! ABC Objects -&amp;gt; Browse on Archvivo -&amp;gt;Ask Priority[4500]&lt;br /&gt;
 IF Request = InsertRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR ALTA &#039;,&#039;ALTA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = ChangeRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A ACTUALIZAR &#039;,&#039;CAMBIO&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = DeleteRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR DE BAJA &#039;,&#039;BAJA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
- Después de la actualización del registro&lt;br /&gt;
!ABC Objects -&amp;gt; Browse on Provincia -&amp;gt;Ask Priority[5500]&lt;br /&gt;
 IF ReturnValue =1&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCIÓN: SE ACTUALIZÓ EL REGISTRO&#039;,&#039;ACTUALIZÓ OK&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF ReturnValue =2&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;SE CANCELÓ LA ACTUALIZACIÓN DEL REGISTRO&#039;,&#039;ATENCIÓN&#039;,ICON:HAND)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar/esconder (cambiar a PROP:HIDE) un control si el browse está vacío - pe. un botón-. ===&lt;br /&gt;
&lt;br /&gt;
En el Browse.UpdateWindow(), última prioridad:&lt;br /&gt;
 ?TuBoton{PROP:Disable}=Choose(Self.Records()&amp;lt;&amp;gt;0,0,1)&lt;br /&gt;
&lt;br /&gt;
===Iniciar un browse con un orden &amp;quot;sort header&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Si queremos que al abrir un browse el mismo se encuentre ordenado como si hubiéramos hecho click en el sortheader, ponemos luego del generated code del evento openwindow lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 BRW1::SortHeader.SetSortFromString(&#039;TAB:Campo&#039;)&lt;br /&gt;
&lt;br /&gt;
donde TAB:Campo es uno de los campos de la tabla que estoy mostrando en el browse.&lt;br /&gt;
&lt;br /&gt;
== EDIT IN PLACE==&lt;br /&gt;
=== Edit in Place o Form, según condición ===&lt;br /&gt;
En BrowseClass, Ask, antes del Parent Call&lt;br /&gt;
 If ?browse:1{proplist:mousedownfield} = 5&lt;br /&gt;
     Self.AskProcedure = 0&lt;br /&gt;
 else&lt;br /&gt;
     Self.AskProcedure = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Puede usarse cualquier condición, en este caso si el usuario hace doble click en la 5a columna se usa edit in place, sino se usa el formulario&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Desactivar Edit in Place de un campo según condición ===&lt;br /&gt;
En las propiedades del EIP del campo admitir la edición del mismo.&lt;br /&gt;
&lt;br /&gt;
En el EIP Field Manager del campo, TakeEvent, antes del Parent Call&lt;br /&gt;
  if Queue:Browse:1.TAB:Campo_de_mi_Tabla &amp;gt; 0 &lt;br /&gt;
     Return EditAction:Cancel&lt;br /&gt;
     thiswindow.reset(true)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
En este ejemplo sólo permito que pueda editarse el campo si el valor actual del mismo es &amp;lt;= 0&lt;br /&gt;
&lt;br /&gt;
=== Inicializar campos al insertar registro ===&lt;br /&gt;
O sea lo que hace el Prime Fields en las formas&lt;br /&gt;
 ABC Objects&lt;br /&gt;
 BROWSE ON TABLA using ?LIST&lt;br /&gt;
 PrimeRecords&lt;br /&gt;
 Después del Parent Call&lt;br /&gt;
 TPS:TuCampo= valor inicial&lt;br /&gt;
&lt;br /&gt;
=== Poner Disable un campo===&lt;br /&gt;
 Local Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 Abc Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 EIP Field Manag...for Field NombreCampo&lt;br /&gt;
 --&amp;gt;&amp;gt;Init [Priority 5001]&lt;br /&gt;
 If SELF.FEQ then SELF.FEQ{Prop:Disable} = true.&lt;br /&gt;
También se pueden cambiar otras propiedades como por ejemplo UPPER (mayúsculas) o READ ONLY (sólo lectura)&lt;br /&gt;
 If SELF.FEQ &lt;br /&gt;
     SELF.FEQ{prop:readonly} = TRUE&lt;br /&gt;
     SELF.FEQ{prop:upr} = TRUE&lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo Modificar el total cuando cambia la cantidad.&lt;br /&gt;
Primero agregar el campo cantidad en Column Specific&lt;br /&gt;
 EditInPlace::DET:Cantidad.TakeEvent PROCEDURE(UNSIGNED Event)&lt;br /&gt;
 ....&lt;br /&gt;
 !Despues del Parent Call&lt;br /&gt;
&lt;br /&gt;
 CASE ReturnValue&lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel&lt;br /&gt;
 ELSE&lt;br /&gt;
     Update(Self.Feq)&lt;br /&gt;
     BRW1.Q.DET:Total = BRW1.Q.DET:Cantidad * BRW1.Q.DET:Importe&lt;br /&gt;
     !Etc... siempre haciendo referencia a los campos de la cola BRW1.Q.&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones ===&lt;br /&gt;
Por ejemplo una validación básica de un número requerido&lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:NroDocumento&lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 ! Validación del nro. de Documento &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     UPDATE(Self.Feq) &lt;br /&gt;
     IF NOT BRW1.Q.Cli:NroDocumento &lt;br /&gt;
         BEEP(BEEP:SystemExclamation) ; YIELD() &lt;br /&gt;
         MESSAGE(&#039;No se informó el número de Documento&#039;, | &lt;br /&gt;
         &#039;Atención!&#039;, ICON:Exclamation) &lt;br /&gt;
         ReturnValue = EditAction:NONE &lt;br /&gt;
         Return ReturnValue &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Validación con un lookup a una tabla &lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:Provincia &lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 !Valida Provincia &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     Update(Self.Feq) &lt;br /&gt;
     Pro:Codigo= BRW1.Q.Cli:Provincia &lt;br /&gt;
     IF Access:Provincia.Fetch(Pro:PorCodigo) &lt;br /&gt;
         GlobalRequest = SelectRecord &lt;br /&gt;
         SelectProvincia &lt;br /&gt;
         IF NOT Pro:Codigo &lt;br /&gt;
             ReturnValue = EditAction:NONE &lt;br /&gt;
             Return ReturnValue &lt;br /&gt;
         ELSE &lt;br /&gt;
             BRW1.Q.Cli:Provincia = Pro:Codigo &lt;br /&gt;
             BRW1.Q.Pro:NOMBRE = Pro:NOMBRE &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== GLOBALES ==&lt;br /&gt;
&lt;br /&gt;
=== Cambiar los mensajes de error del SQL === &lt;br /&gt;
Con cambiar los TRN no alcanza para ese tipo de errores. &lt;br /&gt;
 &lt;br /&gt;
Lo que se puede hacer es determinar el mensaje que viene desde el SQLServer &lt;br /&gt;
para mostrar un mensaje mas amigable. &lt;br /&gt;
 &lt;br /&gt;
El embebido es &lt;br /&gt;
Global Embeds: &lt;br /&gt;
 Global Objets &lt;br /&gt;
 Abc Objects &lt;br /&gt;
 Error Manager &lt;br /&gt;
 TakeNotify &lt;br /&gt;
 !Antes del Parent Call &lt;br /&gt;
 IF INSTRING(&#039;COLUMN REFERENCE&#039;, SELF.SubsString(),1,1) &lt;br /&gt;
 SELF.Msg(&#039;El registro no puede borrarse porque tiene datos de detalle &lt;br /&gt;
 que dependen de él. |Presione [OK] para una descripción detallada del &lt;br /&gt;
 error&#039;,SELF.GetErrorBufferTitle(),ICON:Exclamation,Button:OK,BUTTON:OK,0) &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Hay que armar un IF de estos por cada tipo de error... &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validación de campos (Edit in place o Form)=== &lt;br /&gt;
 &lt;br /&gt;
Para validar campos lo ideal es usar los Global Embeds &lt;br /&gt;
 Global Embeds &lt;br /&gt;
 Field Level Validation &lt;br /&gt;
 Tabla &lt;br /&gt;
 Campo &lt;br /&gt;
 IF &amp;lt;No cumple Condición&amp;gt; &lt;br /&gt;
 Message(&#039;error...&#039;) &lt;br /&gt;
 RETURN Level:Notify &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Esto te va a funcionar &amp;quot;para siempre&amp;quot; ya sea que uses Edit in place, un Form &lt;br /&gt;
o código embebido para actualizar la tabla. &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Aplicaciones_de_Ejemplo&amp;diff=75</id>
		<title>Aplicaciones de Ejemplo</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Aplicaciones_de_Ejemplo&amp;diff=75"/>
		<updated>2015-03-07T22:54:47Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Esta sección está destinada a contener aplicaciones (.app) de ejemplo.&lt;br /&gt;
&lt;br /&gt;
== Templates Clarion ==&lt;br /&gt;
[http://templatesclarion.com.ar/downloads/ Sección Downloads ]&lt;br /&gt;
&lt;br /&gt;
== Ejemplos de &amp;quot;Crispy Development Labs&amp;quot; ==&lt;br /&gt;
http://www.users.on.net/~crispy/&lt;br /&gt;
&lt;br /&gt;
Encriptación, tratamiento de imágenes, compresión, winsock, y otras aplicaciones de ejemplo con código en Clarion 6.&lt;br /&gt;
&lt;br /&gt;
== SICyA Software Ltda. ==&lt;br /&gt;
&lt;br /&gt;
http://www.sicya.com&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ID Call&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ejemplo de como hacer un identificador de llamadas desde Clarion utilizando WinEvent.&lt;br /&gt;
&lt;br /&gt;
[http://templatesclarion.com.ar/downloads/ Descargarlo de aqui...]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Templates_gratuitos&amp;diff=74</id>
		<title>Templates gratuitos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Templates_gratuitos&amp;diff=74"/>
		<updated>2015-03-07T22:52:13Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Evolution Consulting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Existen diversos templates adicionales para Clarion que extienden notablemente su funcionalidad.&lt;br /&gt;
&lt;br /&gt;
Esta sección debería incluir el nombre, una breve descripción del mismo, las versiones compatibles de Clarion y el sitio desde donde puede descargarse.&lt;br /&gt;
&lt;br /&gt;
== ABCFree ==&lt;br /&gt;
&lt;br /&gt;
Es el conjunto de templates y librerias gratuitas más interesante para Clarion.&lt;br /&gt;
Esta disponible en http://www.authord.com/Clarion . Frecuentemente actualizado y cubre todos los niveles de programación con Clarion: bajo y alto nivel. Fundamental&lt;br /&gt;
&lt;br /&gt;
== Botpl ==&lt;br /&gt;
Sitio web: http://comsoft7.com/Botpl.htm&lt;br /&gt;
&lt;br /&gt;
Incluye:&lt;br /&gt;
&lt;br /&gt;
AppSpecsControl, BarCodeLabelControl,BrowseSearch,LabelControl,ListHorzRuntime,ListVertRuntime, PerCentGraph,PerCentGraphVert,Bo_resc 32bit only.&lt;br /&gt;
&lt;br /&gt;
== Clarion Australia ==&lt;br /&gt;
http://www.comformark.com.au/&lt;br /&gt;
&lt;br /&gt;
Clarion Autralia&lt;br /&gt;
&lt;br /&gt;
== Clarion FreeImage Project ==&lt;br /&gt;
&lt;br /&gt;
http://www.clarionfreeimage.com/&lt;br /&gt;
&lt;br /&gt;
Conjunto de clases y un template que implementa la librería open source FreeImage para procesamiento de imágenes en Clarion 5.5 y 6.x.&lt;br /&gt;
Tiene una seccion[http://www.clarionfreeimage.com/related.html] con varias clases y ejemplos: escanear con eztwain, enumerar monitores, barras de progreso e iconos en Barras de estado, botones con alpha blend y smooth scrolling control&lt;br /&gt;
&lt;br /&gt;
== Templates Clarion (Distribuidor oficial de Clarion) ==&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ Seccion Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ MENSAJES DE CLARION EN ESPAÑOL ]&lt;br /&gt;
&lt;br /&gt;
Traducción al español de todos los botones, mensajes, etc... que se utilizan en la generación de los Wizzards. Actualizado siempre a la última version de Clarion. Una herramienta indispensable para nuestra comunidad Latinoamericana.&lt;br /&gt;
&lt;br /&gt;
Para instalar simplemente copie los archivos al directorio Clarion6\LIBSRC.&lt;br /&gt;
&lt;br /&gt;
También agregamos la traducción del Calendario ABUTILUI&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ EC_Mail Template]&lt;br /&gt;
&lt;br /&gt;
El producto está compuesto por un Control Template para envío de mail y un Extension Template para enviar los WMF del preview por mail con selector de página. Permite guardar el wmf en un word y generar el attach automáticamente dentro de un mail o bien dejarlo en segundo plano del aplicativo.&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ EVOLUTION TOOLS (Clarion 5, 5.5 y 6.1) ]&lt;br /&gt;
&lt;br /&gt;
Incluye el Control Template tan solicitado &amp;quot;página de páginas&amp;quot; en los reportes.&lt;br /&gt;
&lt;br /&gt;
Evita el mensaje &#039;No hay registros para procesar&#039;&lt;br /&gt;
&lt;br /&gt;
STREAM y FLUSH Automático en los process.&lt;br /&gt;
&lt;br /&gt;
Control template que nos permite pegar un calendario en una windows. La diferencia de este template con otros free es que éste agrega el calendario dentro de la misma ventana como &amp;quot;Control Template&amp;quot;, los otros son simplemente procedimientos aparte.&lt;br /&gt;
&lt;br /&gt;
Enter por Tab mejorado.&lt;br /&gt;
&lt;br /&gt;
Imprimir Página Desde - Hasta desde Preview.&lt;br /&gt;
&lt;br /&gt;
Configuración de Impresora en Preview.&lt;br /&gt;
&lt;br /&gt;
Impresión Página Actual en Preview.&lt;br /&gt;
&lt;br /&gt;
Este template se irá actualizando periódicamente, se aceptan sugerencias...&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ ARBOL DE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Pequeño Utility template que genera el árbol de procedimientos en un archivo NombreAPP.TXT&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ CLARION BATCH COMPILER (beta 11) ]&lt;br /&gt;
&lt;br /&gt;
Este excelente producto de Cristian Olsen compila en modo Batch todos los APPs del sistema. Compatible con todas las versiones de Clarion&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ INFORMACION DE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Template muy útil para volcar información detallada de los procedimientos de un app, con nombre, tipo, prototipo, ultima modificación, si es local o externo, etc (Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ GRABAR TAB ELEGIDO ]&lt;br /&gt;
&lt;br /&gt;
Se agrega a los browses con múltiples tabs y graba como se lo utilizó la ultima vez para cuando se reingrese, se pare nuevamente en ese tab(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ TRACE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Este es mas complejo, es global y se indica un procedimiento que es le que recibirá el procedimiento y app por el que se está pasando, este procedimiento (que el usuario debe crear) es que debe grabar en un archivo deseado, el resultado. En mi caso graba en un txt, el procedimiento, app, fecha y hora, y tengo una variable en un INI para indicar si debe grabarse o no.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ CAMPOS OBLIGATORIOS ]&lt;br /&gt;
&lt;br /&gt;
Extensión que hace no se pueda salir de los campos obligatorios. Es global con opciones locales (se puede deshabilitar en cada procedimiento). Importante: Es necesario crear un alert key global para salir del procedimiento para dejar escapar al usuario en caso de necesidad.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ VARIOS ]&lt;br /&gt;
&lt;br /&gt;
Tiene 2 funciones, si se presiona CrtlAltP, indica en un message en que procedimiento estamos y en que APP está y una función que si estás parado en un campo con formato de fecha y presionas el + del teclado numérico asigna la fecha del día.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ DCT2SQL ]&lt;br /&gt;
&lt;br /&gt;
La última versión de uno de los templates mas populares para la generación de Scripts SQL a partir del DCT (Gracias Roberto Artigas)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ MCI ]&lt;br /&gt;
&lt;br /&gt;
Template que reproduce audio (Wav, Mp3) y video (Avi, Mpg) (Gracias Victor Pierri)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ Calendario + 18 funciones ]&lt;br /&gt;
&lt;br /&gt;
Template del estilo PopUp Calendario y un conjunto de 18 Funciones muy útiles (Ver mas info) Gracias Francisco J. Carabez&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ Print Driver ]&lt;br /&gt;
&lt;br /&gt;
Template para impresoras matriciales, traducido y mejorado por Ruben Caporossi . Simplemente se registra en Global Extensions del app y las funciones están disponibles&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ Esta página se actualiza constantemente...]&lt;br /&gt;
&lt;br /&gt;
== SICyA Software ==&lt;br /&gt;
http://www.sicya.com&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; SICyA Templates &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
AutoCompletar_SICyA - Control entry de autocompletado desde una tabla.&lt;br /&gt;
&lt;br /&gt;
Calendario_SICyA - Calendario con estilo XP con manejo de dominicales y feriados.&lt;br /&gt;
&lt;br /&gt;
LlamaProcedimiento_SICyA - Llama procedimientos con parámetros o en forma thread.&lt;br /&gt;
&lt;br /&gt;
VolumeDiscoDuro_SICyA - Captura Serial, nombre del Volumen y Tipo Archivos de un Disco&lt;br /&gt;
&lt;br /&gt;
Botones_SICyA - Extensión para tener Botones con un estilo propio en aplicaciones no XP.&lt;br /&gt;
&lt;br /&gt;
[http://www.sicya.com/download/SICyA_Templates_Build_051007.exe Descargar el template aqui...]&lt;br /&gt;
&lt;br /&gt;
== Solace ==&lt;br /&gt;
&lt;br /&gt;
http://www.solace-software.demon.co.uk/freetemplates.htm&lt;br /&gt;
&lt;br /&gt;
Enhanced standard HTML help template&lt;br /&gt;
&lt;br /&gt;
Colour all columns in a browse on a condition without having to individually specify each column&lt;br /&gt;
&lt;br /&gt;
Screen Resolution&lt;br /&gt;
&lt;br /&gt;
Make Directory&lt;br /&gt;
&lt;br /&gt;
Read Only Window&lt;br /&gt;
&lt;br /&gt;
Open Close Files in Source Template&lt;br /&gt;
&lt;br /&gt;
Add Wallpaper to every Window&lt;br /&gt;
&lt;br /&gt;
Override Recursive Insert Message &lt;br /&gt;
&lt;br /&gt;
Global extension to change the Font of every screen in your app.&lt;br /&gt;
&lt;br /&gt;
Global Extension to allow users to make all controls flat&lt;br /&gt;
&lt;br /&gt;
== tabajara ==&lt;br /&gt;
&lt;br /&gt;
http://www.tabajara.com/downloads.html&lt;br /&gt;
&lt;br /&gt;
Browser to HTML - Just populate a Button and you can export to HTML&lt;br /&gt;
&lt;br /&gt;
Browser to CSV - Just populate a Button, and Done! This way you can export to Excel.&lt;br /&gt;
&lt;br /&gt;
Files to CSV - Choose files to export data. (export files to CSV selecting from DCT)&lt;br /&gt;
&lt;br /&gt;
Report Green Bar - makes shadowed every other report detail.&lt;br /&gt;
&lt;br /&gt;
== xFunction ==&lt;br /&gt;
&lt;br /&gt;
Colección gratuita de templates de código de la empresa Sealsoft. Incluyen funciones para manejo de fechas, archivos y paths, y algunas otras. Puede descargarse de http://www.seal-soft.com&lt;br /&gt;
&lt;br /&gt;
== Locus Templates ==&lt;br /&gt;
&lt;br /&gt;
http://www.riebens.co.za/index.php?option=com_content&amp;amp;view=article&amp;amp;id=39&amp;amp;Itemid=183&lt;br /&gt;
&lt;br /&gt;
Excelente conjunto de templates que abarcan varias categorias: &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CONTROL TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* PageTree	Seleccionar una hoja de propiedades de un listbox tipo tree&lt;br /&gt;
* PopupDate	Seleccionar fecha desde un calendario&lt;br /&gt;
* PopupDirectory	Seleccionar directorio&lt;br /&gt;
* RichEdit	Completo editor de texto enriquecido (RTF) totalmente escrito en clarion con toolbar y tabulador.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PROCEDURES:&#039;&#039;&#039;&lt;br /&gt;
* QBEDialog	Crea Dialogo QBE (Query by Example).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CODE TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* CWPrintEngine	Imprimir un reporte creado con el CW Report Writer&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;EXTENSION TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* BrowseEdit	Edit in place para un browse box con validación de campos y lookup&lt;br /&gt;
* BrowseTotal	Totalizar campos en un browse box.&lt;br /&gt;
* BrowseValue	Crea un checkbox editable&lt;br /&gt;
* FormSplit	Divisores verticales u horizontales&lt;br /&gt;
* GetIniFile	Obtiene y guarda valores en un archivo ini.&lt;br /&gt;
* LimitStarts	Evita comenzar 2 MDI threads a la vez&lt;br /&gt;
* PopupToolbar	Toolbar ocultable &lt;br /&gt;
* ReportFilter	Seleccionar registros para imprimir y resaltar. Incluye un visor de reporte&lt;br /&gt;
* FILE MANAGER	Posibilita cambiar el dct, recompilar, y todos los archivos son actualizados automáticamente a la nueva version&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=73</id>
		<title>Puntos Embebidos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=73"/>
		<updated>2015-03-07T22:49:40Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Recorrer la cola de las páginas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los puntos embebidos son la pesadilla de todo principiante de Clarion. Son extremadamente útiles, pero son muy difíciles de aprender. Para colmo, la abstracción que implementa la clase ABC hace más difícil todavía conocerlos y aprovecharlos. Por eso esta sección es de vital importancia.&lt;br /&gt;
&lt;br /&gt;
== FORMULARIOS ==&lt;br /&gt;
=== ¿Qué procedimiento llamó al Form? ===&lt;br /&gt;
Al principio del WindowManager.Init del Form (primer prioridad disponible)&lt;br /&gt;
&lt;br /&gt;
 GlobalErrors.GetProcedureName()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones complejas ===&lt;br /&gt;
Por ejemplo validar un Email:&lt;br /&gt;
En el accepted del campo&lt;br /&gt;
Puedes hacerlo con MATCH, ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# = MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
Devuelve 1 o 0 si el mail no es válido.&lt;br /&gt;
El MATCH puede usarse con expresiones regulares para validar casi cualquier cosa...&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se Abre/inicializa el Form ===&lt;br /&gt;
ThisWindow.Init&lt;br /&gt;
 !Es interesante entrar por el botón source a este embed para entender bien todas sus prioridades&lt;br /&gt;
 !GlobalRequest (pasada por el browse) se guarda en la propiedad ThisWindow.Request&lt;br /&gt;
 !Se puede preguntar por SELF.Request para saber para qué se lo llamó al form: &lt;br /&gt;
 !InsertRecord EQUATE (1)&lt;br /&gt;
 !ChangeRecord EQUATE (2)&lt;br /&gt;
 !DeleteRecord EQUATE (3)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar el Form a &amp;quot;Solo lectura&amp;quot; ante una condición===&lt;br /&gt;
 ThisWindow.Init&lt;br /&gt;
 ! [Priority 4950] La prioridad es importante!&lt;br /&gt;
 IF FAC:facturado = 1 THEN SELF.Request = ViewRecord.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Truco: Llamar al form para insertar desde el menú ===&lt;br /&gt;
Podríamos asumir que si la GlobalRequest está en blanco es que se lo&lt;br /&gt;
llamó para insertar, evitaríamos asi el paso por un Browse&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !If GlobalRequest = 0 Then GlobalRequest = InsertRecord.&lt;br /&gt;
&lt;br /&gt;
Si la tabla tiene una clave Autonumber, se complica un poco mas, sería asi:&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !Por ej prioridad 300&lt;br /&gt;
 If GlobalRequest = 0&lt;br /&gt;
     GlobalRequest = InsertRecord&lt;br /&gt;
     DesdeMenu# = True&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
 !Después de Open Files:&lt;br /&gt;
 !Por ej prioridad 7800&lt;br /&gt;
 If DesdeMenu# = True&lt;br /&gt;
 Access:People.PrimeAutoinc()&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Llamar a un form para editar una tabla con un solo registro ===&lt;br /&gt;
Típicamente una tabla de parametros, obviamente no queremos pasar por un browse&lt;br /&gt;
 WindowManager.Init,&lt;br /&gt;
 !al principio&lt;br /&gt;
 GlobalRequest = ChangeRecord&lt;br /&gt;
&lt;br /&gt;
 !Luego de Open files&lt;br /&gt;
 Set(Tabla)&lt;br /&gt;
 access:Tabla.Next()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se confirma un Form ===&lt;br /&gt;
ThisWindow.TakeCompleted&lt;br /&gt;
 ! [Priority 2800]&lt;br /&gt;
 !ANTES DE QUE SE CONFIRME LA GRABACION&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 ReturnValue = PARENT.TakeCompleted()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 !YA SE GRABÓ EL REGISTRO.&lt;br /&gt;
 !VERIFICAR SI SELF.Response=RequestCompleted A VER SI SE GRABÓ OK.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se cierra un Form ===&lt;br /&gt;
ThisWindow.Kill&lt;br /&gt;
 !VERIFICAR LOS valores de SELF.Request y SELF.Response&lt;br /&gt;
 !Para decidir que acciones tomar&lt;br /&gt;
 !Este punto ya es &amp;quot;demasiado tarde&amp;quot; para hacer algo antes de que se grabe el registro&lt;br /&gt;
 !Para eso usar TakeCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se produce el borrado sin abrir el Form ===&lt;br /&gt;
Si tenemos un form para actualizar una tabla, y definimos que el borrado sea Confirmando (Standard Warning) o Automático (Automatic Delete), y necesitamos ejecutar un código en el form cuando se efectúe el borrado, usamos:&lt;br /&gt;
&lt;br /&gt;
ThisWindow.PrimeUpdate, después del Parent Call&lt;br /&gt;
&lt;br /&gt;
 if self.request = DeleteRecord and self.Response = RequestCompleted&lt;br /&gt;
 !lo que quiero hacer&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que el borrado de un registro no pasa por el TakeCompleted, excepto cuando se usa la ventana del form (Display Form).&lt;br /&gt;
&lt;br /&gt;
Aporte de Gustavo Olmedo [http://www.evolutionconsulting.com.ar/downloads.html (Templates Clarion)] (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó cualquier campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
En el TakeCompleted ponemos el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF NOT SELF.Primary.Me.EqualBuffer(SELF.Saved)&lt;br /&gt;
 ! message(&#039;Cambio&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Aporte de Pablo Guarnieri y Gustavo Olmendo&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó un campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
 IF CLI:Campo &amp;lt;&amp;gt; history::CLI:Record.Campo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Forzar grabación del form === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para grabar el form inclusive cuando el usuario lo cancele&lt;br /&gt;
&lt;br /&gt;
TakeCloseEvent PROCEDURE(),BYTE,VIRTUAL&lt;br /&gt;
 IF loc:condicion &lt;br /&gt;
    SELF.CancelAction = Cancel:Save !immediate save (no confirmation)&lt;br /&gt;
 END&lt;br /&gt;
 &lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar un Drop Combo === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para filtrar un drop combo utilizando pro:sqlfilter, suponemos que en &lt;br /&gt;
la variable loc:filtro se arma el filtro ha enviar, algo asi como: &#039;a.idtercero = &amp;lt;39&amp;gt;90909090&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
FDCB14 es el nombre del objeto el cual se puede verificar en propiedades --&amp;gt; clases.&lt;br /&gt;
&lt;br /&gt;
ApplyFilter PROCEDURE,VIRTUAL&lt;br /&gt;
 FDCB14::View:FileDropCombo{PROP:SQLFILTER} =  &amp;lt;39&amp;gt;&#039;&amp;amp;clip(loc:filtro)&amp;amp;&#039;&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
 IF FILEERRORCODE()&lt;br /&gt;
    FDCB14::View:FileDropCombo{PROP:SQLFILTER} = &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Obtener el número autogenerado por SQL Server en tablas con identity === &lt;br /&gt;
Después del Parent Call, en el TakeCompleted del Form:&lt;br /&gt;
 IF Self.Response=RequestCompleted AND Self.Request = InsertRecord&lt;br /&gt;
    Tabla{prop:Sql}= &#039;SELECT @@IDENTITY&#039; !busco el número que se asignó&lt;br /&gt;
    IF not Access:Tabla.Next()&lt;br /&gt;
       !en el primer campo de Tabla viene cargado el número autogenerado&lt;br /&gt;
    else&lt;br /&gt;
       message(&#039;Error&#039;)&lt;br /&gt;
    end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Tomado de una respuesta de Fernando Cerini en el foro.&lt;br /&gt;
&lt;br /&gt;
== REPORTES Y PROCESOS ==&lt;br /&gt;
=== Ocultar un campo del detalle según condición ===&lt;br /&gt;
 !En TakeRecord, antes del Print (Process Manager)&lt;br /&gt;
 IF &amp;lt;CONDICION&amp;gt;&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=True&lt;br /&gt;
 ELSE&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=False !si la condición no se cumple, vuelvo a hacer visible el control&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Saber si un proceso se completó ===&lt;br /&gt;
O sea que no se salió por el botón de cancelar&lt;br /&gt;
 !En el WindowManager.Kill&lt;br /&gt;
 IF Self.Response = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
 &lt;br /&gt;
=== Inicializar el número de página ===&lt;br /&gt;
 !WindowManager.OpenReport, despues del Parent Call&lt;br /&gt;
 IF ReturnValue = Level:Benign&lt;br /&gt;
  Report{PROP:NextPageNo} = xxx&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar la impresión ===&lt;br /&gt;
 !Local Objects, Abc Objects, Previewer, Display, After ParentCall.&lt;br /&gt;
 !impresión prohibida&lt;br /&gt;
 ReturnValue = False&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
 If ReturnValue and DemoVersion&lt;br /&gt;
   ReturnValue = False&lt;br /&gt;
   Message(&amp;quot;Está utilizando una versión del demo, no puede imprimir este documento !&amp;quot;)&lt;br /&gt;
 End&lt;br /&gt;
Aporte de Olivier Cretey&lt;br /&gt;
&lt;br /&gt;
Otra opción, en Previewer.TakeAccepted, antes del Parent Call&lt;br /&gt;
 IF CLIP(ACCEPTED(){PROP:TIP}) = &#039;Print this report&#039; THEN RETURN LEVEL:BENIGN.&lt;br /&gt;
&lt;br /&gt;
O sea pregunto por el Tool Tip del botón que se ha presionado. Ojo, si lo tienes traducido tienes que cambiar el &#039;Print this report&#039; por tu Tool Tip.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un Proceso ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt; Validate Records --&amp;gt;&amp;gt; [Priority 5600] &lt;br /&gt;
 If &amp;lt;Condición de Filtro&amp;gt;&lt;br /&gt;
     Return Record:Filtered &lt;br /&gt;
 Else &lt;br /&gt;
     Return Record:OK &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
 &lt;br /&gt;
=== Habilitar o deshabilitar el Print Preview ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 Self.SkipPreview = Loc:Preview &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Cantidad de Páginas generadas ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 ENDPAGE(SELF.Report) &lt;br /&gt;
 Loc:Paginas = RECORDS(SELF.PreviewQueue) &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un Transporte ===&lt;br /&gt;
Necesitas crear 3 details.&lt;br /&gt;
DetailDatos&lt;br /&gt;
DetailTransporte: aca van las variables locales con los totales&lt;br /&gt;
DetailSalto: este detail es vacío y con la propiedad PageAfter&lt;br /&gt;
&lt;br /&gt;
En el embed TakeRecord (antes de los PRINTs) habría que hacer algo asi&lt;br /&gt;
 LOC:Fila += 1&lt;br /&gt;
 If LOC:Fila % 28 = 0 !28 líneas por página...&lt;br /&gt;
     PRINT(RPT:DetailSalto)&lt;br /&gt;
     PRINT(RPT:DetailTransporte)&lt;br /&gt;
     LOC:Fila = 1&lt;br /&gt;
 End&lt;br /&gt;
 LOC:Total += LIBRO:Total&lt;br /&gt;
 PRINT (RPT:Detalle)&lt;br /&gt;
 RETURN LEVEL:Benign&lt;br /&gt;
&lt;br /&gt;
Marcelo Martínez&lt;br /&gt;
y [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Acelerar las actualizaciones ===&lt;br /&gt;
Para que los procesos que agreguen registros funcionen mas rápido hay que agregar un Logout o Stream en Init y un Commit o Flush en el kill.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Se imprime o se Cancela? ===&lt;br /&gt;
Los embeds son&lt;br /&gt;
 ABC Objectd&lt;br /&gt;
 --WindowManager(ReportManager)&lt;br /&gt;
 --CancelPrintReport&lt;br /&gt;
 -Se Cancela&lt;br /&gt;
&lt;br /&gt;
 --PrintReport&lt;br /&gt;
 -Se imprime&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Recorrer la cola de las páginas ===&lt;br /&gt;
Cada página del reporte genera una imagen .WMF, la cual se guarda en el directorio temporal.&lt;br /&gt;
Con este ejemplo se puede recorrer la cola donde se guardan los nombres de estos archivos. Ésto es lo que usa por ejemplo el  [http://templatesclarion.com.ar/downloads/ EC_Mail Template] para enviar estas páginas por mail.&lt;br /&gt;
 Previewer.Open PROCEDURE&lt;br /&gt;
 ....&lt;br /&gt;
 loop a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
     get(SELF.ImageQueue,a#)&lt;br /&gt;
     message(SELF.ImageQueue)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir una Queue ===&lt;br /&gt;
La mejor forma de hacerlo en Clarion6 es en Report Properties - General -&lt;br /&gt;
Datasource: Queue.&lt;br /&gt;
&lt;br /&gt;
Yo generalmente pongo los parametros en la ventana y cargo la queue en el&lt;br /&gt;
evento accepted del PauseButton.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un SQL ===&lt;br /&gt;
Lo que yo hago es poner todos los parámetros en la ventana del reporte.&lt;br /&gt;
En el accepted del boton de pausa cargo la cola de memoria con:&lt;br /&gt;
&lt;br /&gt;
 SQL{PROP:SQL} = !aca armo el string SQL&lt;br /&gt;
 IF ERRORCODE() THEN STOP( FILEERROR()).&lt;br /&gt;
 FREE(ColaMemoria)&lt;br /&gt;
 LOOP&lt;br /&gt;
     NEXT(SQL) !O ABC, como prefieras...&lt;br /&gt;
     IF ERRORCODE() THEN BREAK.&lt;br /&gt;
     ColaMemoria :=: SQL:Record&lt;br /&gt;
     ADD(ColaMemoria)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
El reporte lo configuro para trabajar con la cola (data source) y en el&lt;br /&gt;
Detail del reporte pongo los campos de la cola de memoria.&lt;br /&gt;
Lo ideal es tener una cola de memoria global con el atributo thread y usar&lt;br /&gt;
siempre la misma para todo.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar o hacer cortes de control manuales en reportes ===&lt;br /&gt;
En TakeRecord, antes del Print.&lt;br /&gt;
 &lt;br /&gt;
!Actualizar contadores&lt;br /&gt;
&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; CampoCorte&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; 0 !para evitar la primera vez&lt;br /&gt;
 !Inicializar los contadores&lt;br /&gt;
 END&lt;br /&gt;
 AUX=CAMPO&lt;br /&gt;
 !SE VIENE EL CORTE&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Este método TakeRecord se usa también para actualizar cualquier variable calculada antes de la impresión de la banda de detalle.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo BLOB ===&lt;br /&gt;
Este código va en el método TakeRecord, antes del PRINT&lt;br /&gt;
&lt;br /&gt;
 Report$?Image1{PROP:NoWidth} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:NoHeight} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:ImageBlob} = STU:Photograph{PROP:Handle}&lt;br /&gt;
 IF Report$?Image1{PROP:Height} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Width}/Report$?Image1{PROP:Height}&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
 IF Report$?Image1{PROP:Width} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Height}/Report$?Image1{PROP:Width}&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo CSTRING ===&lt;br /&gt;
Este caso es similar al anterior, pero en el campo se encuentra el path donde está la imagen&lt;br /&gt;
 !En el método TakeRecord, antes del PRINT&lt;br /&gt;
 Report$?Image1{PROP:Text} = PRO:Foto&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Evitar el cartel &amp;quot;No records to process&amp;quot; en un proceso ===&lt;br /&gt;
 !En el metodo TAKE NO RECORDS poner un RETURN antes del parent call.&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir el reporte en blanco, cuando no hay registros ===&lt;br /&gt;
En WindowManager. Next, antes del Parent Call con prioridad 500.&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 500] antes del Parent Call&lt;br /&gt;
 If Primera=0 !variable local byte&lt;br /&gt;
    Primera=1&lt;br /&gt;
    SELF.Process.RecordsProcessed = 1&lt;br /&gt;
    Return Level:Benign&lt;br /&gt;
 End&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Cuando hay filtros y rangos, esta solución suele duplicar el primer registro del detalle.&lt;br /&gt;
Para Solucionar esto en ProcessManager NextPROCEDURE(BYTE ProcessRecord) con prioridad 7500 se debe colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF ReturnValue = 0 AND LOC:Primera = 0 THEN !Si hay un registro&lt;br /&gt;
    LOC:Primera = 1        !Dejo al reporte seguir su curso normal&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Mario Wojcik&lt;br /&gt;
&lt;br /&gt;
=== Detectar el último registro en un process o Reporte (fin de archivo) ===&lt;br /&gt;
 ThisProcess.Next PROCEDURE(BYTE ProcessRecords=True)&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 !Fin del proceso&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
Esto por ejemplo es muy útil para cambiar etiquetas en los totales generales del reporte, en un page footer&lt;br /&gt;
 ThisReport.Next PROCEDURE(BYTE ProcessRecords)&lt;br /&gt;
 ....&lt;br /&gt;
 ! [Priority 5001] despues del Parent Call&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 REPORT$?LabelTotal{prop:text}= &#039;Total&#039;&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Reporte con múltiples detalles ===&lt;br /&gt;
Por Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 Viajes&lt;br /&gt;
 |--&amp;gt;pasajeros&lt;br /&gt;
 |--&amp;gt;comisiones&lt;br /&gt;
&lt;br /&gt;
Habría que poner solo la tabla viajes en el Table Schematic. Pasajeros y Comisiones en Other Tables&lt;br /&gt;
&lt;br /&gt;
En el reporte crear 3 details, uno para cada tabla.&lt;br /&gt;
&lt;br /&gt;
En ThisReport.TakeRecord, antes de los PRINTs&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 5500]&lt;br /&gt;
 PRINT(RPT:DetailViaje)&lt;br /&gt;
 CLEAR(PAS:RECORD)&lt;br /&gt;
 PAS:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(PAS:ClavePorViaje, PAS:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Pasajeros.Next() OR PAS:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailPasajeros)&lt;br /&gt;
 END&lt;br /&gt;
 !Y lo mismo para las comisiones&lt;br /&gt;
 CLEAR(COM:RECORD)&lt;br /&gt;
 COM:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(COM:ClavePorViaje, COM:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Comisiones.Next() OR COM:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailComisiones)&lt;br /&gt;
 END&lt;br /&gt;
 Return Level:Benign !ya imprimí todo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Otra alternativa podría ser utilizando el Template &#039;&#039;&#039;ReportChildFiles&#039;&#039;&#039; (desde version 6.X ?) ya que puede ser utilizado mas de una vez en un mismo reporte, apuntando cada instancia a un archivo &amp;quot;hijo&amp;quot; diferente.&lt;br /&gt;
Es fácil de configurar: Se debe seleccionar la tabla CHILD y la PARENT. En el reporte hay que definir el REPORT DETAIL (para el CHILD) y ponerle algún nombre en el label que luego debe ser configurado en el Template.&lt;br /&gt;
&lt;br /&gt;
Jose Sturniolo&lt;br /&gt;
&lt;br /&gt;
=== Imprimir exactamente lo que estamos viendo en el browse ===&lt;br /&gt;
En el browse pones un botón que llame al reporte y en parameters:&lt;br /&gt;
(Brw1.view{PROP:Filter}, Brw1.view{PROP:Order})&lt;br /&gt;
&lt;br /&gt;
En las propiedades del reporte o proceso:&lt;br /&gt;
Prototype: (STRING, STRING)&lt;br /&gt;
Parameters: (FILTRO, ORDEN)&lt;br /&gt;
&lt;br /&gt;
En WindowManager.Init, al final:&lt;br /&gt;
 ThisReport.SetFilter(FILTRO) ! o ThisProcess....&lt;br /&gt;
 ThisReport.SetOrder(ORDEN)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar tamaño de hoja en el reporte ===&lt;br /&gt;
En el embed WindowManager &#039;OpenReport&#039;, PRIORITY(7500)&lt;br /&gt;
&lt;br /&gt;
 IF ~ReturnValue&lt;br /&gt;
 SETTARGET(REPORT)&lt;br /&gt;
 CASE PRINTER{PROPPRINT:Paper}&lt;br /&gt;
 OF PAPER:LETTER&lt;br /&gt;
     REPORT{PROP:height} = 8500&lt;br /&gt;
     ?Footer{PROP:Ypos} = 9000&lt;br /&gt;
 OF PAPER:LEGAL&lt;br /&gt;
     REPORT{PROP:height} = 11000&lt;br /&gt;
     ?Footer{PROP:Ypos} = 11500&lt;br /&gt;
 etc.&lt;br /&gt;
 END&lt;br /&gt;
 SETTARGET()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
etc. con los tamaños de papel que quieras.&lt;br /&gt;
Esto acomoda el contenido del reporte en run-time, haciéndolo ocupar más &lt;br /&gt;
o menos hoja según sea el largo de la misma. Chiche, ¿no?.&lt;br /&gt;
Ajustá los valores a tus necesidades.&lt;br /&gt;
Para tener en cuenta: el usuario tiene que elegir el tamaño del papel &lt;br /&gt;
ANTES de generar el reporte. Si ya está en la vista previa, el reporte ya &lt;br /&gt;
está generado, por lo tanto si cambia el largo de hoja ahí, no se lo va a &lt;br /&gt;
tomar.&lt;br /&gt;
&lt;br /&gt;
Jorge Lavera&lt;br /&gt;
&lt;br /&gt;
=== Cambiar Impresora ===&lt;br /&gt;
En Global Properties--&amp;gt;Embeds--&amp;gt;Before Global INCLUDEs&lt;br /&gt;
 INCLUDE(&#039;PRNPROP.CLW&#039;)&lt;br /&gt;
 !para poder acceder a las propiedades de las impresoras&lt;br /&gt;
&lt;br /&gt;
Luego en el Reporte en &lt;br /&gt;
 ThisReport.Open()&lt;br /&gt;
 !para guardar la impresora por defecto de Windows&lt;br /&gt;
 GLO:IMPRESORA = PRINTER{PROPPRINT:Device}&lt;br /&gt;
 !Seteo la impresora que quiero usar.&lt;br /&gt;
 !El string debe ser igual al que figura en IMPRESORAS&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = &#039;HP Deskjet 840&#039;&lt;br /&gt;
&lt;br /&gt;
y por último en&lt;br /&gt;
 ThisReport.Kill()&lt;br /&gt;
 !para devolver la impresora por defecto de windows&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = CLIP(GLO:IMPRESORA)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Guillermo Ondetti, Pragma Sistemas&lt;br /&gt;
&lt;br /&gt;
=== Detectar Salto de Página de Reporte ===&lt;br /&gt;
Este sería el codigo, siempre y cuando no tengas break groups (ahi se complica bastante)&lt;br /&gt;
El embebido es TakeRecord en ABC, o Before Print Detail en Legacy.&lt;br /&gt;
 VarLocal += REPORT$?Detail{PROP:height}&lt;br /&gt;
 IF VarLocal &amp;gt; REPORT{PROP:height}&lt;br /&gt;
     VarLocal = REPORT$?Detail{PROP:height}&lt;br /&gt;
     !En el siguiente PRINT Cambia la página...&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Aplicar Filtro sql en el reporte ===&lt;br /&gt;
Se arma el filtro si se quiere en una variable por ejemlo loc:sql&lt;br /&gt;
y se aplica en Local Objects --&amp;gt; Abc Objects -- &amp;gt; Process manager --&amp;gt; Apply Filter antes del parent call, asi:&lt;br /&gt;
&lt;br /&gt;
 Process:View{Prop:SqlFilter}=Loc:SQL&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez&lt;br /&gt;
&lt;br /&gt;
=== Imprimir mas de una Copia por Reporte  ===&lt;br /&gt;
Se tiene que poner en el Window Manager --&amp;gt; Open (Prioridad(5000))&lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=n  !! n = Cantidad de copias &lt;br /&gt;
&lt;br /&gt;
Luego es aconsejable poner en el Window Manager --&amp;gt; Kill &lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=1 &lt;br /&gt;
&lt;br /&gt;
ASC Sergio D. Caballero&lt;br /&gt;
&lt;br /&gt;
== BROWSES ==&lt;br /&gt;
=== Actualizar un campo al hacer click en una columna ===&lt;br /&gt;
Por ejemplo, en People.app&lt;br /&gt;
&lt;br /&gt;
En el evento Accepted del Control del browse.&lt;br /&gt;
 !Si se hizo click en el campo&lt;br /&gt;
 IF ?BROWSE:1{PropList:MouseDownField}= 4&lt;br /&gt;
    ACCESS:PEOPLE.Fetch(PEO:KeyId)&lt;br /&gt;
    PEO:Gender = &#039;X&#039;&lt;br /&gt;
    ACCESS:PEOPLE.Update()&lt;br /&gt;
    BRW1.ResetFromFile()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar con SQL===&lt;br /&gt;
A veces es muy útil aplicar un filtro SQL encima de todos los demas filtros que ya tenga el browse, por ejemplo para filtrar por usuario, por sucursal, etc.&lt;br /&gt;
Yo normalmente le pongo el filtro SQL en el método windowmanager.Reset, &lt;br /&gt;
prioridad 5000&lt;br /&gt;
 BRW1.View{PROP:SQLFILTER}=&#039;+ filtro sql&#039;&lt;br /&gt;
Luego se refresca normalmente, o manualmente con ThisWindow.Reset (1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Activar un Browse invisible, o sea que está en otro TAB ===&lt;br /&gt;
Esto es especialmente útil cuando necesitamos que se ejecuten totalizadores del browse aunque éste no esté visible en la pantalla.&lt;br /&gt;
!ABC Objects -&amp;gt; &lt;br /&gt;
Local Objects -&amp;gt;&lt;br /&gt;
Windows Manager-&amp;gt;&lt;br /&gt;
Init Priority[7500] &lt;br /&gt;
 BRW2.ActiveInvisible = True &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Copiar un Registro ===&lt;br /&gt;
&lt;br /&gt;
    !ABC Objects -&amp;gt; Browse on Clientes -&amp;gt; PrimeRecord Priority[4500] &lt;br /&gt;
    IF Loc:Copiar &lt;br /&gt;
     SuppressClear = True &lt;br /&gt;
     CLEAR(Loc:Copiar) &lt;br /&gt;
    END!IF &lt;br /&gt;
&lt;br /&gt;
    !Control Events --&amp;gt; Copiar -&amp;gt; Accepted -&amp;gt; Priority[5000] &lt;br /&gt;
    Loc:Copiar = True &lt;br /&gt;
    POST(EVENT:Accepted,?UseDelBotonAgregar) &lt;br /&gt;
&lt;br /&gt;
    !Notas: Crear Variable Local Loc:Copiar &lt;br /&gt;
    ! SuppressClear es un Parametro de BrowseClass.PrimeRecord&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar el Popup ===&lt;br /&gt;
 !ABC Objects -&amp;gt; Local Objects -&amp;gt; Windows Manager--&amp;gt;&amp;gt;Init Priority[9001] &lt;br /&gt;
 Brw1.Popup.KILL&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Ordenamiento Dinámico ===&lt;br /&gt;
En Clarion6 se puede hacer automáticamente con la opcion Sort Headers.&lt;br /&gt;
Si se quiere hacer desde código para ordenar por cualquier campo, se puede utilizar:&lt;br /&gt;
    Brw1.SetOrder(&#039;TAB:Campo&#039;) &lt;br /&gt;
    Brw1.ApplyOrder() &lt;br /&gt;
    ThisWindow.Reset(1) &lt;br /&gt;
Por ejemplo si quisiera emular un ordenamiento con el doble click sobre una columna, habría que alertar el doble click en al browse, y el código sería mas o menos asi.&lt;br /&gt;
 Control Event -&amp;gt; Browse:1 -&amp;gt;Alert Key [4500] &lt;br /&gt;
 ! Código usado para cambiar el Orden del Browse &lt;br /&gt;
 ! cuando se hace doble click en la columna &lt;br /&gt;
 IF KEYCODE()=MouseLeft2 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;Codigo&#039; &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;Nombre&#039; &lt;br /&gt;
     Loc:Columna = ?Browse:1{PropList:MouseDownField} &lt;br /&gt;
     CASE Loc:Columna &lt;br /&gt;
     OF 1 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;&amp;lt;&amp;lt;&amp;lt;CODIGO&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;LCA:LOCALIDAD&#039;) &lt;br /&gt;
     OF 2 &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;&amp;lt;&amp;lt;&amp;lt;NOMBRE&amp;gt;&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;UPPER(LCA:NOMBRE)&#039;) &lt;br /&gt;
     END!CASE &lt;br /&gt;
     Brw1.ApplyOrder() &lt;br /&gt;
     ThisWindow.Reset(1) &lt;br /&gt;
 END!IF &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Locator Múltiple ===&lt;br /&gt;
Por ejemplo, para posicionarme en un código de cuenta contable:&lt;br /&gt;
Lo que podrías hacer es poner una variable string sobre el browse y poner un&lt;br /&gt;
código mas o menos asi en su accepted del entry&lt;br /&gt;
&lt;br /&gt;
 !Asumiendo que cada código tiene cuatro dígitos&lt;br /&gt;
 !Revisar la sección String Slicing en el Help&lt;br /&gt;
 Cue:Cuenta = Loc:Cuenta[1:4]&lt;br /&gt;
 Cue:SubCuenta = Loc:Cuenta[5:8]&lt;br /&gt;
 Cue:SubSubCuenta = Loc:Cuenta[9:12]&lt;br /&gt;
 SET(Cue:PorCodigo,Cue:PorCodigo)&lt;br /&gt;
 Access:Cuentas.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Otro ejempo, en un browse de órdenes, posicionarse según el nombre del cliente&lt;br /&gt;
&lt;br /&gt;
 CLI:Nombre = LOC:Cliente&lt;br /&gt;
 SET(CLI:PorNombre, CLI:PorNombre)&lt;br /&gt;
 ACCESS:Clientes.Next()&lt;br /&gt;
&lt;br /&gt;
 ORD:CodCliente = CLI:CodCliente&lt;br /&gt;
 SET(ORD:PorCliente, ORD:PorCliente)&lt;br /&gt;
 ACCESS:Ordenes.Next()&lt;br /&gt;
&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Pintar un browse según un campo ===&lt;br /&gt;
Por ejemplo cuando vemos las facturas de un Cliente se repite el nombre, este código pinta diferente cada grupo de nombres.&lt;br /&gt;
Primero hay que ponerle el atributo color al campo que necesites pintar, desde list box format.&lt;br /&gt;
Luego va el siguiente código, en WindowManager.Reset antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 Aux = &#039;&#039;&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (BRW1.Q)&lt;br /&gt;
     GET(BRW1.Q, F#)&lt;br /&gt;
     IF Aux &amp;lt;&amp;gt; BRW1.Q.CLI:Nombre&lt;br /&gt;
         Col# = 1- Col#&lt;br /&gt;
         Aux = BRW1.Q.CLI:Nombre&lt;br /&gt;
     END&lt;br /&gt;
     If Col#&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:SILVER&lt;br /&gt;
     Else&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:WHITE&lt;br /&gt;
     End&lt;br /&gt;
     PUT(BRW1.Q)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Refrescar un browse desde otra ventana ===&lt;br /&gt;
Lo mas fácil sería usando NOTIFY.&lt;br /&gt;
En la Ventana 1 (la del browse a refrescar)&lt;br /&gt;
 WindowManager.Init&lt;br /&gt;
 GLO:THREAD = THREAD() !VARIABLE GLOBAL LONG&lt;br /&gt;
&lt;br /&gt;
 Window Events&lt;br /&gt;
 Notify&lt;br /&gt;
 BRW1.ResetfromBuffer() ! o ThisWindow.Reset(1)?&lt;br /&gt;
&lt;br /&gt;
En la ventana 2, cuando se necesite refrescar la 1&lt;br /&gt;
 NOTIFY (999, GLO:THREAD)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que en éste caso no estoy usando ese parámetro.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Iniciar el browse en un Tab determinado ===&lt;br /&gt;
En ThisWindow.Init, al final&lt;br /&gt;
 SELF.FirstField = ?Tab:4 !Use del tab&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Actualizar el resultado de un totaling del browse de detalle, en el Encabezado ===&lt;br /&gt;
En el Browse de abajo (el de detalle)&lt;br /&gt;
 ResetFromView, prioridad 4500 - La prioridad es importante&lt;br /&gt;
 GET(Encabezado, ENC:Por_Numero)&lt;br /&gt;
 ENC:Total = loc:total !ÉSTA ES LA VARIABLE DEL TOTALING&lt;br /&gt;
 PUT (Encabezado)&lt;br /&gt;
 IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtro Dinámico ===&lt;br /&gt;
Poner un control Text donde el usuario pueda escribir cualquier filtro&lt;br /&gt;
 X# = EVALUATE(Filtro)&lt;br /&gt;
 IF ERRORCODE()&lt;br /&gt;
     MESSAGE(&#039;ERROR DE SINTAXIS EN EL FILTRO: &#039; &amp;amp; ERROR(), &#039;ATENCION&#039;)&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.SetFilter(Filtro)&lt;br /&gt;
     ThisWindow.Reset(1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Rangos múltiples y dinámicos ===&lt;br /&gt;
Si tenemos una clave con varios componentes, en Actions del browse ponemos un rango por current value, elegimos el componente de la clave hasta el cual queremos hacer el rango.&lt;br /&gt;
El siguiente componente de la clave se puede usar como locator.&lt;br /&gt;
Por ejemplo si tenemos una clave con Tipo+Provincia+Localidad, hacemos un rango de current value por provincia y nos queda un locator por localidad.&lt;br /&gt;
&lt;br /&gt;
 BRW1.ApplyRange PROCEDURE&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 RAN:Tipo= loc:tipo&lt;br /&gt;
 RAN:Provincia=loc:provincia&lt;br /&gt;
 SELF.Order.Rangelist.AssignLeftToRight()&lt;br /&gt;
&lt;br /&gt;
En algun boton de aplicar rango&lt;br /&gt;
 BRW1.ApplyRange()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, deshabilitar condicionalmente la actualización de registros ===&lt;br /&gt;
 IF &amp;lt;Condición&amp;gt;&lt;br /&gt;
     !Deshabilitar Actualización&lt;br /&gt;
     BRW1.InsertControl=FALSE&lt;br /&gt;
     BRW1.ChangeControl=FALSE&lt;br /&gt;
     BRW1.DeleteControl=FALSE&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.InsertControl=?INSERT&lt;br /&gt;
     BRW1.ChangeControl=?CHANGE&lt;br /&gt;
     BRW1.DeleteControl=?DELETE&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar el cambio de registro seleccionado en un Browse ===&lt;br /&gt;
Ejemplo mostrar una foto del cliente al costado del browse&lt;br /&gt;
 BRW1.TakeNewSelection PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !EN CLI:FOTO ESTA EL PATH COMPLETO DE LA FOTO&lt;br /&gt;
 IF CLI:FOTO &amp;lt;&amp;gt; &#039;&#039;&lt;br /&gt;
     ?Foto{PROP:TEXT}= CLI:FOTO &lt;br /&gt;
 ELSE&lt;br /&gt;
     ?Foto{PROP:TEXT}= &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un browse ===&lt;br /&gt;
Ejemplo: Mostrar sólo los clientes que tengan alguna orden&lt;br /&gt;
&lt;br /&gt;
 BRW1.ValidateRecord PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !FILTROS COMPLEJOS&lt;br /&gt;
 !EJ: MOSTRAR SOLO LOS CLIENTES QUE TENGAN ALGUNA ORDEN&lt;br /&gt;
 CLEAR(ORD:RECORD)&lt;br /&gt;
 Ord:CodigoCliente=CLI:ID&lt;br /&gt;
 SET(Ord:FK_Ordenes_CLIENTES,Ord:FK_Ordenes_CLIENTES)&lt;br /&gt;
 NEXT(ORDENES)&lt;br /&gt;
 IF ERRORCODE() OR (Ord:CodigoCliente &amp;lt;&amp;gt; CLI:ID) THEN RETURN Record:Filtered.&lt;br /&gt;
 &lt;br /&gt;
 RETURN Record:OK&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Poner un campo &amp;quot;saldo&amp;quot; en un browse ===&lt;br /&gt;
ThisWindow.Reset, antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 S#=0&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (Queue:Browse:1)&lt;br /&gt;
     GET(Queue:Browse:1, F#)&lt;br /&gt;
     S# += Queue:Browse:1.ORD:Total_Impo&lt;br /&gt;
     Queue:Browse:1.Saldo = S#&lt;br /&gt;
     PUT(Queue:Browse:1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Resetear/inicializar un Locator ===&lt;br /&gt;
El método a ejecutar es&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
&lt;br /&gt;
Los nombres de las instancias de Locators por cada TAB se llaman:&lt;br /&gt;
 BRW1::Sort0:Locator.Set&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
 BRW1::Sort2:Locator.Set&lt;br /&gt;
 !etc..&lt;br /&gt;
&lt;br /&gt;
Luego sería bueno volver a poner el foco en el browse para que se pueda seguir usando el locator normalmente&lt;br /&gt;
 select (?Browse:1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, disparar un procedimiento después de generar un alta, modificación, etc. ===&lt;br /&gt;
&lt;br /&gt;
El proceso a disparar se hace desde el browse, la idea es saber si del Form volvió aceptando o canceló la actualización. El punto embebido es:&lt;br /&gt;
&lt;br /&gt;
 Local Objects&lt;br /&gt;
 BRW1 (o el objeto de tipo browse class que sea)&lt;br /&gt;
 ResetFromAsk (después del Parent.call)&lt;br /&gt;
 &lt;br /&gt;
 IF VCRRequest=VCR:None&lt;br /&gt;
 CASE Request&lt;br /&gt;
 OF InsertRecord&lt;br /&gt;
     IF Response = RequestCompleted&lt;br /&gt;
     !Hacer algún proceso&lt;br /&gt;
     END&lt;br /&gt;
 END&lt;br /&gt;
 END!&lt;br /&gt;
&lt;br /&gt;
=== Inserción continua refrescando el Browse ===&lt;br /&gt;
Este otro método es similar al anterior, también sirve para lo mismo.&lt;br /&gt;
Agrego un ejemplo para hacer inserción continua en el Form y además se vaya actualizando el browse&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Run PROCEDURE(USHORT Number,BYTE Request)&lt;br /&gt;
 ! Cuidado que existen dos ThisWindow.Run, seleccionar el correcto&lt;br /&gt;
 ! [Priority 8500]&lt;br /&gt;
 IF Request = InsertRecord And ReturnValue = RequestCompleted&lt;br /&gt;
     POST(EVENT:ACCEPTED, BRW1.InsertControl)&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Posicionar un browse en un registro seleccionado ===&lt;br /&gt;
&lt;br /&gt;
Al abrir un browse a veces necesitamos posicionar el selector en un registro determinado, tal como lo hacen los browses para selección.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para posicionar el browse en el registro más cercano al proporcionado por el usuario:&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Open PROCEDURE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 ! End of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 CODE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Executable Code Section&amp;quot;&lt;br /&gt;
 ! [Priority 500]&lt;br /&gt;
 CLI:cliente= LOC:Cliente&lt;br /&gt;
 ACCESS:Clientes.fetch(CLI:Kcodigo)&lt;br /&gt;
 BRW1.selecting=1&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 PARENT.Open()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 BRW1.selecting=0&lt;br /&gt;
&lt;br /&gt;
Otra idea, propuesta por Matías Flores:&lt;br /&gt;
Ubicarlo por el valor de los campos de la clave. Por ejemplo, si en un browse de clientes querés posicionarte en un cliente que tiene un código determinado (Loc:Codigo):&lt;br /&gt;
&lt;br /&gt;
 Cli:Codigo = Loc:Codigo&lt;br /&gt;
 SET(Cli:PorCodigo,Cli:PorCodigo)&lt;br /&gt;
 Access:Clientes.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
un ejemplo parecido al anterior, pero en legacy, sería:&lt;br /&gt;
 CLI:Codigo = LOC:Codigo&lt;br /&gt;
 BRW1::LocateMode = LocateOnValue&lt;br /&gt;
 DO BRW1::LocateRecord&lt;br /&gt;
&lt;br /&gt;
Una opción más es:&lt;br /&gt;
En el WindowManager.init, antes de Initialize browse y después de OpenFiles, colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 BRWx.StartAtCurrent = True&lt;br /&gt;
 TAB:Campo = Valor_Buscado&lt;br /&gt;
 get(Tabla, TAB:Key_que_ordena_por_Campo)&lt;br /&gt;
&lt;br /&gt;
=== En Legacy, activar un filtro sobre un browse abierto. ===&lt;br /&gt;
&lt;br /&gt;
Esto se pone en el punto embebido &amp;quot;Before opening VIEW&amp;quot;. Acordarse de BINDEAR todas las variables que se necesiten.&lt;br /&gt;
&lt;br /&gt;
 !---ANTES DE ABRIR EL VIEW--- &lt;br /&gt;
 if SoloPendientes then&lt;br /&gt;
 BRW2::View:Browse{Prop:Filter} = |&lt;br /&gt;
 &#039;MER:numertra = BRW2::Sort1:Reset:TRA:numertra AND MER:saldunid &amp;lt;&amp;gt; 0&#039;&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo cuando quieras presentar el nombre completo sin los espacios de un campo a otro. Pones en el browse una variable local.&lt;br /&gt;
En el SETQUEUERECORD (4500)&lt;br /&gt;
 &lt;br /&gt;
 Loc:ApellidoNombre = clip(CON:Apellido) &amp;amp; &#039; &#039; &amp;amp; CON:Nombre&lt;br /&gt;
&lt;br /&gt;
!(Tip de Alex B.)&lt;br /&gt;
&lt;br /&gt;
=== Código antes y después de una actualización DESDE UN BROWSE. ===&lt;br /&gt;
&lt;br /&gt;
- Antes de la llamada al Form de actualización&lt;br /&gt;
! ABC Objects -&amp;gt; Browse on Archvivo -&amp;gt;Ask Priority[4500]&lt;br /&gt;
 IF Request = InsertRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR ALTA &#039;,&#039;ALTA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = ChangeRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A ACTUALIZAR &#039;,&#039;CAMBIO&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = DeleteRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR DE BAJA &#039;,&#039;BAJA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
- Después de la actualización del registro&lt;br /&gt;
!ABC Objects -&amp;gt; Browse on Provincia -&amp;gt;Ask Priority[5500]&lt;br /&gt;
 IF ReturnValue =1&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCIÓN: SE ACTUALIZÓ EL REGISTRO&#039;,&#039;ACTUALIZÓ OK&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF ReturnValue =2&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;SE CANCELÓ LA ACTUALIZACIÓN DEL REGISTRO&#039;,&#039;ATENCIÓN&#039;,ICON:HAND)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar/esconder (cambiar a PROP:HIDE) un control si el browse está vacío - pe. un botón-. ===&lt;br /&gt;
&lt;br /&gt;
En el Browse.UpdateWindow(), última prioridad:&lt;br /&gt;
 ?TuBoton{PROP:Disable}=Choose(Self.Records()&amp;lt;&amp;gt;0,0,1)&lt;br /&gt;
&lt;br /&gt;
===Iniciar un browse con un orden &amp;quot;sort header&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Si queremos que al abrir un browse el mismo se encuentre ordenado como si hubiéramos hecho click en el sortheader, ponemos luego del generated code del evento openwindow lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 BRW1::SortHeader.SetSortFromString(&#039;TAB:Campo&#039;)&lt;br /&gt;
&lt;br /&gt;
donde TAB:Campo es uno de los campos de la tabla que estoy mostrando en el browse.&lt;br /&gt;
&lt;br /&gt;
== EDIT IN PLACE==&lt;br /&gt;
=== Edit in Place o Form, según condición ===&lt;br /&gt;
En BrowseClass, Ask, antes del Parent Call&lt;br /&gt;
 If ?browse:1{proplist:mousedownfield} = 5&lt;br /&gt;
     Self.AskProcedure = 0&lt;br /&gt;
 else&lt;br /&gt;
     Self.AskProcedure = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Puede usarse cualquier condición, en este caso si el usuario hace doble click en la 5a columna se usa edit in place, sino se usa el formulario&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Desactivar Edit in Place de un campo según condición ===&lt;br /&gt;
En las propiedades del EIP del campo admitir la edición del mismo.&lt;br /&gt;
&lt;br /&gt;
En el EIP Field Manager del campo, TakeEvent, antes del Parent Call&lt;br /&gt;
  if Queue:Browse:1.TAB:Campo_de_mi_Tabla &amp;gt; 0 &lt;br /&gt;
     Return EditAction:Cancel&lt;br /&gt;
     thiswindow.reset(true)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
En este ejemplo sólo permito que pueda editarse el campo si el valor actual del mismo es &amp;lt;= 0&lt;br /&gt;
&lt;br /&gt;
=== Inicializar campos al insertar registro ===&lt;br /&gt;
O sea lo que hace el Prime Fields en las formas&lt;br /&gt;
 ABC Objects&lt;br /&gt;
 BROWSE ON TABLA using ?LIST&lt;br /&gt;
 PrimeRecords&lt;br /&gt;
 Después del Parent Call&lt;br /&gt;
 TPS:TuCampo= valor inicial&lt;br /&gt;
&lt;br /&gt;
=== Poner Disable un campo===&lt;br /&gt;
 Local Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 Abc Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 EIP Field Manag...for Field NombreCampo&lt;br /&gt;
 --&amp;gt;&amp;gt;Init [Priority 5001]&lt;br /&gt;
 If SELF.FEQ then SELF.FEQ{Prop:Disable} = true.&lt;br /&gt;
También se pueden cambiar otras propiedades como por ejemplo UPPER (mayúsculas) o READ ONLY (sólo lectura)&lt;br /&gt;
 If SELF.FEQ &lt;br /&gt;
     SELF.FEQ{prop:readonly} = TRUE&lt;br /&gt;
     SELF.FEQ{prop:upr} = TRUE&lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo Modificar el total cuando cambia la cantidad.&lt;br /&gt;
Primero agregar el campo cantidad en Column Specific&lt;br /&gt;
 EditInPlace::DET:Cantidad.TakeEvent PROCEDURE(UNSIGNED Event)&lt;br /&gt;
 ....&lt;br /&gt;
 !Despues del Parent Call&lt;br /&gt;
&lt;br /&gt;
 CASE ReturnValue&lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel&lt;br /&gt;
 ELSE&lt;br /&gt;
     Update(Self.Feq)&lt;br /&gt;
     BRW1.Q.DET:Total = BRW1.Q.DET:Cantidad * BRW1.Q.DET:Importe&lt;br /&gt;
     !Etc... siempre haciendo referencia a los campos de la cola BRW1.Q.&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones ===&lt;br /&gt;
Por ejemplo una validación básica de un número requerido&lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:NroDocumento&lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 ! Validación del nro. de Documento &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     UPDATE(Self.Feq) &lt;br /&gt;
     IF NOT BRW1.Q.Cli:NroDocumento &lt;br /&gt;
         BEEP(BEEP:SystemExclamation) ; YIELD() &lt;br /&gt;
         MESSAGE(&#039;No se informó el número de Documento&#039;, | &lt;br /&gt;
         &#039;Atención!&#039;, ICON:Exclamation) &lt;br /&gt;
         ReturnValue = EditAction:NONE &lt;br /&gt;
         Return ReturnValue &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Validación con un lookup a una tabla &lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:Provincia &lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 !Valida Provincia &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     Update(Self.Feq) &lt;br /&gt;
     Pro:Codigo= BRW1.Q.Cli:Provincia &lt;br /&gt;
     IF Access:Provincia.Fetch(Pro:PorCodigo) &lt;br /&gt;
         GlobalRequest = SelectRecord &lt;br /&gt;
         SelectProvincia &lt;br /&gt;
         IF NOT Pro:Codigo &lt;br /&gt;
             ReturnValue = EditAction:NONE &lt;br /&gt;
             Return ReturnValue &lt;br /&gt;
         ELSE &lt;br /&gt;
             BRW1.Q.Cli:Provincia = Pro:Codigo &lt;br /&gt;
             BRW1.Q.Pro:NOMBRE = Pro:NOMBRE &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== GLOBALES ==&lt;br /&gt;
&lt;br /&gt;
=== Cambiar los mensajes de error del SQL === &lt;br /&gt;
Con cambiar los TRN no alcanza para ese tipo de errores. &lt;br /&gt;
 &lt;br /&gt;
Lo que se puede hacer es determinar el mensaje que viene desde el SQLServer &lt;br /&gt;
para mostrar un mensaje mas amigable. &lt;br /&gt;
 &lt;br /&gt;
El embebido es &lt;br /&gt;
Global Embeds: &lt;br /&gt;
 Global Objets &lt;br /&gt;
 Abc Objects &lt;br /&gt;
 Error Manager &lt;br /&gt;
 TakeNotify &lt;br /&gt;
 !Antes del Parent Call &lt;br /&gt;
 IF INSTRING(&#039;COLUMN REFERENCE&#039;, SELF.SubsString(),1,1) &lt;br /&gt;
 SELF.Msg(&#039;El registro no puede borrarse porque tiene datos de detalle &lt;br /&gt;
 que dependen de él. |Presione [OK] para una descripción detallada del &lt;br /&gt;
 error&#039;,SELF.GetErrorBufferTitle(),ICON:Exclamation,Button:OK,BUTTON:OK,0) &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Hay que armar un IF de estos por cada tipo de error... &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validación de campos (Edit in place o Form)=== &lt;br /&gt;
 &lt;br /&gt;
Para validar campos lo ideal es usar los Global Embeds &lt;br /&gt;
 Global Embeds &lt;br /&gt;
 Field Level Validation &lt;br /&gt;
 Tabla &lt;br /&gt;
 Campo &lt;br /&gt;
 IF &amp;lt;No cumple Condición&amp;gt; &lt;br /&gt;
 Message(&#039;error...&#039;) &lt;br /&gt;
 RETURN Level:Notify &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Esto te va a funcionar &amp;quot;para siempre&amp;quot; ya sea que uses Edit in place, un Form &lt;br /&gt;
o código embebido para actualizar la tabla. &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=72</id>
		<title>Puntos Embebidos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=72"/>
		<updated>2015-03-07T22:49:04Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Recorrer la cola de las páginas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los puntos embebidos son la pesadilla de todo principiante de Clarion. Son extremadamente útiles, pero son muy difíciles de aprender. Para colmo, la abstracción que implementa la clase ABC hace más difícil todavía conocerlos y aprovecharlos. Por eso esta sección es de vital importancia.&lt;br /&gt;
&lt;br /&gt;
== FORMULARIOS ==&lt;br /&gt;
=== ¿Qué procedimiento llamó al Form? ===&lt;br /&gt;
Al principio del WindowManager.Init del Form (primer prioridad disponible)&lt;br /&gt;
&lt;br /&gt;
 GlobalErrors.GetProcedureName()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones complejas ===&lt;br /&gt;
Por ejemplo validar un Email:&lt;br /&gt;
En el accepted del campo&lt;br /&gt;
Puedes hacerlo con MATCH, ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# = MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
Devuelve 1 o 0 si el mail no es válido.&lt;br /&gt;
El MATCH puede usarse con expresiones regulares para validar casi cualquier cosa...&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se Abre/inicializa el Form ===&lt;br /&gt;
ThisWindow.Init&lt;br /&gt;
 !Es interesante entrar por el botón source a este embed para entender bien todas sus prioridades&lt;br /&gt;
 !GlobalRequest (pasada por el browse) se guarda en la propiedad ThisWindow.Request&lt;br /&gt;
 !Se puede preguntar por SELF.Request para saber para qué se lo llamó al form: &lt;br /&gt;
 !InsertRecord EQUATE (1)&lt;br /&gt;
 !ChangeRecord EQUATE (2)&lt;br /&gt;
 !DeleteRecord EQUATE (3)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar el Form a &amp;quot;Solo lectura&amp;quot; ante una condición===&lt;br /&gt;
 ThisWindow.Init&lt;br /&gt;
 ! [Priority 4950] La prioridad es importante!&lt;br /&gt;
 IF FAC:facturado = 1 THEN SELF.Request = ViewRecord.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Truco: Llamar al form para insertar desde el menú ===&lt;br /&gt;
Podríamos asumir que si la GlobalRequest está en blanco es que se lo&lt;br /&gt;
llamó para insertar, evitaríamos asi el paso por un Browse&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !If GlobalRequest = 0 Then GlobalRequest = InsertRecord.&lt;br /&gt;
&lt;br /&gt;
Si la tabla tiene una clave Autonumber, se complica un poco mas, sería asi:&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !Por ej prioridad 300&lt;br /&gt;
 If GlobalRequest = 0&lt;br /&gt;
     GlobalRequest = InsertRecord&lt;br /&gt;
     DesdeMenu# = True&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
 !Después de Open Files:&lt;br /&gt;
 !Por ej prioridad 7800&lt;br /&gt;
 If DesdeMenu# = True&lt;br /&gt;
 Access:People.PrimeAutoinc()&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Llamar a un form para editar una tabla con un solo registro ===&lt;br /&gt;
Típicamente una tabla de parametros, obviamente no queremos pasar por un browse&lt;br /&gt;
 WindowManager.Init,&lt;br /&gt;
 !al principio&lt;br /&gt;
 GlobalRequest = ChangeRecord&lt;br /&gt;
&lt;br /&gt;
 !Luego de Open files&lt;br /&gt;
 Set(Tabla)&lt;br /&gt;
 access:Tabla.Next()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se confirma un Form ===&lt;br /&gt;
ThisWindow.TakeCompleted&lt;br /&gt;
 ! [Priority 2800]&lt;br /&gt;
 !ANTES DE QUE SE CONFIRME LA GRABACION&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 ReturnValue = PARENT.TakeCompleted()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 !YA SE GRABÓ EL REGISTRO.&lt;br /&gt;
 !VERIFICAR SI SELF.Response=RequestCompleted A VER SI SE GRABÓ OK.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se cierra un Form ===&lt;br /&gt;
ThisWindow.Kill&lt;br /&gt;
 !VERIFICAR LOS valores de SELF.Request y SELF.Response&lt;br /&gt;
 !Para decidir que acciones tomar&lt;br /&gt;
 !Este punto ya es &amp;quot;demasiado tarde&amp;quot; para hacer algo antes de que se grabe el registro&lt;br /&gt;
 !Para eso usar TakeCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se produce el borrado sin abrir el Form ===&lt;br /&gt;
Si tenemos un form para actualizar una tabla, y definimos que el borrado sea Confirmando (Standard Warning) o Automático (Automatic Delete), y necesitamos ejecutar un código en el form cuando se efectúe el borrado, usamos:&lt;br /&gt;
&lt;br /&gt;
ThisWindow.PrimeUpdate, después del Parent Call&lt;br /&gt;
&lt;br /&gt;
 if self.request = DeleteRecord and self.Response = RequestCompleted&lt;br /&gt;
 !lo que quiero hacer&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que el borrado de un registro no pasa por el TakeCompleted, excepto cuando se usa la ventana del form (Display Form).&lt;br /&gt;
&lt;br /&gt;
Aporte de Gustavo Olmedo [http://www.evolutionconsulting.com.ar/downloads.html (Templates Clarion)] (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó cualquier campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
En el TakeCompleted ponemos el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF NOT SELF.Primary.Me.EqualBuffer(SELF.Saved)&lt;br /&gt;
 ! message(&#039;Cambio&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Aporte de Pablo Guarnieri y Gustavo Olmendo&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó un campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
 IF CLI:Campo &amp;lt;&amp;gt; history::CLI:Record.Campo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Forzar grabación del form === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para grabar el form inclusive cuando el usuario lo cancele&lt;br /&gt;
&lt;br /&gt;
TakeCloseEvent PROCEDURE(),BYTE,VIRTUAL&lt;br /&gt;
 IF loc:condicion &lt;br /&gt;
    SELF.CancelAction = Cancel:Save !immediate save (no confirmation)&lt;br /&gt;
 END&lt;br /&gt;
 &lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar un Drop Combo === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para filtrar un drop combo utilizando pro:sqlfilter, suponemos que en &lt;br /&gt;
la variable loc:filtro se arma el filtro ha enviar, algo asi como: &#039;a.idtercero = &amp;lt;39&amp;gt;90909090&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
FDCB14 es el nombre del objeto el cual se puede verificar en propiedades --&amp;gt; clases.&lt;br /&gt;
&lt;br /&gt;
ApplyFilter PROCEDURE,VIRTUAL&lt;br /&gt;
 FDCB14::View:FileDropCombo{PROP:SQLFILTER} =  &amp;lt;39&amp;gt;&#039;&amp;amp;clip(loc:filtro)&amp;amp;&#039;&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
 IF FILEERRORCODE()&lt;br /&gt;
    FDCB14::View:FileDropCombo{PROP:SQLFILTER} = &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Obtener el número autogenerado por SQL Server en tablas con identity === &lt;br /&gt;
Después del Parent Call, en el TakeCompleted del Form:&lt;br /&gt;
 IF Self.Response=RequestCompleted AND Self.Request = InsertRecord&lt;br /&gt;
    Tabla{prop:Sql}= &#039;SELECT @@IDENTITY&#039; !busco el número que se asignó&lt;br /&gt;
    IF not Access:Tabla.Next()&lt;br /&gt;
       !en el primer campo de Tabla viene cargado el número autogenerado&lt;br /&gt;
    else&lt;br /&gt;
       message(&#039;Error&#039;)&lt;br /&gt;
    end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Tomado de una respuesta de Fernando Cerini en el foro.&lt;br /&gt;
&lt;br /&gt;
== REPORTES Y PROCESOS ==&lt;br /&gt;
=== Ocultar un campo del detalle según condición ===&lt;br /&gt;
 !En TakeRecord, antes del Print (Process Manager)&lt;br /&gt;
 IF &amp;lt;CONDICION&amp;gt;&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=True&lt;br /&gt;
 ELSE&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=False !si la condición no se cumple, vuelvo a hacer visible el control&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Saber si un proceso se completó ===&lt;br /&gt;
O sea que no se salió por el botón de cancelar&lt;br /&gt;
 !En el WindowManager.Kill&lt;br /&gt;
 IF Self.Response = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
 &lt;br /&gt;
=== Inicializar el número de página ===&lt;br /&gt;
 !WindowManager.OpenReport, despues del Parent Call&lt;br /&gt;
 IF ReturnValue = Level:Benign&lt;br /&gt;
  Report{PROP:NextPageNo} = xxx&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar la impresión ===&lt;br /&gt;
 !Local Objects, Abc Objects, Previewer, Display, After ParentCall.&lt;br /&gt;
 !impresión prohibida&lt;br /&gt;
 ReturnValue = False&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
 If ReturnValue and DemoVersion&lt;br /&gt;
   ReturnValue = False&lt;br /&gt;
   Message(&amp;quot;Está utilizando una versión del demo, no puede imprimir este documento !&amp;quot;)&lt;br /&gt;
 End&lt;br /&gt;
Aporte de Olivier Cretey&lt;br /&gt;
&lt;br /&gt;
Otra opción, en Previewer.TakeAccepted, antes del Parent Call&lt;br /&gt;
 IF CLIP(ACCEPTED(){PROP:TIP}) = &#039;Print this report&#039; THEN RETURN LEVEL:BENIGN.&lt;br /&gt;
&lt;br /&gt;
O sea pregunto por el Tool Tip del botón que se ha presionado. Ojo, si lo tienes traducido tienes que cambiar el &#039;Print this report&#039; por tu Tool Tip.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un Proceso ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt; Validate Records --&amp;gt;&amp;gt; [Priority 5600] &lt;br /&gt;
 If &amp;lt;Condición de Filtro&amp;gt;&lt;br /&gt;
     Return Record:Filtered &lt;br /&gt;
 Else &lt;br /&gt;
     Return Record:OK &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
 &lt;br /&gt;
=== Habilitar o deshabilitar el Print Preview ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 Self.SkipPreview = Loc:Preview &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Cantidad de Páginas generadas ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 ENDPAGE(SELF.Report) &lt;br /&gt;
 Loc:Paginas = RECORDS(SELF.PreviewQueue) &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un Transporte ===&lt;br /&gt;
Necesitas crear 3 details.&lt;br /&gt;
DetailDatos&lt;br /&gt;
DetailTransporte: aca van las variables locales con los totales&lt;br /&gt;
DetailSalto: este detail es vacío y con la propiedad PageAfter&lt;br /&gt;
&lt;br /&gt;
En el embed TakeRecord (antes de los PRINTs) habría que hacer algo asi&lt;br /&gt;
 LOC:Fila += 1&lt;br /&gt;
 If LOC:Fila % 28 = 0 !28 líneas por página...&lt;br /&gt;
     PRINT(RPT:DetailSalto)&lt;br /&gt;
     PRINT(RPT:DetailTransporte)&lt;br /&gt;
     LOC:Fila = 1&lt;br /&gt;
 End&lt;br /&gt;
 LOC:Total += LIBRO:Total&lt;br /&gt;
 PRINT (RPT:Detalle)&lt;br /&gt;
 RETURN LEVEL:Benign&lt;br /&gt;
&lt;br /&gt;
Marcelo Martínez&lt;br /&gt;
y [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Acelerar las actualizaciones ===&lt;br /&gt;
Para que los procesos que agreguen registros funcionen mas rápido hay que agregar un Logout o Stream en Init y un Commit o Flush en el kill.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Se imprime o se Cancela? ===&lt;br /&gt;
Los embeds son&lt;br /&gt;
 ABC Objectd&lt;br /&gt;
 --WindowManager(ReportManager)&lt;br /&gt;
 --CancelPrintReport&lt;br /&gt;
 -Se Cancela&lt;br /&gt;
&lt;br /&gt;
 --PrintReport&lt;br /&gt;
 -Se imprime&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Recorrer la cola de las páginas ===&lt;br /&gt;
Cada página del reporte genera una imagen .WMF, la cual se guarda en el directorio temporal.&lt;br /&gt;
Con este ejemplo se puede recorrer la cola donde se guardan los nombres de estos archivos. Ésto es lo que usa por ejemplo el  [http://www.http://templatesclarion.com.ar/downloads/ EC_Mail Template] para enviar estas páginas por mail.&lt;br /&gt;
 Previewer.Open PROCEDURE&lt;br /&gt;
 ....&lt;br /&gt;
 loop a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
     get(SELF.ImageQueue,a#)&lt;br /&gt;
     message(SELF.ImageQueue)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir una Queue ===&lt;br /&gt;
La mejor forma de hacerlo en Clarion6 es en Report Properties - General -&lt;br /&gt;
Datasource: Queue.&lt;br /&gt;
&lt;br /&gt;
Yo generalmente pongo los parametros en la ventana y cargo la queue en el&lt;br /&gt;
evento accepted del PauseButton.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un SQL ===&lt;br /&gt;
Lo que yo hago es poner todos los parámetros en la ventana del reporte.&lt;br /&gt;
En el accepted del boton de pausa cargo la cola de memoria con:&lt;br /&gt;
&lt;br /&gt;
 SQL{PROP:SQL} = !aca armo el string SQL&lt;br /&gt;
 IF ERRORCODE() THEN STOP( FILEERROR()).&lt;br /&gt;
 FREE(ColaMemoria)&lt;br /&gt;
 LOOP&lt;br /&gt;
     NEXT(SQL) !O ABC, como prefieras...&lt;br /&gt;
     IF ERRORCODE() THEN BREAK.&lt;br /&gt;
     ColaMemoria :=: SQL:Record&lt;br /&gt;
     ADD(ColaMemoria)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
El reporte lo configuro para trabajar con la cola (data source) y en el&lt;br /&gt;
Detail del reporte pongo los campos de la cola de memoria.&lt;br /&gt;
Lo ideal es tener una cola de memoria global con el atributo thread y usar&lt;br /&gt;
siempre la misma para todo.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar o hacer cortes de control manuales en reportes ===&lt;br /&gt;
En TakeRecord, antes del Print.&lt;br /&gt;
 &lt;br /&gt;
!Actualizar contadores&lt;br /&gt;
&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; CampoCorte&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; 0 !para evitar la primera vez&lt;br /&gt;
 !Inicializar los contadores&lt;br /&gt;
 END&lt;br /&gt;
 AUX=CAMPO&lt;br /&gt;
 !SE VIENE EL CORTE&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Este método TakeRecord se usa también para actualizar cualquier variable calculada antes de la impresión de la banda de detalle.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo BLOB ===&lt;br /&gt;
Este código va en el método TakeRecord, antes del PRINT&lt;br /&gt;
&lt;br /&gt;
 Report$?Image1{PROP:NoWidth} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:NoHeight} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:ImageBlob} = STU:Photograph{PROP:Handle}&lt;br /&gt;
 IF Report$?Image1{PROP:Height} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Width}/Report$?Image1{PROP:Height}&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
 IF Report$?Image1{PROP:Width} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Height}/Report$?Image1{PROP:Width}&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo CSTRING ===&lt;br /&gt;
Este caso es similar al anterior, pero en el campo se encuentra el path donde está la imagen&lt;br /&gt;
 !En el método TakeRecord, antes del PRINT&lt;br /&gt;
 Report$?Image1{PROP:Text} = PRO:Foto&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Evitar el cartel &amp;quot;No records to process&amp;quot; en un proceso ===&lt;br /&gt;
 !En el metodo TAKE NO RECORDS poner un RETURN antes del parent call.&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir el reporte en blanco, cuando no hay registros ===&lt;br /&gt;
En WindowManager. Next, antes del Parent Call con prioridad 500.&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 500] antes del Parent Call&lt;br /&gt;
 If Primera=0 !variable local byte&lt;br /&gt;
    Primera=1&lt;br /&gt;
    SELF.Process.RecordsProcessed = 1&lt;br /&gt;
    Return Level:Benign&lt;br /&gt;
 End&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Cuando hay filtros y rangos, esta solución suele duplicar el primer registro del detalle.&lt;br /&gt;
Para Solucionar esto en ProcessManager NextPROCEDURE(BYTE ProcessRecord) con prioridad 7500 se debe colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF ReturnValue = 0 AND LOC:Primera = 0 THEN !Si hay un registro&lt;br /&gt;
    LOC:Primera = 1        !Dejo al reporte seguir su curso normal&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Mario Wojcik&lt;br /&gt;
&lt;br /&gt;
=== Detectar el último registro en un process o Reporte (fin de archivo) ===&lt;br /&gt;
 ThisProcess.Next PROCEDURE(BYTE ProcessRecords=True)&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 !Fin del proceso&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
Esto por ejemplo es muy útil para cambiar etiquetas en los totales generales del reporte, en un page footer&lt;br /&gt;
 ThisReport.Next PROCEDURE(BYTE ProcessRecords)&lt;br /&gt;
 ....&lt;br /&gt;
 ! [Priority 5001] despues del Parent Call&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 REPORT$?LabelTotal{prop:text}= &#039;Total&#039;&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Reporte con múltiples detalles ===&lt;br /&gt;
Por Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 Viajes&lt;br /&gt;
 |--&amp;gt;pasajeros&lt;br /&gt;
 |--&amp;gt;comisiones&lt;br /&gt;
&lt;br /&gt;
Habría que poner solo la tabla viajes en el Table Schematic. Pasajeros y Comisiones en Other Tables&lt;br /&gt;
&lt;br /&gt;
En el reporte crear 3 details, uno para cada tabla.&lt;br /&gt;
&lt;br /&gt;
En ThisReport.TakeRecord, antes de los PRINTs&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 5500]&lt;br /&gt;
 PRINT(RPT:DetailViaje)&lt;br /&gt;
 CLEAR(PAS:RECORD)&lt;br /&gt;
 PAS:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(PAS:ClavePorViaje, PAS:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Pasajeros.Next() OR PAS:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailPasajeros)&lt;br /&gt;
 END&lt;br /&gt;
 !Y lo mismo para las comisiones&lt;br /&gt;
 CLEAR(COM:RECORD)&lt;br /&gt;
 COM:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(COM:ClavePorViaje, COM:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Comisiones.Next() OR COM:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailComisiones)&lt;br /&gt;
 END&lt;br /&gt;
 Return Level:Benign !ya imprimí todo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Otra alternativa podría ser utilizando el Template &#039;&#039;&#039;ReportChildFiles&#039;&#039;&#039; (desde version 6.X ?) ya que puede ser utilizado mas de una vez en un mismo reporte, apuntando cada instancia a un archivo &amp;quot;hijo&amp;quot; diferente.&lt;br /&gt;
Es fácil de configurar: Se debe seleccionar la tabla CHILD y la PARENT. En el reporte hay que definir el REPORT DETAIL (para el CHILD) y ponerle algún nombre en el label que luego debe ser configurado en el Template.&lt;br /&gt;
&lt;br /&gt;
Jose Sturniolo&lt;br /&gt;
&lt;br /&gt;
=== Imprimir exactamente lo que estamos viendo en el browse ===&lt;br /&gt;
En el browse pones un botón que llame al reporte y en parameters:&lt;br /&gt;
(Brw1.view{PROP:Filter}, Brw1.view{PROP:Order})&lt;br /&gt;
&lt;br /&gt;
En las propiedades del reporte o proceso:&lt;br /&gt;
Prototype: (STRING, STRING)&lt;br /&gt;
Parameters: (FILTRO, ORDEN)&lt;br /&gt;
&lt;br /&gt;
En WindowManager.Init, al final:&lt;br /&gt;
 ThisReport.SetFilter(FILTRO) ! o ThisProcess....&lt;br /&gt;
 ThisReport.SetOrder(ORDEN)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar tamaño de hoja en el reporte ===&lt;br /&gt;
En el embed WindowManager &#039;OpenReport&#039;, PRIORITY(7500)&lt;br /&gt;
&lt;br /&gt;
 IF ~ReturnValue&lt;br /&gt;
 SETTARGET(REPORT)&lt;br /&gt;
 CASE PRINTER{PROPPRINT:Paper}&lt;br /&gt;
 OF PAPER:LETTER&lt;br /&gt;
     REPORT{PROP:height} = 8500&lt;br /&gt;
     ?Footer{PROP:Ypos} = 9000&lt;br /&gt;
 OF PAPER:LEGAL&lt;br /&gt;
     REPORT{PROP:height} = 11000&lt;br /&gt;
     ?Footer{PROP:Ypos} = 11500&lt;br /&gt;
 etc.&lt;br /&gt;
 END&lt;br /&gt;
 SETTARGET()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
etc. con los tamaños de papel que quieras.&lt;br /&gt;
Esto acomoda el contenido del reporte en run-time, haciéndolo ocupar más &lt;br /&gt;
o menos hoja según sea el largo de la misma. Chiche, ¿no?.&lt;br /&gt;
Ajustá los valores a tus necesidades.&lt;br /&gt;
Para tener en cuenta: el usuario tiene que elegir el tamaño del papel &lt;br /&gt;
ANTES de generar el reporte. Si ya está en la vista previa, el reporte ya &lt;br /&gt;
está generado, por lo tanto si cambia el largo de hoja ahí, no se lo va a &lt;br /&gt;
tomar.&lt;br /&gt;
&lt;br /&gt;
Jorge Lavera&lt;br /&gt;
&lt;br /&gt;
=== Cambiar Impresora ===&lt;br /&gt;
En Global Properties--&amp;gt;Embeds--&amp;gt;Before Global INCLUDEs&lt;br /&gt;
 INCLUDE(&#039;PRNPROP.CLW&#039;)&lt;br /&gt;
 !para poder acceder a las propiedades de las impresoras&lt;br /&gt;
&lt;br /&gt;
Luego en el Reporte en &lt;br /&gt;
 ThisReport.Open()&lt;br /&gt;
 !para guardar la impresora por defecto de Windows&lt;br /&gt;
 GLO:IMPRESORA = PRINTER{PROPPRINT:Device}&lt;br /&gt;
 !Seteo la impresora que quiero usar.&lt;br /&gt;
 !El string debe ser igual al que figura en IMPRESORAS&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = &#039;HP Deskjet 840&#039;&lt;br /&gt;
&lt;br /&gt;
y por último en&lt;br /&gt;
 ThisReport.Kill()&lt;br /&gt;
 !para devolver la impresora por defecto de windows&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = CLIP(GLO:IMPRESORA)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Guillermo Ondetti, Pragma Sistemas&lt;br /&gt;
&lt;br /&gt;
=== Detectar Salto de Página de Reporte ===&lt;br /&gt;
Este sería el codigo, siempre y cuando no tengas break groups (ahi se complica bastante)&lt;br /&gt;
El embebido es TakeRecord en ABC, o Before Print Detail en Legacy.&lt;br /&gt;
 VarLocal += REPORT$?Detail{PROP:height}&lt;br /&gt;
 IF VarLocal &amp;gt; REPORT{PROP:height}&lt;br /&gt;
     VarLocal = REPORT$?Detail{PROP:height}&lt;br /&gt;
     !En el siguiente PRINT Cambia la página...&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Aplicar Filtro sql en el reporte ===&lt;br /&gt;
Se arma el filtro si se quiere en una variable por ejemlo loc:sql&lt;br /&gt;
y se aplica en Local Objects --&amp;gt; Abc Objects -- &amp;gt; Process manager --&amp;gt; Apply Filter antes del parent call, asi:&lt;br /&gt;
&lt;br /&gt;
 Process:View{Prop:SqlFilter}=Loc:SQL&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez&lt;br /&gt;
&lt;br /&gt;
=== Imprimir mas de una Copia por Reporte  ===&lt;br /&gt;
Se tiene que poner en el Window Manager --&amp;gt; Open (Prioridad(5000))&lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=n  !! n = Cantidad de copias &lt;br /&gt;
&lt;br /&gt;
Luego es aconsejable poner en el Window Manager --&amp;gt; Kill &lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=1 &lt;br /&gt;
&lt;br /&gt;
ASC Sergio D. Caballero&lt;br /&gt;
&lt;br /&gt;
== BROWSES ==&lt;br /&gt;
=== Actualizar un campo al hacer click en una columna ===&lt;br /&gt;
Por ejemplo, en People.app&lt;br /&gt;
&lt;br /&gt;
En el evento Accepted del Control del browse.&lt;br /&gt;
 !Si se hizo click en el campo&lt;br /&gt;
 IF ?BROWSE:1{PropList:MouseDownField}= 4&lt;br /&gt;
    ACCESS:PEOPLE.Fetch(PEO:KeyId)&lt;br /&gt;
    PEO:Gender = &#039;X&#039;&lt;br /&gt;
    ACCESS:PEOPLE.Update()&lt;br /&gt;
    BRW1.ResetFromFile()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar con SQL===&lt;br /&gt;
A veces es muy útil aplicar un filtro SQL encima de todos los demas filtros que ya tenga el browse, por ejemplo para filtrar por usuario, por sucursal, etc.&lt;br /&gt;
Yo normalmente le pongo el filtro SQL en el método windowmanager.Reset, &lt;br /&gt;
prioridad 5000&lt;br /&gt;
 BRW1.View{PROP:SQLFILTER}=&#039;+ filtro sql&#039;&lt;br /&gt;
Luego se refresca normalmente, o manualmente con ThisWindow.Reset (1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Activar un Browse invisible, o sea que está en otro TAB ===&lt;br /&gt;
Esto es especialmente útil cuando necesitamos que se ejecuten totalizadores del browse aunque éste no esté visible en la pantalla.&lt;br /&gt;
!ABC Objects -&amp;gt; &lt;br /&gt;
Local Objects -&amp;gt;&lt;br /&gt;
Windows Manager-&amp;gt;&lt;br /&gt;
Init Priority[7500] &lt;br /&gt;
 BRW2.ActiveInvisible = True &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Copiar un Registro ===&lt;br /&gt;
&lt;br /&gt;
    !ABC Objects -&amp;gt; Browse on Clientes -&amp;gt; PrimeRecord Priority[4500] &lt;br /&gt;
    IF Loc:Copiar &lt;br /&gt;
     SuppressClear = True &lt;br /&gt;
     CLEAR(Loc:Copiar) &lt;br /&gt;
    END!IF &lt;br /&gt;
&lt;br /&gt;
    !Control Events --&amp;gt; Copiar -&amp;gt; Accepted -&amp;gt; Priority[5000] &lt;br /&gt;
    Loc:Copiar = True &lt;br /&gt;
    POST(EVENT:Accepted,?UseDelBotonAgregar) &lt;br /&gt;
&lt;br /&gt;
    !Notas: Crear Variable Local Loc:Copiar &lt;br /&gt;
    ! SuppressClear es un Parametro de BrowseClass.PrimeRecord&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar el Popup ===&lt;br /&gt;
 !ABC Objects -&amp;gt; Local Objects -&amp;gt; Windows Manager--&amp;gt;&amp;gt;Init Priority[9001] &lt;br /&gt;
 Brw1.Popup.KILL&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Ordenamiento Dinámico ===&lt;br /&gt;
En Clarion6 se puede hacer automáticamente con la opcion Sort Headers.&lt;br /&gt;
Si se quiere hacer desde código para ordenar por cualquier campo, se puede utilizar:&lt;br /&gt;
    Brw1.SetOrder(&#039;TAB:Campo&#039;) &lt;br /&gt;
    Brw1.ApplyOrder() &lt;br /&gt;
    ThisWindow.Reset(1) &lt;br /&gt;
Por ejemplo si quisiera emular un ordenamiento con el doble click sobre una columna, habría que alertar el doble click en al browse, y el código sería mas o menos asi.&lt;br /&gt;
 Control Event -&amp;gt; Browse:1 -&amp;gt;Alert Key [4500] &lt;br /&gt;
 ! Código usado para cambiar el Orden del Browse &lt;br /&gt;
 ! cuando se hace doble click en la columna &lt;br /&gt;
 IF KEYCODE()=MouseLeft2 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;Codigo&#039; &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;Nombre&#039; &lt;br /&gt;
     Loc:Columna = ?Browse:1{PropList:MouseDownField} &lt;br /&gt;
     CASE Loc:Columna &lt;br /&gt;
     OF 1 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;&amp;lt;&amp;lt;&amp;lt;CODIGO&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;LCA:LOCALIDAD&#039;) &lt;br /&gt;
     OF 2 &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;&amp;lt;&amp;lt;&amp;lt;NOMBRE&amp;gt;&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;UPPER(LCA:NOMBRE)&#039;) &lt;br /&gt;
     END!CASE &lt;br /&gt;
     Brw1.ApplyOrder() &lt;br /&gt;
     ThisWindow.Reset(1) &lt;br /&gt;
 END!IF &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Locator Múltiple ===&lt;br /&gt;
Por ejemplo, para posicionarme en un código de cuenta contable:&lt;br /&gt;
Lo que podrías hacer es poner una variable string sobre el browse y poner un&lt;br /&gt;
código mas o menos asi en su accepted del entry&lt;br /&gt;
&lt;br /&gt;
 !Asumiendo que cada código tiene cuatro dígitos&lt;br /&gt;
 !Revisar la sección String Slicing en el Help&lt;br /&gt;
 Cue:Cuenta = Loc:Cuenta[1:4]&lt;br /&gt;
 Cue:SubCuenta = Loc:Cuenta[5:8]&lt;br /&gt;
 Cue:SubSubCuenta = Loc:Cuenta[9:12]&lt;br /&gt;
 SET(Cue:PorCodigo,Cue:PorCodigo)&lt;br /&gt;
 Access:Cuentas.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Otro ejempo, en un browse de órdenes, posicionarse según el nombre del cliente&lt;br /&gt;
&lt;br /&gt;
 CLI:Nombre = LOC:Cliente&lt;br /&gt;
 SET(CLI:PorNombre, CLI:PorNombre)&lt;br /&gt;
 ACCESS:Clientes.Next()&lt;br /&gt;
&lt;br /&gt;
 ORD:CodCliente = CLI:CodCliente&lt;br /&gt;
 SET(ORD:PorCliente, ORD:PorCliente)&lt;br /&gt;
 ACCESS:Ordenes.Next()&lt;br /&gt;
&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Pintar un browse según un campo ===&lt;br /&gt;
Por ejemplo cuando vemos las facturas de un Cliente se repite el nombre, este código pinta diferente cada grupo de nombres.&lt;br /&gt;
Primero hay que ponerle el atributo color al campo que necesites pintar, desde list box format.&lt;br /&gt;
Luego va el siguiente código, en WindowManager.Reset antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 Aux = &#039;&#039;&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (BRW1.Q)&lt;br /&gt;
     GET(BRW1.Q, F#)&lt;br /&gt;
     IF Aux &amp;lt;&amp;gt; BRW1.Q.CLI:Nombre&lt;br /&gt;
         Col# = 1- Col#&lt;br /&gt;
         Aux = BRW1.Q.CLI:Nombre&lt;br /&gt;
     END&lt;br /&gt;
     If Col#&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:SILVER&lt;br /&gt;
     Else&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:WHITE&lt;br /&gt;
     End&lt;br /&gt;
     PUT(BRW1.Q)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Refrescar un browse desde otra ventana ===&lt;br /&gt;
Lo mas fácil sería usando NOTIFY.&lt;br /&gt;
En la Ventana 1 (la del browse a refrescar)&lt;br /&gt;
 WindowManager.Init&lt;br /&gt;
 GLO:THREAD = THREAD() !VARIABLE GLOBAL LONG&lt;br /&gt;
&lt;br /&gt;
 Window Events&lt;br /&gt;
 Notify&lt;br /&gt;
 BRW1.ResetfromBuffer() ! o ThisWindow.Reset(1)?&lt;br /&gt;
&lt;br /&gt;
En la ventana 2, cuando se necesite refrescar la 1&lt;br /&gt;
 NOTIFY (999, GLO:THREAD)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que en éste caso no estoy usando ese parámetro.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Iniciar el browse en un Tab determinado ===&lt;br /&gt;
En ThisWindow.Init, al final&lt;br /&gt;
 SELF.FirstField = ?Tab:4 !Use del tab&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Actualizar el resultado de un totaling del browse de detalle, en el Encabezado ===&lt;br /&gt;
En el Browse de abajo (el de detalle)&lt;br /&gt;
 ResetFromView, prioridad 4500 - La prioridad es importante&lt;br /&gt;
 GET(Encabezado, ENC:Por_Numero)&lt;br /&gt;
 ENC:Total = loc:total !ÉSTA ES LA VARIABLE DEL TOTALING&lt;br /&gt;
 PUT (Encabezado)&lt;br /&gt;
 IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtro Dinámico ===&lt;br /&gt;
Poner un control Text donde el usuario pueda escribir cualquier filtro&lt;br /&gt;
 X# = EVALUATE(Filtro)&lt;br /&gt;
 IF ERRORCODE()&lt;br /&gt;
     MESSAGE(&#039;ERROR DE SINTAXIS EN EL FILTRO: &#039; &amp;amp; ERROR(), &#039;ATENCION&#039;)&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.SetFilter(Filtro)&lt;br /&gt;
     ThisWindow.Reset(1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Rangos múltiples y dinámicos ===&lt;br /&gt;
Si tenemos una clave con varios componentes, en Actions del browse ponemos un rango por current value, elegimos el componente de la clave hasta el cual queremos hacer el rango.&lt;br /&gt;
El siguiente componente de la clave se puede usar como locator.&lt;br /&gt;
Por ejemplo si tenemos una clave con Tipo+Provincia+Localidad, hacemos un rango de current value por provincia y nos queda un locator por localidad.&lt;br /&gt;
&lt;br /&gt;
 BRW1.ApplyRange PROCEDURE&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 RAN:Tipo= loc:tipo&lt;br /&gt;
 RAN:Provincia=loc:provincia&lt;br /&gt;
 SELF.Order.Rangelist.AssignLeftToRight()&lt;br /&gt;
&lt;br /&gt;
En algun boton de aplicar rango&lt;br /&gt;
 BRW1.ApplyRange()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, deshabilitar condicionalmente la actualización de registros ===&lt;br /&gt;
 IF &amp;lt;Condición&amp;gt;&lt;br /&gt;
     !Deshabilitar Actualización&lt;br /&gt;
     BRW1.InsertControl=FALSE&lt;br /&gt;
     BRW1.ChangeControl=FALSE&lt;br /&gt;
     BRW1.DeleteControl=FALSE&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.InsertControl=?INSERT&lt;br /&gt;
     BRW1.ChangeControl=?CHANGE&lt;br /&gt;
     BRW1.DeleteControl=?DELETE&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar el cambio de registro seleccionado en un Browse ===&lt;br /&gt;
Ejemplo mostrar una foto del cliente al costado del browse&lt;br /&gt;
 BRW1.TakeNewSelection PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !EN CLI:FOTO ESTA EL PATH COMPLETO DE LA FOTO&lt;br /&gt;
 IF CLI:FOTO &amp;lt;&amp;gt; &#039;&#039;&lt;br /&gt;
     ?Foto{PROP:TEXT}= CLI:FOTO &lt;br /&gt;
 ELSE&lt;br /&gt;
     ?Foto{PROP:TEXT}= &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un browse ===&lt;br /&gt;
Ejemplo: Mostrar sólo los clientes que tengan alguna orden&lt;br /&gt;
&lt;br /&gt;
 BRW1.ValidateRecord PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !FILTROS COMPLEJOS&lt;br /&gt;
 !EJ: MOSTRAR SOLO LOS CLIENTES QUE TENGAN ALGUNA ORDEN&lt;br /&gt;
 CLEAR(ORD:RECORD)&lt;br /&gt;
 Ord:CodigoCliente=CLI:ID&lt;br /&gt;
 SET(Ord:FK_Ordenes_CLIENTES,Ord:FK_Ordenes_CLIENTES)&lt;br /&gt;
 NEXT(ORDENES)&lt;br /&gt;
 IF ERRORCODE() OR (Ord:CodigoCliente &amp;lt;&amp;gt; CLI:ID) THEN RETURN Record:Filtered.&lt;br /&gt;
 &lt;br /&gt;
 RETURN Record:OK&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Poner un campo &amp;quot;saldo&amp;quot; en un browse ===&lt;br /&gt;
ThisWindow.Reset, antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 S#=0&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (Queue:Browse:1)&lt;br /&gt;
     GET(Queue:Browse:1, F#)&lt;br /&gt;
     S# += Queue:Browse:1.ORD:Total_Impo&lt;br /&gt;
     Queue:Browse:1.Saldo = S#&lt;br /&gt;
     PUT(Queue:Browse:1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Resetear/inicializar un Locator ===&lt;br /&gt;
El método a ejecutar es&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
&lt;br /&gt;
Los nombres de las instancias de Locators por cada TAB se llaman:&lt;br /&gt;
 BRW1::Sort0:Locator.Set&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
 BRW1::Sort2:Locator.Set&lt;br /&gt;
 !etc..&lt;br /&gt;
&lt;br /&gt;
Luego sería bueno volver a poner el foco en el browse para que se pueda seguir usando el locator normalmente&lt;br /&gt;
 select (?Browse:1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, disparar un procedimiento después de generar un alta, modificación, etc. ===&lt;br /&gt;
&lt;br /&gt;
El proceso a disparar se hace desde el browse, la idea es saber si del Form volvió aceptando o canceló la actualización. El punto embebido es:&lt;br /&gt;
&lt;br /&gt;
 Local Objects&lt;br /&gt;
 BRW1 (o el objeto de tipo browse class que sea)&lt;br /&gt;
 ResetFromAsk (después del Parent.call)&lt;br /&gt;
 &lt;br /&gt;
 IF VCRRequest=VCR:None&lt;br /&gt;
 CASE Request&lt;br /&gt;
 OF InsertRecord&lt;br /&gt;
     IF Response = RequestCompleted&lt;br /&gt;
     !Hacer algún proceso&lt;br /&gt;
     END&lt;br /&gt;
 END&lt;br /&gt;
 END!&lt;br /&gt;
&lt;br /&gt;
=== Inserción continua refrescando el Browse ===&lt;br /&gt;
Este otro método es similar al anterior, también sirve para lo mismo.&lt;br /&gt;
Agrego un ejemplo para hacer inserción continua en el Form y además se vaya actualizando el browse&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Run PROCEDURE(USHORT Number,BYTE Request)&lt;br /&gt;
 ! Cuidado que existen dos ThisWindow.Run, seleccionar el correcto&lt;br /&gt;
 ! [Priority 8500]&lt;br /&gt;
 IF Request = InsertRecord And ReturnValue = RequestCompleted&lt;br /&gt;
     POST(EVENT:ACCEPTED, BRW1.InsertControl)&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Posicionar un browse en un registro seleccionado ===&lt;br /&gt;
&lt;br /&gt;
Al abrir un browse a veces necesitamos posicionar el selector en un registro determinado, tal como lo hacen los browses para selección.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para posicionar el browse en el registro más cercano al proporcionado por el usuario:&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Open PROCEDURE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 ! End of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 CODE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Executable Code Section&amp;quot;&lt;br /&gt;
 ! [Priority 500]&lt;br /&gt;
 CLI:cliente= LOC:Cliente&lt;br /&gt;
 ACCESS:Clientes.fetch(CLI:Kcodigo)&lt;br /&gt;
 BRW1.selecting=1&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 PARENT.Open()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 BRW1.selecting=0&lt;br /&gt;
&lt;br /&gt;
Otra idea, propuesta por Matías Flores:&lt;br /&gt;
Ubicarlo por el valor de los campos de la clave. Por ejemplo, si en un browse de clientes querés posicionarte en un cliente que tiene un código determinado (Loc:Codigo):&lt;br /&gt;
&lt;br /&gt;
 Cli:Codigo = Loc:Codigo&lt;br /&gt;
 SET(Cli:PorCodigo,Cli:PorCodigo)&lt;br /&gt;
 Access:Clientes.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
un ejemplo parecido al anterior, pero en legacy, sería:&lt;br /&gt;
 CLI:Codigo = LOC:Codigo&lt;br /&gt;
 BRW1::LocateMode = LocateOnValue&lt;br /&gt;
 DO BRW1::LocateRecord&lt;br /&gt;
&lt;br /&gt;
Una opción más es:&lt;br /&gt;
En el WindowManager.init, antes de Initialize browse y después de OpenFiles, colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 BRWx.StartAtCurrent = True&lt;br /&gt;
 TAB:Campo = Valor_Buscado&lt;br /&gt;
 get(Tabla, TAB:Key_que_ordena_por_Campo)&lt;br /&gt;
&lt;br /&gt;
=== En Legacy, activar un filtro sobre un browse abierto. ===&lt;br /&gt;
&lt;br /&gt;
Esto se pone en el punto embebido &amp;quot;Before opening VIEW&amp;quot;. Acordarse de BINDEAR todas las variables que se necesiten.&lt;br /&gt;
&lt;br /&gt;
 !---ANTES DE ABRIR EL VIEW--- &lt;br /&gt;
 if SoloPendientes then&lt;br /&gt;
 BRW2::View:Browse{Prop:Filter} = |&lt;br /&gt;
 &#039;MER:numertra = BRW2::Sort1:Reset:TRA:numertra AND MER:saldunid &amp;lt;&amp;gt; 0&#039;&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo cuando quieras presentar el nombre completo sin los espacios de un campo a otro. Pones en el browse una variable local.&lt;br /&gt;
En el SETQUEUERECORD (4500)&lt;br /&gt;
 &lt;br /&gt;
 Loc:ApellidoNombre = clip(CON:Apellido) &amp;amp; &#039; &#039; &amp;amp; CON:Nombre&lt;br /&gt;
&lt;br /&gt;
!(Tip de Alex B.)&lt;br /&gt;
&lt;br /&gt;
=== Código antes y después de una actualización DESDE UN BROWSE. ===&lt;br /&gt;
&lt;br /&gt;
- Antes de la llamada al Form de actualización&lt;br /&gt;
! ABC Objects -&amp;gt; Browse on Archvivo -&amp;gt;Ask Priority[4500]&lt;br /&gt;
 IF Request = InsertRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR ALTA &#039;,&#039;ALTA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = ChangeRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A ACTUALIZAR &#039;,&#039;CAMBIO&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = DeleteRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR DE BAJA &#039;,&#039;BAJA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
- Después de la actualización del registro&lt;br /&gt;
!ABC Objects -&amp;gt; Browse on Provincia -&amp;gt;Ask Priority[5500]&lt;br /&gt;
 IF ReturnValue =1&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCIÓN: SE ACTUALIZÓ EL REGISTRO&#039;,&#039;ACTUALIZÓ OK&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF ReturnValue =2&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;SE CANCELÓ LA ACTUALIZACIÓN DEL REGISTRO&#039;,&#039;ATENCIÓN&#039;,ICON:HAND)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar/esconder (cambiar a PROP:HIDE) un control si el browse está vacío - pe. un botón-. ===&lt;br /&gt;
&lt;br /&gt;
En el Browse.UpdateWindow(), última prioridad:&lt;br /&gt;
 ?TuBoton{PROP:Disable}=Choose(Self.Records()&amp;lt;&amp;gt;0,0,1)&lt;br /&gt;
&lt;br /&gt;
===Iniciar un browse con un orden &amp;quot;sort header&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Si queremos que al abrir un browse el mismo se encuentre ordenado como si hubiéramos hecho click en el sortheader, ponemos luego del generated code del evento openwindow lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 BRW1::SortHeader.SetSortFromString(&#039;TAB:Campo&#039;)&lt;br /&gt;
&lt;br /&gt;
donde TAB:Campo es uno de los campos de la tabla que estoy mostrando en el browse.&lt;br /&gt;
&lt;br /&gt;
== EDIT IN PLACE==&lt;br /&gt;
=== Edit in Place o Form, según condición ===&lt;br /&gt;
En BrowseClass, Ask, antes del Parent Call&lt;br /&gt;
 If ?browse:1{proplist:mousedownfield} = 5&lt;br /&gt;
     Self.AskProcedure = 0&lt;br /&gt;
 else&lt;br /&gt;
     Self.AskProcedure = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Puede usarse cualquier condición, en este caso si el usuario hace doble click en la 5a columna se usa edit in place, sino se usa el formulario&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Desactivar Edit in Place de un campo según condición ===&lt;br /&gt;
En las propiedades del EIP del campo admitir la edición del mismo.&lt;br /&gt;
&lt;br /&gt;
En el EIP Field Manager del campo, TakeEvent, antes del Parent Call&lt;br /&gt;
  if Queue:Browse:1.TAB:Campo_de_mi_Tabla &amp;gt; 0 &lt;br /&gt;
     Return EditAction:Cancel&lt;br /&gt;
     thiswindow.reset(true)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
En este ejemplo sólo permito que pueda editarse el campo si el valor actual del mismo es &amp;lt;= 0&lt;br /&gt;
&lt;br /&gt;
=== Inicializar campos al insertar registro ===&lt;br /&gt;
O sea lo que hace el Prime Fields en las formas&lt;br /&gt;
 ABC Objects&lt;br /&gt;
 BROWSE ON TABLA using ?LIST&lt;br /&gt;
 PrimeRecords&lt;br /&gt;
 Después del Parent Call&lt;br /&gt;
 TPS:TuCampo= valor inicial&lt;br /&gt;
&lt;br /&gt;
=== Poner Disable un campo===&lt;br /&gt;
 Local Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 Abc Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 EIP Field Manag...for Field NombreCampo&lt;br /&gt;
 --&amp;gt;&amp;gt;Init [Priority 5001]&lt;br /&gt;
 If SELF.FEQ then SELF.FEQ{Prop:Disable} = true.&lt;br /&gt;
También se pueden cambiar otras propiedades como por ejemplo UPPER (mayúsculas) o READ ONLY (sólo lectura)&lt;br /&gt;
 If SELF.FEQ &lt;br /&gt;
     SELF.FEQ{prop:readonly} = TRUE&lt;br /&gt;
     SELF.FEQ{prop:upr} = TRUE&lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo Modificar el total cuando cambia la cantidad.&lt;br /&gt;
Primero agregar el campo cantidad en Column Specific&lt;br /&gt;
 EditInPlace::DET:Cantidad.TakeEvent PROCEDURE(UNSIGNED Event)&lt;br /&gt;
 ....&lt;br /&gt;
 !Despues del Parent Call&lt;br /&gt;
&lt;br /&gt;
 CASE ReturnValue&lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel&lt;br /&gt;
 ELSE&lt;br /&gt;
     Update(Self.Feq)&lt;br /&gt;
     BRW1.Q.DET:Total = BRW1.Q.DET:Cantidad * BRW1.Q.DET:Importe&lt;br /&gt;
     !Etc... siempre haciendo referencia a los campos de la cola BRW1.Q.&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones ===&lt;br /&gt;
Por ejemplo una validación básica de un número requerido&lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:NroDocumento&lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 ! Validación del nro. de Documento &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     UPDATE(Self.Feq) &lt;br /&gt;
     IF NOT BRW1.Q.Cli:NroDocumento &lt;br /&gt;
         BEEP(BEEP:SystemExclamation) ; YIELD() &lt;br /&gt;
         MESSAGE(&#039;No se informó el número de Documento&#039;, | &lt;br /&gt;
         &#039;Atención!&#039;, ICON:Exclamation) &lt;br /&gt;
         ReturnValue = EditAction:NONE &lt;br /&gt;
         Return ReturnValue &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Validación con un lookup a una tabla &lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:Provincia &lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 !Valida Provincia &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     Update(Self.Feq) &lt;br /&gt;
     Pro:Codigo= BRW1.Q.Cli:Provincia &lt;br /&gt;
     IF Access:Provincia.Fetch(Pro:PorCodigo) &lt;br /&gt;
         GlobalRequest = SelectRecord &lt;br /&gt;
         SelectProvincia &lt;br /&gt;
         IF NOT Pro:Codigo &lt;br /&gt;
             ReturnValue = EditAction:NONE &lt;br /&gt;
             Return ReturnValue &lt;br /&gt;
         ELSE &lt;br /&gt;
             BRW1.Q.Cli:Provincia = Pro:Codigo &lt;br /&gt;
             BRW1.Q.Pro:NOMBRE = Pro:NOMBRE &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== GLOBALES ==&lt;br /&gt;
&lt;br /&gt;
=== Cambiar los mensajes de error del SQL === &lt;br /&gt;
Con cambiar los TRN no alcanza para ese tipo de errores. &lt;br /&gt;
 &lt;br /&gt;
Lo que se puede hacer es determinar el mensaje que viene desde el SQLServer &lt;br /&gt;
para mostrar un mensaje mas amigable. &lt;br /&gt;
 &lt;br /&gt;
El embebido es &lt;br /&gt;
Global Embeds: &lt;br /&gt;
 Global Objets &lt;br /&gt;
 Abc Objects &lt;br /&gt;
 Error Manager &lt;br /&gt;
 TakeNotify &lt;br /&gt;
 !Antes del Parent Call &lt;br /&gt;
 IF INSTRING(&#039;COLUMN REFERENCE&#039;, SELF.SubsString(),1,1) &lt;br /&gt;
 SELF.Msg(&#039;El registro no puede borrarse porque tiene datos de detalle &lt;br /&gt;
 que dependen de él. |Presione [OK] para una descripción detallada del &lt;br /&gt;
 error&#039;,SELF.GetErrorBufferTitle(),ICON:Exclamation,Button:OK,BUTTON:OK,0) &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Hay que armar un IF de estos por cada tipo de error... &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validación de campos (Edit in place o Form)=== &lt;br /&gt;
 &lt;br /&gt;
Para validar campos lo ideal es usar los Global Embeds &lt;br /&gt;
 Global Embeds &lt;br /&gt;
 Field Level Validation &lt;br /&gt;
 Tabla &lt;br /&gt;
 Campo &lt;br /&gt;
 IF &amp;lt;No cumple Condición&amp;gt; &lt;br /&gt;
 Message(&#039;error...&#039;) &lt;br /&gt;
 RETURN Level:Notify &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Esto te va a funcionar &amp;quot;para siempre&amp;quot; ya sea que uses Edit in place, un Form &lt;br /&gt;
o código embebido para actualizar la tabla. &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=71</id>
		<title>Puntos Embebidos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=71"/>
		<updated>2015-03-07T22:46:43Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Acelerar las actualizaciones */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los puntos embebidos son la pesadilla de todo principiante de Clarion. Son extremadamente útiles, pero son muy difíciles de aprender. Para colmo, la abstracción que implementa la clase ABC hace más difícil todavía conocerlos y aprovecharlos. Por eso esta sección es de vital importancia.&lt;br /&gt;
&lt;br /&gt;
== FORMULARIOS ==&lt;br /&gt;
=== ¿Qué procedimiento llamó al Form? ===&lt;br /&gt;
Al principio del WindowManager.Init del Form (primer prioridad disponible)&lt;br /&gt;
&lt;br /&gt;
 GlobalErrors.GetProcedureName()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones complejas ===&lt;br /&gt;
Por ejemplo validar un Email:&lt;br /&gt;
En el accepted del campo&lt;br /&gt;
Puedes hacerlo con MATCH, ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# = MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
Devuelve 1 o 0 si el mail no es válido.&lt;br /&gt;
El MATCH puede usarse con expresiones regulares para validar casi cualquier cosa...&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se Abre/inicializa el Form ===&lt;br /&gt;
ThisWindow.Init&lt;br /&gt;
 !Es interesante entrar por el botón source a este embed para entender bien todas sus prioridades&lt;br /&gt;
 !GlobalRequest (pasada por el browse) se guarda en la propiedad ThisWindow.Request&lt;br /&gt;
 !Se puede preguntar por SELF.Request para saber para qué se lo llamó al form: &lt;br /&gt;
 !InsertRecord EQUATE (1)&lt;br /&gt;
 !ChangeRecord EQUATE (2)&lt;br /&gt;
 !DeleteRecord EQUATE (3)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar el Form a &amp;quot;Solo lectura&amp;quot; ante una condición===&lt;br /&gt;
 ThisWindow.Init&lt;br /&gt;
 ! [Priority 4950] La prioridad es importante!&lt;br /&gt;
 IF FAC:facturado = 1 THEN SELF.Request = ViewRecord.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Truco: Llamar al form para insertar desde el menú ===&lt;br /&gt;
Podríamos asumir que si la GlobalRequest está en blanco es que se lo&lt;br /&gt;
llamó para insertar, evitaríamos asi el paso por un Browse&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !If GlobalRequest = 0 Then GlobalRequest = InsertRecord.&lt;br /&gt;
&lt;br /&gt;
Si la tabla tiene una clave Autonumber, se complica un poco mas, sería asi:&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !Por ej prioridad 300&lt;br /&gt;
 If GlobalRequest = 0&lt;br /&gt;
     GlobalRequest = InsertRecord&lt;br /&gt;
     DesdeMenu# = True&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
 !Después de Open Files:&lt;br /&gt;
 !Por ej prioridad 7800&lt;br /&gt;
 If DesdeMenu# = True&lt;br /&gt;
 Access:People.PrimeAutoinc()&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Llamar a un form para editar una tabla con un solo registro ===&lt;br /&gt;
Típicamente una tabla de parametros, obviamente no queremos pasar por un browse&lt;br /&gt;
 WindowManager.Init,&lt;br /&gt;
 !al principio&lt;br /&gt;
 GlobalRequest = ChangeRecord&lt;br /&gt;
&lt;br /&gt;
 !Luego de Open files&lt;br /&gt;
 Set(Tabla)&lt;br /&gt;
 access:Tabla.Next()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se confirma un Form ===&lt;br /&gt;
ThisWindow.TakeCompleted&lt;br /&gt;
 ! [Priority 2800]&lt;br /&gt;
 !ANTES DE QUE SE CONFIRME LA GRABACION&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 ReturnValue = PARENT.TakeCompleted()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 !YA SE GRABÓ EL REGISTRO.&lt;br /&gt;
 !VERIFICAR SI SELF.Response=RequestCompleted A VER SI SE GRABÓ OK.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se cierra un Form ===&lt;br /&gt;
ThisWindow.Kill&lt;br /&gt;
 !VERIFICAR LOS valores de SELF.Request y SELF.Response&lt;br /&gt;
 !Para decidir que acciones tomar&lt;br /&gt;
 !Este punto ya es &amp;quot;demasiado tarde&amp;quot; para hacer algo antes de que se grabe el registro&lt;br /&gt;
 !Para eso usar TakeCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se produce el borrado sin abrir el Form ===&lt;br /&gt;
Si tenemos un form para actualizar una tabla, y definimos que el borrado sea Confirmando (Standard Warning) o Automático (Automatic Delete), y necesitamos ejecutar un código en el form cuando se efectúe el borrado, usamos:&lt;br /&gt;
&lt;br /&gt;
ThisWindow.PrimeUpdate, después del Parent Call&lt;br /&gt;
&lt;br /&gt;
 if self.request = DeleteRecord and self.Response = RequestCompleted&lt;br /&gt;
 !lo que quiero hacer&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que el borrado de un registro no pasa por el TakeCompleted, excepto cuando se usa la ventana del form (Display Form).&lt;br /&gt;
&lt;br /&gt;
Aporte de Gustavo Olmedo [http://www.evolutionconsulting.com.ar/downloads.html (Templates Clarion)] (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó cualquier campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
En el TakeCompleted ponemos el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF NOT SELF.Primary.Me.EqualBuffer(SELF.Saved)&lt;br /&gt;
 ! message(&#039;Cambio&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Aporte de Pablo Guarnieri y Gustavo Olmendo&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó un campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
 IF CLI:Campo &amp;lt;&amp;gt; history::CLI:Record.Campo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Forzar grabación del form === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para grabar el form inclusive cuando el usuario lo cancele&lt;br /&gt;
&lt;br /&gt;
TakeCloseEvent PROCEDURE(),BYTE,VIRTUAL&lt;br /&gt;
 IF loc:condicion &lt;br /&gt;
    SELF.CancelAction = Cancel:Save !immediate save (no confirmation)&lt;br /&gt;
 END&lt;br /&gt;
 &lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar un Drop Combo === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para filtrar un drop combo utilizando pro:sqlfilter, suponemos que en &lt;br /&gt;
la variable loc:filtro se arma el filtro ha enviar, algo asi como: &#039;a.idtercero = &amp;lt;39&amp;gt;90909090&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
FDCB14 es el nombre del objeto el cual se puede verificar en propiedades --&amp;gt; clases.&lt;br /&gt;
&lt;br /&gt;
ApplyFilter PROCEDURE,VIRTUAL&lt;br /&gt;
 FDCB14::View:FileDropCombo{PROP:SQLFILTER} =  &amp;lt;39&amp;gt;&#039;&amp;amp;clip(loc:filtro)&amp;amp;&#039;&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
 IF FILEERRORCODE()&lt;br /&gt;
    FDCB14::View:FileDropCombo{PROP:SQLFILTER} = &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Obtener el número autogenerado por SQL Server en tablas con identity === &lt;br /&gt;
Después del Parent Call, en el TakeCompleted del Form:&lt;br /&gt;
 IF Self.Response=RequestCompleted AND Self.Request = InsertRecord&lt;br /&gt;
    Tabla{prop:Sql}= &#039;SELECT @@IDENTITY&#039; !busco el número que se asignó&lt;br /&gt;
    IF not Access:Tabla.Next()&lt;br /&gt;
       !en el primer campo de Tabla viene cargado el número autogenerado&lt;br /&gt;
    else&lt;br /&gt;
       message(&#039;Error&#039;)&lt;br /&gt;
    end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Tomado de una respuesta de Fernando Cerini en el foro.&lt;br /&gt;
&lt;br /&gt;
== REPORTES Y PROCESOS ==&lt;br /&gt;
=== Ocultar un campo del detalle según condición ===&lt;br /&gt;
 !En TakeRecord, antes del Print (Process Manager)&lt;br /&gt;
 IF &amp;lt;CONDICION&amp;gt;&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=True&lt;br /&gt;
 ELSE&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=False !si la condición no se cumple, vuelvo a hacer visible el control&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Saber si un proceso se completó ===&lt;br /&gt;
O sea que no se salió por el botón de cancelar&lt;br /&gt;
 !En el WindowManager.Kill&lt;br /&gt;
 IF Self.Response = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
 &lt;br /&gt;
=== Inicializar el número de página ===&lt;br /&gt;
 !WindowManager.OpenReport, despues del Parent Call&lt;br /&gt;
 IF ReturnValue = Level:Benign&lt;br /&gt;
  Report{PROP:NextPageNo} = xxx&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar la impresión ===&lt;br /&gt;
 !Local Objects, Abc Objects, Previewer, Display, After ParentCall.&lt;br /&gt;
 !impresión prohibida&lt;br /&gt;
 ReturnValue = False&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
 If ReturnValue and DemoVersion&lt;br /&gt;
   ReturnValue = False&lt;br /&gt;
   Message(&amp;quot;Está utilizando una versión del demo, no puede imprimir este documento !&amp;quot;)&lt;br /&gt;
 End&lt;br /&gt;
Aporte de Olivier Cretey&lt;br /&gt;
&lt;br /&gt;
Otra opción, en Previewer.TakeAccepted, antes del Parent Call&lt;br /&gt;
 IF CLIP(ACCEPTED(){PROP:TIP}) = &#039;Print this report&#039; THEN RETURN LEVEL:BENIGN.&lt;br /&gt;
&lt;br /&gt;
O sea pregunto por el Tool Tip del botón que se ha presionado. Ojo, si lo tienes traducido tienes que cambiar el &#039;Print this report&#039; por tu Tool Tip.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un Proceso ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt; Validate Records --&amp;gt;&amp;gt; [Priority 5600] &lt;br /&gt;
 If &amp;lt;Condición de Filtro&amp;gt;&lt;br /&gt;
     Return Record:Filtered &lt;br /&gt;
 Else &lt;br /&gt;
     Return Record:OK &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
 &lt;br /&gt;
=== Habilitar o deshabilitar el Print Preview ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 Self.SkipPreview = Loc:Preview &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Cantidad de Páginas generadas ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 ENDPAGE(SELF.Report) &lt;br /&gt;
 Loc:Paginas = RECORDS(SELF.PreviewQueue) &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un Transporte ===&lt;br /&gt;
Necesitas crear 3 details.&lt;br /&gt;
DetailDatos&lt;br /&gt;
DetailTransporte: aca van las variables locales con los totales&lt;br /&gt;
DetailSalto: este detail es vacío y con la propiedad PageAfter&lt;br /&gt;
&lt;br /&gt;
En el embed TakeRecord (antes de los PRINTs) habría que hacer algo asi&lt;br /&gt;
 LOC:Fila += 1&lt;br /&gt;
 If LOC:Fila % 28 = 0 !28 líneas por página...&lt;br /&gt;
     PRINT(RPT:DetailSalto)&lt;br /&gt;
     PRINT(RPT:DetailTransporte)&lt;br /&gt;
     LOC:Fila = 1&lt;br /&gt;
 End&lt;br /&gt;
 LOC:Total += LIBRO:Total&lt;br /&gt;
 PRINT (RPT:Detalle)&lt;br /&gt;
 RETURN LEVEL:Benign&lt;br /&gt;
&lt;br /&gt;
Marcelo Martínez&lt;br /&gt;
y [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Acelerar las actualizaciones ===&lt;br /&gt;
Para que los procesos que agreguen registros funcionen mas rápido hay que agregar un Logout o Stream en Init y un Commit o Flush en el kill.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Se imprime o se Cancela? ===&lt;br /&gt;
Los embeds son&lt;br /&gt;
 ABC Objectd&lt;br /&gt;
 --WindowManager(ReportManager)&lt;br /&gt;
 --CancelPrintReport&lt;br /&gt;
 -Se Cancela&lt;br /&gt;
&lt;br /&gt;
 --PrintReport&lt;br /&gt;
 -Se imprime&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Recorrer la cola de las páginas ===&lt;br /&gt;
Cada página del reporte genera una imagen .WMF, la cual se guarda en el directorio temporal.&lt;br /&gt;
Con este ejemplo se puede recorrer la cola donde se guardan los nombres de estos archivos. Ésto es lo que usa por ejemplo el Evolution Mail Template para enviar estas páginas por mail.&lt;br /&gt;
 Previewer.Open PROCEDURE&lt;br /&gt;
 ....&lt;br /&gt;
 loop a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
     get(SELF.ImageQueue,a#)&lt;br /&gt;
     message(SELF.ImageQueue)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir una Queue ===&lt;br /&gt;
La mejor forma de hacerlo en Clarion6 es en Report Properties - General -&lt;br /&gt;
Datasource: Queue.&lt;br /&gt;
&lt;br /&gt;
Yo generalmente pongo los parametros en la ventana y cargo la queue en el&lt;br /&gt;
evento accepted del PauseButton.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un SQL ===&lt;br /&gt;
Lo que yo hago es poner todos los parámetros en la ventana del reporte.&lt;br /&gt;
En el accepted del boton de pausa cargo la cola de memoria con:&lt;br /&gt;
&lt;br /&gt;
 SQL{PROP:SQL} = !aca armo el string SQL&lt;br /&gt;
 IF ERRORCODE() THEN STOP( FILEERROR()).&lt;br /&gt;
 FREE(ColaMemoria)&lt;br /&gt;
 LOOP&lt;br /&gt;
     NEXT(SQL) !O ABC, como prefieras...&lt;br /&gt;
     IF ERRORCODE() THEN BREAK.&lt;br /&gt;
     ColaMemoria :=: SQL:Record&lt;br /&gt;
     ADD(ColaMemoria)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
El reporte lo configuro para trabajar con la cola (data source) y en el&lt;br /&gt;
Detail del reporte pongo los campos de la cola de memoria.&lt;br /&gt;
Lo ideal es tener una cola de memoria global con el atributo thread y usar&lt;br /&gt;
siempre la misma para todo.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar o hacer cortes de control manuales en reportes ===&lt;br /&gt;
En TakeRecord, antes del Print.&lt;br /&gt;
 &lt;br /&gt;
!Actualizar contadores&lt;br /&gt;
&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; CampoCorte&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; 0 !para evitar la primera vez&lt;br /&gt;
 !Inicializar los contadores&lt;br /&gt;
 END&lt;br /&gt;
 AUX=CAMPO&lt;br /&gt;
 !SE VIENE EL CORTE&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Este método TakeRecord se usa también para actualizar cualquier variable calculada antes de la impresión de la banda de detalle.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo BLOB ===&lt;br /&gt;
Este código va en el método TakeRecord, antes del PRINT&lt;br /&gt;
&lt;br /&gt;
 Report$?Image1{PROP:NoWidth} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:NoHeight} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:ImageBlob} = STU:Photograph{PROP:Handle}&lt;br /&gt;
 IF Report$?Image1{PROP:Height} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Width}/Report$?Image1{PROP:Height}&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
 IF Report$?Image1{PROP:Width} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Height}/Report$?Image1{PROP:Width}&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo CSTRING ===&lt;br /&gt;
Este caso es similar al anterior, pero en el campo se encuentra el path donde está la imagen&lt;br /&gt;
 !En el método TakeRecord, antes del PRINT&lt;br /&gt;
 Report$?Image1{PROP:Text} = PRO:Foto&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Evitar el cartel &amp;quot;No records to process&amp;quot; en un proceso ===&lt;br /&gt;
 !En el metodo TAKE NO RECORDS poner un RETURN antes del parent call.&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir el reporte en blanco, cuando no hay registros ===&lt;br /&gt;
En WindowManager. Next, antes del Parent Call con prioridad 500.&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 500] antes del Parent Call&lt;br /&gt;
 If Primera=0 !variable local byte&lt;br /&gt;
    Primera=1&lt;br /&gt;
    SELF.Process.RecordsProcessed = 1&lt;br /&gt;
    Return Level:Benign&lt;br /&gt;
 End&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Cuando hay filtros y rangos, esta solución suele duplicar el primer registro del detalle.&lt;br /&gt;
Para Solucionar esto en ProcessManager NextPROCEDURE(BYTE ProcessRecord) con prioridad 7500 se debe colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF ReturnValue = 0 AND LOC:Primera = 0 THEN !Si hay un registro&lt;br /&gt;
    LOC:Primera = 1        !Dejo al reporte seguir su curso normal&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Mario Wojcik&lt;br /&gt;
&lt;br /&gt;
=== Detectar el último registro en un process o Reporte (fin de archivo) ===&lt;br /&gt;
 ThisProcess.Next PROCEDURE(BYTE ProcessRecords=True)&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 !Fin del proceso&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
Esto por ejemplo es muy útil para cambiar etiquetas en los totales generales del reporte, en un page footer&lt;br /&gt;
 ThisReport.Next PROCEDURE(BYTE ProcessRecords)&lt;br /&gt;
 ....&lt;br /&gt;
 ! [Priority 5001] despues del Parent Call&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 REPORT$?LabelTotal{prop:text}= &#039;Total&#039;&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Reporte con múltiples detalles ===&lt;br /&gt;
Por Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 Viajes&lt;br /&gt;
 |--&amp;gt;pasajeros&lt;br /&gt;
 |--&amp;gt;comisiones&lt;br /&gt;
&lt;br /&gt;
Habría que poner solo la tabla viajes en el Table Schematic. Pasajeros y Comisiones en Other Tables&lt;br /&gt;
&lt;br /&gt;
En el reporte crear 3 details, uno para cada tabla.&lt;br /&gt;
&lt;br /&gt;
En ThisReport.TakeRecord, antes de los PRINTs&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 5500]&lt;br /&gt;
 PRINT(RPT:DetailViaje)&lt;br /&gt;
 CLEAR(PAS:RECORD)&lt;br /&gt;
 PAS:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(PAS:ClavePorViaje, PAS:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Pasajeros.Next() OR PAS:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailPasajeros)&lt;br /&gt;
 END&lt;br /&gt;
 !Y lo mismo para las comisiones&lt;br /&gt;
 CLEAR(COM:RECORD)&lt;br /&gt;
 COM:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(COM:ClavePorViaje, COM:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Comisiones.Next() OR COM:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailComisiones)&lt;br /&gt;
 END&lt;br /&gt;
 Return Level:Benign !ya imprimí todo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Otra alternativa podría ser utilizando el Template &#039;&#039;&#039;ReportChildFiles&#039;&#039;&#039; (desde version 6.X ?) ya que puede ser utilizado mas de una vez en un mismo reporte, apuntando cada instancia a un archivo &amp;quot;hijo&amp;quot; diferente.&lt;br /&gt;
Es fácil de configurar: Se debe seleccionar la tabla CHILD y la PARENT. En el reporte hay que definir el REPORT DETAIL (para el CHILD) y ponerle algún nombre en el label que luego debe ser configurado en el Template.&lt;br /&gt;
&lt;br /&gt;
Jose Sturniolo&lt;br /&gt;
&lt;br /&gt;
=== Imprimir exactamente lo que estamos viendo en el browse ===&lt;br /&gt;
En el browse pones un botón que llame al reporte y en parameters:&lt;br /&gt;
(Brw1.view{PROP:Filter}, Brw1.view{PROP:Order})&lt;br /&gt;
&lt;br /&gt;
En las propiedades del reporte o proceso:&lt;br /&gt;
Prototype: (STRING, STRING)&lt;br /&gt;
Parameters: (FILTRO, ORDEN)&lt;br /&gt;
&lt;br /&gt;
En WindowManager.Init, al final:&lt;br /&gt;
 ThisReport.SetFilter(FILTRO) ! o ThisProcess....&lt;br /&gt;
 ThisReport.SetOrder(ORDEN)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar tamaño de hoja en el reporte ===&lt;br /&gt;
En el embed WindowManager &#039;OpenReport&#039;, PRIORITY(7500)&lt;br /&gt;
&lt;br /&gt;
 IF ~ReturnValue&lt;br /&gt;
 SETTARGET(REPORT)&lt;br /&gt;
 CASE PRINTER{PROPPRINT:Paper}&lt;br /&gt;
 OF PAPER:LETTER&lt;br /&gt;
     REPORT{PROP:height} = 8500&lt;br /&gt;
     ?Footer{PROP:Ypos} = 9000&lt;br /&gt;
 OF PAPER:LEGAL&lt;br /&gt;
     REPORT{PROP:height} = 11000&lt;br /&gt;
     ?Footer{PROP:Ypos} = 11500&lt;br /&gt;
 etc.&lt;br /&gt;
 END&lt;br /&gt;
 SETTARGET()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
etc. con los tamaños de papel que quieras.&lt;br /&gt;
Esto acomoda el contenido del reporte en run-time, haciéndolo ocupar más &lt;br /&gt;
o menos hoja según sea el largo de la misma. Chiche, ¿no?.&lt;br /&gt;
Ajustá los valores a tus necesidades.&lt;br /&gt;
Para tener en cuenta: el usuario tiene que elegir el tamaño del papel &lt;br /&gt;
ANTES de generar el reporte. Si ya está en la vista previa, el reporte ya &lt;br /&gt;
está generado, por lo tanto si cambia el largo de hoja ahí, no se lo va a &lt;br /&gt;
tomar.&lt;br /&gt;
&lt;br /&gt;
Jorge Lavera&lt;br /&gt;
&lt;br /&gt;
=== Cambiar Impresora ===&lt;br /&gt;
En Global Properties--&amp;gt;Embeds--&amp;gt;Before Global INCLUDEs&lt;br /&gt;
 INCLUDE(&#039;PRNPROP.CLW&#039;)&lt;br /&gt;
 !para poder acceder a las propiedades de las impresoras&lt;br /&gt;
&lt;br /&gt;
Luego en el Reporte en &lt;br /&gt;
 ThisReport.Open()&lt;br /&gt;
 !para guardar la impresora por defecto de Windows&lt;br /&gt;
 GLO:IMPRESORA = PRINTER{PROPPRINT:Device}&lt;br /&gt;
 !Seteo la impresora que quiero usar.&lt;br /&gt;
 !El string debe ser igual al que figura en IMPRESORAS&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = &#039;HP Deskjet 840&#039;&lt;br /&gt;
&lt;br /&gt;
y por último en&lt;br /&gt;
 ThisReport.Kill()&lt;br /&gt;
 !para devolver la impresora por defecto de windows&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = CLIP(GLO:IMPRESORA)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Guillermo Ondetti, Pragma Sistemas&lt;br /&gt;
&lt;br /&gt;
=== Detectar Salto de Página de Reporte ===&lt;br /&gt;
Este sería el codigo, siempre y cuando no tengas break groups (ahi se complica bastante)&lt;br /&gt;
El embebido es TakeRecord en ABC, o Before Print Detail en Legacy.&lt;br /&gt;
 VarLocal += REPORT$?Detail{PROP:height}&lt;br /&gt;
 IF VarLocal &amp;gt; REPORT{PROP:height}&lt;br /&gt;
     VarLocal = REPORT$?Detail{PROP:height}&lt;br /&gt;
     !En el siguiente PRINT Cambia la página...&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Aplicar Filtro sql en el reporte ===&lt;br /&gt;
Se arma el filtro si se quiere en una variable por ejemlo loc:sql&lt;br /&gt;
y se aplica en Local Objects --&amp;gt; Abc Objects -- &amp;gt; Process manager --&amp;gt; Apply Filter antes del parent call, asi:&lt;br /&gt;
&lt;br /&gt;
 Process:View{Prop:SqlFilter}=Loc:SQL&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez&lt;br /&gt;
&lt;br /&gt;
=== Imprimir mas de una Copia por Reporte  ===&lt;br /&gt;
Se tiene que poner en el Window Manager --&amp;gt; Open (Prioridad(5000))&lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=n  !! n = Cantidad de copias &lt;br /&gt;
&lt;br /&gt;
Luego es aconsejable poner en el Window Manager --&amp;gt; Kill &lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=1 &lt;br /&gt;
&lt;br /&gt;
ASC Sergio D. Caballero&lt;br /&gt;
&lt;br /&gt;
== BROWSES ==&lt;br /&gt;
=== Actualizar un campo al hacer click en una columna ===&lt;br /&gt;
Por ejemplo, en People.app&lt;br /&gt;
&lt;br /&gt;
En el evento Accepted del Control del browse.&lt;br /&gt;
 !Si se hizo click en el campo&lt;br /&gt;
 IF ?BROWSE:1{PropList:MouseDownField}= 4&lt;br /&gt;
    ACCESS:PEOPLE.Fetch(PEO:KeyId)&lt;br /&gt;
    PEO:Gender = &#039;X&#039;&lt;br /&gt;
    ACCESS:PEOPLE.Update()&lt;br /&gt;
    BRW1.ResetFromFile()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar con SQL===&lt;br /&gt;
A veces es muy útil aplicar un filtro SQL encima de todos los demas filtros que ya tenga el browse, por ejemplo para filtrar por usuario, por sucursal, etc.&lt;br /&gt;
Yo normalmente le pongo el filtro SQL en el método windowmanager.Reset, &lt;br /&gt;
prioridad 5000&lt;br /&gt;
 BRW1.View{PROP:SQLFILTER}=&#039;+ filtro sql&#039;&lt;br /&gt;
Luego se refresca normalmente, o manualmente con ThisWindow.Reset (1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Activar un Browse invisible, o sea que está en otro TAB ===&lt;br /&gt;
Esto es especialmente útil cuando necesitamos que se ejecuten totalizadores del browse aunque éste no esté visible en la pantalla.&lt;br /&gt;
!ABC Objects -&amp;gt; &lt;br /&gt;
Local Objects -&amp;gt;&lt;br /&gt;
Windows Manager-&amp;gt;&lt;br /&gt;
Init Priority[7500] &lt;br /&gt;
 BRW2.ActiveInvisible = True &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Copiar un Registro ===&lt;br /&gt;
&lt;br /&gt;
    !ABC Objects -&amp;gt; Browse on Clientes -&amp;gt; PrimeRecord Priority[4500] &lt;br /&gt;
    IF Loc:Copiar &lt;br /&gt;
     SuppressClear = True &lt;br /&gt;
     CLEAR(Loc:Copiar) &lt;br /&gt;
    END!IF &lt;br /&gt;
&lt;br /&gt;
    !Control Events --&amp;gt; Copiar -&amp;gt; Accepted -&amp;gt; Priority[5000] &lt;br /&gt;
    Loc:Copiar = True &lt;br /&gt;
    POST(EVENT:Accepted,?UseDelBotonAgregar) &lt;br /&gt;
&lt;br /&gt;
    !Notas: Crear Variable Local Loc:Copiar &lt;br /&gt;
    ! SuppressClear es un Parametro de BrowseClass.PrimeRecord&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar el Popup ===&lt;br /&gt;
 !ABC Objects -&amp;gt; Local Objects -&amp;gt; Windows Manager--&amp;gt;&amp;gt;Init Priority[9001] &lt;br /&gt;
 Brw1.Popup.KILL&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Ordenamiento Dinámico ===&lt;br /&gt;
En Clarion6 se puede hacer automáticamente con la opcion Sort Headers.&lt;br /&gt;
Si se quiere hacer desde código para ordenar por cualquier campo, se puede utilizar:&lt;br /&gt;
    Brw1.SetOrder(&#039;TAB:Campo&#039;) &lt;br /&gt;
    Brw1.ApplyOrder() &lt;br /&gt;
    ThisWindow.Reset(1) &lt;br /&gt;
Por ejemplo si quisiera emular un ordenamiento con el doble click sobre una columna, habría que alertar el doble click en al browse, y el código sería mas o menos asi.&lt;br /&gt;
 Control Event -&amp;gt; Browse:1 -&amp;gt;Alert Key [4500] &lt;br /&gt;
 ! Código usado para cambiar el Orden del Browse &lt;br /&gt;
 ! cuando se hace doble click en la columna &lt;br /&gt;
 IF KEYCODE()=MouseLeft2 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;Codigo&#039; &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;Nombre&#039; &lt;br /&gt;
     Loc:Columna = ?Browse:1{PropList:MouseDownField} &lt;br /&gt;
     CASE Loc:Columna &lt;br /&gt;
     OF 1 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;&amp;lt;&amp;lt;&amp;lt;CODIGO&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;LCA:LOCALIDAD&#039;) &lt;br /&gt;
     OF 2 &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;&amp;lt;&amp;lt;&amp;lt;NOMBRE&amp;gt;&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;UPPER(LCA:NOMBRE)&#039;) &lt;br /&gt;
     END!CASE &lt;br /&gt;
     Brw1.ApplyOrder() &lt;br /&gt;
     ThisWindow.Reset(1) &lt;br /&gt;
 END!IF &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Locator Múltiple ===&lt;br /&gt;
Por ejemplo, para posicionarme en un código de cuenta contable:&lt;br /&gt;
Lo que podrías hacer es poner una variable string sobre el browse y poner un&lt;br /&gt;
código mas o menos asi en su accepted del entry&lt;br /&gt;
&lt;br /&gt;
 !Asumiendo que cada código tiene cuatro dígitos&lt;br /&gt;
 !Revisar la sección String Slicing en el Help&lt;br /&gt;
 Cue:Cuenta = Loc:Cuenta[1:4]&lt;br /&gt;
 Cue:SubCuenta = Loc:Cuenta[5:8]&lt;br /&gt;
 Cue:SubSubCuenta = Loc:Cuenta[9:12]&lt;br /&gt;
 SET(Cue:PorCodigo,Cue:PorCodigo)&lt;br /&gt;
 Access:Cuentas.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Otro ejempo, en un browse de órdenes, posicionarse según el nombre del cliente&lt;br /&gt;
&lt;br /&gt;
 CLI:Nombre = LOC:Cliente&lt;br /&gt;
 SET(CLI:PorNombre, CLI:PorNombre)&lt;br /&gt;
 ACCESS:Clientes.Next()&lt;br /&gt;
&lt;br /&gt;
 ORD:CodCliente = CLI:CodCliente&lt;br /&gt;
 SET(ORD:PorCliente, ORD:PorCliente)&lt;br /&gt;
 ACCESS:Ordenes.Next()&lt;br /&gt;
&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Pintar un browse según un campo ===&lt;br /&gt;
Por ejemplo cuando vemos las facturas de un Cliente se repite el nombre, este código pinta diferente cada grupo de nombres.&lt;br /&gt;
Primero hay que ponerle el atributo color al campo que necesites pintar, desde list box format.&lt;br /&gt;
Luego va el siguiente código, en WindowManager.Reset antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 Aux = &#039;&#039;&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (BRW1.Q)&lt;br /&gt;
     GET(BRW1.Q, F#)&lt;br /&gt;
     IF Aux &amp;lt;&amp;gt; BRW1.Q.CLI:Nombre&lt;br /&gt;
         Col# = 1- Col#&lt;br /&gt;
         Aux = BRW1.Q.CLI:Nombre&lt;br /&gt;
     END&lt;br /&gt;
     If Col#&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:SILVER&lt;br /&gt;
     Else&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:WHITE&lt;br /&gt;
     End&lt;br /&gt;
     PUT(BRW1.Q)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Refrescar un browse desde otra ventana ===&lt;br /&gt;
Lo mas fácil sería usando NOTIFY.&lt;br /&gt;
En la Ventana 1 (la del browse a refrescar)&lt;br /&gt;
 WindowManager.Init&lt;br /&gt;
 GLO:THREAD = THREAD() !VARIABLE GLOBAL LONG&lt;br /&gt;
&lt;br /&gt;
 Window Events&lt;br /&gt;
 Notify&lt;br /&gt;
 BRW1.ResetfromBuffer() ! o ThisWindow.Reset(1)?&lt;br /&gt;
&lt;br /&gt;
En la ventana 2, cuando se necesite refrescar la 1&lt;br /&gt;
 NOTIFY (999, GLO:THREAD)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que en éste caso no estoy usando ese parámetro.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Iniciar el browse en un Tab determinado ===&lt;br /&gt;
En ThisWindow.Init, al final&lt;br /&gt;
 SELF.FirstField = ?Tab:4 !Use del tab&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Actualizar el resultado de un totaling del browse de detalle, en el Encabezado ===&lt;br /&gt;
En el Browse de abajo (el de detalle)&lt;br /&gt;
 ResetFromView, prioridad 4500 - La prioridad es importante&lt;br /&gt;
 GET(Encabezado, ENC:Por_Numero)&lt;br /&gt;
 ENC:Total = loc:total !ÉSTA ES LA VARIABLE DEL TOTALING&lt;br /&gt;
 PUT (Encabezado)&lt;br /&gt;
 IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtro Dinámico ===&lt;br /&gt;
Poner un control Text donde el usuario pueda escribir cualquier filtro&lt;br /&gt;
 X# = EVALUATE(Filtro)&lt;br /&gt;
 IF ERRORCODE()&lt;br /&gt;
     MESSAGE(&#039;ERROR DE SINTAXIS EN EL FILTRO: &#039; &amp;amp; ERROR(), &#039;ATENCION&#039;)&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.SetFilter(Filtro)&lt;br /&gt;
     ThisWindow.Reset(1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Rangos múltiples y dinámicos ===&lt;br /&gt;
Si tenemos una clave con varios componentes, en Actions del browse ponemos un rango por current value, elegimos el componente de la clave hasta el cual queremos hacer el rango.&lt;br /&gt;
El siguiente componente de la clave se puede usar como locator.&lt;br /&gt;
Por ejemplo si tenemos una clave con Tipo+Provincia+Localidad, hacemos un rango de current value por provincia y nos queda un locator por localidad.&lt;br /&gt;
&lt;br /&gt;
 BRW1.ApplyRange PROCEDURE&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 RAN:Tipo= loc:tipo&lt;br /&gt;
 RAN:Provincia=loc:provincia&lt;br /&gt;
 SELF.Order.Rangelist.AssignLeftToRight()&lt;br /&gt;
&lt;br /&gt;
En algun boton de aplicar rango&lt;br /&gt;
 BRW1.ApplyRange()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, deshabilitar condicionalmente la actualización de registros ===&lt;br /&gt;
 IF &amp;lt;Condición&amp;gt;&lt;br /&gt;
     !Deshabilitar Actualización&lt;br /&gt;
     BRW1.InsertControl=FALSE&lt;br /&gt;
     BRW1.ChangeControl=FALSE&lt;br /&gt;
     BRW1.DeleteControl=FALSE&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.InsertControl=?INSERT&lt;br /&gt;
     BRW1.ChangeControl=?CHANGE&lt;br /&gt;
     BRW1.DeleteControl=?DELETE&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar el cambio de registro seleccionado en un Browse ===&lt;br /&gt;
Ejemplo mostrar una foto del cliente al costado del browse&lt;br /&gt;
 BRW1.TakeNewSelection PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !EN CLI:FOTO ESTA EL PATH COMPLETO DE LA FOTO&lt;br /&gt;
 IF CLI:FOTO &amp;lt;&amp;gt; &#039;&#039;&lt;br /&gt;
     ?Foto{PROP:TEXT}= CLI:FOTO &lt;br /&gt;
 ELSE&lt;br /&gt;
     ?Foto{PROP:TEXT}= &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un browse ===&lt;br /&gt;
Ejemplo: Mostrar sólo los clientes que tengan alguna orden&lt;br /&gt;
&lt;br /&gt;
 BRW1.ValidateRecord PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !FILTROS COMPLEJOS&lt;br /&gt;
 !EJ: MOSTRAR SOLO LOS CLIENTES QUE TENGAN ALGUNA ORDEN&lt;br /&gt;
 CLEAR(ORD:RECORD)&lt;br /&gt;
 Ord:CodigoCliente=CLI:ID&lt;br /&gt;
 SET(Ord:FK_Ordenes_CLIENTES,Ord:FK_Ordenes_CLIENTES)&lt;br /&gt;
 NEXT(ORDENES)&lt;br /&gt;
 IF ERRORCODE() OR (Ord:CodigoCliente &amp;lt;&amp;gt; CLI:ID) THEN RETURN Record:Filtered.&lt;br /&gt;
 &lt;br /&gt;
 RETURN Record:OK&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Poner un campo &amp;quot;saldo&amp;quot; en un browse ===&lt;br /&gt;
ThisWindow.Reset, antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 S#=0&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (Queue:Browse:1)&lt;br /&gt;
     GET(Queue:Browse:1, F#)&lt;br /&gt;
     S# += Queue:Browse:1.ORD:Total_Impo&lt;br /&gt;
     Queue:Browse:1.Saldo = S#&lt;br /&gt;
     PUT(Queue:Browse:1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Resetear/inicializar un Locator ===&lt;br /&gt;
El método a ejecutar es&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
&lt;br /&gt;
Los nombres de las instancias de Locators por cada TAB se llaman:&lt;br /&gt;
 BRW1::Sort0:Locator.Set&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
 BRW1::Sort2:Locator.Set&lt;br /&gt;
 !etc..&lt;br /&gt;
&lt;br /&gt;
Luego sería bueno volver a poner el foco en el browse para que se pueda seguir usando el locator normalmente&lt;br /&gt;
 select (?Browse:1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, disparar un procedimiento después de generar un alta, modificación, etc. ===&lt;br /&gt;
&lt;br /&gt;
El proceso a disparar se hace desde el browse, la idea es saber si del Form volvió aceptando o canceló la actualización. El punto embebido es:&lt;br /&gt;
&lt;br /&gt;
 Local Objects&lt;br /&gt;
 BRW1 (o el objeto de tipo browse class que sea)&lt;br /&gt;
 ResetFromAsk (después del Parent.call)&lt;br /&gt;
 &lt;br /&gt;
 IF VCRRequest=VCR:None&lt;br /&gt;
 CASE Request&lt;br /&gt;
 OF InsertRecord&lt;br /&gt;
     IF Response = RequestCompleted&lt;br /&gt;
     !Hacer algún proceso&lt;br /&gt;
     END&lt;br /&gt;
 END&lt;br /&gt;
 END!&lt;br /&gt;
&lt;br /&gt;
=== Inserción continua refrescando el Browse ===&lt;br /&gt;
Este otro método es similar al anterior, también sirve para lo mismo.&lt;br /&gt;
Agrego un ejemplo para hacer inserción continua en el Form y además se vaya actualizando el browse&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Run PROCEDURE(USHORT Number,BYTE Request)&lt;br /&gt;
 ! Cuidado que existen dos ThisWindow.Run, seleccionar el correcto&lt;br /&gt;
 ! [Priority 8500]&lt;br /&gt;
 IF Request = InsertRecord And ReturnValue = RequestCompleted&lt;br /&gt;
     POST(EVENT:ACCEPTED, BRW1.InsertControl)&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Posicionar un browse en un registro seleccionado ===&lt;br /&gt;
&lt;br /&gt;
Al abrir un browse a veces necesitamos posicionar el selector en un registro determinado, tal como lo hacen los browses para selección.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para posicionar el browse en el registro más cercano al proporcionado por el usuario:&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Open PROCEDURE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 ! End of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 CODE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Executable Code Section&amp;quot;&lt;br /&gt;
 ! [Priority 500]&lt;br /&gt;
 CLI:cliente= LOC:Cliente&lt;br /&gt;
 ACCESS:Clientes.fetch(CLI:Kcodigo)&lt;br /&gt;
 BRW1.selecting=1&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 PARENT.Open()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 BRW1.selecting=0&lt;br /&gt;
&lt;br /&gt;
Otra idea, propuesta por Matías Flores:&lt;br /&gt;
Ubicarlo por el valor de los campos de la clave. Por ejemplo, si en un browse de clientes querés posicionarte en un cliente que tiene un código determinado (Loc:Codigo):&lt;br /&gt;
&lt;br /&gt;
 Cli:Codigo = Loc:Codigo&lt;br /&gt;
 SET(Cli:PorCodigo,Cli:PorCodigo)&lt;br /&gt;
 Access:Clientes.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
un ejemplo parecido al anterior, pero en legacy, sería:&lt;br /&gt;
 CLI:Codigo = LOC:Codigo&lt;br /&gt;
 BRW1::LocateMode = LocateOnValue&lt;br /&gt;
 DO BRW1::LocateRecord&lt;br /&gt;
&lt;br /&gt;
Una opción más es:&lt;br /&gt;
En el WindowManager.init, antes de Initialize browse y después de OpenFiles, colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 BRWx.StartAtCurrent = True&lt;br /&gt;
 TAB:Campo = Valor_Buscado&lt;br /&gt;
 get(Tabla, TAB:Key_que_ordena_por_Campo)&lt;br /&gt;
&lt;br /&gt;
=== En Legacy, activar un filtro sobre un browse abierto. ===&lt;br /&gt;
&lt;br /&gt;
Esto se pone en el punto embebido &amp;quot;Before opening VIEW&amp;quot;. Acordarse de BINDEAR todas las variables que se necesiten.&lt;br /&gt;
&lt;br /&gt;
 !---ANTES DE ABRIR EL VIEW--- &lt;br /&gt;
 if SoloPendientes then&lt;br /&gt;
 BRW2::View:Browse{Prop:Filter} = |&lt;br /&gt;
 &#039;MER:numertra = BRW2::Sort1:Reset:TRA:numertra AND MER:saldunid &amp;lt;&amp;gt; 0&#039;&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo cuando quieras presentar el nombre completo sin los espacios de un campo a otro. Pones en el browse una variable local.&lt;br /&gt;
En el SETQUEUERECORD (4500)&lt;br /&gt;
 &lt;br /&gt;
 Loc:ApellidoNombre = clip(CON:Apellido) &amp;amp; &#039; &#039; &amp;amp; CON:Nombre&lt;br /&gt;
&lt;br /&gt;
!(Tip de Alex B.)&lt;br /&gt;
&lt;br /&gt;
=== Código antes y después de una actualización DESDE UN BROWSE. ===&lt;br /&gt;
&lt;br /&gt;
- Antes de la llamada al Form de actualización&lt;br /&gt;
! ABC Objects -&amp;gt; Browse on Archvivo -&amp;gt;Ask Priority[4500]&lt;br /&gt;
 IF Request = InsertRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR ALTA &#039;,&#039;ALTA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = ChangeRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A ACTUALIZAR &#039;,&#039;CAMBIO&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = DeleteRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR DE BAJA &#039;,&#039;BAJA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
- Después de la actualización del registro&lt;br /&gt;
!ABC Objects -&amp;gt; Browse on Provincia -&amp;gt;Ask Priority[5500]&lt;br /&gt;
 IF ReturnValue =1&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCIÓN: SE ACTUALIZÓ EL REGISTRO&#039;,&#039;ACTUALIZÓ OK&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF ReturnValue =2&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;SE CANCELÓ LA ACTUALIZACIÓN DEL REGISTRO&#039;,&#039;ATENCIÓN&#039;,ICON:HAND)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar/esconder (cambiar a PROP:HIDE) un control si el browse está vacío - pe. un botón-. ===&lt;br /&gt;
&lt;br /&gt;
En el Browse.UpdateWindow(), última prioridad:&lt;br /&gt;
 ?TuBoton{PROP:Disable}=Choose(Self.Records()&amp;lt;&amp;gt;0,0,1)&lt;br /&gt;
&lt;br /&gt;
===Iniciar un browse con un orden &amp;quot;sort header&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Si queremos que al abrir un browse el mismo se encuentre ordenado como si hubiéramos hecho click en el sortheader, ponemos luego del generated code del evento openwindow lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 BRW1::SortHeader.SetSortFromString(&#039;TAB:Campo&#039;)&lt;br /&gt;
&lt;br /&gt;
donde TAB:Campo es uno de los campos de la tabla que estoy mostrando en el browse.&lt;br /&gt;
&lt;br /&gt;
== EDIT IN PLACE==&lt;br /&gt;
=== Edit in Place o Form, según condición ===&lt;br /&gt;
En BrowseClass, Ask, antes del Parent Call&lt;br /&gt;
 If ?browse:1{proplist:mousedownfield} = 5&lt;br /&gt;
     Self.AskProcedure = 0&lt;br /&gt;
 else&lt;br /&gt;
     Self.AskProcedure = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Puede usarse cualquier condición, en este caso si el usuario hace doble click en la 5a columna se usa edit in place, sino se usa el formulario&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Desactivar Edit in Place de un campo según condición ===&lt;br /&gt;
En las propiedades del EIP del campo admitir la edición del mismo.&lt;br /&gt;
&lt;br /&gt;
En el EIP Field Manager del campo, TakeEvent, antes del Parent Call&lt;br /&gt;
  if Queue:Browse:1.TAB:Campo_de_mi_Tabla &amp;gt; 0 &lt;br /&gt;
     Return EditAction:Cancel&lt;br /&gt;
     thiswindow.reset(true)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
En este ejemplo sólo permito que pueda editarse el campo si el valor actual del mismo es &amp;lt;= 0&lt;br /&gt;
&lt;br /&gt;
=== Inicializar campos al insertar registro ===&lt;br /&gt;
O sea lo que hace el Prime Fields en las formas&lt;br /&gt;
 ABC Objects&lt;br /&gt;
 BROWSE ON TABLA using ?LIST&lt;br /&gt;
 PrimeRecords&lt;br /&gt;
 Después del Parent Call&lt;br /&gt;
 TPS:TuCampo= valor inicial&lt;br /&gt;
&lt;br /&gt;
=== Poner Disable un campo===&lt;br /&gt;
 Local Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 Abc Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 EIP Field Manag...for Field NombreCampo&lt;br /&gt;
 --&amp;gt;&amp;gt;Init [Priority 5001]&lt;br /&gt;
 If SELF.FEQ then SELF.FEQ{Prop:Disable} = true.&lt;br /&gt;
También se pueden cambiar otras propiedades como por ejemplo UPPER (mayúsculas) o READ ONLY (sólo lectura)&lt;br /&gt;
 If SELF.FEQ &lt;br /&gt;
     SELF.FEQ{prop:readonly} = TRUE&lt;br /&gt;
     SELF.FEQ{prop:upr} = TRUE&lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo Modificar el total cuando cambia la cantidad.&lt;br /&gt;
Primero agregar el campo cantidad en Column Specific&lt;br /&gt;
 EditInPlace::DET:Cantidad.TakeEvent PROCEDURE(UNSIGNED Event)&lt;br /&gt;
 ....&lt;br /&gt;
 !Despues del Parent Call&lt;br /&gt;
&lt;br /&gt;
 CASE ReturnValue&lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel&lt;br /&gt;
 ELSE&lt;br /&gt;
     Update(Self.Feq)&lt;br /&gt;
     BRW1.Q.DET:Total = BRW1.Q.DET:Cantidad * BRW1.Q.DET:Importe&lt;br /&gt;
     !Etc... siempre haciendo referencia a los campos de la cola BRW1.Q.&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones ===&lt;br /&gt;
Por ejemplo una validación básica de un número requerido&lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:NroDocumento&lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 ! Validación del nro. de Documento &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     UPDATE(Self.Feq) &lt;br /&gt;
     IF NOT BRW1.Q.Cli:NroDocumento &lt;br /&gt;
         BEEP(BEEP:SystemExclamation) ; YIELD() &lt;br /&gt;
         MESSAGE(&#039;No se informó el número de Documento&#039;, | &lt;br /&gt;
         &#039;Atención!&#039;, ICON:Exclamation) &lt;br /&gt;
         ReturnValue = EditAction:NONE &lt;br /&gt;
         Return ReturnValue &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Validación con un lookup a una tabla &lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:Provincia &lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 !Valida Provincia &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     Update(Self.Feq) &lt;br /&gt;
     Pro:Codigo= BRW1.Q.Cli:Provincia &lt;br /&gt;
     IF Access:Provincia.Fetch(Pro:PorCodigo) &lt;br /&gt;
         GlobalRequest = SelectRecord &lt;br /&gt;
         SelectProvincia &lt;br /&gt;
         IF NOT Pro:Codigo &lt;br /&gt;
             ReturnValue = EditAction:NONE &lt;br /&gt;
             Return ReturnValue &lt;br /&gt;
         ELSE &lt;br /&gt;
             BRW1.Q.Cli:Provincia = Pro:Codigo &lt;br /&gt;
             BRW1.Q.Pro:NOMBRE = Pro:NOMBRE &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== GLOBALES ==&lt;br /&gt;
&lt;br /&gt;
=== Cambiar los mensajes de error del SQL === &lt;br /&gt;
Con cambiar los TRN no alcanza para ese tipo de errores. &lt;br /&gt;
 &lt;br /&gt;
Lo que se puede hacer es determinar el mensaje que viene desde el SQLServer &lt;br /&gt;
para mostrar un mensaje mas amigable. &lt;br /&gt;
 &lt;br /&gt;
El embebido es &lt;br /&gt;
Global Embeds: &lt;br /&gt;
 Global Objets &lt;br /&gt;
 Abc Objects &lt;br /&gt;
 Error Manager &lt;br /&gt;
 TakeNotify &lt;br /&gt;
 !Antes del Parent Call &lt;br /&gt;
 IF INSTRING(&#039;COLUMN REFERENCE&#039;, SELF.SubsString(),1,1) &lt;br /&gt;
 SELF.Msg(&#039;El registro no puede borrarse porque tiene datos de detalle &lt;br /&gt;
 que dependen de él. |Presione [OK] para una descripción detallada del &lt;br /&gt;
 error&#039;,SELF.GetErrorBufferTitle(),ICON:Exclamation,Button:OK,BUTTON:OK,0) &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Hay que armar un IF de estos por cada tipo de error... &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validación de campos (Edit in place o Form)=== &lt;br /&gt;
 &lt;br /&gt;
Para validar campos lo ideal es usar los Global Embeds &lt;br /&gt;
 Global Embeds &lt;br /&gt;
 Field Level Validation &lt;br /&gt;
 Tabla &lt;br /&gt;
 Campo &lt;br /&gt;
 IF &amp;lt;No cumple Condición&amp;gt; &lt;br /&gt;
 Message(&#039;error...&#039;) &lt;br /&gt;
 RETURN Level:Notify &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Esto te va a funcionar &amp;quot;para siempre&amp;quot; ya sea que uses Edit in place, un Form &lt;br /&gt;
o código embebido para actualizar la tabla. &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=70</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=70"/>
		<updated>2015-03-07T22:42:55Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Repositorios de archivos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
[news://news.softvelocity.com/softvelocity.clarion.intl.spanish Grupo de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
=== Clarionhub (en inglés) ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionhub.com www.clarionhub.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://faq.clarionmag.com ClarionFAQ en Clarion Magazine]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Página de ayuda con Templates de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ Página que contiene Webinars y tutoriales. Muy útil.]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://http://templatesclarion.com.ar/downloads/ Templates Clarion - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=69</id>
		<title>Puntos Embebidos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=69"/>
		<updated>2015-03-07T22:41:45Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Texto reemplazado: «(Evolution)» por «(Templates Clarion)»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los puntos embebidos son la pesadilla de todo principiante de Clarion. Son extremadamente útiles, pero son muy difíciles de aprender. Para colmo, la abstracción que implementa la clase ABC hace más difícil todavía conocerlos y aprovecharlos. Por eso esta sección es de vital importancia.&lt;br /&gt;
&lt;br /&gt;
== FORMULARIOS ==&lt;br /&gt;
=== ¿Qué procedimiento llamó al Form? ===&lt;br /&gt;
Al principio del WindowManager.Init del Form (primer prioridad disponible)&lt;br /&gt;
&lt;br /&gt;
 GlobalErrors.GetProcedureName()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones complejas ===&lt;br /&gt;
Por ejemplo validar un Email:&lt;br /&gt;
En el accepted del campo&lt;br /&gt;
Puedes hacerlo con MATCH, ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# = MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
Devuelve 1 o 0 si el mail no es válido.&lt;br /&gt;
El MATCH puede usarse con expresiones regulares para validar casi cualquier cosa...&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se Abre/inicializa el Form ===&lt;br /&gt;
ThisWindow.Init&lt;br /&gt;
 !Es interesante entrar por el botón source a este embed para entender bien todas sus prioridades&lt;br /&gt;
 !GlobalRequest (pasada por el browse) se guarda en la propiedad ThisWindow.Request&lt;br /&gt;
 !Se puede preguntar por SELF.Request para saber para qué se lo llamó al form: &lt;br /&gt;
 !InsertRecord EQUATE (1)&lt;br /&gt;
 !ChangeRecord EQUATE (2)&lt;br /&gt;
 !DeleteRecord EQUATE (3)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar el Form a &amp;quot;Solo lectura&amp;quot; ante una condición===&lt;br /&gt;
 ThisWindow.Init&lt;br /&gt;
 ! [Priority 4950] La prioridad es importante!&lt;br /&gt;
 IF FAC:facturado = 1 THEN SELF.Request = ViewRecord.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Truco: Llamar al form para insertar desde el menú ===&lt;br /&gt;
Podríamos asumir que si la GlobalRequest está en blanco es que se lo&lt;br /&gt;
llamó para insertar, evitaríamos asi el paso por un Browse&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !If GlobalRequest = 0 Then GlobalRequest = InsertRecord.&lt;br /&gt;
&lt;br /&gt;
Si la tabla tiene una clave Autonumber, se complica un poco mas, sería asi:&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !Por ej prioridad 300&lt;br /&gt;
 If GlobalRequest = 0&lt;br /&gt;
     GlobalRequest = InsertRecord&lt;br /&gt;
     DesdeMenu# = True&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
 !Después de Open Files:&lt;br /&gt;
 !Por ej prioridad 7800&lt;br /&gt;
 If DesdeMenu# = True&lt;br /&gt;
 Access:People.PrimeAutoinc()&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Llamar a un form para editar una tabla con un solo registro ===&lt;br /&gt;
Típicamente una tabla de parametros, obviamente no queremos pasar por un browse&lt;br /&gt;
 WindowManager.Init,&lt;br /&gt;
 !al principio&lt;br /&gt;
 GlobalRequest = ChangeRecord&lt;br /&gt;
&lt;br /&gt;
 !Luego de Open files&lt;br /&gt;
 Set(Tabla)&lt;br /&gt;
 access:Tabla.Next()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se confirma un Form ===&lt;br /&gt;
ThisWindow.TakeCompleted&lt;br /&gt;
 ! [Priority 2800]&lt;br /&gt;
 !ANTES DE QUE SE CONFIRME LA GRABACION&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 ReturnValue = PARENT.TakeCompleted()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 !YA SE GRABÓ EL REGISTRO.&lt;br /&gt;
 !VERIFICAR SI SELF.Response=RequestCompleted A VER SI SE GRABÓ OK.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se cierra un Form ===&lt;br /&gt;
ThisWindow.Kill&lt;br /&gt;
 !VERIFICAR LOS valores de SELF.Request y SELF.Response&lt;br /&gt;
 !Para decidir que acciones tomar&lt;br /&gt;
 !Este punto ya es &amp;quot;demasiado tarde&amp;quot; para hacer algo antes de que se grabe el registro&lt;br /&gt;
 !Para eso usar TakeCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se produce el borrado sin abrir el Form ===&lt;br /&gt;
Si tenemos un form para actualizar una tabla, y definimos que el borrado sea Confirmando (Standard Warning) o Automático (Automatic Delete), y necesitamos ejecutar un código en el form cuando se efectúe el borrado, usamos:&lt;br /&gt;
&lt;br /&gt;
ThisWindow.PrimeUpdate, después del Parent Call&lt;br /&gt;
&lt;br /&gt;
 if self.request = DeleteRecord and self.Response = RequestCompleted&lt;br /&gt;
 !lo que quiero hacer&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que el borrado de un registro no pasa por el TakeCompleted, excepto cuando se usa la ventana del form (Display Form).&lt;br /&gt;
&lt;br /&gt;
Aporte de Gustavo Olmedo [http://www.evolutionconsulting.com.ar/downloads.html (Templates Clarion)] (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó cualquier campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
En el TakeCompleted ponemos el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF NOT SELF.Primary.Me.EqualBuffer(SELF.Saved)&lt;br /&gt;
 ! message(&#039;Cambio&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Aporte de Pablo Guarnieri y Gustavo Olmendo&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó un campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
 IF CLI:Campo &amp;lt;&amp;gt; history::CLI:Record.Campo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Forzar grabación del form === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para grabar el form inclusive cuando el usuario lo cancele&lt;br /&gt;
&lt;br /&gt;
TakeCloseEvent PROCEDURE(),BYTE,VIRTUAL&lt;br /&gt;
 IF loc:condicion &lt;br /&gt;
    SELF.CancelAction = Cancel:Save !immediate save (no confirmation)&lt;br /&gt;
 END&lt;br /&gt;
 &lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar un Drop Combo === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para filtrar un drop combo utilizando pro:sqlfilter, suponemos que en &lt;br /&gt;
la variable loc:filtro se arma el filtro ha enviar, algo asi como: &#039;a.idtercero = &amp;lt;39&amp;gt;90909090&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
FDCB14 es el nombre del objeto el cual se puede verificar en propiedades --&amp;gt; clases.&lt;br /&gt;
&lt;br /&gt;
ApplyFilter PROCEDURE,VIRTUAL&lt;br /&gt;
 FDCB14::View:FileDropCombo{PROP:SQLFILTER} =  &amp;lt;39&amp;gt;&#039;&amp;amp;clip(loc:filtro)&amp;amp;&#039;&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
 IF FILEERRORCODE()&lt;br /&gt;
    FDCB14::View:FileDropCombo{PROP:SQLFILTER} = &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Obtener el número autogenerado por SQL Server en tablas con identity === &lt;br /&gt;
Después del Parent Call, en el TakeCompleted del Form:&lt;br /&gt;
 IF Self.Response=RequestCompleted AND Self.Request = InsertRecord&lt;br /&gt;
    Tabla{prop:Sql}= &#039;SELECT @@IDENTITY&#039; !busco el número que se asignó&lt;br /&gt;
    IF not Access:Tabla.Next()&lt;br /&gt;
       !en el primer campo de Tabla viene cargado el número autogenerado&lt;br /&gt;
    else&lt;br /&gt;
       message(&#039;Error&#039;)&lt;br /&gt;
    end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Tomado de una respuesta de Fernando Cerini en el foro.&lt;br /&gt;
&lt;br /&gt;
== REPORTES Y PROCESOS ==&lt;br /&gt;
=== Ocultar un campo del detalle según condición ===&lt;br /&gt;
 !En TakeRecord, antes del Print (Process Manager)&lt;br /&gt;
 IF &amp;lt;CONDICION&amp;gt;&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=True&lt;br /&gt;
 ELSE&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=False !si la condición no se cumple, vuelvo a hacer visible el control&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Saber si un proceso se completó ===&lt;br /&gt;
O sea que no se salió por el botón de cancelar&lt;br /&gt;
 !En el WindowManager.Kill&lt;br /&gt;
 IF Self.Response = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
 &lt;br /&gt;
=== Inicializar el número de página ===&lt;br /&gt;
 !WindowManager.OpenReport, despues del Parent Call&lt;br /&gt;
 IF ReturnValue = Level:Benign&lt;br /&gt;
  Report{PROP:NextPageNo} = xxx&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar la impresión ===&lt;br /&gt;
 !Local Objects, Abc Objects, Previewer, Display, After ParentCall.&lt;br /&gt;
 !impresión prohibida&lt;br /&gt;
 ReturnValue = False&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
 If ReturnValue and DemoVersion&lt;br /&gt;
   ReturnValue = False&lt;br /&gt;
   Message(&amp;quot;Está utilizando una versión del demo, no puede imprimir este documento !&amp;quot;)&lt;br /&gt;
 End&lt;br /&gt;
Aporte de Olivier Cretey&lt;br /&gt;
&lt;br /&gt;
Otra opción, en Previewer.TakeAccepted, antes del Parent Call&lt;br /&gt;
 IF CLIP(ACCEPTED(){PROP:TIP}) = &#039;Print this report&#039; THEN RETURN LEVEL:BENIGN.&lt;br /&gt;
&lt;br /&gt;
O sea pregunto por el Tool Tip del botón que se ha presionado. Ojo, si lo tienes traducido tienes que cambiar el &#039;Print this report&#039; por tu Tool Tip.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un Proceso ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt; Validate Records --&amp;gt;&amp;gt; [Priority 5600] &lt;br /&gt;
 If &amp;lt;Condición de Filtro&amp;gt;&lt;br /&gt;
     Return Record:Filtered &lt;br /&gt;
 Else &lt;br /&gt;
     Return Record:OK &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
 &lt;br /&gt;
=== Habilitar o deshabilitar el Print Preview ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 Self.SkipPreview = Loc:Preview &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Cantidad de Páginas generadas ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 ENDPAGE(SELF.Report) &lt;br /&gt;
 Loc:Paginas = RECORDS(SELF.PreviewQueue) &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un Transporte ===&lt;br /&gt;
Necesitas crear 3 details.&lt;br /&gt;
DetailDatos&lt;br /&gt;
DetailTransporte: aca van las variables locales con los totales&lt;br /&gt;
DetailSalto: este detail es vacío y con la propiedad PageAfter&lt;br /&gt;
&lt;br /&gt;
En el embed TakeRecord (antes de los PRINTs) habría que hacer algo asi&lt;br /&gt;
 LOC:Fila += 1&lt;br /&gt;
 If LOC:Fila % 28 = 0 !28 líneas por página...&lt;br /&gt;
     PRINT(RPT:DetailSalto)&lt;br /&gt;
     PRINT(RPT:DetailTransporte)&lt;br /&gt;
     LOC:Fila = 1&lt;br /&gt;
 End&lt;br /&gt;
 LOC:Total += LIBRO:Total&lt;br /&gt;
 PRINT (RPT:Detalle)&lt;br /&gt;
 RETURN LEVEL:Benign&lt;br /&gt;
&lt;br /&gt;
Marcelo Martínez&lt;br /&gt;
y [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Acelerar las actualizaciones ===&lt;br /&gt;
Para que los procesos que agreguen registros funcionen mas rápido hay que agregar un Logout o Stream en Init y un Commit o Flush en el kill&lt;br /&gt;
(El Evolution Tools tiene una extension que hace eso mismo.)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Se imprime o se Cancela? ===&lt;br /&gt;
Los embeds son&lt;br /&gt;
 ABC Objectd&lt;br /&gt;
 --WindowManager(ReportManager)&lt;br /&gt;
 --CancelPrintReport&lt;br /&gt;
 -Se Cancela&lt;br /&gt;
&lt;br /&gt;
 --PrintReport&lt;br /&gt;
 -Se imprime&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Recorrer la cola de las páginas ===&lt;br /&gt;
Cada página del reporte genera una imagen .WMF, la cual se guarda en el directorio temporal.&lt;br /&gt;
Con este ejemplo se puede recorrer la cola donde se guardan los nombres de estos archivos. Ésto es lo que usa por ejemplo el Evolution Mail Template para enviar estas páginas por mail.&lt;br /&gt;
 Previewer.Open PROCEDURE&lt;br /&gt;
 ....&lt;br /&gt;
 loop a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
     get(SELF.ImageQueue,a#)&lt;br /&gt;
     message(SELF.ImageQueue)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir una Queue ===&lt;br /&gt;
La mejor forma de hacerlo en Clarion6 es en Report Properties - General -&lt;br /&gt;
Datasource: Queue.&lt;br /&gt;
&lt;br /&gt;
Yo generalmente pongo los parametros en la ventana y cargo la queue en el&lt;br /&gt;
evento accepted del PauseButton.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un SQL ===&lt;br /&gt;
Lo que yo hago es poner todos los parámetros en la ventana del reporte.&lt;br /&gt;
En el accepted del boton de pausa cargo la cola de memoria con:&lt;br /&gt;
&lt;br /&gt;
 SQL{PROP:SQL} = !aca armo el string SQL&lt;br /&gt;
 IF ERRORCODE() THEN STOP( FILEERROR()).&lt;br /&gt;
 FREE(ColaMemoria)&lt;br /&gt;
 LOOP&lt;br /&gt;
     NEXT(SQL) !O ABC, como prefieras...&lt;br /&gt;
     IF ERRORCODE() THEN BREAK.&lt;br /&gt;
     ColaMemoria :=: SQL:Record&lt;br /&gt;
     ADD(ColaMemoria)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
El reporte lo configuro para trabajar con la cola (data source) y en el&lt;br /&gt;
Detail del reporte pongo los campos de la cola de memoria.&lt;br /&gt;
Lo ideal es tener una cola de memoria global con el atributo thread y usar&lt;br /&gt;
siempre la misma para todo.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar o hacer cortes de control manuales en reportes ===&lt;br /&gt;
En TakeRecord, antes del Print.&lt;br /&gt;
 &lt;br /&gt;
!Actualizar contadores&lt;br /&gt;
&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; CampoCorte&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; 0 !para evitar la primera vez&lt;br /&gt;
 !Inicializar los contadores&lt;br /&gt;
 END&lt;br /&gt;
 AUX=CAMPO&lt;br /&gt;
 !SE VIENE EL CORTE&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Este método TakeRecord se usa también para actualizar cualquier variable calculada antes de la impresión de la banda de detalle.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo BLOB ===&lt;br /&gt;
Este código va en el método TakeRecord, antes del PRINT&lt;br /&gt;
&lt;br /&gt;
 Report$?Image1{PROP:NoWidth} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:NoHeight} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:ImageBlob} = STU:Photograph{PROP:Handle}&lt;br /&gt;
 IF Report$?Image1{PROP:Height} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Width}/Report$?Image1{PROP:Height}&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
 IF Report$?Image1{PROP:Width} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Height}/Report$?Image1{PROP:Width}&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo CSTRING ===&lt;br /&gt;
Este caso es similar al anterior, pero en el campo se encuentra el path donde está la imagen&lt;br /&gt;
 !En el método TakeRecord, antes del PRINT&lt;br /&gt;
 Report$?Image1{PROP:Text} = PRO:Foto&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Evitar el cartel &amp;quot;No records to process&amp;quot; en un proceso ===&lt;br /&gt;
 !En el metodo TAKE NO RECORDS poner un RETURN antes del parent call.&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir el reporte en blanco, cuando no hay registros ===&lt;br /&gt;
En WindowManager. Next, antes del Parent Call con prioridad 500.&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 500] antes del Parent Call&lt;br /&gt;
 If Primera=0 !variable local byte&lt;br /&gt;
    Primera=1&lt;br /&gt;
    SELF.Process.RecordsProcessed = 1&lt;br /&gt;
    Return Level:Benign&lt;br /&gt;
 End&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Cuando hay filtros y rangos, esta solución suele duplicar el primer registro del detalle.&lt;br /&gt;
Para Solucionar esto en ProcessManager NextPROCEDURE(BYTE ProcessRecord) con prioridad 7500 se debe colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF ReturnValue = 0 AND LOC:Primera = 0 THEN !Si hay un registro&lt;br /&gt;
    LOC:Primera = 1        !Dejo al reporte seguir su curso normal&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Mario Wojcik&lt;br /&gt;
&lt;br /&gt;
=== Detectar el último registro en un process o Reporte (fin de archivo) ===&lt;br /&gt;
 ThisProcess.Next PROCEDURE(BYTE ProcessRecords=True)&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 !Fin del proceso&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
Esto por ejemplo es muy útil para cambiar etiquetas en los totales generales del reporte, en un page footer&lt;br /&gt;
 ThisReport.Next PROCEDURE(BYTE ProcessRecords)&lt;br /&gt;
 ....&lt;br /&gt;
 ! [Priority 5001] despues del Parent Call&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 REPORT$?LabelTotal{prop:text}= &#039;Total&#039;&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Reporte con múltiples detalles ===&lt;br /&gt;
Por Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 Viajes&lt;br /&gt;
 |--&amp;gt;pasajeros&lt;br /&gt;
 |--&amp;gt;comisiones&lt;br /&gt;
&lt;br /&gt;
Habría que poner solo la tabla viajes en el Table Schematic. Pasajeros y Comisiones en Other Tables&lt;br /&gt;
&lt;br /&gt;
En el reporte crear 3 details, uno para cada tabla.&lt;br /&gt;
&lt;br /&gt;
En ThisReport.TakeRecord, antes de los PRINTs&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 5500]&lt;br /&gt;
 PRINT(RPT:DetailViaje)&lt;br /&gt;
 CLEAR(PAS:RECORD)&lt;br /&gt;
 PAS:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(PAS:ClavePorViaje, PAS:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Pasajeros.Next() OR PAS:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailPasajeros)&lt;br /&gt;
 END&lt;br /&gt;
 !Y lo mismo para las comisiones&lt;br /&gt;
 CLEAR(COM:RECORD)&lt;br /&gt;
 COM:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(COM:ClavePorViaje, COM:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Comisiones.Next() OR COM:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailComisiones)&lt;br /&gt;
 END&lt;br /&gt;
 Return Level:Benign !ya imprimí todo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Otra alternativa podría ser utilizando el Template &#039;&#039;&#039;ReportChildFiles&#039;&#039;&#039; (desde version 6.X ?) ya que puede ser utilizado mas de una vez en un mismo reporte, apuntando cada instancia a un archivo &amp;quot;hijo&amp;quot; diferente.&lt;br /&gt;
Es fácil de configurar: Se debe seleccionar la tabla CHILD y la PARENT. En el reporte hay que definir el REPORT DETAIL (para el CHILD) y ponerle algún nombre en el label que luego debe ser configurado en el Template.&lt;br /&gt;
&lt;br /&gt;
Jose Sturniolo&lt;br /&gt;
&lt;br /&gt;
=== Imprimir exactamente lo que estamos viendo en el browse ===&lt;br /&gt;
En el browse pones un botón que llame al reporte y en parameters:&lt;br /&gt;
(Brw1.view{PROP:Filter}, Brw1.view{PROP:Order})&lt;br /&gt;
&lt;br /&gt;
En las propiedades del reporte o proceso:&lt;br /&gt;
Prototype: (STRING, STRING)&lt;br /&gt;
Parameters: (FILTRO, ORDEN)&lt;br /&gt;
&lt;br /&gt;
En WindowManager.Init, al final:&lt;br /&gt;
 ThisReport.SetFilter(FILTRO) ! o ThisProcess....&lt;br /&gt;
 ThisReport.SetOrder(ORDEN)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar tamaño de hoja en el reporte ===&lt;br /&gt;
En el embed WindowManager &#039;OpenReport&#039;, PRIORITY(7500)&lt;br /&gt;
&lt;br /&gt;
 IF ~ReturnValue&lt;br /&gt;
 SETTARGET(REPORT)&lt;br /&gt;
 CASE PRINTER{PROPPRINT:Paper}&lt;br /&gt;
 OF PAPER:LETTER&lt;br /&gt;
     REPORT{PROP:height} = 8500&lt;br /&gt;
     ?Footer{PROP:Ypos} = 9000&lt;br /&gt;
 OF PAPER:LEGAL&lt;br /&gt;
     REPORT{PROP:height} = 11000&lt;br /&gt;
     ?Footer{PROP:Ypos} = 11500&lt;br /&gt;
 etc.&lt;br /&gt;
 END&lt;br /&gt;
 SETTARGET()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
etc. con los tamaños de papel que quieras.&lt;br /&gt;
Esto acomoda el contenido del reporte en run-time, haciéndolo ocupar más &lt;br /&gt;
o menos hoja según sea el largo de la misma. Chiche, ¿no?.&lt;br /&gt;
Ajustá los valores a tus necesidades.&lt;br /&gt;
Para tener en cuenta: el usuario tiene que elegir el tamaño del papel &lt;br /&gt;
ANTES de generar el reporte. Si ya está en la vista previa, el reporte ya &lt;br /&gt;
está generado, por lo tanto si cambia el largo de hoja ahí, no se lo va a &lt;br /&gt;
tomar.&lt;br /&gt;
&lt;br /&gt;
Jorge Lavera&lt;br /&gt;
&lt;br /&gt;
=== Cambiar Impresora ===&lt;br /&gt;
En Global Properties--&amp;gt;Embeds--&amp;gt;Before Global INCLUDEs&lt;br /&gt;
 INCLUDE(&#039;PRNPROP.CLW&#039;)&lt;br /&gt;
 !para poder acceder a las propiedades de las impresoras&lt;br /&gt;
&lt;br /&gt;
Luego en el Reporte en &lt;br /&gt;
 ThisReport.Open()&lt;br /&gt;
 !para guardar la impresora por defecto de Windows&lt;br /&gt;
 GLO:IMPRESORA = PRINTER{PROPPRINT:Device}&lt;br /&gt;
 !Seteo la impresora que quiero usar.&lt;br /&gt;
 !El string debe ser igual al que figura en IMPRESORAS&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = &#039;HP Deskjet 840&#039;&lt;br /&gt;
&lt;br /&gt;
y por último en&lt;br /&gt;
 ThisReport.Kill()&lt;br /&gt;
 !para devolver la impresora por defecto de windows&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = CLIP(GLO:IMPRESORA)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Guillermo Ondetti, Pragma Sistemas&lt;br /&gt;
&lt;br /&gt;
=== Detectar Salto de Página de Reporte ===&lt;br /&gt;
Este sería el codigo, siempre y cuando no tengas break groups (ahi se complica bastante)&lt;br /&gt;
El embebido es TakeRecord en ABC, o Before Print Detail en Legacy.&lt;br /&gt;
 VarLocal += REPORT$?Detail{PROP:height}&lt;br /&gt;
 IF VarLocal &amp;gt; REPORT{PROP:height}&lt;br /&gt;
     VarLocal = REPORT$?Detail{PROP:height}&lt;br /&gt;
     !En el siguiente PRINT Cambia la página...&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Aplicar Filtro sql en el reporte ===&lt;br /&gt;
Se arma el filtro si se quiere en una variable por ejemlo loc:sql&lt;br /&gt;
y se aplica en Local Objects --&amp;gt; Abc Objects -- &amp;gt; Process manager --&amp;gt; Apply Filter antes del parent call, asi:&lt;br /&gt;
&lt;br /&gt;
 Process:View{Prop:SqlFilter}=Loc:SQL&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez&lt;br /&gt;
&lt;br /&gt;
=== Imprimir mas de una Copia por Reporte  ===&lt;br /&gt;
Se tiene que poner en el Window Manager --&amp;gt; Open (Prioridad(5000))&lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=n  !! n = Cantidad de copias &lt;br /&gt;
&lt;br /&gt;
Luego es aconsejable poner en el Window Manager --&amp;gt; Kill &lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=1 &lt;br /&gt;
&lt;br /&gt;
ASC Sergio D. Caballero&lt;br /&gt;
&lt;br /&gt;
== BROWSES ==&lt;br /&gt;
=== Actualizar un campo al hacer click en una columna ===&lt;br /&gt;
Por ejemplo, en People.app&lt;br /&gt;
&lt;br /&gt;
En el evento Accepted del Control del browse.&lt;br /&gt;
 !Si se hizo click en el campo&lt;br /&gt;
 IF ?BROWSE:1{PropList:MouseDownField}= 4&lt;br /&gt;
    ACCESS:PEOPLE.Fetch(PEO:KeyId)&lt;br /&gt;
    PEO:Gender = &#039;X&#039;&lt;br /&gt;
    ACCESS:PEOPLE.Update()&lt;br /&gt;
    BRW1.ResetFromFile()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar con SQL===&lt;br /&gt;
A veces es muy útil aplicar un filtro SQL encima de todos los demas filtros que ya tenga el browse, por ejemplo para filtrar por usuario, por sucursal, etc.&lt;br /&gt;
Yo normalmente le pongo el filtro SQL en el método windowmanager.Reset, &lt;br /&gt;
prioridad 5000&lt;br /&gt;
 BRW1.View{PROP:SQLFILTER}=&#039;+ filtro sql&#039;&lt;br /&gt;
Luego se refresca normalmente, o manualmente con ThisWindow.Reset (1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Activar un Browse invisible, o sea que está en otro TAB ===&lt;br /&gt;
Esto es especialmente útil cuando necesitamos que se ejecuten totalizadores del browse aunque éste no esté visible en la pantalla.&lt;br /&gt;
!ABC Objects -&amp;gt; &lt;br /&gt;
Local Objects -&amp;gt;&lt;br /&gt;
Windows Manager-&amp;gt;&lt;br /&gt;
Init Priority[7500] &lt;br /&gt;
 BRW2.ActiveInvisible = True &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Copiar un Registro ===&lt;br /&gt;
&lt;br /&gt;
    !ABC Objects -&amp;gt; Browse on Clientes -&amp;gt; PrimeRecord Priority[4500] &lt;br /&gt;
    IF Loc:Copiar &lt;br /&gt;
     SuppressClear = True &lt;br /&gt;
     CLEAR(Loc:Copiar) &lt;br /&gt;
    END!IF &lt;br /&gt;
&lt;br /&gt;
    !Control Events --&amp;gt; Copiar -&amp;gt; Accepted -&amp;gt; Priority[5000] &lt;br /&gt;
    Loc:Copiar = True &lt;br /&gt;
    POST(EVENT:Accepted,?UseDelBotonAgregar) &lt;br /&gt;
&lt;br /&gt;
    !Notas: Crear Variable Local Loc:Copiar &lt;br /&gt;
    ! SuppressClear es un Parametro de BrowseClass.PrimeRecord&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar el Popup ===&lt;br /&gt;
 !ABC Objects -&amp;gt; Local Objects -&amp;gt; Windows Manager--&amp;gt;&amp;gt;Init Priority[9001] &lt;br /&gt;
 Brw1.Popup.KILL&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Ordenamiento Dinámico ===&lt;br /&gt;
En Clarion6 se puede hacer automáticamente con la opcion Sort Headers.&lt;br /&gt;
Si se quiere hacer desde código para ordenar por cualquier campo, se puede utilizar:&lt;br /&gt;
    Brw1.SetOrder(&#039;TAB:Campo&#039;) &lt;br /&gt;
    Brw1.ApplyOrder() &lt;br /&gt;
    ThisWindow.Reset(1) &lt;br /&gt;
Por ejemplo si quisiera emular un ordenamiento con el doble click sobre una columna, habría que alertar el doble click en al browse, y el código sería mas o menos asi.&lt;br /&gt;
 Control Event -&amp;gt; Browse:1 -&amp;gt;Alert Key [4500] &lt;br /&gt;
 ! Código usado para cambiar el Orden del Browse &lt;br /&gt;
 ! cuando se hace doble click en la columna &lt;br /&gt;
 IF KEYCODE()=MouseLeft2 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;Codigo&#039; &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;Nombre&#039; &lt;br /&gt;
     Loc:Columna = ?Browse:1{PropList:MouseDownField} &lt;br /&gt;
     CASE Loc:Columna &lt;br /&gt;
     OF 1 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;&amp;lt;&amp;lt;&amp;lt;CODIGO&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;LCA:LOCALIDAD&#039;) &lt;br /&gt;
     OF 2 &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;&amp;lt;&amp;lt;&amp;lt;NOMBRE&amp;gt;&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;UPPER(LCA:NOMBRE)&#039;) &lt;br /&gt;
     END!CASE &lt;br /&gt;
     Brw1.ApplyOrder() &lt;br /&gt;
     ThisWindow.Reset(1) &lt;br /&gt;
 END!IF &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Locator Múltiple ===&lt;br /&gt;
Por ejemplo, para posicionarme en un código de cuenta contable:&lt;br /&gt;
Lo que podrías hacer es poner una variable string sobre el browse y poner un&lt;br /&gt;
código mas o menos asi en su accepted del entry&lt;br /&gt;
&lt;br /&gt;
 !Asumiendo que cada código tiene cuatro dígitos&lt;br /&gt;
 !Revisar la sección String Slicing en el Help&lt;br /&gt;
 Cue:Cuenta = Loc:Cuenta[1:4]&lt;br /&gt;
 Cue:SubCuenta = Loc:Cuenta[5:8]&lt;br /&gt;
 Cue:SubSubCuenta = Loc:Cuenta[9:12]&lt;br /&gt;
 SET(Cue:PorCodigo,Cue:PorCodigo)&lt;br /&gt;
 Access:Cuentas.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Otro ejempo, en un browse de órdenes, posicionarse según el nombre del cliente&lt;br /&gt;
&lt;br /&gt;
 CLI:Nombre = LOC:Cliente&lt;br /&gt;
 SET(CLI:PorNombre, CLI:PorNombre)&lt;br /&gt;
 ACCESS:Clientes.Next()&lt;br /&gt;
&lt;br /&gt;
 ORD:CodCliente = CLI:CodCliente&lt;br /&gt;
 SET(ORD:PorCliente, ORD:PorCliente)&lt;br /&gt;
 ACCESS:Ordenes.Next()&lt;br /&gt;
&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Pintar un browse según un campo ===&lt;br /&gt;
Por ejemplo cuando vemos las facturas de un Cliente se repite el nombre, este código pinta diferente cada grupo de nombres.&lt;br /&gt;
Primero hay que ponerle el atributo color al campo que necesites pintar, desde list box format.&lt;br /&gt;
Luego va el siguiente código, en WindowManager.Reset antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 Aux = &#039;&#039;&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (BRW1.Q)&lt;br /&gt;
     GET(BRW1.Q, F#)&lt;br /&gt;
     IF Aux &amp;lt;&amp;gt; BRW1.Q.CLI:Nombre&lt;br /&gt;
         Col# = 1- Col#&lt;br /&gt;
         Aux = BRW1.Q.CLI:Nombre&lt;br /&gt;
     END&lt;br /&gt;
     If Col#&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:SILVER&lt;br /&gt;
     Else&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:WHITE&lt;br /&gt;
     End&lt;br /&gt;
     PUT(BRW1.Q)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Refrescar un browse desde otra ventana ===&lt;br /&gt;
Lo mas fácil sería usando NOTIFY.&lt;br /&gt;
En la Ventana 1 (la del browse a refrescar)&lt;br /&gt;
 WindowManager.Init&lt;br /&gt;
 GLO:THREAD = THREAD() !VARIABLE GLOBAL LONG&lt;br /&gt;
&lt;br /&gt;
 Window Events&lt;br /&gt;
 Notify&lt;br /&gt;
 BRW1.ResetfromBuffer() ! o ThisWindow.Reset(1)?&lt;br /&gt;
&lt;br /&gt;
En la ventana 2, cuando se necesite refrescar la 1&lt;br /&gt;
 NOTIFY (999, GLO:THREAD)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que en éste caso no estoy usando ese parámetro.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Iniciar el browse en un Tab determinado ===&lt;br /&gt;
En ThisWindow.Init, al final&lt;br /&gt;
 SELF.FirstField = ?Tab:4 !Use del tab&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Actualizar el resultado de un totaling del browse de detalle, en el Encabezado ===&lt;br /&gt;
En el Browse de abajo (el de detalle)&lt;br /&gt;
 ResetFromView, prioridad 4500 - La prioridad es importante&lt;br /&gt;
 GET(Encabezado, ENC:Por_Numero)&lt;br /&gt;
 ENC:Total = loc:total !ÉSTA ES LA VARIABLE DEL TOTALING&lt;br /&gt;
 PUT (Encabezado)&lt;br /&gt;
 IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtro Dinámico ===&lt;br /&gt;
Poner un control Text donde el usuario pueda escribir cualquier filtro&lt;br /&gt;
 X# = EVALUATE(Filtro)&lt;br /&gt;
 IF ERRORCODE()&lt;br /&gt;
     MESSAGE(&#039;ERROR DE SINTAXIS EN EL FILTRO: &#039; &amp;amp; ERROR(), &#039;ATENCION&#039;)&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.SetFilter(Filtro)&lt;br /&gt;
     ThisWindow.Reset(1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Rangos múltiples y dinámicos ===&lt;br /&gt;
Si tenemos una clave con varios componentes, en Actions del browse ponemos un rango por current value, elegimos el componente de la clave hasta el cual queremos hacer el rango.&lt;br /&gt;
El siguiente componente de la clave se puede usar como locator.&lt;br /&gt;
Por ejemplo si tenemos una clave con Tipo+Provincia+Localidad, hacemos un rango de current value por provincia y nos queda un locator por localidad.&lt;br /&gt;
&lt;br /&gt;
 BRW1.ApplyRange PROCEDURE&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 RAN:Tipo= loc:tipo&lt;br /&gt;
 RAN:Provincia=loc:provincia&lt;br /&gt;
 SELF.Order.Rangelist.AssignLeftToRight()&lt;br /&gt;
&lt;br /&gt;
En algun boton de aplicar rango&lt;br /&gt;
 BRW1.ApplyRange()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, deshabilitar condicionalmente la actualización de registros ===&lt;br /&gt;
 IF &amp;lt;Condición&amp;gt;&lt;br /&gt;
     !Deshabilitar Actualización&lt;br /&gt;
     BRW1.InsertControl=FALSE&lt;br /&gt;
     BRW1.ChangeControl=FALSE&lt;br /&gt;
     BRW1.DeleteControl=FALSE&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.InsertControl=?INSERT&lt;br /&gt;
     BRW1.ChangeControl=?CHANGE&lt;br /&gt;
     BRW1.DeleteControl=?DELETE&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar el cambio de registro seleccionado en un Browse ===&lt;br /&gt;
Ejemplo mostrar una foto del cliente al costado del browse&lt;br /&gt;
 BRW1.TakeNewSelection PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !EN CLI:FOTO ESTA EL PATH COMPLETO DE LA FOTO&lt;br /&gt;
 IF CLI:FOTO &amp;lt;&amp;gt; &#039;&#039;&lt;br /&gt;
     ?Foto{PROP:TEXT}= CLI:FOTO &lt;br /&gt;
 ELSE&lt;br /&gt;
     ?Foto{PROP:TEXT}= &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un browse ===&lt;br /&gt;
Ejemplo: Mostrar sólo los clientes que tengan alguna orden&lt;br /&gt;
&lt;br /&gt;
 BRW1.ValidateRecord PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !FILTROS COMPLEJOS&lt;br /&gt;
 !EJ: MOSTRAR SOLO LOS CLIENTES QUE TENGAN ALGUNA ORDEN&lt;br /&gt;
 CLEAR(ORD:RECORD)&lt;br /&gt;
 Ord:CodigoCliente=CLI:ID&lt;br /&gt;
 SET(Ord:FK_Ordenes_CLIENTES,Ord:FK_Ordenes_CLIENTES)&lt;br /&gt;
 NEXT(ORDENES)&lt;br /&gt;
 IF ERRORCODE() OR (Ord:CodigoCliente &amp;lt;&amp;gt; CLI:ID) THEN RETURN Record:Filtered.&lt;br /&gt;
 &lt;br /&gt;
 RETURN Record:OK&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Poner un campo &amp;quot;saldo&amp;quot; en un browse ===&lt;br /&gt;
ThisWindow.Reset, antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 S#=0&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (Queue:Browse:1)&lt;br /&gt;
     GET(Queue:Browse:1, F#)&lt;br /&gt;
     S# += Queue:Browse:1.ORD:Total_Impo&lt;br /&gt;
     Queue:Browse:1.Saldo = S#&lt;br /&gt;
     PUT(Queue:Browse:1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Resetear/inicializar un Locator ===&lt;br /&gt;
El método a ejecutar es&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
&lt;br /&gt;
Los nombres de las instancias de Locators por cada TAB se llaman:&lt;br /&gt;
 BRW1::Sort0:Locator.Set&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
 BRW1::Sort2:Locator.Set&lt;br /&gt;
 !etc..&lt;br /&gt;
&lt;br /&gt;
Luego sería bueno volver a poner el foco en el browse para que se pueda seguir usando el locator normalmente&lt;br /&gt;
 select (?Browse:1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, disparar un procedimiento después de generar un alta, modificación, etc. ===&lt;br /&gt;
&lt;br /&gt;
El proceso a disparar se hace desde el browse, la idea es saber si del Form volvió aceptando o canceló la actualización. El punto embebido es:&lt;br /&gt;
&lt;br /&gt;
 Local Objects&lt;br /&gt;
 BRW1 (o el objeto de tipo browse class que sea)&lt;br /&gt;
 ResetFromAsk (después del Parent.call)&lt;br /&gt;
 &lt;br /&gt;
 IF VCRRequest=VCR:None&lt;br /&gt;
 CASE Request&lt;br /&gt;
 OF InsertRecord&lt;br /&gt;
     IF Response = RequestCompleted&lt;br /&gt;
     !Hacer algún proceso&lt;br /&gt;
     END&lt;br /&gt;
 END&lt;br /&gt;
 END!&lt;br /&gt;
&lt;br /&gt;
=== Inserción continua refrescando el Browse ===&lt;br /&gt;
Este otro método es similar al anterior, también sirve para lo mismo.&lt;br /&gt;
Agrego un ejemplo para hacer inserción continua en el Form y además se vaya actualizando el browse&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Run PROCEDURE(USHORT Number,BYTE Request)&lt;br /&gt;
 ! Cuidado que existen dos ThisWindow.Run, seleccionar el correcto&lt;br /&gt;
 ! [Priority 8500]&lt;br /&gt;
 IF Request = InsertRecord And ReturnValue = RequestCompleted&lt;br /&gt;
     POST(EVENT:ACCEPTED, BRW1.InsertControl)&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Posicionar un browse en un registro seleccionado ===&lt;br /&gt;
&lt;br /&gt;
Al abrir un browse a veces necesitamos posicionar el selector en un registro determinado, tal como lo hacen los browses para selección.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para posicionar el browse en el registro más cercano al proporcionado por el usuario:&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Open PROCEDURE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 ! End of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 CODE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Executable Code Section&amp;quot;&lt;br /&gt;
 ! [Priority 500]&lt;br /&gt;
 CLI:cliente= LOC:Cliente&lt;br /&gt;
 ACCESS:Clientes.fetch(CLI:Kcodigo)&lt;br /&gt;
 BRW1.selecting=1&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 PARENT.Open()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 BRW1.selecting=0&lt;br /&gt;
&lt;br /&gt;
Otra idea, propuesta por Matías Flores:&lt;br /&gt;
Ubicarlo por el valor de los campos de la clave. Por ejemplo, si en un browse de clientes querés posicionarte en un cliente que tiene un código determinado (Loc:Codigo):&lt;br /&gt;
&lt;br /&gt;
 Cli:Codigo = Loc:Codigo&lt;br /&gt;
 SET(Cli:PorCodigo,Cli:PorCodigo)&lt;br /&gt;
 Access:Clientes.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
un ejemplo parecido al anterior, pero en legacy, sería:&lt;br /&gt;
 CLI:Codigo = LOC:Codigo&lt;br /&gt;
 BRW1::LocateMode = LocateOnValue&lt;br /&gt;
 DO BRW1::LocateRecord&lt;br /&gt;
&lt;br /&gt;
Una opción más es:&lt;br /&gt;
En el WindowManager.init, antes de Initialize browse y después de OpenFiles, colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 BRWx.StartAtCurrent = True&lt;br /&gt;
 TAB:Campo = Valor_Buscado&lt;br /&gt;
 get(Tabla, TAB:Key_que_ordena_por_Campo)&lt;br /&gt;
&lt;br /&gt;
=== En Legacy, activar un filtro sobre un browse abierto. ===&lt;br /&gt;
&lt;br /&gt;
Esto se pone en el punto embebido &amp;quot;Before opening VIEW&amp;quot;. Acordarse de BINDEAR todas las variables que se necesiten.&lt;br /&gt;
&lt;br /&gt;
 !---ANTES DE ABRIR EL VIEW--- &lt;br /&gt;
 if SoloPendientes then&lt;br /&gt;
 BRW2::View:Browse{Prop:Filter} = |&lt;br /&gt;
 &#039;MER:numertra = BRW2::Sort1:Reset:TRA:numertra AND MER:saldunid &amp;lt;&amp;gt; 0&#039;&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo cuando quieras presentar el nombre completo sin los espacios de un campo a otro. Pones en el browse una variable local.&lt;br /&gt;
En el SETQUEUERECORD (4500)&lt;br /&gt;
 &lt;br /&gt;
 Loc:ApellidoNombre = clip(CON:Apellido) &amp;amp; &#039; &#039; &amp;amp; CON:Nombre&lt;br /&gt;
&lt;br /&gt;
!(Tip de Alex B.)&lt;br /&gt;
&lt;br /&gt;
=== Código antes y después de una actualización DESDE UN BROWSE. ===&lt;br /&gt;
&lt;br /&gt;
- Antes de la llamada al Form de actualización&lt;br /&gt;
! ABC Objects -&amp;gt; Browse on Archvivo -&amp;gt;Ask Priority[4500]&lt;br /&gt;
 IF Request = InsertRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR ALTA &#039;,&#039;ALTA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = ChangeRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A ACTUALIZAR &#039;,&#039;CAMBIO&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = DeleteRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR DE BAJA &#039;,&#039;BAJA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
- Después de la actualización del registro&lt;br /&gt;
!ABC Objects -&amp;gt; Browse on Provincia -&amp;gt;Ask Priority[5500]&lt;br /&gt;
 IF ReturnValue =1&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCIÓN: SE ACTUALIZÓ EL REGISTRO&#039;,&#039;ACTUALIZÓ OK&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF ReturnValue =2&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;SE CANCELÓ LA ACTUALIZACIÓN DEL REGISTRO&#039;,&#039;ATENCIÓN&#039;,ICON:HAND)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar/esconder (cambiar a PROP:HIDE) un control si el browse está vacío - pe. un botón-. ===&lt;br /&gt;
&lt;br /&gt;
En el Browse.UpdateWindow(), última prioridad:&lt;br /&gt;
 ?TuBoton{PROP:Disable}=Choose(Self.Records()&amp;lt;&amp;gt;0,0,1)&lt;br /&gt;
&lt;br /&gt;
===Iniciar un browse con un orden &amp;quot;sort header&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Si queremos que al abrir un browse el mismo se encuentre ordenado como si hubiéramos hecho click en el sortheader, ponemos luego del generated code del evento openwindow lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 BRW1::SortHeader.SetSortFromString(&#039;TAB:Campo&#039;)&lt;br /&gt;
&lt;br /&gt;
donde TAB:Campo es uno de los campos de la tabla que estoy mostrando en el browse.&lt;br /&gt;
&lt;br /&gt;
== EDIT IN PLACE==&lt;br /&gt;
=== Edit in Place o Form, según condición ===&lt;br /&gt;
En BrowseClass, Ask, antes del Parent Call&lt;br /&gt;
 If ?browse:1{proplist:mousedownfield} = 5&lt;br /&gt;
     Self.AskProcedure = 0&lt;br /&gt;
 else&lt;br /&gt;
     Self.AskProcedure = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Puede usarse cualquier condición, en este caso si el usuario hace doble click en la 5a columna se usa edit in place, sino se usa el formulario&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Desactivar Edit in Place de un campo según condición ===&lt;br /&gt;
En las propiedades del EIP del campo admitir la edición del mismo.&lt;br /&gt;
&lt;br /&gt;
En el EIP Field Manager del campo, TakeEvent, antes del Parent Call&lt;br /&gt;
  if Queue:Browse:1.TAB:Campo_de_mi_Tabla &amp;gt; 0 &lt;br /&gt;
     Return EditAction:Cancel&lt;br /&gt;
     thiswindow.reset(true)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
En este ejemplo sólo permito que pueda editarse el campo si el valor actual del mismo es &amp;lt;= 0&lt;br /&gt;
&lt;br /&gt;
=== Inicializar campos al insertar registro ===&lt;br /&gt;
O sea lo que hace el Prime Fields en las formas&lt;br /&gt;
 ABC Objects&lt;br /&gt;
 BROWSE ON TABLA using ?LIST&lt;br /&gt;
 PrimeRecords&lt;br /&gt;
 Después del Parent Call&lt;br /&gt;
 TPS:TuCampo= valor inicial&lt;br /&gt;
&lt;br /&gt;
=== Poner Disable un campo===&lt;br /&gt;
 Local Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 Abc Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 EIP Field Manag...for Field NombreCampo&lt;br /&gt;
 --&amp;gt;&amp;gt;Init [Priority 5001]&lt;br /&gt;
 If SELF.FEQ then SELF.FEQ{Prop:Disable} = true.&lt;br /&gt;
También se pueden cambiar otras propiedades como por ejemplo UPPER (mayúsculas) o READ ONLY (sólo lectura)&lt;br /&gt;
 If SELF.FEQ &lt;br /&gt;
     SELF.FEQ{prop:readonly} = TRUE&lt;br /&gt;
     SELF.FEQ{prop:upr} = TRUE&lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo Modificar el total cuando cambia la cantidad.&lt;br /&gt;
Primero agregar el campo cantidad en Column Specific&lt;br /&gt;
 EditInPlace::DET:Cantidad.TakeEvent PROCEDURE(UNSIGNED Event)&lt;br /&gt;
 ....&lt;br /&gt;
 !Despues del Parent Call&lt;br /&gt;
&lt;br /&gt;
 CASE ReturnValue&lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel&lt;br /&gt;
 ELSE&lt;br /&gt;
     Update(Self.Feq)&lt;br /&gt;
     BRW1.Q.DET:Total = BRW1.Q.DET:Cantidad * BRW1.Q.DET:Importe&lt;br /&gt;
     !Etc... siempre haciendo referencia a los campos de la cola BRW1.Q.&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones ===&lt;br /&gt;
Por ejemplo una validación básica de un número requerido&lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:NroDocumento&lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 ! Validación del nro. de Documento &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     UPDATE(Self.Feq) &lt;br /&gt;
     IF NOT BRW1.Q.Cli:NroDocumento &lt;br /&gt;
         BEEP(BEEP:SystemExclamation) ; YIELD() &lt;br /&gt;
         MESSAGE(&#039;No se informó el número de Documento&#039;, | &lt;br /&gt;
         &#039;Atención!&#039;, ICON:Exclamation) &lt;br /&gt;
         ReturnValue = EditAction:NONE &lt;br /&gt;
         Return ReturnValue &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Validación con un lookup a una tabla &lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:Provincia &lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 !Valida Provincia &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     Update(Self.Feq) &lt;br /&gt;
     Pro:Codigo= BRW1.Q.Cli:Provincia &lt;br /&gt;
     IF Access:Provincia.Fetch(Pro:PorCodigo) &lt;br /&gt;
         GlobalRequest = SelectRecord &lt;br /&gt;
         SelectProvincia &lt;br /&gt;
         IF NOT Pro:Codigo &lt;br /&gt;
             ReturnValue = EditAction:NONE &lt;br /&gt;
             Return ReturnValue &lt;br /&gt;
         ELSE &lt;br /&gt;
             BRW1.Q.Cli:Provincia = Pro:Codigo &lt;br /&gt;
             BRW1.Q.Pro:NOMBRE = Pro:NOMBRE &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== GLOBALES ==&lt;br /&gt;
&lt;br /&gt;
=== Cambiar los mensajes de error del SQL === &lt;br /&gt;
Con cambiar los TRN no alcanza para ese tipo de errores. &lt;br /&gt;
 &lt;br /&gt;
Lo que se puede hacer es determinar el mensaje que viene desde el SQLServer &lt;br /&gt;
para mostrar un mensaje mas amigable. &lt;br /&gt;
 &lt;br /&gt;
El embebido es &lt;br /&gt;
Global Embeds: &lt;br /&gt;
 Global Objets &lt;br /&gt;
 Abc Objects &lt;br /&gt;
 Error Manager &lt;br /&gt;
 TakeNotify &lt;br /&gt;
 !Antes del Parent Call &lt;br /&gt;
 IF INSTRING(&#039;COLUMN REFERENCE&#039;, SELF.SubsString(),1,1) &lt;br /&gt;
 SELF.Msg(&#039;El registro no puede borrarse porque tiene datos de detalle &lt;br /&gt;
 que dependen de él. |Presione [OK] para una descripción detallada del &lt;br /&gt;
 error&#039;,SELF.GetErrorBufferTitle(),ICON:Exclamation,Button:OK,BUTTON:OK,0) &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Hay que armar un IF de estos por cada tipo de error... &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validación de campos (Edit in place o Form)=== &lt;br /&gt;
 &lt;br /&gt;
Para validar campos lo ideal es usar los Global Embeds &lt;br /&gt;
 Global Embeds &lt;br /&gt;
 Field Level Validation &lt;br /&gt;
 Tabla &lt;br /&gt;
 Campo &lt;br /&gt;
 IF &amp;lt;No cumple Condición&amp;gt; &lt;br /&gt;
 Message(&#039;error...&#039;) &lt;br /&gt;
 RETURN Level:Notify &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Esto te va a funcionar &amp;quot;para siempre&amp;quot; ya sea que uses Edit in place, un Form &lt;br /&gt;
o código embebido para actualizar la tabla. &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=68</id>
		<title>Puntos Embebidos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=68"/>
		<updated>2015-03-07T22:41:22Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Texto reemplazado: «(Evolution Consulting)» por «(Templates Clarion)»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los puntos embebidos son la pesadilla de todo principiante de Clarion. Son extremadamente útiles, pero son muy difíciles de aprender. Para colmo, la abstracción que implementa la clase ABC hace más difícil todavía conocerlos y aprovecharlos. Por eso esta sección es de vital importancia.&lt;br /&gt;
&lt;br /&gt;
== FORMULARIOS ==&lt;br /&gt;
=== ¿Qué procedimiento llamó al Form? ===&lt;br /&gt;
Al principio del WindowManager.Init del Form (primer prioridad disponible)&lt;br /&gt;
&lt;br /&gt;
 GlobalErrors.GetProcedureName()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones complejas ===&lt;br /&gt;
Por ejemplo validar un Email:&lt;br /&gt;
En el accepted del campo&lt;br /&gt;
Puedes hacerlo con MATCH, ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# = MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
Devuelve 1 o 0 si el mail no es válido.&lt;br /&gt;
El MATCH puede usarse con expresiones regulares para validar casi cualquier cosa...&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se Abre/inicializa el Form ===&lt;br /&gt;
ThisWindow.Init&lt;br /&gt;
 !Es interesante entrar por el botón source a este embed para entender bien todas sus prioridades&lt;br /&gt;
 !GlobalRequest (pasada por el browse) se guarda en la propiedad ThisWindow.Request&lt;br /&gt;
 !Se puede preguntar por SELF.Request para saber para qué se lo llamó al form: &lt;br /&gt;
 !InsertRecord EQUATE (1)&lt;br /&gt;
 !ChangeRecord EQUATE (2)&lt;br /&gt;
 !DeleteRecord EQUATE (3)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar el Form a &amp;quot;Solo lectura&amp;quot; ante una condición===&lt;br /&gt;
 ThisWindow.Init&lt;br /&gt;
 ! [Priority 4950] La prioridad es importante!&lt;br /&gt;
 IF FAC:facturado = 1 THEN SELF.Request = ViewRecord.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Truco: Llamar al form para insertar desde el menú ===&lt;br /&gt;
Podríamos asumir que si la GlobalRequest está en blanco es que se lo&lt;br /&gt;
llamó para insertar, evitaríamos asi el paso por un Browse&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !If GlobalRequest = 0 Then GlobalRequest = InsertRecord.&lt;br /&gt;
&lt;br /&gt;
Si la tabla tiene una clave Autonumber, se complica un poco mas, sería asi:&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !Por ej prioridad 300&lt;br /&gt;
 If GlobalRequest = 0&lt;br /&gt;
     GlobalRequest = InsertRecord&lt;br /&gt;
     DesdeMenu# = True&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
 !Después de Open Files:&lt;br /&gt;
 !Por ej prioridad 7800&lt;br /&gt;
 If DesdeMenu# = True&lt;br /&gt;
 Access:People.PrimeAutoinc()&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Llamar a un form para editar una tabla con un solo registro ===&lt;br /&gt;
Típicamente una tabla de parametros, obviamente no queremos pasar por un browse&lt;br /&gt;
 WindowManager.Init,&lt;br /&gt;
 !al principio&lt;br /&gt;
 GlobalRequest = ChangeRecord&lt;br /&gt;
&lt;br /&gt;
 !Luego de Open files&lt;br /&gt;
 Set(Tabla)&lt;br /&gt;
 access:Tabla.Next()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se confirma un Form ===&lt;br /&gt;
ThisWindow.TakeCompleted&lt;br /&gt;
 ! [Priority 2800]&lt;br /&gt;
 !ANTES DE QUE SE CONFIRME LA GRABACION&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 ReturnValue = PARENT.TakeCompleted()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 !YA SE GRABÓ EL REGISTRO.&lt;br /&gt;
 !VERIFICAR SI SELF.Response=RequestCompleted A VER SI SE GRABÓ OK.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se cierra un Form ===&lt;br /&gt;
ThisWindow.Kill&lt;br /&gt;
 !VERIFICAR LOS valores de SELF.Request y SELF.Response&lt;br /&gt;
 !Para decidir que acciones tomar&lt;br /&gt;
 !Este punto ya es &amp;quot;demasiado tarde&amp;quot; para hacer algo antes de que se grabe el registro&lt;br /&gt;
 !Para eso usar TakeCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se produce el borrado sin abrir el Form ===&lt;br /&gt;
Si tenemos un form para actualizar una tabla, y definimos que el borrado sea Confirmando (Standard Warning) o Automático (Automatic Delete), y necesitamos ejecutar un código en el form cuando se efectúe el borrado, usamos:&lt;br /&gt;
&lt;br /&gt;
ThisWindow.PrimeUpdate, después del Parent Call&lt;br /&gt;
&lt;br /&gt;
 if self.request = DeleteRecord and self.Response = RequestCompleted&lt;br /&gt;
 !lo que quiero hacer&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que el borrado de un registro no pasa por el TakeCompleted, excepto cuando se usa la ventana del form (Display Form).&lt;br /&gt;
&lt;br /&gt;
Aporte de Gustavo Olmedo [http://www.evolutionconsulting.com.ar/downloads.html (Evolution)] (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó cualquier campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
En el TakeCompleted ponemos el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF NOT SELF.Primary.Me.EqualBuffer(SELF.Saved)&lt;br /&gt;
 ! message(&#039;Cambio&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Aporte de Pablo Guarnieri y Gustavo Olmendo&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó un campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
 IF CLI:Campo &amp;lt;&amp;gt; history::CLI:Record.Campo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Forzar grabación del form === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para grabar el form inclusive cuando el usuario lo cancele&lt;br /&gt;
&lt;br /&gt;
TakeCloseEvent PROCEDURE(),BYTE,VIRTUAL&lt;br /&gt;
 IF loc:condicion &lt;br /&gt;
    SELF.CancelAction = Cancel:Save !immediate save (no confirmation)&lt;br /&gt;
 END&lt;br /&gt;
 &lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar un Drop Combo === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para filtrar un drop combo utilizando pro:sqlfilter, suponemos que en &lt;br /&gt;
la variable loc:filtro se arma el filtro ha enviar, algo asi como: &#039;a.idtercero = &amp;lt;39&amp;gt;90909090&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
FDCB14 es el nombre del objeto el cual se puede verificar en propiedades --&amp;gt; clases.&lt;br /&gt;
&lt;br /&gt;
ApplyFilter PROCEDURE,VIRTUAL&lt;br /&gt;
 FDCB14::View:FileDropCombo{PROP:SQLFILTER} =  &amp;lt;39&amp;gt;&#039;&amp;amp;clip(loc:filtro)&amp;amp;&#039;&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
 IF FILEERRORCODE()&lt;br /&gt;
    FDCB14::View:FileDropCombo{PROP:SQLFILTER} = &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Obtener el número autogenerado por SQL Server en tablas con identity === &lt;br /&gt;
Después del Parent Call, en el TakeCompleted del Form:&lt;br /&gt;
 IF Self.Response=RequestCompleted AND Self.Request = InsertRecord&lt;br /&gt;
    Tabla{prop:Sql}= &#039;SELECT @@IDENTITY&#039; !busco el número que se asignó&lt;br /&gt;
    IF not Access:Tabla.Next()&lt;br /&gt;
       !en el primer campo de Tabla viene cargado el número autogenerado&lt;br /&gt;
    else&lt;br /&gt;
       message(&#039;Error&#039;)&lt;br /&gt;
    end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Tomado de una respuesta de Fernando Cerini en el foro.&lt;br /&gt;
&lt;br /&gt;
== REPORTES Y PROCESOS ==&lt;br /&gt;
=== Ocultar un campo del detalle según condición ===&lt;br /&gt;
 !En TakeRecord, antes del Print (Process Manager)&lt;br /&gt;
 IF &amp;lt;CONDICION&amp;gt;&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=True&lt;br /&gt;
 ELSE&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=False !si la condición no se cumple, vuelvo a hacer visible el control&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Saber si un proceso se completó ===&lt;br /&gt;
O sea que no se salió por el botón de cancelar&lt;br /&gt;
 !En el WindowManager.Kill&lt;br /&gt;
 IF Self.Response = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
 &lt;br /&gt;
=== Inicializar el número de página ===&lt;br /&gt;
 !WindowManager.OpenReport, despues del Parent Call&lt;br /&gt;
 IF ReturnValue = Level:Benign&lt;br /&gt;
  Report{PROP:NextPageNo} = xxx&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar la impresión ===&lt;br /&gt;
 !Local Objects, Abc Objects, Previewer, Display, After ParentCall.&lt;br /&gt;
 !impresión prohibida&lt;br /&gt;
 ReturnValue = False&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
 If ReturnValue and DemoVersion&lt;br /&gt;
   ReturnValue = False&lt;br /&gt;
   Message(&amp;quot;Está utilizando una versión del demo, no puede imprimir este documento !&amp;quot;)&lt;br /&gt;
 End&lt;br /&gt;
Aporte de Olivier Cretey&lt;br /&gt;
&lt;br /&gt;
Otra opción, en Previewer.TakeAccepted, antes del Parent Call&lt;br /&gt;
 IF CLIP(ACCEPTED(){PROP:TIP}) = &#039;Print this report&#039; THEN RETURN LEVEL:BENIGN.&lt;br /&gt;
&lt;br /&gt;
O sea pregunto por el Tool Tip del botón que se ha presionado. Ojo, si lo tienes traducido tienes que cambiar el &#039;Print this report&#039; por tu Tool Tip.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un Proceso ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt; Validate Records --&amp;gt;&amp;gt; [Priority 5600] &lt;br /&gt;
 If &amp;lt;Condición de Filtro&amp;gt;&lt;br /&gt;
     Return Record:Filtered &lt;br /&gt;
 Else &lt;br /&gt;
     Return Record:OK &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
 &lt;br /&gt;
=== Habilitar o deshabilitar el Print Preview ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 Self.SkipPreview = Loc:Preview &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Cantidad de Páginas generadas ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 ENDPAGE(SELF.Report) &lt;br /&gt;
 Loc:Paginas = RECORDS(SELF.PreviewQueue) &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un Transporte ===&lt;br /&gt;
Necesitas crear 3 details.&lt;br /&gt;
DetailDatos&lt;br /&gt;
DetailTransporte: aca van las variables locales con los totales&lt;br /&gt;
DetailSalto: este detail es vacío y con la propiedad PageAfter&lt;br /&gt;
&lt;br /&gt;
En el embed TakeRecord (antes de los PRINTs) habría que hacer algo asi&lt;br /&gt;
 LOC:Fila += 1&lt;br /&gt;
 If LOC:Fila % 28 = 0 !28 líneas por página...&lt;br /&gt;
     PRINT(RPT:DetailSalto)&lt;br /&gt;
     PRINT(RPT:DetailTransporte)&lt;br /&gt;
     LOC:Fila = 1&lt;br /&gt;
 End&lt;br /&gt;
 LOC:Total += LIBRO:Total&lt;br /&gt;
 PRINT (RPT:Detalle)&lt;br /&gt;
 RETURN LEVEL:Benign&lt;br /&gt;
&lt;br /&gt;
Marcelo Martínez&lt;br /&gt;
y [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Acelerar las actualizaciones ===&lt;br /&gt;
Para que los procesos que agreguen registros funcionen mas rápido hay que agregar un Logout o Stream en Init y un Commit o Flush en el kill&lt;br /&gt;
(El Evolution Tools tiene una extension que hace eso mismo.)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Se imprime o se Cancela? ===&lt;br /&gt;
Los embeds son&lt;br /&gt;
 ABC Objectd&lt;br /&gt;
 --WindowManager(ReportManager)&lt;br /&gt;
 --CancelPrintReport&lt;br /&gt;
 -Se Cancela&lt;br /&gt;
&lt;br /&gt;
 --PrintReport&lt;br /&gt;
 -Se imprime&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Recorrer la cola de las páginas ===&lt;br /&gt;
Cada página del reporte genera una imagen .WMF, la cual se guarda en el directorio temporal.&lt;br /&gt;
Con este ejemplo se puede recorrer la cola donde se guardan los nombres de estos archivos. Ésto es lo que usa por ejemplo el Evolution Mail Template para enviar estas páginas por mail.&lt;br /&gt;
 Previewer.Open PROCEDURE&lt;br /&gt;
 ....&lt;br /&gt;
 loop a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
     get(SELF.ImageQueue,a#)&lt;br /&gt;
     message(SELF.ImageQueue)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir una Queue ===&lt;br /&gt;
La mejor forma de hacerlo en Clarion6 es en Report Properties - General -&lt;br /&gt;
Datasource: Queue.&lt;br /&gt;
&lt;br /&gt;
Yo generalmente pongo los parametros en la ventana y cargo la queue en el&lt;br /&gt;
evento accepted del PauseButton.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un SQL ===&lt;br /&gt;
Lo que yo hago es poner todos los parámetros en la ventana del reporte.&lt;br /&gt;
En el accepted del boton de pausa cargo la cola de memoria con:&lt;br /&gt;
&lt;br /&gt;
 SQL{PROP:SQL} = !aca armo el string SQL&lt;br /&gt;
 IF ERRORCODE() THEN STOP( FILEERROR()).&lt;br /&gt;
 FREE(ColaMemoria)&lt;br /&gt;
 LOOP&lt;br /&gt;
     NEXT(SQL) !O ABC, como prefieras...&lt;br /&gt;
     IF ERRORCODE() THEN BREAK.&lt;br /&gt;
     ColaMemoria :=: SQL:Record&lt;br /&gt;
     ADD(ColaMemoria)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
El reporte lo configuro para trabajar con la cola (data source) y en el&lt;br /&gt;
Detail del reporte pongo los campos de la cola de memoria.&lt;br /&gt;
Lo ideal es tener una cola de memoria global con el atributo thread y usar&lt;br /&gt;
siempre la misma para todo.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar o hacer cortes de control manuales en reportes ===&lt;br /&gt;
En TakeRecord, antes del Print.&lt;br /&gt;
 &lt;br /&gt;
!Actualizar contadores&lt;br /&gt;
&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; CampoCorte&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; 0 !para evitar la primera vez&lt;br /&gt;
 !Inicializar los contadores&lt;br /&gt;
 END&lt;br /&gt;
 AUX=CAMPO&lt;br /&gt;
 !SE VIENE EL CORTE&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Este método TakeRecord se usa también para actualizar cualquier variable calculada antes de la impresión de la banda de detalle.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo BLOB ===&lt;br /&gt;
Este código va en el método TakeRecord, antes del PRINT&lt;br /&gt;
&lt;br /&gt;
 Report$?Image1{PROP:NoWidth} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:NoHeight} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:ImageBlob} = STU:Photograph{PROP:Handle}&lt;br /&gt;
 IF Report$?Image1{PROP:Height} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Width}/Report$?Image1{PROP:Height}&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
 IF Report$?Image1{PROP:Width} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Height}/Report$?Image1{PROP:Width}&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo CSTRING ===&lt;br /&gt;
Este caso es similar al anterior, pero en el campo se encuentra el path donde está la imagen&lt;br /&gt;
 !En el método TakeRecord, antes del PRINT&lt;br /&gt;
 Report$?Image1{PROP:Text} = PRO:Foto&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Evitar el cartel &amp;quot;No records to process&amp;quot; en un proceso ===&lt;br /&gt;
 !En el metodo TAKE NO RECORDS poner un RETURN antes del parent call.&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir el reporte en blanco, cuando no hay registros ===&lt;br /&gt;
En WindowManager. Next, antes del Parent Call con prioridad 500.&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 500] antes del Parent Call&lt;br /&gt;
 If Primera=0 !variable local byte&lt;br /&gt;
    Primera=1&lt;br /&gt;
    SELF.Process.RecordsProcessed = 1&lt;br /&gt;
    Return Level:Benign&lt;br /&gt;
 End&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Cuando hay filtros y rangos, esta solución suele duplicar el primer registro del detalle.&lt;br /&gt;
Para Solucionar esto en ProcessManager NextPROCEDURE(BYTE ProcessRecord) con prioridad 7500 se debe colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF ReturnValue = 0 AND LOC:Primera = 0 THEN !Si hay un registro&lt;br /&gt;
    LOC:Primera = 1        !Dejo al reporte seguir su curso normal&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Mario Wojcik&lt;br /&gt;
&lt;br /&gt;
=== Detectar el último registro en un process o Reporte (fin de archivo) ===&lt;br /&gt;
 ThisProcess.Next PROCEDURE(BYTE ProcessRecords=True)&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 !Fin del proceso&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
Esto por ejemplo es muy útil para cambiar etiquetas en los totales generales del reporte, en un page footer&lt;br /&gt;
 ThisReport.Next PROCEDURE(BYTE ProcessRecords)&lt;br /&gt;
 ....&lt;br /&gt;
 ! [Priority 5001] despues del Parent Call&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 REPORT$?LabelTotal{prop:text}= &#039;Total&#039;&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Reporte con múltiples detalles ===&lt;br /&gt;
Por Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 Viajes&lt;br /&gt;
 |--&amp;gt;pasajeros&lt;br /&gt;
 |--&amp;gt;comisiones&lt;br /&gt;
&lt;br /&gt;
Habría que poner solo la tabla viajes en el Table Schematic. Pasajeros y Comisiones en Other Tables&lt;br /&gt;
&lt;br /&gt;
En el reporte crear 3 details, uno para cada tabla.&lt;br /&gt;
&lt;br /&gt;
En ThisReport.TakeRecord, antes de los PRINTs&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 5500]&lt;br /&gt;
 PRINT(RPT:DetailViaje)&lt;br /&gt;
 CLEAR(PAS:RECORD)&lt;br /&gt;
 PAS:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(PAS:ClavePorViaje, PAS:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Pasajeros.Next() OR PAS:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailPasajeros)&lt;br /&gt;
 END&lt;br /&gt;
 !Y lo mismo para las comisiones&lt;br /&gt;
 CLEAR(COM:RECORD)&lt;br /&gt;
 COM:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(COM:ClavePorViaje, COM:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Comisiones.Next() OR COM:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailComisiones)&lt;br /&gt;
 END&lt;br /&gt;
 Return Level:Benign !ya imprimí todo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Otra alternativa podría ser utilizando el Template &#039;&#039;&#039;ReportChildFiles&#039;&#039;&#039; (desde version 6.X ?) ya que puede ser utilizado mas de una vez en un mismo reporte, apuntando cada instancia a un archivo &amp;quot;hijo&amp;quot; diferente.&lt;br /&gt;
Es fácil de configurar: Se debe seleccionar la tabla CHILD y la PARENT. En el reporte hay que definir el REPORT DETAIL (para el CHILD) y ponerle algún nombre en el label que luego debe ser configurado en el Template.&lt;br /&gt;
&lt;br /&gt;
Jose Sturniolo&lt;br /&gt;
&lt;br /&gt;
=== Imprimir exactamente lo que estamos viendo en el browse ===&lt;br /&gt;
En el browse pones un botón que llame al reporte y en parameters:&lt;br /&gt;
(Brw1.view{PROP:Filter}, Brw1.view{PROP:Order})&lt;br /&gt;
&lt;br /&gt;
En las propiedades del reporte o proceso:&lt;br /&gt;
Prototype: (STRING, STRING)&lt;br /&gt;
Parameters: (FILTRO, ORDEN)&lt;br /&gt;
&lt;br /&gt;
En WindowManager.Init, al final:&lt;br /&gt;
 ThisReport.SetFilter(FILTRO) ! o ThisProcess....&lt;br /&gt;
 ThisReport.SetOrder(ORDEN)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar tamaño de hoja en el reporte ===&lt;br /&gt;
En el embed WindowManager &#039;OpenReport&#039;, PRIORITY(7500)&lt;br /&gt;
&lt;br /&gt;
 IF ~ReturnValue&lt;br /&gt;
 SETTARGET(REPORT)&lt;br /&gt;
 CASE PRINTER{PROPPRINT:Paper}&lt;br /&gt;
 OF PAPER:LETTER&lt;br /&gt;
     REPORT{PROP:height} = 8500&lt;br /&gt;
     ?Footer{PROP:Ypos} = 9000&lt;br /&gt;
 OF PAPER:LEGAL&lt;br /&gt;
     REPORT{PROP:height} = 11000&lt;br /&gt;
     ?Footer{PROP:Ypos} = 11500&lt;br /&gt;
 etc.&lt;br /&gt;
 END&lt;br /&gt;
 SETTARGET()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
etc. con los tamaños de papel que quieras.&lt;br /&gt;
Esto acomoda el contenido del reporte en run-time, haciéndolo ocupar más &lt;br /&gt;
o menos hoja según sea el largo de la misma. Chiche, ¿no?.&lt;br /&gt;
Ajustá los valores a tus necesidades.&lt;br /&gt;
Para tener en cuenta: el usuario tiene que elegir el tamaño del papel &lt;br /&gt;
ANTES de generar el reporte. Si ya está en la vista previa, el reporte ya &lt;br /&gt;
está generado, por lo tanto si cambia el largo de hoja ahí, no se lo va a &lt;br /&gt;
tomar.&lt;br /&gt;
&lt;br /&gt;
Jorge Lavera&lt;br /&gt;
&lt;br /&gt;
=== Cambiar Impresora ===&lt;br /&gt;
En Global Properties--&amp;gt;Embeds--&amp;gt;Before Global INCLUDEs&lt;br /&gt;
 INCLUDE(&#039;PRNPROP.CLW&#039;)&lt;br /&gt;
 !para poder acceder a las propiedades de las impresoras&lt;br /&gt;
&lt;br /&gt;
Luego en el Reporte en &lt;br /&gt;
 ThisReport.Open()&lt;br /&gt;
 !para guardar la impresora por defecto de Windows&lt;br /&gt;
 GLO:IMPRESORA = PRINTER{PROPPRINT:Device}&lt;br /&gt;
 !Seteo la impresora que quiero usar.&lt;br /&gt;
 !El string debe ser igual al que figura en IMPRESORAS&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = &#039;HP Deskjet 840&#039;&lt;br /&gt;
&lt;br /&gt;
y por último en&lt;br /&gt;
 ThisReport.Kill()&lt;br /&gt;
 !para devolver la impresora por defecto de windows&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = CLIP(GLO:IMPRESORA)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Guillermo Ondetti, Pragma Sistemas&lt;br /&gt;
&lt;br /&gt;
=== Detectar Salto de Página de Reporte ===&lt;br /&gt;
Este sería el codigo, siempre y cuando no tengas break groups (ahi se complica bastante)&lt;br /&gt;
El embebido es TakeRecord en ABC, o Before Print Detail en Legacy.&lt;br /&gt;
 VarLocal += REPORT$?Detail{PROP:height}&lt;br /&gt;
 IF VarLocal &amp;gt; REPORT{PROP:height}&lt;br /&gt;
     VarLocal = REPORT$?Detail{PROP:height}&lt;br /&gt;
     !En el siguiente PRINT Cambia la página...&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Aplicar Filtro sql en el reporte ===&lt;br /&gt;
Se arma el filtro si se quiere en una variable por ejemlo loc:sql&lt;br /&gt;
y se aplica en Local Objects --&amp;gt; Abc Objects -- &amp;gt; Process manager --&amp;gt; Apply Filter antes del parent call, asi:&lt;br /&gt;
&lt;br /&gt;
 Process:View{Prop:SqlFilter}=Loc:SQL&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez&lt;br /&gt;
&lt;br /&gt;
=== Imprimir mas de una Copia por Reporte  ===&lt;br /&gt;
Se tiene que poner en el Window Manager --&amp;gt; Open (Prioridad(5000))&lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=n  !! n = Cantidad de copias &lt;br /&gt;
&lt;br /&gt;
Luego es aconsejable poner en el Window Manager --&amp;gt; Kill &lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=1 &lt;br /&gt;
&lt;br /&gt;
ASC Sergio D. Caballero&lt;br /&gt;
&lt;br /&gt;
== BROWSES ==&lt;br /&gt;
=== Actualizar un campo al hacer click en una columna ===&lt;br /&gt;
Por ejemplo, en People.app&lt;br /&gt;
&lt;br /&gt;
En el evento Accepted del Control del browse.&lt;br /&gt;
 !Si se hizo click en el campo&lt;br /&gt;
 IF ?BROWSE:1{PropList:MouseDownField}= 4&lt;br /&gt;
    ACCESS:PEOPLE.Fetch(PEO:KeyId)&lt;br /&gt;
    PEO:Gender = &#039;X&#039;&lt;br /&gt;
    ACCESS:PEOPLE.Update()&lt;br /&gt;
    BRW1.ResetFromFile()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar con SQL===&lt;br /&gt;
A veces es muy útil aplicar un filtro SQL encima de todos los demas filtros que ya tenga el browse, por ejemplo para filtrar por usuario, por sucursal, etc.&lt;br /&gt;
Yo normalmente le pongo el filtro SQL en el método windowmanager.Reset, &lt;br /&gt;
prioridad 5000&lt;br /&gt;
 BRW1.View{PROP:SQLFILTER}=&#039;+ filtro sql&#039;&lt;br /&gt;
Luego se refresca normalmente, o manualmente con ThisWindow.Reset (1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Activar un Browse invisible, o sea que está en otro TAB ===&lt;br /&gt;
Esto es especialmente útil cuando necesitamos que se ejecuten totalizadores del browse aunque éste no esté visible en la pantalla.&lt;br /&gt;
!ABC Objects -&amp;gt; &lt;br /&gt;
Local Objects -&amp;gt;&lt;br /&gt;
Windows Manager-&amp;gt;&lt;br /&gt;
Init Priority[7500] &lt;br /&gt;
 BRW2.ActiveInvisible = True &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Copiar un Registro ===&lt;br /&gt;
&lt;br /&gt;
    !ABC Objects -&amp;gt; Browse on Clientes -&amp;gt; PrimeRecord Priority[4500] &lt;br /&gt;
    IF Loc:Copiar &lt;br /&gt;
     SuppressClear = True &lt;br /&gt;
     CLEAR(Loc:Copiar) &lt;br /&gt;
    END!IF &lt;br /&gt;
&lt;br /&gt;
    !Control Events --&amp;gt; Copiar -&amp;gt; Accepted -&amp;gt; Priority[5000] &lt;br /&gt;
    Loc:Copiar = True &lt;br /&gt;
    POST(EVENT:Accepted,?UseDelBotonAgregar) &lt;br /&gt;
&lt;br /&gt;
    !Notas: Crear Variable Local Loc:Copiar &lt;br /&gt;
    ! SuppressClear es un Parametro de BrowseClass.PrimeRecord&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar el Popup ===&lt;br /&gt;
 !ABC Objects -&amp;gt; Local Objects -&amp;gt; Windows Manager--&amp;gt;&amp;gt;Init Priority[9001] &lt;br /&gt;
 Brw1.Popup.KILL&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Ordenamiento Dinámico ===&lt;br /&gt;
En Clarion6 se puede hacer automáticamente con la opcion Sort Headers.&lt;br /&gt;
Si se quiere hacer desde código para ordenar por cualquier campo, se puede utilizar:&lt;br /&gt;
    Brw1.SetOrder(&#039;TAB:Campo&#039;) &lt;br /&gt;
    Brw1.ApplyOrder() &lt;br /&gt;
    ThisWindow.Reset(1) &lt;br /&gt;
Por ejemplo si quisiera emular un ordenamiento con el doble click sobre una columna, habría que alertar el doble click en al browse, y el código sería mas o menos asi.&lt;br /&gt;
 Control Event -&amp;gt; Browse:1 -&amp;gt;Alert Key [4500] &lt;br /&gt;
 ! Código usado para cambiar el Orden del Browse &lt;br /&gt;
 ! cuando se hace doble click en la columna &lt;br /&gt;
 IF KEYCODE()=MouseLeft2 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;Codigo&#039; &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;Nombre&#039; &lt;br /&gt;
     Loc:Columna = ?Browse:1{PropList:MouseDownField} &lt;br /&gt;
     CASE Loc:Columna &lt;br /&gt;
     OF 1 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;&amp;lt;&amp;lt;&amp;lt;CODIGO&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;LCA:LOCALIDAD&#039;) &lt;br /&gt;
     OF 2 &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;&amp;lt;&amp;lt;&amp;lt;NOMBRE&amp;gt;&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;UPPER(LCA:NOMBRE)&#039;) &lt;br /&gt;
     END!CASE &lt;br /&gt;
     Brw1.ApplyOrder() &lt;br /&gt;
     ThisWindow.Reset(1) &lt;br /&gt;
 END!IF &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Locator Múltiple ===&lt;br /&gt;
Por ejemplo, para posicionarme en un código de cuenta contable:&lt;br /&gt;
Lo que podrías hacer es poner una variable string sobre el browse y poner un&lt;br /&gt;
código mas o menos asi en su accepted del entry&lt;br /&gt;
&lt;br /&gt;
 !Asumiendo que cada código tiene cuatro dígitos&lt;br /&gt;
 !Revisar la sección String Slicing en el Help&lt;br /&gt;
 Cue:Cuenta = Loc:Cuenta[1:4]&lt;br /&gt;
 Cue:SubCuenta = Loc:Cuenta[5:8]&lt;br /&gt;
 Cue:SubSubCuenta = Loc:Cuenta[9:12]&lt;br /&gt;
 SET(Cue:PorCodigo,Cue:PorCodigo)&lt;br /&gt;
 Access:Cuentas.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Otro ejempo, en un browse de órdenes, posicionarse según el nombre del cliente&lt;br /&gt;
&lt;br /&gt;
 CLI:Nombre = LOC:Cliente&lt;br /&gt;
 SET(CLI:PorNombre, CLI:PorNombre)&lt;br /&gt;
 ACCESS:Clientes.Next()&lt;br /&gt;
&lt;br /&gt;
 ORD:CodCliente = CLI:CodCliente&lt;br /&gt;
 SET(ORD:PorCliente, ORD:PorCliente)&lt;br /&gt;
 ACCESS:Ordenes.Next()&lt;br /&gt;
&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Pintar un browse según un campo ===&lt;br /&gt;
Por ejemplo cuando vemos las facturas de un Cliente se repite el nombre, este código pinta diferente cada grupo de nombres.&lt;br /&gt;
Primero hay que ponerle el atributo color al campo que necesites pintar, desde list box format.&lt;br /&gt;
Luego va el siguiente código, en WindowManager.Reset antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 Aux = &#039;&#039;&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (BRW1.Q)&lt;br /&gt;
     GET(BRW1.Q, F#)&lt;br /&gt;
     IF Aux &amp;lt;&amp;gt; BRW1.Q.CLI:Nombre&lt;br /&gt;
         Col# = 1- Col#&lt;br /&gt;
         Aux = BRW1.Q.CLI:Nombre&lt;br /&gt;
     END&lt;br /&gt;
     If Col#&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:SILVER&lt;br /&gt;
     Else&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:WHITE&lt;br /&gt;
     End&lt;br /&gt;
     PUT(BRW1.Q)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Refrescar un browse desde otra ventana ===&lt;br /&gt;
Lo mas fácil sería usando NOTIFY.&lt;br /&gt;
En la Ventana 1 (la del browse a refrescar)&lt;br /&gt;
 WindowManager.Init&lt;br /&gt;
 GLO:THREAD = THREAD() !VARIABLE GLOBAL LONG&lt;br /&gt;
&lt;br /&gt;
 Window Events&lt;br /&gt;
 Notify&lt;br /&gt;
 BRW1.ResetfromBuffer() ! o ThisWindow.Reset(1)?&lt;br /&gt;
&lt;br /&gt;
En la ventana 2, cuando se necesite refrescar la 1&lt;br /&gt;
 NOTIFY (999, GLO:THREAD)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que en éste caso no estoy usando ese parámetro.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Iniciar el browse en un Tab determinado ===&lt;br /&gt;
En ThisWindow.Init, al final&lt;br /&gt;
 SELF.FirstField = ?Tab:4 !Use del tab&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Actualizar el resultado de un totaling del browse de detalle, en el Encabezado ===&lt;br /&gt;
En el Browse de abajo (el de detalle)&lt;br /&gt;
 ResetFromView, prioridad 4500 - La prioridad es importante&lt;br /&gt;
 GET(Encabezado, ENC:Por_Numero)&lt;br /&gt;
 ENC:Total = loc:total !ÉSTA ES LA VARIABLE DEL TOTALING&lt;br /&gt;
 PUT (Encabezado)&lt;br /&gt;
 IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtro Dinámico ===&lt;br /&gt;
Poner un control Text donde el usuario pueda escribir cualquier filtro&lt;br /&gt;
 X# = EVALUATE(Filtro)&lt;br /&gt;
 IF ERRORCODE()&lt;br /&gt;
     MESSAGE(&#039;ERROR DE SINTAXIS EN EL FILTRO: &#039; &amp;amp; ERROR(), &#039;ATENCION&#039;)&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.SetFilter(Filtro)&lt;br /&gt;
     ThisWindow.Reset(1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Rangos múltiples y dinámicos ===&lt;br /&gt;
Si tenemos una clave con varios componentes, en Actions del browse ponemos un rango por current value, elegimos el componente de la clave hasta el cual queremos hacer el rango.&lt;br /&gt;
El siguiente componente de la clave se puede usar como locator.&lt;br /&gt;
Por ejemplo si tenemos una clave con Tipo+Provincia+Localidad, hacemos un rango de current value por provincia y nos queda un locator por localidad.&lt;br /&gt;
&lt;br /&gt;
 BRW1.ApplyRange PROCEDURE&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 RAN:Tipo= loc:tipo&lt;br /&gt;
 RAN:Provincia=loc:provincia&lt;br /&gt;
 SELF.Order.Rangelist.AssignLeftToRight()&lt;br /&gt;
&lt;br /&gt;
En algun boton de aplicar rango&lt;br /&gt;
 BRW1.ApplyRange()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, deshabilitar condicionalmente la actualización de registros ===&lt;br /&gt;
 IF &amp;lt;Condición&amp;gt;&lt;br /&gt;
     !Deshabilitar Actualización&lt;br /&gt;
     BRW1.InsertControl=FALSE&lt;br /&gt;
     BRW1.ChangeControl=FALSE&lt;br /&gt;
     BRW1.DeleteControl=FALSE&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.InsertControl=?INSERT&lt;br /&gt;
     BRW1.ChangeControl=?CHANGE&lt;br /&gt;
     BRW1.DeleteControl=?DELETE&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar el cambio de registro seleccionado en un Browse ===&lt;br /&gt;
Ejemplo mostrar una foto del cliente al costado del browse&lt;br /&gt;
 BRW1.TakeNewSelection PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !EN CLI:FOTO ESTA EL PATH COMPLETO DE LA FOTO&lt;br /&gt;
 IF CLI:FOTO &amp;lt;&amp;gt; &#039;&#039;&lt;br /&gt;
     ?Foto{PROP:TEXT}= CLI:FOTO &lt;br /&gt;
 ELSE&lt;br /&gt;
     ?Foto{PROP:TEXT}= &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un browse ===&lt;br /&gt;
Ejemplo: Mostrar sólo los clientes que tengan alguna orden&lt;br /&gt;
&lt;br /&gt;
 BRW1.ValidateRecord PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !FILTROS COMPLEJOS&lt;br /&gt;
 !EJ: MOSTRAR SOLO LOS CLIENTES QUE TENGAN ALGUNA ORDEN&lt;br /&gt;
 CLEAR(ORD:RECORD)&lt;br /&gt;
 Ord:CodigoCliente=CLI:ID&lt;br /&gt;
 SET(Ord:FK_Ordenes_CLIENTES,Ord:FK_Ordenes_CLIENTES)&lt;br /&gt;
 NEXT(ORDENES)&lt;br /&gt;
 IF ERRORCODE() OR (Ord:CodigoCliente &amp;lt;&amp;gt; CLI:ID) THEN RETURN Record:Filtered.&lt;br /&gt;
 &lt;br /&gt;
 RETURN Record:OK&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Poner un campo &amp;quot;saldo&amp;quot; en un browse ===&lt;br /&gt;
ThisWindow.Reset, antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 S#=0&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (Queue:Browse:1)&lt;br /&gt;
     GET(Queue:Browse:1, F#)&lt;br /&gt;
     S# += Queue:Browse:1.ORD:Total_Impo&lt;br /&gt;
     Queue:Browse:1.Saldo = S#&lt;br /&gt;
     PUT(Queue:Browse:1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Resetear/inicializar un Locator ===&lt;br /&gt;
El método a ejecutar es&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
&lt;br /&gt;
Los nombres de las instancias de Locators por cada TAB se llaman:&lt;br /&gt;
 BRW1::Sort0:Locator.Set&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
 BRW1::Sort2:Locator.Set&lt;br /&gt;
 !etc..&lt;br /&gt;
&lt;br /&gt;
Luego sería bueno volver a poner el foco en el browse para que se pueda seguir usando el locator normalmente&lt;br /&gt;
 select (?Browse:1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, disparar un procedimiento después de generar un alta, modificación, etc. ===&lt;br /&gt;
&lt;br /&gt;
El proceso a disparar se hace desde el browse, la idea es saber si del Form volvió aceptando o canceló la actualización. El punto embebido es:&lt;br /&gt;
&lt;br /&gt;
 Local Objects&lt;br /&gt;
 BRW1 (o el objeto de tipo browse class que sea)&lt;br /&gt;
 ResetFromAsk (después del Parent.call)&lt;br /&gt;
 &lt;br /&gt;
 IF VCRRequest=VCR:None&lt;br /&gt;
 CASE Request&lt;br /&gt;
 OF InsertRecord&lt;br /&gt;
     IF Response = RequestCompleted&lt;br /&gt;
     !Hacer algún proceso&lt;br /&gt;
     END&lt;br /&gt;
 END&lt;br /&gt;
 END!&lt;br /&gt;
&lt;br /&gt;
=== Inserción continua refrescando el Browse ===&lt;br /&gt;
Este otro método es similar al anterior, también sirve para lo mismo.&lt;br /&gt;
Agrego un ejemplo para hacer inserción continua en el Form y además se vaya actualizando el browse&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Run PROCEDURE(USHORT Number,BYTE Request)&lt;br /&gt;
 ! Cuidado que existen dos ThisWindow.Run, seleccionar el correcto&lt;br /&gt;
 ! [Priority 8500]&lt;br /&gt;
 IF Request = InsertRecord And ReturnValue = RequestCompleted&lt;br /&gt;
     POST(EVENT:ACCEPTED, BRW1.InsertControl)&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Posicionar un browse en un registro seleccionado ===&lt;br /&gt;
&lt;br /&gt;
Al abrir un browse a veces necesitamos posicionar el selector en un registro determinado, tal como lo hacen los browses para selección.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para posicionar el browse en el registro más cercano al proporcionado por el usuario:&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Open PROCEDURE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 ! End of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 CODE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Executable Code Section&amp;quot;&lt;br /&gt;
 ! [Priority 500]&lt;br /&gt;
 CLI:cliente= LOC:Cliente&lt;br /&gt;
 ACCESS:Clientes.fetch(CLI:Kcodigo)&lt;br /&gt;
 BRW1.selecting=1&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 PARENT.Open()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 BRW1.selecting=0&lt;br /&gt;
&lt;br /&gt;
Otra idea, propuesta por Matías Flores:&lt;br /&gt;
Ubicarlo por el valor de los campos de la clave. Por ejemplo, si en un browse de clientes querés posicionarte en un cliente que tiene un código determinado (Loc:Codigo):&lt;br /&gt;
&lt;br /&gt;
 Cli:Codigo = Loc:Codigo&lt;br /&gt;
 SET(Cli:PorCodigo,Cli:PorCodigo)&lt;br /&gt;
 Access:Clientes.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
un ejemplo parecido al anterior, pero en legacy, sería:&lt;br /&gt;
 CLI:Codigo = LOC:Codigo&lt;br /&gt;
 BRW1::LocateMode = LocateOnValue&lt;br /&gt;
 DO BRW1::LocateRecord&lt;br /&gt;
&lt;br /&gt;
Una opción más es:&lt;br /&gt;
En el WindowManager.init, antes de Initialize browse y después de OpenFiles, colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 BRWx.StartAtCurrent = True&lt;br /&gt;
 TAB:Campo = Valor_Buscado&lt;br /&gt;
 get(Tabla, TAB:Key_que_ordena_por_Campo)&lt;br /&gt;
&lt;br /&gt;
=== En Legacy, activar un filtro sobre un browse abierto. ===&lt;br /&gt;
&lt;br /&gt;
Esto se pone en el punto embebido &amp;quot;Before opening VIEW&amp;quot;. Acordarse de BINDEAR todas las variables que se necesiten.&lt;br /&gt;
&lt;br /&gt;
 !---ANTES DE ABRIR EL VIEW--- &lt;br /&gt;
 if SoloPendientes then&lt;br /&gt;
 BRW2::View:Browse{Prop:Filter} = |&lt;br /&gt;
 &#039;MER:numertra = BRW2::Sort1:Reset:TRA:numertra AND MER:saldunid &amp;lt;&amp;gt; 0&#039;&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo cuando quieras presentar el nombre completo sin los espacios de un campo a otro. Pones en el browse una variable local.&lt;br /&gt;
En el SETQUEUERECORD (4500)&lt;br /&gt;
 &lt;br /&gt;
 Loc:ApellidoNombre = clip(CON:Apellido) &amp;amp; &#039; &#039; &amp;amp; CON:Nombre&lt;br /&gt;
&lt;br /&gt;
!(Tip de Alex B.)&lt;br /&gt;
&lt;br /&gt;
=== Código antes y después de una actualización DESDE UN BROWSE. ===&lt;br /&gt;
&lt;br /&gt;
- Antes de la llamada al Form de actualización&lt;br /&gt;
! ABC Objects -&amp;gt; Browse on Archvivo -&amp;gt;Ask Priority[4500]&lt;br /&gt;
 IF Request = InsertRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR ALTA &#039;,&#039;ALTA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = ChangeRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A ACTUALIZAR &#039;,&#039;CAMBIO&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = DeleteRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR DE BAJA &#039;,&#039;BAJA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
- Después de la actualización del registro&lt;br /&gt;
!ABC Objects -&amp;gt; Browse on Provincia -&amp;gt;Ask Priority[5500]&lt;br /&gt;
 IF ReturnValue =1&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCIÓN: SE ACTUALIZÓ EL REGISTRO&#039;,&#039;ACTUALIZÓ OK&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF ReturnValue =2&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;SE CANCELÓ LA ACTUALIZACIÓN DEL REGISTRO&#039;,&#039;ATENCIÓN&#039;,ICON:HAND)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar/esconder (cambiar a PROP:HIDE) un control si el browse está vacío - pe. un botón-. ===&lt;br /&gt;
&lt;br /&gt;
En el Browse.UpdateWindow(), última prioridad:&lt;br /&gt;
 ?TuBoton{PROP:Disable}=Choose(Self.Records()&amp;lt;&amp;gt;0,0,1)&lt;br /&gt;
&lt;br /&gt;
===Iniciar un browse con un orden &amp;quot;sort header&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Si queremos que al abrir un browse el mismo se encuentre ordenado como si hubiéramos hecho click en el sortheader, ponemos luego del generated code del evento openwindow lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 BRW1::SortHeader.SetSortFromString(&#039;TAB:Campo&#039;)&lt;br /&gt;
&lt;br /&gt;
donde TAB:Campo es uno de los campos de la tabla que estoy mostrando en el browse.&lt;br /&gt;
&lt;br /&gt;
== EDIT IN PLACE==&lt;br /&gt;
=== Edit in Place o Form, según condición ===&lt;br /&gt;
En BrowseClass, Ask, antes del Parent Call&lt;br /&gt;
 If ?browse:1{proplist:mousedownfield} = 5&lt;br /&gt;
     Self.AskProcedure = 0&lt;br /&gt;
 else&lt;br /&gt;
     Self.AskProcedure = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Puede usarse cualquier condición, en este caso si el usuario hace doble click en la 5a columna se usa edit in place, sino se usa el formulario&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Desactivar Edit in Place de un campo según condición ===&lt;br /&gt;
En las propiedades del EIP del campo admitir la edición del mismo.&lt;br /&gt;
&lt;br /&gt;
En el EIP Field Manager del campo, TakeEvent, antes del Parent Call&lt;br /&gt;
  if Queue:Browse:1.TAB:Campo_de_mi_Tabla &amp;gt; 0 &lt;br /&gt;
     Return EditAction:Cancel&lt;br /&gt;
     thiswindow.reset(true)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
En este ejemplo sólo permito que pueda editarse el campo si el valor actual del mismo es &amp;lt;= 0&lt;br /&gt;
&lt;br /&gt;
=== Inicializar campos al insertar registro ===&lt;br /&gt;
O sea lo que hace el Prime Fields en las formas&lt;br /&gt;
 ABC Objects&lt;br /&gt;
 BROWSE ON TABLA using ?LIST&lt;br /&gt;
 PrimeRecords&lt;br /&gt;
 Después del Parent Call&lt;br /&gt;
 TPS:TuCampo= valor inicial&lt;br /&gt;
&lt;br /&gt;
=== Poner Disable un campo===&lt;br /&gt;
 Local Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 Abc Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 EIP Field Manag...for Field NombreCampo&lt;br /&gt;
 --&amp;gt;&amp;gt;Init [Priority 5001]&lt;br /&gt;
 If SELF.FEQ then SELF.FEQ{Prop:Disable} = true.&lt;br /&gt;
También se pueden cambiar otras propiedades como por ejemplo UPPER (mayúsculas) o READ ONLY (sólo lectura)&lt;br /&gt;
 If SELF.FEQ &lt;br /&gt;
     SELF.FEQ{prop:readonly} = TRUE&lt;br /&gt;
     SELF.FEQ{prop:upr} = TRUE&lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo Modificar el total cuando cambia la cantidad.&lt;br /&gt;
Primero agregar el campo cantidad en Column Specific&lt;br /&gt;
 EditInPlace::DET:Cantidad.TakeEvent PROCEDURE(UNSIGNED Event)&lt;br /&gt;
 ....&lt;br /&gt;
 !Despues del Parent Call&lt;br /&gt;
&lt;br /&gt;
 CASE ReturnValue&lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel&lt;br /&gt;
 ELSE&lt;br /&gt;
     Update(Self.Feq)&lt;br /&gt;
     BRW1.Q.DET:Total = BRW1.Q.DET:Cantidad * BRW1.Q.DET:Importe&lt;br /&gt;
     !Etc... siempre haciendo referencia a los campos de la cola BRW1.Q.&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones ===&lt;br /&gt;
Por ejemplo una validación básica de un número requerido&lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:NroDocumento&lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 ! Validación del nro. de Documento &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     UPDATE(Self.Feq) &lt;br /&gt;
     IF NOT BRW1.Q.Cli:NroDocumento &lt;br /&gt;
         BEEP(BEEP:SystemExclamation) ; YIELD() &lt;br /&gt;
         MESSAGE(&#039;No se informó el número de Documento&#039;, | &lt;br /&gt;
         &#039;Atención!&#039;, ICON:Exclamation) &lt;br /&gt;
         ReturnValue = EditAction:NONE &lt;br /&gt;
         Return ReturnValue &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Validación con un lookup a una tabla &lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:Provincia &lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 !Valida Provincia &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     Update(Self.Feq) &lt;br /&gt;
     Pro:Codigo= BRW1.Q.Cli:Provincia &lt;br /&gt;
     IF Access:Provincia.Fetch(Pro:PorCodigo) &lt;br /&gt;
         GlobalRequest = SelectRecord &lt;br /&gt;
         SelectProvincia &lt;br /&gt;
         IF NOT Pro:Codigo &lt;br /&gt;
             ReturnValue = EditAction:NONE &lt;br /&gt;
             Return ReturnValue &lt;br /&gt;
         ELSE &lt;br /&gt;
             BRW1.Q.Cli:Provincia = Pro:Codigo &lt;br /&gt;
             BRW1.Q.Pro:NOMBRE = Pro:NOMBRE &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
== GLOBALES ==&lt;br /&gt;
&lt;br /&gt;
=== Cambiar los mensajes de error del SQL === &lt;br /&gt;
Con cambiar los TRN no alcanza para ese tipo de errores. &lt;br /&gt;
 &lt;br /&gt;
Lo que se puede hacer es determinar el mensaje que viene desde el SQLServer &lt;br /&gt;
para mostrar un mensaje mas amigable. &lt;br /&gt;
 &lt;br /&gt;
El embebido es &lt;br /&gt;
Global Embeds: &lt;br /&gt;
 Global Objets &lt;br /&gt;
 Abc Objects &lt;br /&gt;
 Error Manager &lt;br /&gt;
 TakeNotify &lt;br /&gt;
 !Antes del Parent Call &lt;br /&gt;
 IF INSTRING(&#039;COLUMN REFERENCE&#039;, SELF.SubsString(),1,1) &lt;br /&gt;
 SELF.Msg(&#039;El registro no puede borrarse porque tiene datos de detalle &lt;br /&gt;
 que dependen de él. |Presione [OK] para una descripción detallada del &lt;br /&gt;
 error&#039;,SELF.GetErrorBufferTitle(),ICON:Exclamation,Button:OK,BUTTON:OK,0) &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Hay que armar un IF de estos por cada tipo de error... &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validación de campos (Edit in place o Form)=== &lt;br /&gt;
 &lt;br /&gt;
Para validar campos lo ideal es usar los Global Embeds &lt;br /&gt;
 Global Embeds &lt;br /&gt;
 Field Level Validation &lt;br /&gt;
 Tabla &lt;br /&gt;
 Campo &lt;br /&gt;
 IF &amp;lt;No cumple Condición&amp;gt; &lt;br /&gt;
 Message(&#039;error...&#039;) &lt;br /&gt;
 RETURN Level:Notify &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Esto te va a funcionar &amp;quot;para siempre&amp;quot; ya sea que uses Edit in place, un Form &lt;br /&gt;
o código embebido para actualizar la tabla. &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Manuales&amp;diff=67</id>
		<title>Manuales</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Manuales&amp;diff=67"/>
		<updated>2015-03-07T22:41:15Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Texto reemplazado: «(Evolution Consulting)» por «(Templates Clarion)»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los programadores Clarion reconocemos que existe una falencia importante en la cantidad de manuales disponibles para Clarion, eso es especialmente notable en nuestra lengua.&lt;br /&gt;
&lt;br /&gt;
Por eso es importante conocer los manuales diponibles y dónde descargarlos o acceder.&lt;br /&gt;
&lt;br /&gt;
== Clarion 5 Primeros pasos ==&lt;br /&gt;
&lt;br /&gt;
Una traducción del Getting Started de Clarion 5 realizado por Unisoft. &#039;&#039;&#039;Altamente recomendable.&#039;&#039;&#039; Sobre todo para los que principiantes que les cuesta leer en inglés.&lt;br /&gt;
&lt;br /&gt;
[http://www.lawebdelprogramador.com/cursos/enlace.php?idp=1066&amp;amp;id=16&amp;amp;texto=Clarion Manual primeros pasos Clarion 5]&lt;br /&gt;
&lt;br /&gt;
== Anti Manual de SQL ==&lt;br /&gt;
&lt;br /&gt;
De Mauricio Nicastro.&lt;br /&gt;
&lt;br /&gt;
Imposible empezar a incursionar en SQL sin leerlo.&lt;br /&gt;
&lt;br /&gt;
[[Anti Manual de SQL]]&lt;br /&gt;
&lt;br /&gt;
== Los mejores puntos embebidos ==&lt;br /&gt;
&lt;br /&gt;
De Mauricio Nicastro.&lt;br /&gt;
&lt;br /&gt;
Este tema tiene una sección propia en este Wiki, pero el documento tiene consistencia de manual, por eso lo incluyo en forma completa.&lt;br /&gt;
&lt;br /&gt;
[[Los mejores puntos embebidos]]&lt;br /&gt;
&lt;br /&gt;
== Guia de las mejores prácticas de Clarion ==&lt;br /&gt;
&lt;br /&gt;
De Cristian Olsen.&lt;br /&gt;
&lt;br /&gt;
[[Guia de las mejores prácticas de Clarion]]&lt;br /&gt;
&lt;br /&gt;
== SQL Embebido ==&lt;br /&gt;
Doc. que explica como usar sql embebido y un ejemplo de como crear un editor de SQL&lt;br /&gt;
	&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== Migración TPS a SQL ==&lt;br /&gt;
Primeros pasos en la migración de TPS a SQL. Basado en una presentación del creador de los drivers, Scott Ferret. La cual tuve la suerte de presenciar y me tomé el atrevimiento de hacer algunos cambios...&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== Funciones ODBC ==&lt;br /&gt;
Lista de funciones muy útiles de ODBC.&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== Strings de Conexión ==&lt;br /&gt;
De diversas bases en formato DSNLess (sin necesidad de crear el DNS).&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== Tipos de Datos SQL ==&lt;br /&gt;
Compatibilidad de tipos entre SQL y Clarion.&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== Multithreading con Clarion6 ==&lt;br /&gt;
Uso correcto de variables y queues globales. Ejemplos de Secciones criticas, Mutexs y Semáforos. Incluye documentación de la charla presentada en CONDEV por Fernando Cerini&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== Firebird ==&lt;br /&gt;
Primeros pasos en la instalación del Firebird. (Gracias Roque Delia)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Manuales&amp;diff=66</id>
		<title>Manuales</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Manuales&amp;diff=66"/>
		<updated>2015-03-07T22:40:02Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Texto reemplazado: «www.evolutionconsulting.com.ar/download.html» por «www.templatesclarion.com.ar/downloads/»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los programadores Clarion reconocemos que existe una falencia importante en la cantidad de manuales disponibles para Clarion, eso es especialmente notable en nuestra lengua.&lt;br /&gt;
&lt;br /&gt;
Por eso es importante conocer los manuales diponibles y dónde descargarlos o acceder.&lt;br /&gt;
&lt;br /&gt;
== Clarion 5 Primeros pasos ==&lt;br /&gt;
&lt;br /&gt;
Una traducción del Getting Started de Clarion 5 realizado por Unisoft. &#039;&#039;&#039;Altamente recomendable.&#039;&#039;&#039; Sobre todo para los que principiantes que les cuesta leer en inglés.&lt;br /&gt;
&lt;br /&gt;
[http://www.lawebdelprogramador.com/cursos/enlace.php?idp=1066&amp;amp;id=16&amp;amp;texto=Clarion Manual primeros pasos Clarion 5]&lt;br /&gt;
&lt;br /&gt;
== Anti Manual de SQL ==&lt;br /&gt;
&lt;br /&gt;
De Mauricio Nicastro.&lt;br /&gt;
&lt;br /&gt;
Imposible empezar a incursionar en SQL sin leerlo.&lt;br /&gt;
&lt;br /&gt;
[[Anti Manual de SQL]]&lt;br /&gt;
&lt;br /&gt;
== Los mejores puntos embebidos ==&lt;br /&gt;
&lt;br /&gt;
De Mauricio Nicastro.&lt;br /&gt;
&lt;br /&gt;
Este tema tiene una sección propia en este Wiki, pero el documento tiene consistencia de manual, por eso lo incluyo en forma completa.&lt;br /&gt;
&lt;br /&gt;
[[Los mejores puntos embebidos]]&lt;br /&gt;
&lt;br /&gt;
== Guia de las mejores prácticas de Clarion ==&lt;br /&gt;
&lt;br /&gt;
De Cristian Olsen.&lt;br /&gt;
&lt;br /&gt;
[[Guia de las mejores prácticas de Clarion]]&lt;br /&gt;
&lt;br /&gt;
== SQL Embebido ==&lt;br /&gt;
Doc. que explica como usar sql embebido y un ejemplo de como crear un editor de SQL&lt;br /&gt;
	&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== Migración TPS a SQL ==&lt;br /&gt;
Primeros pasos en la migración de TPS a SQL. Basado en una presentación del creador de los drivers, Scott Ferret. La cual tuve la suerte de presenciar y me tomé el atrevimiento de hacer algunos cambios...&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Funciones ODBC ==&lt;br /&gt;
Lista de funciones muy útiles de ODBC.&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Strings de Conexión ==&lt;br /&gt;
De diversas bases en formato DSNLess (sin necesidad de crear el DNS).&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Tipos de Datos SQL ==&lt;br /&gt;
Compatibilidad de tipos entre SQL y Clarion.&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Multithreading con Clarion6 ==&lt;br /&gt;
Uso correcto de variables y queues globales. Ejemplos de Secciones criticas, Mutexs y Semáforos. Incluye documentación de la charla presentada en CONDEV por Fernando Cerini&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Firebird ==&lt;br /&gt;
Primeros pasos en la instalación del Firebird. (Gracias Roque Delia)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Evolution Consulting)]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=65</id>
		<title>Puntos Embebidos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Puntos_Embebidos&amp;diff=65"/>
		<updated>2015-03-07T22:39:52Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Texto reemplazado: «www.evolutionconsulting.com.ar/download.html» por «www.templatesclarion.com.ar/downloads/»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los puntos embebidos son la pesadilla de todo principiante de Clarion. Son extremadamente útiles, pero son muy difíciles de aprender. Para colmo, la abstracción que implementa la clase ABC hace más difícil todavía conocerlos y aprovecharlos. Por eso esta sección es de vital importancia.&lt;br /&gt;
&lt;br /&gt;
== FORMULARIOS ==&lt;br /&gt;
=== ¿Qué procedimiento llamó al Form? ===&lt;br /&gt;
Al principio del WindowManager.Init del Form (primer prioridad disponible)&lt;br /&gt;
&lt;br /&gt;
 GlobalErrors.GetProcedureName()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones complejas ===&lt;br /&gt;
Por ejemplo validar un Email:&lt;br /&gt;
En el accepted del campo&lt;br /&gt;
Puedes hacerlo con MATCH, ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# = MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
Devuelve 1 o 0 si el mail no es válido.&lt;br /&gt;
El MATCH puede usarse con expresiones regulares para validar casi cualquier cosa...&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se Abre/inicializa el Form ===&lt;br /&gt;
ThisWindow.Init&lt;br /&gt;
 !Es interesante entrar por el botón source a este embed para entender bien todas sus prioridades&lt;br /&gt;
 !GlobalRequest (pasada por el browse) se guarda en la propiedad ThisWindow.Request&lt;br /&gt;
 !Se puede preguntar por SELF.Request para saber para qué se lo llamó al form: &lt;br /&gt;
 !InsertRecord EQUATE (1)&lt;br /&gt;
 !ChangeRecord EQUATE (2)&lt;br /&gt;
 !DeleteRecord EQUATE (3)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar el Form a &amp;quot;Solo lectura&amp;quot; ante una condición===&lt;br /&gt;
 ThisWindow.Init&lt;br /&gt;
 ! [Priority 4950] La prioridad es importante!&lt;br /&gt;
 IF FAC:facturado = 1 THEN SELF.Request = ViewRecord.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Truco: Llamar al form para insertar desde el menú ===&lt;br /&gt;
Podríamos asumir que si la GlobalRequest está en blanco es que se lo&lt;br /&gt;
llamó para insertar, evitaríamos asi el paso por un Browse&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !If GlobalRequest = 0 Then GlobalRequest = InsertRecord.&lt;br /&gt;
&lt;br /&gt;
Si la tabla tiene una clave Autonumber, se complica un poco mas, sería asi:&lt;br /&gt;
 !Al principio del Init (antes de Snap-Shot global Request):&lt;br /&gt;
 !Por ej prioridad 300&lt;br /&gt;
 If GlobalRequest = 0&lt;br /&gt;
     GlobalRequest = InsertRecord&lt;br /&gt;
     DesdeMenu# = True&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
 !Después de Open Files:&lt;br /&gt;
 !Por ej prioridad 7800&lt;br /&gt;
 If DesdeMenu# = True&lt;br /&gt;
 Access:People.PrimeAutoinc()&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Llamar a un form para editar una tabla con un solo registro ===&lt;br /&gt;
Típicamente una tabla de parametros, obviamente no queremos pasar por un browse&lt;br /&gt;
 WindowManager.Init,&lt;br /&gt;
 !al principio&lt;br /&gt;
 GlobalRequest = ChangeRecord&lt;br /&gt;
&lt;br /&gt;
 !Luego de Open files&lt;br /&gt;
 Set(Tabla)&lt;br /&gt;
 access:Tabla.Next()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se confirma un Form ===&lt;br /&gt;
ThisWindow.TakeCompleted&lt;br /&gt;
 ! [Priority 2800]&lt;br /&gt;
 !ANTES DE QUE SE CONFIRME LA GRABACION&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 ReturnValue = PARENT.TakeCompleted()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 !YA SE GRABÓ EL REGISTRO.&lt;br /&gt;
 !VERIFICAR SI SELF.Response=RequestCompleted A VER SI SE GRABÓ OK.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se cierra un Form ===&lt;br /&gt;
ThisWindow.Kill&lt;br /&gt;
 !VERIFICAR LOS valores de SELF.Request y SELF.Response&lt;br /&gt;
 !Para decidir que acciones tomar&lt;br /&gt;
 !Este punto ya es &amp;quot;demasiado tarde&amp;quot; para hacer algo antes de que se grabe el registro&lt;br /&gt;
 !Para eso usar TakeCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cuando se produce el borrado sin abrir el Form ===&lt;br /&gt;
Si tenemos un form para actualizar una tabla, y definimos que el borrado sea Confirmando (Standard Warning) o Automático (Automatic Delete), y necesitamos ejecutar un código en el form cuando se efectúe el borrado, usamos:&lt;br /&gt;
&lt;br /&gt;
ThisWindow.PrimeUpdate, después del Parent Call&lt;br /&gt;
&lt;br /&gt;
 if self.request = DeleteRecord and self.Response = RequestCompleted&lt;br /&gt;
 !lo que quiero hacer&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Hay que tener en cuenta que el borrado de un registro no pasa por el TakeCompleted, excepto cuando se usa la ventana del form (Display Form).&lt;br /&gt;
&lt;br /&gt;
Aporte de Gustavo Olmedo [http://www.evolutionconsulting.com.ar/downloads.html (Evolution)] (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó cualquier campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
En el TakeCompleted ponemos el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF NOT SELF.Primary.Me.EqualBuffer(SELF.Saved)&lt;br /&gt;
 ! message(&#039;Cambio&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Aporte de Pablo Guarnieri y Gustavo Olmendo&lt;br /&gt;
&lt;br /&gt;
=== Chequear si se modificó un campo del FORM ===&lt;br /&gt;
&lt;br /&gt;
 IF CLI:Campo &amp;lt;&amp;gt; history::CLI:Record.Campo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Forzar grabación del form === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para grabar el form inclusive cuando el usuario lo cancele&lt;br /&gt;
&lt;br /&gt;
TakeCloseEvent PROCEDURE(),BYTE,VIRTUAL&lt;br /&gt;
 IF loc:condicion &lt;br /&gt;
    SELF.CancelAction = Cancel:Save !immediate save (no confirmation)&lt;br /&gt;
 END&lt;br /&gt;
 &lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar un Drop Combo === &lt;br /&gt;
 &lt;br /&gt;
Este código sirve para filtrar un drop combo utilizando pro:sqlfilter, suponemos que en &lt;br /&gt;
la variable loc:filtro se arma el filtro ha enviar, algo asi como: &#039;a.idtercero = &amp;lt;39&amp;gt;90909090&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
FDCB14 es el nombre del objeto el cual se puede verificar en propiedades --&amp;gt; clases.&lt;br /&gt;
&lt;br /&gt;
ApplyFilter PROCEDURE,VIRTUAL&lt;br /&gt;
 FDCB14::View:FileDropCombo{PROP:SQLFILTER} =  &amp;lt;39&amp;gt;&#039;&amp;amp;clip(loc:filtro)&amp;amp;&#039;&amp;lt;39&amp;gt;&#039;&lt;br /&gt;
 IF FILEERRORCODE()&lt;br /&gt;
    FDCB14::View:FileDropCombo{PROP:SQLFILTER} = &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez Delgado [http://www.doxasistemas.com (Doxa Sistemas)]&lt;br /&gt;
&lt;br /&gt;
=== Obtener el número autogenerado por SQL Server en tablas con identity === &lt;br /&gt;
Después del Parent Call, en el TakeCompleted del Form:&lt;br /&gt;
 IF Self.Response=RequestCompleted AND Self.Request = InsertRecord&lt;br /&gt;
    Tabla{prop:Sql}= &#039;SELECT @@IDENTITY&#039; !busco el número que se asignó&lt;br /&gt;
    IF not Access:Tabla.Next()&lt;br /&gt;
       !en el primer campo de Tabla viene cargado el número autogenerado&lt;br /&gt;
    else&lt;br /&gt;
       message(&#039;Error&#039;)&lt;br /&gt;
    end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Tomado de una respuesta de Fernando Cerini en el foro.&lt;br /&gt;
&lt;br /&gt;
== REPORTES Y PROCESOS ==&lt;br /&gt;
=== Ocultar un campo del detalle según condición ===&lt;br /&gt;
 !En TakeRecord, antes del Print (Process Manager)&lt;br /&gt;
 IF &amp;lt;CONDICION&amp;gt;&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=True&lt;br /&gt;
 ELSE&lt;br /&gt;
  REPORT$?Control{PROP:HIDE}=False !si la condición no se cumple, vuelvo a hacer visible el control&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Saber si un proceso se completó ===&lt;br /&gt;
O sea que no se salió por el botón de cancelar&lt;br /&gt;
 !En el WindowManager.Kill&lt;br /&gt;
 IF Self.Response = RequestCompleted&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
 &lt;br /&gt;
=== Inicializar el número de página ===&lt;br /&gt;
 !WindowManager.OpenReport, despues del Parent Call&lt;br /&gt;
 IF ReturnValue = Level:Benign&lt;br /&gt;
  Report{PROP:NextPageNo} = xxx&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar la impresión ===&lt;br /&gt;
 !Local Objects, Abc Objects, Previewer, Display, After ParentCall.&lt;br /&gt;
 !impresión prohibida&lt;br /&gt;
 ReturnValue = False&lt;br /&gt;
&lt;br /&gt;
Por ejemplo:&lt;br /&gt;
&lt;br /&gt;
 If ReturnValue and DemoVersion&lt;br /&gt;
   ReturnValue = False&lt;br /&gt;
   Message(&amp;quot;Está utilizando una versión del demo, no puede imprimir este documento !&amp;quot;)&lt;br /&gt;
 End&lt;br /&gt;
Aporte de Olivier Cretey&lt;br /&gt;
&lt;br /&gt;
Otra opción, en Previewer.TakeAccepted, antes del Parent Call&lt;br /&gt;
 IF CLIP(ACCEPTED(){PROP:TIP}) = &#039;Print this report&#039; THEN RETURN LEVEL:BENIGN.&lt;br /&gt;
&lt;br /&gt;
O sea pregunto por el Tool Tip del botón que se ha presionado. Ojo, si lo tienes traducido tienes que cambiar el &#039;Print this report&#039; por tu Tool Tip.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un Proceso ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt; Validate Records --&amp;gt;&amp;gt; [Priority 5600] &lt;br /&gt;
 If &amp;lt;Condición de Filtro&amp;gt;&lt;br /&gt;
     Return Record:Filtered &lt;br /&gt;
 Else &lt;br /&gt;
     Return Record:OK &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
 &lt;br /&gt;
=== Habilitar o deshabilitar el Print Preview ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 Self.SkipPreview = Loc:Preview &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Cantidad de Páginas generadas ===&lt;br /&gt;
 !Windows Manager --&amp;gt;&amp;gt;Ask preview --&amp;gt;&amp;gt; [Priority 5000] &lt;br /&gt;
 ENDPAGE(SELF.Report) &lt;br /&gt;
 Loc:Paginas = RECORDS(SELF.PreviewQueue) &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un Transporte ===&lt;br /&gt;
Necesitas crear 3 details.&lt;br /&gt;
DetailDatos&lt;br /&gt;
DetailTransporte: aca van las variables locales con los totales&lt;br /&gt;
DetailSalto: este detail es vacío y con la propiedad PageAfter&lt;br /&gt;
&lt;br /&gt;
En el embed TakeRecord (antes de los PRINTs) habría que hacer algo asi&lt;br /&gt;
 LOC:Fila += 1&lt;br /&gt;
 If LOC:Fila % 28 = 0 !28 líneas por página...&lt;br /&gt;
     PRINT(RPT:DetailSalto)&lt;br /&gt;
     PRINT(RPT:DetailTransporte)&lt;br /&gt;
     LOC:Fila = 1&lt;br /&gt;
 End&lt;br /&gt;
 LOC:Total += LIBRO:Total&lt;br /&gt;
 PRINT (RPT:Detalle)&lt;br /&gt;
 RETURN LEVEL:Benign&lt;br /&gt;
&lt;br /&gt;
Marcelo Martínez&lt;br /&gt;
y [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Acelerar las actualizaciones ===&lt;br /&gt;
Para que los procesos que agreguen registros funcionen mas rápido hay que agregar un Logout o Stream en Init y un Commit o Flush en el kill&lt;br /&gt;
(El Evolution Tools tiene una extension que hace eso mismo.)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Se imprime o se Cancela? ===&lt;br /&gt;
Los embeds son&lt;br /&gt;
 ABC Objectd&lt;br /&gt;
 --WindowManager(ReportManager)&lt;br /&gt;
 --CancelPrintReport&lt;br /&gt;
 -Se Cancela&lt;br /&gt;
&lt;br /&gt;
 --PrintReport&lt;br /&gt;
 -Se imprime&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Recorrer la cola de las páginas ===&lt;br /&gt;
Cada página del reporte genera una imagen .WMF, la cual se guarda en el directorio temporal.&lt;br /&gt;
Con este ejemplo se puede recorrer la cola donde se guardan los nombres de estos archivos. Ésto es lo que usa por ejemplo el Evolution Mail Template para enviar estas páginas por mail.&lt;br /&gt;
 Previewer.Open PROCEDURE&lt;br /&gt;
 ....&lt;br /&gt;
 loop a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
     get(SELF.ImageQueue,a#)&lt;br /&gt;
     message(SELF.ImageQueue)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir una Queue ===&lt;br /&gt;
La mejor forma de hacerlo en Clarion6 es en Report Properties - General -&lt;br /&gt;
Datasource: Queue.&lt;br /&gt;
&lt;br /&gt;
Yo generalmente pongo los parametros en la ventana y cargo la queue en el&lt;br /&gt;
evento accepted del PauseButton.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir un SQL ===&lt;br /&gt;
Lo que yo hago es poner todos los parámetros en la ventana del reporte.&lt;br /&gt;
En el accepted del boton de pausa cargo la cola de memoria con:&lt;br /&gt;
&lt;br /&gt;
 SQL{PROP:SQL} = !aca armo el string SQL&lt;br /&gt;
 IF ERRORCODE() THEN STOP( FILEERROR()).&lt;br /&gt;
 FREE(ColaMemoria)&lt;br /&gt;
 LOOP&lt;br /&gt;
     NEXT(SQL) !O ABC, como prefieras...&lt;br /&gt;
     IF ERRORCODE() THEN BREAK.&lt;br /&gt;
     ColaMemoria :=: SQL:Record&lt;br /&gt;
     ADD(ColaMemoria)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
El reporte lo configuro para trabajar con la cola (data source) y en el&lt;br /&gt;
Detail del reporte pongo los campos de la cola de memoria.&lt;br /&gt;
Lo ideal es tener una cola de memoria global con el atributo thread y usar&lt;br /&gt;
siempre la misma para todo.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar o hacer cortes de control manuales en reportes ===&lt;br /&gt;
En TakeRecord, antes del Print.&lt;br /&gt;
 &lt;br /&gt;
!Actualizar contadores&lt;br /&gt;
&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; CampoCorte&lt;br /&gt;
 IF AUX &amp;lt;&amp;gt; 0 !para evitar la primera vez&lt;br /&gt;
 !Inicializar los contadores&lt;br /&gt;
 END&lt;br /&gt;
 AUX=CAMPO&lt;br /&gt;
 !SE VIENE EL CORTE&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Este método TakeRecord se usa también para actualizar cualquier variable calculada antes de la impresión de la banda de detalle.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo BLOB ===&lt;br /&gt;
Este código va en el método TakeRecord, antes del PRINT&lt;br /&gt;
&lt;br /&gt;
 Report$?Image1{PROP:NoWidth} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:NoHeight} = TRUE&lt;br /&gt;
 Report$?Image1{PROP:ImageBlob} = STU:Photograph{PROP:Handle}&lt;br /&gt;
 IF Report$?Image1{PROP:Height} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Width}/Report$?Image1{PROP:Height}&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
 IF Report$?Image1{PROP:Width} &amp;gt; 1000&lt;br /&gt;
     AspectRatio$ = Report$?Image1{PROP:Height}/Report$?Image1{PROP:Width}&lt;br /&gt;
     Report$?Image1{PROP:Width} = 1000&lt;br /&gt;
     Report$?Image1{PROP:Height} = 1000 * AspectRatio$&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Impresión de imagenes desde Campo CSTRING ===&lt;br /&gt;
Este caso es similar al anterior, pero en el campo se encuentra el path donde está la imagen&lt;br /&gt;
 !En el método TakeRecord, antes del PRINT&lt;br /&gt;
 Report$?Image1{PROP:Text} = PRO:Foto&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Evitar el cartel &amp;quot;No records to process&amp;quot; en un proceso ===&lt;br /&gt;
 !En el metodo TAKE NO RECORDS poner un RETURN antes del parent call.&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Imprimir el reporte en blanco, cuando no hay registros ===&lt;br /&gt;
En WindowManager. Next, antes del Parent Call con prioridad 500.&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 500] antes del Parent Call&lt;br /&gt;
 If Primera=0 !variable local byte&lt;br /&gt;
    Primera=1&lt;br /&gt;
    SELF.Process.RecordsProcessed = 1&lt;br /&gt;
    Return Level:Benign&lt;br /&gt;
 End&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Cuando hay filtros y rangos, esta solución suele duplicar el primer registro del detalle.&lt;br /&gt;
Para Solucionar esto en ProcessManager NextPROCEDURE(BYTE ProcessRecord) con prioridad 7500 se debe colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 IF ReturnValue = 0 AND LOC:Primera = 0 THEN !Si hay un registro&lt;br /&gt;
    LOC:Primera = 1        !Dejo al reporte seguir su curso normal&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Mario Wojcik&lt;br /&gt;
&lt;br /&gt;
=== Detectar el último registro en un process o Reporte (fin de archivo) ===&lt;br /&gt;
 ThisProcess.Next PROCEDURE(BYTE ProcessRecords=True)&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 !Fin del proceso&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
Esto por ejemplo es muy útil para cambiar etiquetas en los totales generales del reporte, en un page footer&lt;br /&gt;
 ThisReport.Next PROCEDURE(BYTE ProcessRecords)&lt;br /&gt;
 ....&lt;br /&gt;
 ! [Priority 5001] despues del Parent Call&lt;br /&gt;
 If ReturnValue = 5 !Level:Notify&lt;br /&gt;
 REPORT$?LabelTotal{prop:text}= &#039;Total&#039;&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Reporte con múltiples detalles ===&lt;br /&gt;
Por Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 Viajes&lt;br /&gt;
 |--&amp;gt;pasajeros&lt;br /&gt;
 |--&amp;gt;comisiones&lt;br /&gt;
&lt;br /&gt;
Habría que poner solo la tabla viajes en el Table Schematic. Pasajeros y Comisiones en Other Tables&lt;br /&gt;
&lt;br /&gt;
En el reporte crear 3 details, uno para cada tabla.&lt;br /&gt;
&lt;br /&gt;
En ThisReport.TakeRecord, antes de los PRINTs&lt;br /&gt;
&lt;br /&gt;
 ! [Priority 5500]&lt;br /&gt;
 PRINT(RPT:DetailViaje)&lt;br /&gt;
 CLEAR(PAS:RECORD)&lt;br /&gt;
 PAS:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(PAS:ClavePorViaje, PAS:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Pasajeros.Next() OR PAS:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailPasajeros)&lt;br /&gt;
 END&lt;br /&gt;
 !Y lo mismo para las comisiones&lt;br /&gt;
 CLEAR(COM:RECORD)&lt;br /&gt;
 COM:idViaje = VIA:IdViaje&lt;br /&gt;
 SET(COM:ClavePorViaje, COM:ClavePorViaje)&lt;br /&gt;
 LOOP UNTIL ACCESS:Comisiones.Next() OR COM:idViaje &amp;lt;&amp;gt; VIA:IdViaje&lt;br /&gt;
     PRINT(RPT:DetailComisiones)&lt;br /&gt;
 END&lt;br /&gt;
 Return Level:Benign !ya imprimí todo&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Otra alternativa podría ser utilizando el Template &#039;&#039;&#039;ReportChildFiles&#039;&#039;&#039; (desde version 6.X ?) ya que puede ser utilizado mas de una vez en un mismo reporte, apuntando cada instancia a un archivo &amp;quot;hijo&amp;quot; diferente.&lt;br /&gt;
Es fácil de configurar: Se debe seleccionar la tabla CHILD y la PARENT. En el reporte hay que definir el REPORT DETAIL (para el CHILD) y ponerle algún nombre en el label que luego debe ser configurado en el Template.&lt;br /&gt;
&lt;br /&gt;
Jose Sturniolo&lt;br /&gt;
&lt;br /&gt;
=== Imprimir exactamente lo que estamos viendo en el browse ===&lt;br /&gt;
En el browse pones un botón que llame al reporte y en parameters:&lt;br /&gt;
(Brw1.view{PROP:Filter}, Brw1.view{PROP:Order})&lt;br /&gt;
&lt;br /&gt;
En las propiedades del reporte o proceso:&lt;br /&gt;
Prototype: (STRING, STRING)&lt;br /&gt;
Parameters: (FILTRO, ORDEN)&lt;br /&gt;
&lt;br /&gt;
En WindowManager.Init, al final:&lt;br /&gt;
 ThisReport.SetFilter(FILTRO) ! o ThisProcess....&lt;br /&gt;
 ThisReport.SetOrder(ORDEN)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Cambiar tamaño de hoja en el reporte ===&lt;br /&gt;
En el embed WindowManager &#039;OpenReport&#039;, PRIORITY(7500)&lt;br /&gt;
&lt;br /&gt;
 IF ~ReturnValue&lt;br /&gt;
 SETTARGET(REPORT)&lt;br /&gt;
 CASE PRINTER{PROPPRINT:Paper}&lt;br /&gt;
 OF PAPER:LETTER&lt;br /&gt;
     REPORT{PROP:height} = 8500&lt;br /&gt;
     ?Footer{PROP:Ypos} = 9000&lt;br /&gt;
 OF PAPER:LEGAL&lt;br /&gt;
     REPORT{PROP:height} = 11000&lt;br /&gt;
     ?Footer{PROP:Ypos} = 11500&lt;br /&gt;
 etc.&lt;br /&gt;
 END&lt;br /&gt;
 SETTARGET()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
etc. con los tamaños de papel que quieras.&lt;br /&gt;
Esto acomoda el contenido del reporte en run-time, haciéndolo ocupar más &lt;br /&gt;
o menos hoja según sea el largo de la misma. Chiche, ¿no?.&lt;br /&gt;
Ajustá los valores a tus necesidades.&lt;br /&gt;
Para tener en cuenta: el usuario tiene que elegir el tamaño del papel &lt;br /&gt;
ANTES de generar el reporte. Si ya está en la vista previa, el reporte ya &lt;br /&gt;
está generado, por lo tanto si cambia el largo de hoja ahí, no se lo va a &lt;br /&gt;
tomar.&lt;br /&gt;
&lt;br /&gt;
Jorge Lavera&lt;br /&gt;
&lt;br /&gt;
=== Cambiar Impresora ===&lt;br /&gt;
En Global Properties--&amp;gt;Embeds--&amp;gt;Before Global INCLUDEs&lt;br /&gt;
 INCLUDE(&#039;PRNPROP.CLW&#039;)&lt;br /&gt;
 !para poder acceder a las propiedades de las impresoras&lt;br /&gt;
&lt;br /&gt;
Luego en el Reporte en &lt;br /&gt;
 ThisReport.Open()&lt;br /&gt;
 !para guardar la impresora por defecto de Windows&lt;br /&gt;
 GLO:IMPRESORA = PRINTER{PROPPRINT:Device}&lt;br /&gt;
 !Seteo la impresora que quiero usar.&lt;br /&gt;
 !El string debe ser igual al que figura en IMPRESORAS&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = &#039;HP Deskjet 840&#039;&lt;br /&gt;
&lt;br /&gt;
y por último en&lt;br /&gt;
 ThisReport.Kill()&lt;br /&gt;
 !para devolver la impresora por defecto de windows&lt;br /&gt;
 PRINTER{PROPPRINT:Device} = CLIP(GLO:IMPRESORA)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Guillermo Ondetti, Pragma Sistemas&lt;br /&gt;
&lt;br /&gt;
=== Detectar Salto de Página de Reporte ===&lt;br /&gt;
Este sería el codigo, siempre y cuando no tengas break groups (ahi se complica bastante)&lt;br /&gt;
El embebido es TakeRecord en ABC, o Before Print Detail en Legacy.&lt;br /&gt;
 VarLocal += REPORT$?Detail{PROP:height}&lt;br /&gt;
 IF VarLocal &amp;gt; REPORT{PROP:height}&lt;br /&gt;
     VarLocal = REPORT$?Detail{PROP:height}&lt;br /&gt;
     !En el siguiente PRINT Cambia la página...&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Aplicar Filtro sql en el reporte ===&lt;br /&gt;
Se arma el filtro si se quiere en una variable por ejemlo loc:sql&lt;br /&gt;
y se aplica en Local Objects --&amp;gt; Abc Objects -- &amp;gt; Process manager --&amp;gt; Apply Filter antes del parent call, asi:&lt;br /&gt;
&lt;br /&gt;
 Process:View{Prop:SqlFilter}=Loc:SQL&lt;br /&gt;
&lt;br /&gt;
Ivan Dario Benitez&lt;br /&gt;
&lt;br /&gt;
=== Imprimir mas de una Copia por Reporte  ===&lt;br /&gt;
Se tiene que poner en el Window Manager --&amp;gt; Open (Prioridad(5000))&lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=n  !! n = Cantidad de copias &lt;br /&gt;
&lt;br /&gt;
Luego es aconsejable poner en el Window Manager --&amp;gt; Kill &lt;br /&gt;
&lt;br /&gt;
  PRINTER{PROPPRINT:COPIES}=1 &lt;br /&gt;
&lt;br /&gt;
ASC Sergio D. Caballero&lt;br /&gt;
&lt;br /&gt;
== BROWSES ==&lt;br /&gt;
=== Actualizar un campo al hacer click en una columna ===&lt;br /&gt;
Por ejemplo, en People.app&lt;br /&gt;
&lt;br /&gt;
En el evento Accepted del Control del browse.&lt;br /&gt;
 !Si se hizo click en el campo&lt;br /&gt;
 IF ?BROWSE:1{PropList:MouseDownField}= 4&lt;br /&gt;
    ACCESS:PEOPLE.Fetch(PEO:KeyId)&lt;br /&gt;
    PEO:Gender = &#039;X&#039;&lt;br /&gt;
    ACCESS:PEOPLE.Update()&lt;br /&gt;
    BRW1.ResetFromFile()&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtrar con SQL===&lt;br /&gt;
A veces es muy útil aplicar un filtro SQL encima de todos los demas filtros que ya tenga el browse, por ejemplo para filtrar por usuario, por sucursal, etc.&lt;br /&gt;
Yo normalmente le pongo el filtro SQL en el método windowmanager.Reset, &lt;br /&gt;
prioridad 5000&lt;br /&gt;
 BRW1.View{PROP:SQLFILTER}=&#039;+ filtro sql&#039;&lt;br /&gt;
Luego se refresca normalmente, o manualmente con ThisWindow.Reset (1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Activar un Browse invisible, o sea que está en otro TAB ===&lt;br /&gt;
Esto es especialmente útil cuando necesitamos que se ejecuten totalizadores del browse aunque éste no esté visible en la pantalla.&lt;br /&gt;
!ABC Objects -&amp;gt; &lt;br /&gt;
Local Objects -&amp;gt;&lt;br /&gt;
Windows Manager-&amp;gt;&lt;br /&gt;
Init Priority[7500] &lt;br /&gt;
 BRW2.ActiveInvisible = True &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Copiar un Registro ===&lt;br /&gt;
&lt;br /&gt;
    !ABC Objects -&amp;gt; Browse on Clientes -&amp;gt; PrimeRecord Priority[4500] &lt;br /&gt;
    IF Loc:Copiar &lt;br /&gt;
     SuppressClear = True &lt;br /&gt;
     CLEAR(Loc:Copiar) &lt;br /&gt;
    END!IF &lt;br /&gt;
&lt;br /&gt;
    !Control Events --&amp;gt; Copiar -&amp;gt; Accepted -&amp;gt; Priority[5000] &lt;br /&gt;
    Loc:Copiar = True &lt;br /&gt;
    POST(EVENT:Accepted,?UseDelBotonAgregar) &lt;br /&gt;
&lt;br /&gt;
    !Notas: Crear Variable Local Loc:Copiar &lt;br /&gt;
    ! SuppressClear es un Parametro de BrowseClass.PrimeRecord&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar el Popup ===&lt;br /&gt;
 !ABC Objects -&amp;gt; Local Objects -&amp;gt; Windows Manager--&amp;gt;&amp;gt;Init Priority[9001] &lt;br /&gt;
 Brw1.Popup.KILL&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Ordenamiento Dinámico ===&lt;br /&gt;
En Clarion6 se puede hacer automáticamente con la opcion Sort Headers.&lt;br /&gt;
Si se quiere hacer desde código para ordenar por cualquier campo, se puede utilizar:&lt;br /&gt;
    Brw1.SetOrder(&#039;TAB:Campo&#039;) &lt;br /&gt;
    Brw1.ApplyOrder() &lt;br /&gt;
    ThisWindow.Reset(1) &lt;br /&gt;
Por ejemplo si quisiera emular un ordenamiento con el doble click sobre una columna, habría que alertar el doble click en al browse, y el código sería mas o menos asi.&lt;br /&gt;
 Control Event -&amp;gt; Browse:1 -&amp;gt;Alert Key [4500] &lt;br /&gt;
 ! Código usado para cambiar el Orden del Browse &lt;br /&gt;
 ! cuando se hace doble click en la columna &lt;br /&gt;
 IF KEYCODE()=MouseLeft2 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;Codigo&#039; &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;Nombre&#039; &lt;br /&gt;
     Loc:Columna = ?Browse:1{PropList:MouseDownField} &lt;br /&gt;
     CASE Loc:Columna &lt;br /&gt;
     OF 1 &lt;br /&gt;
     ?Browse:1{PropList:Header,1} =&#039;&amp;lt;&amp;lt;&amp;lt;CODIGO&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;LCA:LOCALIDAD&#039;) &lt;br /&gt;
     OF 2 &lt;br /&gt;
     ?Browse:1{PropList:Header,2} =&#039;&amp;lt;&amp;lt;&amp;lt;NOMBRE&amp;gt;&amp;gt;&amp;gt;&amp;gt;&#039; &lt;br /&gt;
     Brw1.SetOrder(&#039;UPPER(LCA:NOMBRE)&#039;) &lt;br /&gt;
     END!CASE &lt;br /&gt;
     Brw1.ApplyOrder() &lt;br /&gt;
     ThisWindow.Reset(1) &lt;br /&gt;
 END!IF &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Locator Múltiple ===&lt;br /&gt;
Por ejemplo, para posicionarme en un código de cuenta contable:&lt;br /&gt;
Lo que podrías hacer es poner una variable string sobre el browse y poner un&lt;br /&gt;
código mas o menos asi en su accepted del entry&lt;br /&gt;
&lt;br /&gt;
 !Asumiendo que cada código tiene cuatro dígitos&lt;br /&gt;
 !Revisar la sección String Slicing en el Help&lt;br /&gt;
 Cue:Cuenta = Loc:Cuenta[1:4]&lt;br /&gt;
 Cue:SubCuenta = Loc:Cuenta[5:8]&lt;br /&gt;
 Cue:SubSubCuenta = Loc:Cuenta[9:12]&lt;br /&gt;
 SET(Cue:PorCodigo,Cue:PorCodigo)&lt;br /&gt;
 Access:Cuentas.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
Otro ejempo, en un browse de órdenes, posicionarse según el nombre del cliente&lt;br /&gt;
&lt;br /&gt;
 CLI:Nombre = LOC:Cliente&lt;br /&gt;
 SET(CLI:PorNombre, CLI:PorNombre)&lt;br /&gt;
 ACCESS:Clientes.Next()&lt;br /&gt;
&lt;br /&gt;
 ORD:CodCliente = CLI:CodCliente&lt;br /&gt;
 SET(ORD:PorCliente, ORD:PorCliente)&lt;br /&gt;
 ACCESS:Ordenes.Next()&lt;br /&gt;
&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Pintar un browse según un campo ===&lt;br /&gt;
Por ejemplo cuando vemos las facturas de un Cliente se repite el nombre, este código pinta diferente cada grupo de nombres.&lt;br /&gt;
Primero hay que ponerle el atributo color al campo que necesites pintar, desde list box format.&lt;br /&gt;
Luego va el siguiente código, en WindowManager.Reset antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 Aux = &#039;&#039;&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (BRW1.Q)&lt;br /&gt;
     GET(BRW1.Q, F#)&lt;br /&gt;
     IF Aux &amp;lt;&amp;gt; BRW1.Q.CLI:Nombre&lt;br /&gt;
         Col# = 1- Col#&lt;br /&gt;
         Aux = BRW1.Q.CLI:Nombre&lt;br /&gt;
     END&lt;br /&gt;
     If Col#&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:SILVER&lt;br /&gt;
     Else&lt;br /&gt;
         BRW1.Q.CLI:Nombre_NormalBG = COLOR:WHITE&lt;br /&gt;
     End&lt;br /&gt;
     PUT(BRW1.Q)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Refrescar un browse desde otra ventana ===&lt;br /&gt;
Lo mas fácil sería usando NOTIFY.&lt;br /&gt;
En la Ventana 1 (la del browse a refrescar)&lt;br /&gt;
 WindowManager.Init&lt;br /&gt;
 GLO:THREAD = THREAD() !VARIABLE GLOBAL LONG&lt;br /&gt;
&lt;br /&gt;
 Window Events&lt;br /&gt;
 Notify&lt;br /&gt;
 BRW1.ResetfromBuffer() ! o ThisWindow.Reset(1)?&lt;br /&gt;
&lt;br /&gt;
En la ventana 2, cuando se necesite refrescar la 1&lt;br /&gt;
 NOTIFY (999, GLO:THREAD)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que en éste caso no estoy usando ese parámetro.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Iniciar el browse en un Tab determinado ===&lt;br /&gt;
En ThisWindow.Init, al final&lt;br /&gt;
 SELF.FirstField = ?Tab:4 !Use del tab&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Actualizar el resultado de un totaling del browse de detalle, en el Encabezado ===&lt;br /&gt;
En el Browse de abajo (el de detalle)&lt;br /&gt;
 ResetFromView, prioridad 4500 - La prioridad es importante&lt;br /&gt;
 GET(Encabezado, ENC:Por_Numero)&lt;br /&gt;
 ENC:Total = loc:total !ÉSTA ES LA VARIABLE DEL TOTALING&lt;br /&gt;
 PUT (Encabezado)&lt;br /&gt;
 IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtro Dinámico ===&lt;br /&gt;
Poner un control Text donde el usuario pueda escribir cualquier filtro&lt;br /&gt;
 X# = EVALUATE(Filtro)&lt;br /&gt;
 IF ERRORCODE()&lt;br /&gt;
     MESSAGE(&#039;ERROR DE SINTAXIS EN EL FILTRO: &#039; &amp;amp; ERROR(), &#039;ATENCION&#039;)&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.SetFilter(Filtro)&lt;br /&gt;
     ThisWindow.Reset(1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Rangos múltiples y dinámicos ===&lt;br /&gt;
Si tenemos una clave con varios componentes, en Actions del browse ponemos un rango por current value, elegimos el componente de la clave hasta el cual queremos hacer el rango.&lt;br /&gt;
El siguiente componente de la clave se puede usar como locator.&lt;br /&gt;
Por ejemplo si tenemos una clave con Tipo+Provincia+Localidad, hacemos un rango de current value por provincia y nos queda un locator por localidad.&lt;br /&gt;
&lt;br /&gt;
 BRW1.ApplyRange PROCEDURE&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 RAN:Tipo= loc:tipo&lt;br /&gt;
 RAN:Provincia=loc:provincia&lt;br /&gt;
 SELF.Order.Rangelist.AssignLeftToRight()&lt;br /&gt;
&lt;br /&gt;
En algun boton de aplicar rango&lt;br /&gt;
 BRW1.ApplyRange()&lt;br /&gt;
 ThisWindow.Reset(1)&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, deshabilitar condicionalmente la actualización de registros ===&lt;br /&gt;
 IF &amp;lt;Condición&amp;gt;&lt;br /&gt;
     !Deshabilitar Actualización&lt;br /&gt;
     BRW1.InsertControl=FALSE&lt;br /&gt;
     BRW1.ChangeControl=FALSE&lt;br /&gt;
     BRW1.DeleteControl=FALSE&lt;br /&gt;
 ELSE&lt;br /&gt;
     BRW1.InsertControl=?INSERT&lt;br /&gt;
     BRW1.ChangeControl=?CHANGE&lt;br /&gt;
     BRW1.DeleteControl=?DELETE&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Detectar el cambio de registro seleccionado en un Browse ===&lt;br /&gt;
Ejemplo mostrar una foto del cliente al costado del browse&lt;br /&gt;
 BRW1.TakeNewSelection PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !EN CLI:FOTO ESTA EL PATH COMPLETO DE LA FOTO&lt;br /&gt;
 IF CLI:FOTO &amp;lt;&amp;gt; &#039;&#039;&lt;br /&gt;
     ?Foto{PROP:TEXT}= CLI:FOTO &lt;br /&gt;
 ELSE&lt;br /&gt;
     ?Foto{PROP:TEXT}= &#039;&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Filtros complejos en un browse ===&lt;br /&gt;
Ejemplo: Mostrar sólo los clientes que tengan alguna orden&lt;br /&gt;
&lt;br /&gt;
 BRW1.ValidateRecord PROCEDURE&lt;br /&gt;
 ! [Priority 5001]&lt;br /&gt;
 !FILTROS COMPLEJOS&lt;br /&gt;
 !EJ: MOSTRAR SOLO LOS CLIENTES QUE TENGAN ALGUNA ORDEN&lt;br /&gt;
 CLEAR(ORD:RECORD)&lt;br /&gt;
 Ord:CodigoCliente=CLI:ID&lt;br /&gt;
 SET(Ord:FK_Ordenes_CLIENTES,Ord:FK_Ordenes_CLIENTES)&lt;br /&gt;
 NEXT(ORDENES)&lt;br /&gt;
 IF ERRORCODE() OR (Ord:CodigoCliente &amp;lt;&amp;gt; CLI:ID) THEN RETURN Record:Filtered.&lt;br /&gt;
 &lt;br /&gt;
 RETURN Record:OK&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Poner un campo &amp;quot;saldo&amp;quot; en un browse ===&lt;br /&gt;
ThisWindow.Reset, antes del Parent Call&lt;br /&gt;
&lt;br /&gt;
 S#=0&lt;br /&gt;
 LOOP F#= 1 TO RECORDS (Queue:Browse:1)&lt;br /&gt;
     GET(Queue:Browse:1, F#)&lt;br /&gt;
     S# += Queue:Browse:1.ORD:Total_Impo&lt;br /&gt;
     Queue:Browse:1.Saldo = S#&lt;br /&gt;
     PUT(Queue:Browse:1)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Resetear/inicializar un Locator ===&lt;br /&gt;
El método a ejecutar es&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
&lt;br /&gt;
Los nombres de las instancias de Locators por cada TAB se llaman:&lt;br /&gt;
 BRW1::Sort0:Locator.Set&lt;br /&gt;
 BRW1::Sort1:Locator.Set&lt;br /&gt;
 BRW1::Sort2:Locator.Set&lt;br /&gt;
 !etc..&lt;br /&gt;
&lt;br /&gt;
Luego sería bueno volver a poner el foco en el browse para que se pueda seguir usando el locator normalmente&lt;br /&gt;
 select (?Browse:1)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== En un Browse, disparar un procedimiento después de generar un alta, modificación, etc. ===&lt;br /&gt;
&lt;br /&gt;
El proceso a disparar se hace desde el browse, la idea es saber si del Form volvió aceptando o canceló la actualización. El punto embebido es:&lt;br /&gt;
&lt;br /&gt;
 Local Objects&lt;br /&gt;
 BRW1 (o el objeto de tipo browse class que sea)&lt;br /&gt;
 ResetFromAsk (después del Parent.call)&lt;br /&gt;
 &lt;br /&gt;
 IF VCRRequest=VCR:None&lt;br /&gt;
 CASE Request&lt;br /&gt;
 OF InsertRecord&lt;br /&gt;
     IF Response = RequestCompleted&lt;br /&gt;
     !Hacer algún proceso&lt;br /&gt;
     END&lt;br /&gt;
 END&lt;br /&gt;
 END!&lt;br /&gt;
&lt;br /&gt;
=== Inserción continua refrescando el Browse ===&lt;br /&gt;
Este otro método es similar al anterior, también sirve para lo mismo.&lt;br /&gt;
Agrego un ejemplo para hacer inserción continua en el Form y además se vaya actualizando el browse&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Run PROCEDURE(USHORT Number,BYTE Request)&lt;br /&gt;
 ! Cuidado que existen dos ThisWindow.Run, seleccionar el correcto&lt;br /&gt;
 ! [Priority 8500]&lt;br /&gt;
 IF Request = InsertRecord And ReturnValue = RequestCompleted&lt;br /&gt;
     POST(EVENT:ACCEPTED, BRW1.InsertControl)&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Posicionar un browse en un registro seleccionado ===&lt;br /&gt;
&lt;br /&gt;
Al abrir un browse a veces necesitamos posicionar el selector en un registro determinado, tal como lo hacen los browses para selección.&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para posicionar el browse en el registro más cercano al proporcionado por el usuario:&lt;br /&gt;
&lt;br /&gt;
 ThisWindow.Open PROCEDURE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 ! [Priority 5000]&lt;br /&gt;
 ! End of &amp;quot;WindowManager Method Data Section&amp;quot;&lt;br /&gt;
 CODE&lt;br /&gt;
 ! Start of &amp;quot;WindowManager Method Executable Code Section&amp;quot;&lt;br /&gt;
 ! [Priority 500]&lt;br /&gt;
 CLI:cliente= LOC:Cliente&lt;br /&gt;
 ACCESS:Clientes.fetch(CLI:Kcodigo)&lt;br /&gt;
 BRW1.selecting=1&lt;br /&gt;
 ! Parent Call&lt;br /&gt;
 PARENT.Open()&lt;br /&gt;
 ! [Priority 6300]&lt;br /&gt;
 BRW1.selecting=0&lt;br /&gt;
&lt;br /&gt;
Otra idea, propuesta por Matías Flores:&lt;br /&gt;
Ubicarlo por el valor de los campos de la clave. Por ejemplo, si en un browse de clientes querés posicionarte en un cliente que tiene un código determinado (Loc:Codigo):&lt;br /&gt;
&lt;br /&gt;
 Cli:Codigo = Loc:Codigo&lt;br /&gt;
 SET(Cli:PorCodigo,Cli:PorCodigo)&lt;br /&gt;
 Access:Clientes.Next()&lt;br /&gt;
 BRW1.ResetFromFile()&lt;br /&gt;
 ThisWindow.Reset(True)&lt;br /&gt;
&lt;br /&gt;
un ejemplo parecido al anterior, pero en legacy, sería:&lt;br /&gt;
 CLI:Codigo = LOC:Codigo&lt;br /&gt;
 BRW1::LocateMode = LocateOnValue&lt;br /&gt;
 DO BRW1::LocateRecord&lt;br /&gt;
&lt;br /&gt;
Una opción más es:&lt;br /&gt;
En el WindowManager.init, antes de Initialize browse y después de OpenFiles, colocar el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 BRWx.StartAtCurrent = True&lt;br /&gt;
 TAB:Campo = Valor_Buscado&lt;br /&gt;
 get(Tabla, TAB:Key_que_ordena_por_Campo)&lt;br /&gt;
&lt;br /&gt;
=== En Legacy, activar un filtro sobre un browse abierto. ===&lt;br /&gt;
&lt;br /&gt;
Esto se pone en el punto embebido &amp;quot;Before opening VIEW&amp;quot;. Acordarse de BINDEAR todas las variables que se necesiten.&lt;br /&gt;
&lt;br /&gt;
 !---ANTES DE ABRIR EL VIEW--- &lt;br /&gt;
 if SoloPendientes then&lt;br /&gt;
 BRW2::View:Browse{Prop:Filter} = |&lt;br /&gt;
 &#039;MER:numertra = BRW2::Sort1:Reset:TRA:numertra AND MER:saldunid &amp;lt;&amp;gt; 0&#039;&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo cuando quieras presentar el nombre completo sin los espacios de un campo a otro. Pones en el browse una variable local.&lt;br /&gt;
En el SETQUEUERECORD (4500)&lt;br /&gt;
 &lt;br /&gt;
 Loc:ApellidoNombre = clip(CON:Apellido) &amp;amp; &#039; &#039; &amp;amp; CON:Nombre&lt;br /&gt;
&lt;br /&gt;
!(Tip de Alex B.)&lt;br /&gt;
&lt;br /&gt;
=== Código antes y después de una actualización DESDE UN BROWSE. ===&lt;br /&gt;
&lt;br /&gt;
- Antes de la llamada al Form de actualización&lt;br /&gt;
! ABC Objects -&amp;gt; Browse on Archvivo -&amp;gt;Ask Priority[4500]&lt;br /&gt;
 IF Request = InsertRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR ALTA &#039;,&#039;ALTA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = ChangeRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A ACTUALIZAR &#039;,&#039;CAMBIO&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF Request = DeleteRecord&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCION: SE VA A DAR DE BAJA &#039;,&#039;BAJA&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
- Después de la actualización del registro&lt;br /&gt;
!ABC Objects -&amp;gt; Browse on Provincia -&amp;gt;Ask Priority[5500]&lt;br /&gt;
 IF ReturnValue =1&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;ATENCIÓN: SE ACTUALIZÓ EL REGISTRO&#039;,&#039;ACTUALIZÓ OK&#039;,ICON:EXCLAMATION)&lt;br /&gt;
 ELSIF ReturnValue =2&lt;br /&gt;
     BEEP&lt;br /&gt;
     MESSAGE(&#039;SE CANCELÓ LA ACTUALIZACIÓN DEL REGISTRO&#039;,&#039;ATENCIÓN&#039;,ICON:HAND)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
=== Deshabilitar/esconder (cambiar a PROP:HIDE) un control si el browse está vacío - pe. un botón-. ===&lt;br /&gt;
&lt;br /&gt;
En el Browse.UpdateWindow(), última prioridad:&lt;br /&gt;
 ?TuBoton{PROP:Disable}=Choose(Self.Records()&amp;lt;&amp;gt;0,0,1)&lt;br /&gt;
&lt;br /&gt;
===Iniciar un browse con un orden &amp;quot;sort header&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
Si queremos que al abrir un browse el mismo se encuentre ordenado como si hubiéramos hecho click en el sortheader, ponemos luego del generated code del evento openwindow lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 BRW1::SortHeader.SetSortFromString(&#039;TAB:Campo&#039;)&lt;br /&gt;
&lt;br /&gt;
donde TAB:Campo es uno de los campos de la tabla que estoy mostrando en el browse.&lt;br /&gt;
&lt;br /&gt;
== EDIT IN PLACE==&lt;br /&gt;
=== Edit in Place o Form, según condición ===&lt;br /&gt;
En BrowseClass, Ask, antes del Parent Call&lt;br /&gt;
 If ?browse:1{proplist:mousedownfield} = 5&lt;br /&gt;
     Self.AskProcedure = 0&lt;br /&gt;
 else&lt;br /&gt;
     Self.AskProcedure = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Puede usarse cualquier condición, en este caso si el usuario hace doble click en la 5a columna se usa edit in place, sino se usa el formulario&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Desactivar Edit in Place de un campo según condición ===&lt;br /&gt;
En las propiedades del EIP del campo admitir la edición del mismo.&lt;br /&gt;
&lt;br /&gt;
En el EIP Field Manager del campo, TakeEvent, antes del Parent Call&lt;br /&gt;
  if Queue:Browse:1.TAB:Campo_de_mi_Tabla &amp;gt; 0 &lt;br /&gt;
     Return EditAction:Cancel&lt;br /&gt;
     thiswindow.reset(true)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
En este ejemplo sólo permito que pueda editarse el campo si el valor actual del mismo es &amp;lt;= 0&lt;br /&gt;
&lt;br /&gt;
=== Inicializar campos al insertar registro ===&lt;br /&gt;
O sea lo que hace el Prime Fields en las formas&lt;br /&gt;
 ABC Objects&lt;br /&gt;
 BROWSE ON TABLA using ?LIST&lt;br /&gt;
 PrimeRecords&lt;br /&gt;
 Después del Parent Call&lt;br /&gt;
 TPS:TuCampo= valor inicial&lt;br /&gt;
&lt;br /&gt;
=== Poner Disable un campo===&lt;br /&gt;
 Local Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 Abc Objects --&amp;gt;&amp;gt;&lt;br /&gt;
 EIP Field Manag...for Field NombreCampo&lt;br /&gt;
 --&amp;gt;&amp;gt;Init [Priority 5001]&lt;br /&gt;
 If SELF.FEQ then SELF.FEQ{Prop:Disable} = true.&lt;br /&gt;
También se pueden cambiar otras propiedades como por ejemplo UPPER (mayúsculas) o READ ONLY (sólo lectura)&lt;br /&gt;
 If SELF.FEQ &lt;br /&gt;
     SELF.FEQ{prop:readonly} = TRUE&lt;br /&gt;
     SELF.FEQ{prop:upr} = TRUE&lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Campos Calculados ===&lt;br /&gt;
Por ejemplo Modificar el total cuando cambia la cantidad.&lt;br /&gt;
Primero agregar el campo cantidad en Column Specific&lt;br /&gt;
 EditInPlace::DET:Cantidad.TakeEvent PROCEDURE(UNSIGNED Event)&lt;br /&gt;
 ....&lt;br /&gt;
 !Despues del Parent Call&lt;br /&gt;
&lt;br /&gt;
 CASE ReturnValue&lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel&lt;br /&gt;
 ELSE&lt;br /&gt;
     Update(Self.Feq)&lt;br /&gt;
     BRW1.Q.DET:Total = BRW1.Q.DET:Cantidad * BRW1.Q.DET:Importe&lt;br /&gt;
     !Etc... siempre haciendo referencia a los campos de la cola BRW1.Q.&lt;br /&gt;
 END&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validaciones ===&lt;br /&gt;
Por ejemplo una validación básica de un número requerido&lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:NroDocumento&lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 ! Validación del nro. de Documento &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     UPDATE(Self.Feq) &lt;br /&gt;
     IF NOT BRW1.Q.Cli:NroDocumento &lt;br /&gt;
         BEEP(BEEP:SystemExclamation) ; YIELD() &lt;br /&gt;
         MESSAGE(&#039;No se informó el número de Documento&#039;, | &lt;br /&gt;
         &#039;Atención!&#039;, ICON:Exclamation) &lt;br /&gt;
         ReturnValue = EditAction:NONE &lt;br /&gt;
         Return ReturnValue &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Validación con un lookup a una tabla &lt;br /&gt;
 !Local Objects --&amp;gt;&amp;gt; Abc Objects --&amp;gt;&amp;gt; EIP Field Manager for Field Cli:Provincia &lt;br /&gt;
  --&amp;gt;&amp;gt;Take Event [Priority 5001] &lt;br /&gt;
 !Valida Provincia &lt;br /&gt;
 CASE ReturnValue &lt;br /&gt;
 OF EditAction:None OROF EditAction:Cancel &lt;br /&gt;
 ELSE &lt;br /&gt;
     Update(Self.Feq) &lt;br /&gt;
     Pro:Codigo= BRW1.Q.Cli:Provincia &lt;br /&gt;
     IF Access:Provincia.Fetch(Pro:PorCodigo) &lt;br /&gt;
         GlobalRequest = SelectRecord &lt;br /&gt;
         SelectProvincia &lt;br /&gt;
         IF NOT Pro:Codigo &lt;br /&gt;
             ReturnValue = EditAction:NONE &lt;br /&gt;
             Return ReturnValue &lt;br /&gt;
         ELSE &lt;br /&gt;
             BRW1.Q.Cli:Provincia = Pro:Codigo &lt;br /&gt;
             BRW1.Q.Pro:NOMBRE = Pro:NOMBRE &lt;br /&gt;
     END &lt;br /&gt;
 END &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
Gustavo Olmedo [http://www.templatesclarion.com.ar/downloads/ (Evolution)]&lt;br /&gt;
&lt;br /&gt;
== GLOBALES ==&lt;br /&gt;
&lt;br /&gt;
=== Cambiar los mensajes de error del SQL === &lt;br /&gt;
Con cambiar los TRN no alcanza para ese tipo de errores. &lt;br /&gt;
 &lt;br /&gt;
Lo que se puede hacer es determinar el mensaje que viene desde el SQLServer &lt;br /&gt;
para mostrar un mensaje mas amigable. &lt;br /&gt;
 &lt;br /&gt;
El embebido es &lt;br /&gt;
Global Embeds: &lt;br /&gt;
 Global Objets &lt;br /&gt;
 Abc Objects &lt;br /&gt;
 Error Manager &lt;br /&gt;
 TakeNotify &lt;br /&gt;
 !Antes del Parent Call &lt;br /&gt;
 IF INSTRING(&#039;COLUMN REFERENCE&#039;, SELF.SubsString(),1,1) &lt;br /&gt;
 SELF.Msg(&#039;El registro no puede borrarse porque tiene datos de detalle &lt;br /&gt;
 que dependen de él. |Presione [OK] para una descripción detallada del &lt;br /&gt;
 error&#039;,SELF.GetErrorBufferTitle(),ICON:Exclamation,Button:OK,BUTTON:OK,0) &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Hay que armar un IF de estos por cada tipo de error... &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
=== Validación de campos (Edit in place o Form)=== &lt;br /&gt;
 &lt;br /&gt;
Para validar campos lo ideal es usar los Global Embeds &lt;br /&gt;
 Global Embeds &lt;br /&gt;
 Field Level Validation &lt;br /&gt;
 Tabla &lt;br /&gt;
 Campo &lt;br /&gt;
 IF &amp;lt;No cumple Condición&amp;gt; &lt;br /&gt;
 Message(&#039;error...&#039;) &lt;br /&gt;
 RETURN Level:Notify &lt;br /&gt;
 END &lt;br /&gt;
 &lt;br /&gt;
Esto te va a funcionar &amp;quot;para siempre&amp;quot; ya sea que uses Edit in place, un Form &lt;br /&gt;
o código embebido para actualizar la tabla. &lt;br /&gt;
 &lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Templates_gratuitos&amp;diff=64</id>
		<title>Templates gratuitos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Templates_gratuitos&amp;diff=64"/>
		<updated>2015-03-07T22:39:52Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Texto reemplazado: «www.evolutionconsulting.com.ar/download.html» por «www.templatesclarion.com.ar/downloads/»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Existen diversos templates adicionales para Clarion que extienden notablemente su funcionalidad.&lt;br /&gt;
&lt;br /&gt;
Esta sección debería incluir el nombre, una breve descripción del mismo, las versiones compatibles de Clarion y el sitio desde donde puede descargarse.&lt;br /&gt;
&lt;br /&gt;
== ABCFree ==&lt;br /&gt;
&lt;br /&gt;
Es el conjunto de templates y librerias gratuitas más interesante para Clarion.&lt;br /&gt;
Esta disponible en http://www.authord.com/Clarion . Frecuentemente actualizado y cubre todos los niveles de programación con Clarion: bajo y alto nivel. Fundamental&lt;br /&gt;
&lt;br /&gt;
== Botpl ==&lt;br /&gt;
Sitio web: http://comsoft7.com/Botpl.htm&lt;br /&gt;
&lt;br /&gt;
Incluye:&lt;br /&gt;
&lt;br /&gt;
AppSpecsControl, BarCodeLabelControl,BrowseSearch,LabelControl,ListHorzRuntime,ListVertRuntime, PerCentGraph,PerCentGraphVert,Bo_resc 32bit only.&lt;br /&gt;
&lt;br /&gt;
== Clarion Australia ==&lt;br /&gt;
http://www.comformark.com.au/&lt;br /&gt;
&lt;br /&gt;
Clarion Autralia&lt;br /&gt;
&lt;br /&gt;
== Clarion FreeImage Project ==&lt;br /&gt;
&lt;br /&gt;
http://www.clarionfreeimage.com/&lt;br /&gt;
&lt;br /&gt;
Conjunto de clases y un template que implementa la librería open source FreeImage para procesamiento de imágenes en Clarion 5.5 y 6.x.&lt;br /&gt;
Tiene una seccion[http://www.clarionfreeimage.com/related.html] con varias clases y ejemplos: escanear con eztwain, enumerar monitores, barras de progreso e iconos en Barras de estado, botones con alpha blend y smooth scrolling control&lt;br /&gt;
&lt;br /&gt;
== Evolution Consulting ==&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ Seccion Downloads]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ MENSAJES DE CLARION EN ESPAÑOL ]&lt;br /&gt;
&lt;br /&gt;
Traducción al español de todos los botones, mensajes, etc... que se utilizan en la generación de los Wizzards. Actualizado siempre a la última version de Clarion 6.1. Una herramienta indispensable para nuestra comunidad Latinoamericana.&lt;br /&gt;
&lt;br /&gt;
Para instalar simplemente copie los archivos al directorio Clarion6\LIBSRC.&lt;br /&gt;
&lt;br /&gt;
También agregamos la traducción del Calendario ABUTILUI&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ EVOLUTION MAIL TEMPLATE    (Clarion 5.0)   (Clarion 5.5)   (Clarion 6.1)   (Clarion 7.2)]&lt;br /&gt;
&lt;br /&gt;
El producto está compuesto por un Control Template para envío de mail y un Extension Template para enviar los WMF del preview por mail con selector de página. Permite guardar el wmf en un word y generar el attach automáticamente dentro de un mail o bien dejarlo en segundo plano del aplicativo.&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ EVOLUTION TOOLS (Clarion 5, 5.5 y 6.1) ]&lt;br /&gt;
&lt;br /&gt;
Incluye el Control Template tan solicitado &amp;quot;página de páginas&amp;quot; en los reportes.&lt;br /&gt;
&lt;br /&gt;
Evita el mensaje &#039;No hay registros para procesar&#039;&lt;br /&gt;
&lt;br /&gt;
STREAM y FLUSH Automático en los process.&lt;br /&gt;
&lt;br /&gt;
Control template que nos permite pegar un calendario en una windows. La diferencia de este template con otros free es que éste agrega el calendario dentro de la misma ventana como &amp;quot;Control Template&amp;quot;, los otros son simplemente procedimientos aparte.&lt;br /&gt;
&lt;br /&gt;
Enter por Tab mejorado.&lt;br /&gt;
&lt;br /&gt;
Imprimir Página Desde - Hasta desde Preview.&lt;br /&gt;
&lt;br /&gt;
Configuración de Impresora en Preview.&lt;br /&gt;
&lt;br /&gt;
Impresión Página Actual en Preview.&lt;br /&gt;
&lt;br /&gt;
Este template se irá actualizando periódicamente, se aceptan sugerencias...&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ ARBOL DE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Pequeño Utility template que genera el árbol de procedimientos en un archivo NombreAPP.TXT&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ CLARION BATCH COMPILER (beta 11) ]&lt;br /&gt;
&lt;br /&gt;
Este excelente producto de Cristian Olsen compila en modo Batch todos los APPs del sistema. Compatible con todas las versiones de Clarion&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ INFORMACION DE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Template muy útil para volcar información detallada de los procedimientos de un app, con nombre, tipo, prototipo, ultima modificación, si es local o externo, etc (Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ GRABAR TAB ELEGIDO ]&lt;br /&gt;
&lt;br /&gt;
Se agrega a los browses con múltiples tabs y graba como se lo utilizó la ultima vez para cuando se reingrese, se pare nuevamente en ese tab(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ TRACE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Este es mas complejo, es global y se indica un procedimiento que es le que recibirá el procedimiento y app por el que se está pasando, este procedimiento (que el usuario debe crear) es que debe grabar en un archivo deseado, el resultado. En mi caso graba en un txt, el procedimiento, app, fecha y hora, y tengo una variable en un INI para indicar si debe grabarse o no.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ CAMPOS OBLIGATORIOS ]&lt;br /&gt;
&lt;br /&gt;
Extensión que hace no se pueda salir de los campos obligatorios. Es global con opciones locales (se puede deshabilitar en cada procedimiento). Importante: Es necesario crear un alert key global para salir del procedimiento para dejar escapar al usuario en caso de necesidad.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ VARIOS ]&lt;br /&gt;
&lt;br /&gt;
Tiene 2 funciones, si se presiona CrtlAltP, indica en un message en que procedimiento estamos y en que APP está y una función que si estás parado en un campo con formato de fecha y presionas el + del teclado numérico asigna la fecha del día.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ DCT2SQL ]&lt;br /&gt;
&lt;br /&gt;
La última versión de uno de los templates mas populares para la generación de Scripts SQL a partir del DCT (Gracias Roberto Artigas)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ MCI ]&lt;br /&gt;
&lt;br /&gt;
Template que reproduce audio (Wav, Mp3) y video (Avi, Mpg) (Gracias Victor Pierri)&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ Calendario + 18 funciones ]&lt;br /&gt;
&lt;br /&gt;
Template del estilo PopUp Calendario y un conjunto de 18 Funciones muy útiles (Ver mas info) Gracias Francisco J. Carabez&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ Print Driver ]&lt;br /&gt;
&lt;br /&gt;
Template para impresoras matriciales, traducido y mejorado por Ruben Caporossi . Simplemente se registra en Global Extensions del app y las funciones están disponibles&lt;br /&gt;
&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ Esta página se actualiza constantemente...]&lt;br /&gt;
&lt;br /&gt;
== SICyA Software ==&lt;br /&gt;
http://www.sicya.com&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; SICyA Templates &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
AutoCompletar_SICyA - Control entry de autocompletado desde una tabla.&lt;br /&gt;
&lt;br /&gt;
Calendario_SICyA - Calendario con estilo XP con manejo de dominicales y feriados.&lt;br /&gt;
&lt;br /&gt;
LlamaProcedimiento_SICyA - Llama procedimientos con parámetros o en forma thread.&lt;br /&gt;
&lt;br /&gt;
VolumeDiscoDuro_SICyA - Captura Serial, nombre del Volumen y Tipo Archivos de un Disco&lt;br /&gt;
&lt;br /&gt;
Botones_SICyA - Extensión para tener Botones con un estilo propio en aplicaciones no XP.&lt;br /&gt;
&lt;br /&gt;
[http://www.sicya.com/download/SICyA_Templates_Build_051007.exe Descargar el template aqui...]&lt;br /&gt;
&lt;br /&gt;
== Solace ==&lt;br /&gt;
&lt;br /&gt;
http://www.solace-software.demon.co.uk/freetemplates.htm&lt;br /&gt;
&lt;br /&gt;
Enhanced standard HTML help template&lt;br /&gt;
&lt;br /&gt;
Colour all columns in a browse on a condition without having to individually specify each column&lt;br /&gt;
&lt;br /&gt;
Screen Resolution&lt;br /&gt;
&lt;br /&gt;
Make Directory&lt;br /&gt;
&lt;br /&gt;
Read Only Window&lt;br /&gt;
&lt;br /&gt;
Open Close Files in Source Template&lt;br /&gt;
&lt;br /&gt;
Add Wallpaper to every Window&lt;br /&gt;
&lt;br /&gt;
Override Recursive Insert Message &lt;br /&gt;
&lt;br /&gt;
Global extension to change the Font of every screen in your app.&lt;br /&gt;
&lt;br /&gt;
Global Extension to allow users to make all controls flat&lt;br /&gt;
&lt;br /&gt;
== tabajara ==&lt;br /&gt;
&lt;br /&gt;
http://www.tabajara.com/downloads.html&lt;br /&gt;
&lt;br /&gt;
Browser to HTML - Just populate a Button and you can export to HTML&lt;br /&gt;
&lt;br /&gt;
Browser to CSV - Just populate a Button, and Done! This way you can export to Excel.&lt;br /&gt;
&lt;br /&gt;
Files to CSV - Choose files to export data. (export files to CSV selecting from DCT)&lt;br /&gt;
&lt;br /&gt;
Report Green Bar - makes shadowed every other report detail.&lt;br /&gt;
&lt;br /&gt;
== xFunction ==&lt;br /&gt;
&lt;br /&gt;
Colección gratuita de templates de código de la empresa Sealsoft. Incluyen funciones para manejo de fechas, archivos y paths, y algunas otras. Puede descargarse de http://www.seal-soft.com&lt;br /&gt;
&lt;br /&gt;
== Locus Templates ==&lt;br /&gt;
&lt;br /&gt;
http://www.riebens.co.za/index.php?option=com_content&amp;amp;view=article&amp;amp;id=39&amp;amp;Itemid=183&lt;br /&gt;
&lt;br /&gt;
Excelente conjunto de templates que abarcan varias categorias: &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CONTROL TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* PageTree	Seleccionar una hoja de propiedades de un listbox tipo tree&lt;br /&gt;
* PopupDate	Seleccionar fecha desde un calendario&lt;br /&gt;
* PopupDirectory	Seleccionar directorio&lt;br /&gt;
* RichEdit	Completo editor de texto enriquecido (RTF) totalmente escrito en clarion con toolbar y tabulador.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PROCEDURES:&#039;&#039;&#039;&lt;br /&gt;
* QBEDialog	Crea Dialogo QBE (Query by Example).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CODE TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* CWPrintEngine	Imprimir un reporte creado con el CW Report Writer&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;EXTENSION TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* BrowseEdit	Edit in place para un browse box con validación de campos y lookup&lt;br /&gt;
* BrowseTotal	Totalizar campos en un browse box.&lt;br /&gt;
* BrowseValue	Crea un checkbox editable&lt;br /&gt;
* FormSplit	Divisores verticales u horizontales&lt;br /&gt;
* GetIniFile	Obtiene y guarda valores en un archivo ini.&lt;br /&gt;
* LimitStarts	Evita comenzar 2 MDI threads a la vez&lt;br /&gt;
* PopupToolbar	Toolbar ocultable &lt;br /&gt;
* ReportFilter	Seleccionar registros para imprimir y resaltar. Incluye un visor de reporte&lt;br /&gt;
* FILE MANAGER	Posibilita cambiar el dct, recompilar, y todos los archivos son actualizados automáticamente a la nueva version&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Codigo_Util&amp;diff=63</id>
		<title>Codigo Util</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Codigo_Util&amp;diff=63"/>
		<updated>2015-03-07T22:38:19Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Texto reemplazado: «[http://www.evolutionconsulting.com.ar/espanol/downloads.html (Evolution Downloads)]» por «[http://templatesclarion.com.ar/downloads/ (Templates Clarion)]»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;En esta sección se incluyen rutinas de código que nos resultaron útiles en más de una ocasión.&lt;br /&gt;
&lt;br /&gt;
== PDF con cualquier versión de Clarion ==&lt;br /&gt;
Después de mucho rebuscar algo gratis que haga esto, hoy pude componer algo:&lt;br /&gt;
1º) Aporte de Fernando Cerini para &amp;quot;capturar&amp;quot; los .wmf de los reportes de Clarion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En el embed PrintPreview.Open, despues de Parent call&lt;br /&gt;
 &lt;br /&gt;
 get(SELF.ImageQueue,POINTER(SELF.ImageQueue))&lt;br /&gt;
 LOOP a# = 1 to RECORDS(SELF.ImageQueue)&lt;br /&gt;
          get(SELF.ImageQueue,a#)&lt;br /&gt;
          COPY(SELF.ImageQueue, &#039;c:\temp\Pagina&#039; &amp;amp; a# &amp;amp;&#039;.WMF&#039;)&lt;br /&gt;
          IF ERRORCODE() THEN MESSAGE(ERROR()).&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
En mi caso, con Clarion 5.0 ABC el embed point fue Previewer.Open, después del Parent call&lt;br /&gt;
&lt;br /&gt;
2º) Instalar OpenOffice y seguir las instrucciones de&lt;br /&gt;
http://www.xml.com/pub/a/2006/01/11/from-microsoft-to-openoffice.html&lt;br /&gt;
para crear la macro.&lt;br /&gt;
La verdad, no pude cambiar el nombre de Module1 a Conversiones o algo así, pero no importó mucho.&lt;br /&gt;
&lt;br /&gt;
3º) Cree un batch con la línea&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;C:\Archivos de Programa\OpenOffice.org 2.3\program\soffice&amp;quot; -invisible macro:///Standard.Module1.SaveAsPDF(c:\temp\pagina8.wmf)&lt;br /&gt;
&lt;br /&gt;
Es lo que dice el instructivo mencionado en el punto 2º) acomodado a mi instalación de OpenOffice, lo corrí y funcionó a la primera prueba.&lt;br /&gt;
&lt;br /&gt;
4º) Sólo queda hacer la llamada mediante RUN en el código de Clarion y santo remedio.&lt;br /&gt;
&lt;br /&gt;
Espero sea de ayuda para alguien.&lt;br /&gt;
Saludos&lt;br /&gt;
Ezequiel&lt;br /&gt;
&lt;br /&gt;
== Como filtrar un Tree ==&lt;br /&gt;
Una tecnica de Saul Perez Quezada para filtrar Arboles (generados con el template Relacion Tree), con filtros en runtime que son complejos, y que no podemos hacer con un simple SetFilter().&lt;br /&gt;
&lt;br /&gt;
Alguien ha posteado una pregunta sobre como Filtrar arboles, yo en lo personal he dejado de usar arboles, por que son bastante lentos y deficientes, pero en algunas aplicaciones es bastante util, de manera que comparto la experiencia y les subo una pequeña explicacion de como filtrar Arboles (generados con el template Relacion Tree), con filtros en runtime que son complejos, y que no podemos hacer con un simple SetFilter(), ya que no existe esto en la propiedad.&lt;br /&gt;
 &lt;br /&gt;
Saludos y espero les sirva.&lt;br /&gt;
 &lt;br /&gt;
Como filtrar un Tree con solamente tablas:&lt;br /&gt;
 &lt;br /&gt;
Dentro del Template para armar los arboles, tiene dentro de Primary y Secondary files la opcion de filtrar, agregando un filtro, pero muchas veces dicho filtro no es tan simple de armar, o necesitamos estarlo cambiando en runtime.&lt;br /&gt;
 &lt;br /&gt;
Aqui les presento un caso y como su solucion, esperando que les sirva...&lt;br /&gt;
 &lt;br /&gt;
Tengo tres tablas:&lt;br /&gt;
 &lt;br /&gt;
Abuelos&lt;br /&gt;
Padres&lt;br /&gt;
Hijos&lt;br /&gt;
 &lt;br /&gt;
Y en la tabla hijos, tengo un campo que define en que nivel de escuela en que va cada hijo: Pre-escolar, Primaria, Secundaria, Bachillerato, Universidad, PostGrado, Maestria y Doctorado.&lt;br /&gt;
 &lt;br /&gt;
En la ventana requiero que el usuario pueda filtrar por el nivel escolar, pero con las siguientes condiciones:&lt;br /&gt;
 &lt;br /&gt;
1.- El usuario puede seleccionar si quiere ver cualquier combinacion de estudios, es decir, que pueda ver los de primaria y universidad solamente o todos, o ninguno...&lt;br /&gt;
2.- Si selecciona un filtro donde resulte que un abuelo o padre no tiene hijos que cumplan la condicion, entonces no debe mostrarnos a esos abuelos y padres...&lt;br /&gt;
 &lt;br /&gt;
Considerando que el Tree template, muestra siempre los niveles de acuerdo al filtro que se arma, pues podria convertirse algo engorroso, estar cambiando el filtro, ya que no es una propiedad del relacion tree, tal como sucede con el browse class, sino que el tree filtra a base de If&#039;s interpuestos al llenar el queue...&lt;br /&gt;
 &lt;br /&gt;
Usando el template y solo poniendo los filtros de NIVELESCOLAR = LOC:MINIVEL, solo mostraria los hijos de un nivel, asi que este metodo no nos servira...&lt;br /&gt;
 &lt;br /&gt;
La idea seria entonces que como filtro usaremos una condicion matematica, si la condicion es Verdadera, entonces mostrara el hijo, de lo contrario no lo mostrara.&lt;br /&gt;
 &lt;br /&gt;
Asi que con el comando EVALUATE, evaluaremos un filtro, dentro del secondary files, opcion filter, si el filtro es bueno (igual a 1), entonces nos mostrara la info de lo contrario no...&lt;br /&gt;
 &lt;br /&gt;
Por ejemplo:&lt;br /&gt;
 &lt;br /&gt;
En el secondary files en buscamos la tabla de Hijos y le escribimos en el filtro:&lt;br /&gt;
 &lt;br /&gt;
0&amp;lt;EVALUATE(Filtro) ! Si el filtro es valido, entonces nos mostrara el resultado, de lo contrario no...&lt;br /&gt;
 &lt;br /&gt;
Declaramos un check box por cada cada condicion, con su respectiva variable: Preescolar, Primaria, Secundaria, etc... que sea tipo byte, con valor true = 1 y valor false = 0&lt;br /&gt;
 &lt;br /&gt;
! En el acepted del check box Preescolar... y cada condicion...&lt;br /&gt;
Do Filtrar&lt;br /&gt;
Display&lt;br /&gt;
 &lt;br /&gt;
! En procedure routines&lt;br /&gt;
Filtrar Routine&lt;br /&gt;
  Clear(Filtro) ! Variable para filtrar&lt;br /&gt;
 &lt;br /&gt;
  If Preescolar Then Filtro = &#039;HIJ:NIVELESCOLAR=&#039;&#039;Preescolar&#039;&#039;&#039; ..&lt;br /&gt;
  &lt;br /&gt;
  If Filtro And Primaria&lt;br /&gt;
    Filtro = Clip(Filtro) &amp;amp; &#039; And HIJ:NIVELESCOLAR=&#039;&#039;Primaria&#039;&#039;&#039;&lt;br /&gt;
  ElsIf Filtro And Primaria&lt;br /&gt;
    Filtro = &#039;HIJ:NIVELESCOLAR=&#039;&#039;Primaria&#039;&#039;&#039;&lt;br /&gt;
  End&lt;br /&gt;
  ! Esto se repite con todas las condiciones...&lt;br /&gt;
  ...&lt;br /&gt;
  ...&lt;br /&gt;
  &lt;br /&gt;
  ! Despues de armar el filtro, refrescar el browse...&lt;br /&gt;
 &lt;br /&gt;
  DO REL4::RefreshTree ! Esta rutina la genera el template, se debe buscar en los modulos su nombre correcto.&lt;br /&gt;
  POST(EVENT:NewSelection,?RelTree)&lt;br /&gt;
 &lt;br /&gt;
 Exit  &lt;br /&gt;
 &lt;br /&gt;
Hasta ahora, lo que se ha logrado es que cuando el usuario seleccione un tipo nivel escolar, nos mostrara o no los hijos, pero resulta, que ahora lo que necesito es que solo me muestre los abuelos que tienen nietos, y los padres que tienen hijos, es entonces por que no tiene caso que el arbol se llene con Mil abuelos, si solo 30 de ellos tienen nietos...&lt;br /&gt;
 &lt;br /&gt;
Para hacer debemos entender como se llena el queue del tree, basicamente, el tree, tantas vueltas como combinaciones de nuestra estructura tengamos, es decir, suponiendo que tenemos 3 abuelos, 3 padres, con 3 hijos cada uno, lo que hace el template es:&lt;br /&gt;
 &lt;br /&gt;
Por cada Abuelo Barre (con Loop) la tabla Padres por completo 1 vez y selecciono los que me corresponden y por cada padre barro la tabla hijos (con Loop) por completo y selecciono los que me corresponden...&lt;br /&gt;
 &lt;br /&gt;
Entonces esta estructura daria 3 x 3 x 3 = 27 vueltas. (Ahora imaginen lo que tarda en entre tablas de 10000 registros...)&lt;br /&gt;
 &lt;br /&gt;
Bueno, siguiendo esta idea, entonces lo que necesitamos, es interceptar cada vuelta en el punto donde no queremos que se ingrese al queue y hacer un break.&lt;br /&gt;
 &lt;br /&gt;
Conociendo esto buscamos en nuestros embeds, embedido llamado:&lt;br /&gt;
 &lt;br /&gt;
RelacionTree After Next Primary File y RelationTree After Next Secondary File...&lt;br /&gt;
 &lt;br /&gt;
Aqui buscamos el archivo que requerimos excluir en algunos casos, que es Padres e Hijos, le escribimos en el caso de Padres:&lt;br /&gt;
 &lt;br /&gt;
PAD:AbueloId = ABU:AbueloId&lt;br /&gt;
If Access:Padres.Fetch(FK AbueloId)  ! Si no existen padres que sean dependientes de este abuelo&lt;br /&gt;
  Break          ! hacer el break al Loop del armado del tree...&lt;br /&gt;
End&lt;br /&gt;
 &lt;br /&gt;
Y el caso de los hijos repetimos la condicion:&lt;br /&gt;
 &lt;br /&gt;
HIJ:PadreId = PAD:PadreId&lt;br /&gt;
If Access:Hijos.Fetch(FK PadreId)  ! Si no existen hijos que sean dependientes de este abuelo&lt;br /&gt;
  Break          ! hacer el break al Loop del armado del tree...&lt;br /&gt;
End&lt;br /&gt;
 &lt;br /&gt;
El efecto sera que no nos mostrara aquellos padres y abuelos que no tengan hijos.&lt;br /&gt;
 &lt;br /&gt;
Si requerimos algo mas complejo podemos usar una vista, en vez de una Fetch a una tabla, pero obviamente se alentara esto cada vez mas y mas al llenar el Arbol.&lt;br /&gt;
 &lt;br /&gt;
Nota&lt;br /&gt;
Si usamos un motor de SQL, una alternativa mucho mas eficiente es declarar un Vista en nuestro motor y diccionario que sirva de base para llenar el Arbol, con esto aumentaria considerablemente la velocidad.&lt;br /&gt;
&lt;br /&gt;
== Reemplazar caracteres en un string ==&lt;br /&gt;
Una rutina generica para reemplazar todas las instancias de un string dentro de otro&lt;br /&gt;
&lt;br /&gt;
 Replace       PROCEDURE(string find,string replace,*cstring into)&lt;br /&gt;
 Locate LONG,AUTO&lt;br /&gt;
  CODE&lt;br /&gt;
    IF UPPER(find)&amp;lt;&amp;gt;UPPER(replace)&lt;br /&gt;
       LOOP&lt;br /&gt;
         Locate = INSTRING(UPPER(find),UPPER(into),1,1)&lt;br /&gt;
         IF ~Locate THEN RETURN .&lt;br /&gt;
         into = SUB(into,1,Locate-1) &amp;amp; replace &amp;amp;SUB(into,Locate+LEN(find),LEN(into))&lt;br /&gt;
       END&lt;br /&gt;
    END&lt;br /&gt;
&lt;br /&gt;
Para llamarlo:&lt;br /&gt;
&lt;br /&gt;
Replace(&#039;Busacr&#039;,&#039;Reemplazar&#039;,Loc:miString)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contar los threads abiertos ==&lt;br /&gt;
Este código fue posteado por Jeff Slarve&lt;br /&gt;
 ChildThreadCount Procedure!,Long&lt;br /&gt;
 Ndx   Long&lt;br /&gt;
 Count Long&lt;br /&gt;
 T     &amp;amp;Window&lt;br /&gt;
 W     &amp;amp;Window&lt;br /&gt;
  Code&lt;br /&gt;
&lt;br /&gt;
  Count = 0&lt;br /&gt;
  SetTarget&lt;br /&gt;
  T &amp;amp;= System{PROP:Target}&lt;br /&gt;
  Loop Ndx = 1 to MaxThreads&lt;br /&gt;
     SetTarget(,Ndx)&lt;br /&gt;
     W &amp;amp;= System{PROP:Target}&lt;br /&gt;
     If NOT W &amp;amp;= T&lt;br /&gt;
       Count += 1&lt;br /&gt;
     end&lt;br /&gt;
  end&lt;br /&gt;
  SetTarget&lt;br /&gt;
  Return Count&lt;br /&gt;
&lt;br /&gt;
== Permitir solo una instancia del EXE en ejecucion ==&lt;br /&gt;
En Inside the global map:&lt;br /&gt;
&lt;br /&gt;
 INCLUDE(&#039;CWUTIL.INC&#039;),ONCE&lt;br /&gt;
&lt;br /&gt;
En Global Program Setup:&lt;br /&gt;
&lt;br /&gt;
 IF NOT BeginUnique(&#039;MiAPP.exe&#039;)&lt;br /&gt;
    BEEP(BEEP:SystemExclamation)&lt;br /&gt;
    YIELD()&lt;br /&gt;
    CASE MESSAGE(&#039;El programa ya esta ejecutando..&#039;,&#039;Ho, ho...&#039;,ICON:Asterisk,BUTTON:OK,BUTTON:OK,0)&lt;br /&gt;
    OF BUTTON:OK&lt;br /&gt;
       HALT()&lt;br /&gt;
    END&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Cambiar los atributos de un archivo ==&lt;br /&gt;
(Del FAQ de SoftVelocity)&lt;br /&gt;
1. En Global Embeds&lt;br /&gt;
&lt;br /&gt;
A. Before Global Includes:&lt;br /&gt;
&lt;br /&gt;
 LPCSTR EQUATE(CSTRING)&lt;br /&gt;
 DWORD EQUATE(ULONG)&lt;br /&gt;
&lt;br /&gt;
B. Global Data: Equates de los artributos&lt;br /&gt;
&lt;br /&gt;
 FILE_ATTRIBUTE_READONLY EQUATE(00000001h)&lt;br /&gt;
 FILE_ATTRIBUTE_HIDDEN EQUATE(00000002h)&lt;br /&gt;
 FILE_ATTRIBUTE_SYSTEM EQUATE(00000004h)&lt;br /&gt;
 FILE_ATTRIBUTE_ARCHIVE EQUATE(00000020h)&lt;br /&gt;
 FILE_ATTRIBUTE_NORMAL EQUATE(00000080h)&lt;br /&gt;
 FILE_ATTRIBUTE_TEMPORARY EQUATE(00000100h)&lt;br /&gt;
&lt;br /&gt;
C. Inside Global Map:&lt;br /&gt;
&lt;br /&gt;
 Module(&#039;Win32.lib&#039;)&lt;br /&gt;
 SetFileAttributes(*CSTRING, ULONG), BOOL, RAW, PASCAL, NAME(&#039;SetFileAttributesA&#039;)&lt;br /&gt;
 GetFileAttributes(*CSTRING), ULONG, RAW, PASCAL, NAME(&#039;GetFileAttributesA&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
2. En el codigo:&lt;br /&gt;
&lt;br /&gt;
 filename CSTRING(50)&lt;br /&gt;
&lt;br /&gt;
 filename = &#039;test.txt&#039;&lt;br /&gt;
 y# = GetFileAttributes(filename) ! Leer atributos&lt;br /&gt;
 y# = SetFileAttributes(filename, FILE_ATTRIBUTE_READONLY)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Crear directorios ==&lt;br /&gt;
Hay 2 opciones:&lt;br /&gt;
&lt;br /&gt;
1- Con Clarion (no sé si estarán estas funciones en versiones anteriores de Clarion)&lt;br /&gt;
&lt;br /&gt;
En &amp;quot;Inside the Global map&amp;quot;&lt;br /&gt;
 Include(&#039;clib.clw&#039;)&lt;br /&gt;
&lt;br /&gt;
En Local Data&lt;br /&gt;
 MiDir Cstring(256)&lt;br /&gt;
 Ret     Long&lt;br /&gt;
&lt;br /&gt;
En tu embed&lt;br /&gt;
 MiDir = &#039;Dirtest&#039;&lt;br /&gt;
 Ret = MkDir(MiDir)&lt;br /&gt;
&lt;br /&gt;
2- Con API&lt;br /&gt;
En Global Embeds - inside global map:&lt;br /&gt;
&lt;br /&gt;
 MODULE(&#039;&#039;)&lt;br /&gt;
  DirAccess(*CSTRING,SHORT=0),SHORT,RAW,NAME(&#039;_access&#039;),PROC&lt;br /&gt;
  MkDir(*CSTRING),SHORT,RAW,NAME(&#039;_mkdir&#039;),PROC&lt;br /&gt;
  DirRename(*CSTRING, *CSTRING), SHORT, RAW, NAME(&#039;_rename&#039;),PROC&lt;br /&gt;
  RmDir(*CSTRING),SHORT,RAW,NAME(&#039;_rmdir&#039;),PROC&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Y en tu embebido podés poner lo siguiente:&lt;br /&gt;
&lt;br /&gt;
 Var=&#039;O:\test&#039;      ! Ojo tiene que ser Cstring&lt;br /&gt;
 IF DirAccess(Var)&amp;lt;&amp;gt;0        !Si no existe&lt;br /&gt;
          MkDir(Var)                    !Crearlo&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
También se puede usar DirRename y RmDir para renombrar o borrar&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Modificar la posicion de un informe ==&lt;br /&gt;
&lt;br /&gt;
Este código permite modificar la posición inicial vertical y horizontal de un informe. Es útil cuando trabajamos con un formulario preimpreso o una hoja membretada y necesitamos desplazar la impresión sin necesidad de reconfigurar el programa.&lt;br /&gt;
&lt;br /&gt;
El punto embebido donde se ubica es After Open the Report.&lt;br /&gt;
&lt;br /&gt;
 !=====================================================&lt;br /&gt;
 ! MODIFICAR LA POSICION DEL INFORME&lt;br /&gt;
 ! El pie de página modificarlo sólo si se usa: &lt;br /&gt;
 ! Por ejemplo se pone ahí el Nro de página o algo así.&lt;br /&gt;
 ! No es necesario cambiar los atributos de las bandas &lt;br /&gt;
 ! de detalle adicionales que se usan en el informe.&lt;br /&gt;
 !-----------------------------------------------------&lt;br /&gt;
 DesplazamientoX =  getini(&#039;Parametros&#039;,|&lt;br /&gt;
                    &#039;DesplazamientoX&#039;,&#039;&#039;,&#039;.\prog.ini&#039;)&lt;br /&gt;
 DesplazamientoY = getini(&#039;Parametros&#039;,|&lt;br /&gt;
                    &#039;DesplazamientoY&#039;,&#039;&#039;,&#039;.\prog.ini&#039;)&lt;br /&gt;
 &lt;br /&gt;
 if DesplazamientoX or DesplazamientoY then&lt;br /&gt;
    SETTARGET(Report)&lt;br /&gt;
    x# = report{prop:Xpos}&lt;br /&gt;
    y# = report{prop:Ypos}&lt;br /&gt;
    x# += DesplazamientoX&lt;br /&gt;
    y# += DesplazamientoY&lt;br /&gt;
    target{prop:Xpos} = x#&lt;br /&gt;
    target{prop:Ypos} = y#&lt;br /&gt;
    settarget&lt;br /&gt;
 &lt;br /&gt;
    SETTARGET(Report,?Encabezado)&lt;br /&gt;
    x# = ?Encabezado{prop:Xpos}&lt;br /&gt;
    y# = ?Encabezado{prop:Ypos}&lt;br /&gt;
    x# += DesplazamientoX&lt;br /&gt;
    y# += DesplazamientoY&lt;br /&gt;
    ?Encabezado{prop:Xpos} = x#&lt;br /&gt;
    ?Encabezado{prop:Ypos} = y#&lt;br /&gt;
    settarget&lt;br /&gt;
 &lt;br /&gt;
    SETTARGET(Report,?PiePagina)&lt;br /&gt;
    x# = ?PiePagina{prop:Xpos}&lt;br /&gt;
    y# = ?PiePagina{prop:Ypos}&lt;br /&gt;
    x# += DesplazamientoX&lt;br /&gt;
    y# += DesplazamientoY&lt;br /&gt;
    ?PiePagina{prop:Xpos} = x#&lt;br /&gt;
    ?PiePagina{prop:Ypos} = y#&lt;br /&gt;
    SETTARGET&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
== Generar un informe a partir de una cola en memoria ==&lt;br /&gt;
&lt;br /&gt;
(Sin pasar por el template)&lt;br /&gt;
&lt;br /&gt;
Se puede definir en el módulo en la parte de DATA el reporte necesario y mandarlo a imprimir.&lt;br /&gt;
&lt;br /&gt;
En DATA SECTION&lt;br /&gt;
&lt;br /&gt;
 WMFQue        QUEUE&lt;br /&gt;
 PageImage       STRING(64)&lt;br /&gt;
               END&lt;br /&gt;
 ReportRunDate LONG&lt;br /&gt;
 ReportRunTime LONG&lt;br /&gt;
 !!&amp;gt; Report (portrait) &lt;br /&gt;
 Report  REPORT,AT(1000,2000,6000,7000),THOUS,PRE(RPT),FONT(&#039;Arial&#039;,10)&lt;br /&gt;
         HEADER,AT(1000,1000,6000,1000)&lt;br /&gt;
         END&lt;br /&gt;
 Detail   DETAIL&lt;br /&gt;
         END&lt;br /&gt;
         FOOTER,AT(1000,9000,6000,1000)&lt;br /&gt;
         END&lt;br /&gt;
         FORM,AT(1000,1000,6000,9000)&lt;br /&gt;
         END&lt;br /&gt;
       END&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
Luego, en el botón que imprime,  poner el siguiente código:&lt;br /&gt;
&lt;br /&gt;
 ReportRunDate = today()&lt;br /&gt;
 ReportRunDate = today()&lt;br /&gt;
 ReportRunTime = clock()&lt;br /&gt;
 OPEN(Report)&lt;br /&gt;
 LOOP x# = 1 to records(ColaError)&lt;br /&gt;
    get(ColaError,x#)&lt;br /&gt;
    PRINT(rpt:DetalleUno)&lt;br /&gt;
 END&lt;br /&gt;
 ENDPAGE(Report)&lt;br /&gt;
 ReportPreview(WMFQue)&lt;br /&gt;
 IF GlobalResponse = RequestCompleted&lt;br /&gt;
    Report{PROP:FlushPreview} = True&lt;br /&gt;
 END&lt;br /&gt;
 CLOSE(Report)&lt;br /&gt;
 FREE(WMFQue)&lt;br /&gt;
&lt;br /&gt;
Este proceso usa el Print Preview de Clarion para visualizar el informe, por consiguiente, la apariencia es totalmente normal para el usuario&lt;br /&gt;
&lt;br /&gt;
== Proceso BATCH que funcione sincronizado con el TIMER de la ventana. ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En un proceso BATCH hecho a mano se puede operar en forma similar al report o al proccess, para eso hay que definir una pantalla que tenga el atributo TIMER (un valor de 1 es suficiente). El código fuente quedaría de la siguiente manera:&lt;br /&gt;
&lt;br /&gt;
 open(PantaTrabaja)&lt;br /&gt;
 Accept&lt;br /&gt;
 case event()&lt;br /&gt;
   of event:openwindow&lt;br /&gt;
      Display()&lt;br /&gt;
      ! Abrir pantalla, Abrir archivos, hacer el set &lt;br /&gt;
      ! Inicial&lt;br /&gt;
   of event:timer&lt;br /&gt;
      ?Mensaje{prop:text} = &#039;Procesando...&#039;&lt;br /&gt;
      display(?Mensaje)&lt;br /&gt;
      loop 2 times&lt;br /&gt;
         next(archivo)&lt;br /&gt;
         if errorcode() then &lt;br /&gt;
            FinArchivo = true&lt;br /&gt;
            Break&lt;br /&gt;
         end&lt;br /&gt;
         ! HACER AQUÍ ALGÚN PROCESO..&lt;br /&gt;
      end&lt;br /&gt;
   of event:closewindow&lt;br /&gt;
      Setcursor()&lt;br /&gt;
      Close(PantaTrabaja)&lt;br /&gt;
      Break&lt;br /&gt;
   End!case&lt;br /&gt;
 &lt;br /&gt;
 case field()&lt;br /&gt;
   of ?BotonCancelar&lt;br /&gt;
      if event() = event:accepted then&lt;br /&gt;
         message(&#039;Proceso cancelado por el usuario.&#039;)&lt;br /&gt;
         post(event:closewindow)&lt;br /&gt;
      end&lt;br /&gt;
   End&lt;br /&gt;
 end!accept&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Drop Combo a mano, con opción a todos y recuerdo de último elegido ==&lt;br /&gt;
&lt;br /&gt;
En muchos de mis informes, cuando pido parámetros asumo lo siguiente, por ejemplo: Si el código de cliente es igual a 0 (cero) se imprimen todos los clientes, sino, se imprime uno solo. Este código permite armar lo mismo con un DropCombo, agregando la opción TODOS LOS XXXX (código Cero).&lt;br /&gt;
&lt;br /&gt;
1. Definir una cola con la siguiente estructura ( por ejemplo ):&lt;br /&gt;
&lt;br /&gt;
 Cola     QUEUE,PRE(col)&lt;br /&gt;
 descri     STRING(20)&lt;br /&gt;
 codigo     SHORT&lt;br /&gt;
          END&lt;br /&gt;
	&lt;br /&gt;
2. Definir una variable local llamada por ejemplo&lt;br /&gt;
&lt;br /&gt;
 Combo1     STRING(20)&lt;br /&gt;
	&lt;br /&gt;
3.	En la pantalla definir una drop combo a mano, en el campo FROM poner el nombre de la COLA, y en el USE poner Combo1 ( no poner ?Combo1 )&lt;br /&gt;
	&lt;br /&gt;
4.	Cargar la cola según corresponda después de abrir archivos, poniendo como último dato el código 0 y el texto &#039;TODOS LOS REGISTROS&#039; y hacer un ADD(Cola,1) para que quede al principio.&lt;br /&gt;
	&lt;br /&gt;
5.	Definir una variable global ( o local estática) que va a guardar el resultado elegido:&lt;br /&gt;
&lt;br /&gt;
 Glo:codigo    short     &lt;br /&gt;
	&lt;br /&gt;
6.	En el evento open window, ANTES de abrir la ventana va el siguiente código&lt;br /&gt;
&lt;br /&gt;
 loop x# = 1 to records(Cola)&lt;br /&gt;
   get(Cola,x#)&lt;br /&gt;
   if col:codigo = glo:codigo then break.&lt;br /&gt;
 end&lt;br /&gt;
 Combo1 = col:descri&lt;br /&gt;
 ?Combo1{prop:selected} = x#&lt;br /&gt;
	&lt;br /&gt;
7.	Al hacer esto, el combo se abre posicionado en el último elemento elegido o en TODOS LOS REGISTROS  si es la primera vez.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== En un report, poner los totales en otra página ==&lt;br /&gt;
&lt;br /&gt;
En algún informe, se puede solicitar como parámetro la opción de imprimir los totales correspondientes en una página nueva. Para ello, después de abrir el report:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 if glo:totpag then&lt;br /&gt;
    settarget(report)&lt;br /&gt;
    ?TituloTotalCategoria{prop:pagebefore} = 1&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
== En un report, cambiar el color de un campo según alguna condición ==&lt;br /&gt;
&lt;br /&gt;
Si durante la impresión de un informe se desea cambiar algún atributo (tal como el color) de un campo puede hacer lo siguiente (antes de imprimir el detalle):&lt;br /&gt;
&lt;br /&gt;
 if cl:impotota &amp;lt;&amp;gt; cl:totacalc&lt;br /&gt;
    settarget(report)&lt;br /&gt;
    ?ARC:importe{PROP:FONTCOLOR} = COLOR:RED&lt;br /&gt;
    settarget(ProgressWindow)&lt;br /&gt;
 else&lt;br /&gt;
    settarget(report)&lt;br /&gt;
    ?ARC:importe{PROP:FONTCOLOR} = COLOR:NONE&lt;br /&gt;
    settarget(ProgressWindow)&lt;br /&gt;
 end&lt;br /&gt;
 print(rpt:Detalle)  ! Imprimir la línea de detalle&lt;br /&gt;
&lt;br /&gt;
== Cerrar todas las ventanas abiertas ==&lt;br /&gt;
 LOOP Thrd# = 2 TO 64 !1 es el Frame&lt;br /&gt;
     POST(Event:CloseWindow,,Thrd#)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Abrir cualquier archivo con ShellExecute ==&lt;br /&gt;
Hay varios templates gratis que implementan Shellexecute, por ejemplo:&lt;br /&gt;
http://www.sterlingdata.com/shellex.htm&lt;br /&gt;
&lt;br /&gt;
Para hacerlo con codigo:&lt;br /&gt;
&lt;br /&gt;
En Global-embed &#039;Inside the Global Map&#039;:&lt;br /&gt;
 Module(&#039;Win32.lib&#039;)&lt;br /&gt;
 ShellExecute(Long,*CString,*CString,*CString,*CString,Short),UShort,PASCAL,RAW,NAME(&#039;ShellExecuteA&#039;)&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
En Local Data&lt;br /&gt;
 LOC:Handle LONG&lt;br /&gt;
 LOC:Op     CSTRING (255)&lt;br /&gt;
 LOC:File   CSTRING (255)&lt;br /&gt;
 LOC:Path   CSTRING (255)&lt;br /&gt;
 LOC:Param  CSTRING (255)&lt;br /&gt;
 LOC:Show   LONG&lt;br /&gt;
 LOC:RetHandle LONG&lt;br /&gt;
&lt;br /&gt;
En el embed&lt;br /&gt;
 LOC:Handle = 0{PROP:Handle}&lt;br /&gt;
 LOC:Op     = &#039;Open&#039;&lt;br /&gt;
 LOC:File   = &#039;C:\TEST.TXT&#039;&lt;br /&gt;
 LOC:Path   = PATH()&lt;br /&gt;
 LOC:Param  = &#039; &#039;&lt;br /&gt;
 LOC:Show   = 1&lt;br /&gt;
 LOC:RetHandle =  ShellExecute(LOC:Handle,LOC:Op,LOC:File,LOC:Param,LOC:Path,LOC:Show)&lt;br /&gt;
 If LOC:Rethandle &amp;lt;&amp;gt; 0 Then&lt;br /&gt;
   Message(&#039;Error&#039;,&#039;Error&#039;,Icon:Exclamation)&lt;br /&gt;
 End&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Abrir una pagina WEB con ShellExecute ==&lt;br /&gt;
(Ver declaraciones del API y variables en el ejemplo anterior)&lt;br /&gt;
&lt;br /&gt;
En el embed&lt;br /&gt;
 LOC:Handle = 0{PROP:Handle}&lt;br /&gt;
 LOC:Op     = &#039;Open&#039;&lt;br /&gt;
 LOC:File   = &#039;http://www.evolutionconsulting.com.ar&#039;&lt;br /&gt;
 LOC:Path   = &#039; &#039;&lt;br /&gt;
 LOC:Param  = &#039; &#039;&lt;br /&gt;
 LOC:Show   = 1&lt;br /&gt;
 LOC:RetHandle = ShellExecute(LOC:Handle,LOC:Op,LOC:File,LOC:Param,LOC:Path,LOC:Show)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Convertir un LONG a un String Binario ==&lt;br /&gt;
 binario=&#039;&#039; !binario es CSTRING&lt;br /&gt;
 LOOP F# = 1 TO 32&lt;br /&gt;
    IF BAND(abinario, 1) !abinario es LONG&lt;br /&gt;
        binario =  &#039;1&#039; &amp;amp; binario&lt;br /&gt;
    ELSE&lt;br /&gt;
        binario = &#039;0&#039; &amp;amp; binario&lt;br /&gt;
    END&lt;br /&gt;
    abinario = abinario / 2&lt;br /&gt;
    if abinario = 0 then break.&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Convertir un string binario a LONG ==&lt;br /&gt;
Para volver del CSTRING al LONG seria simplemente&lt;br /&gt;
 X# = EVALUATE (binario &amp;amp; &#039;b&#039;)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Copiar la QUEUE (solo lo que se esta viendo) de un browse a Excel ==&lt;br /&gt;
 Copiar=&#039;&#039; !Cstring de 4.000.000&lt;br /&gt;
 LOOP C#= 1 TO BRW1.View{Prop:Fields}&lt;br /&gt;
 !Primero una fila con los titulos&lt;br /&gt;
     Copiar= Copiar &amp;amp; ?Browse:1{PropList:Header,C#} &amp;amp; &#039;&amp;lt;9&amp;gt;&#039;&lt;br /&gt;
 END&lt;br /&gt;
 Copiar= Copiar &amp;amp;&#039;&amp;lt;13,10&amp;gt;&#039;&lt;br /&gt;
&lt;br /&gt;
 LOOP F# = 1 TO RECORDS(BRW1.Q)&lt;br /&gt;
    LOOP C#= 1 TO BRW1.View{Prop:Fields}&lt;br /&gt;
        GET(BRW1.Q, F#)&lt;br /&gt;
        Copiar= Copiar &amp;amp; FORMAT(WHAT(BRW1.Q, C#), ?Browse:1{PropList:Picture,C#}) &amp;amp; &#039;&amp;lt;9&amp;gt;&#039;&lt;br /&gt;
    END&lt;br /&gt;
    Copiar= Copiar &amp;amp;&#039;&amp;lt;13,10&amp;gt;&#039;&lt;br /&gt;
 END&lt;br /&gt;
 SETCLIPBOARD(Copiar)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Copiar el VIEW (cuidado: se lee todo) de un browse a Excel ==&lt;br /&gt;
 Copiar=&#039;&#039; !CSTRNG de 4.000.000&lt;br /&gt;
 LOOP C#= 1 TO BRW1.View{Prop:Fields}&lt;br /&gt;
     Copiar= Copiar &amp;amp; ?Browse:1{PropList:Header,C#} &amp;amp; &#039;&amp;lt;9&amp;gt;&#039;&lt;br /&gt;
 END&lt;br /&gt;
 Copiar= Copiar &amp;amp;&#039;&amp;lt;13,10&amp;gt;&#039;&lt;br /&gt;
 &lt;br /&gt;
 SET (BRW1.View)&lt;br /&gt;
 LOOP&lt;br /&gt;
    NEXT(BRW1.View)&lt;br /&gt;
    IF ERRORCODE() THEN BREAK.&lt;br /&gt;
    BRW1.SetQueueRecord&lt;br /&gt;
    LOOP C#= 1 TO BRW1.View{Prop:Fields}&lt;br /&gt;
        Copiar= Copiar &amp;amp; FORMAT(WHAT(BRW1.Q, C#), ?Browse:1{PropList:Picture,C#}) &amp;amp; &#039;&amp;lt;9&amp;gt;&#039;&lt;br /&gt;
    END&lt;br /&gt;
    Copiar= Copiar &amp;amp;&#039;&amp;lt;13,10&amp;gt;&#039;&lt;br /&gt;
 END&lt;br /&gt;
 SETCLIPBOARD(Copiar)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Para que no lea todo el contenido del archivo, sino que procese estrictamente lo mismo que muestra el browse, basta con agregar la antes del BRW1.SetQueueRecord el llamado a BRW1.ValidateRecord().&lt;br /&gt;
  ...&lt;br /&gt;
  LOOP&lt;br /&gt;
    NEXT(BRW1.View)&lt;br /&gt;
    IF ERRORCODE() THEN BREAK.&lt;br /&gt;
    IF BRW1.ValidateRecord() THEN CYCLE.&lt;br /&gt;
    BRW1.SetQueueRecrod&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
Daniel Ruzo&lt;br /&gt;
&lt;br /&gt;
== Mostrar iconos en un listbox desde una queue ==&lt;br /&gt;
Ejemplo: marcar en una cola de memoria si un empleado tiene entrada y/o salida&lt;br /&gt;
&lt;br /&gt;
Primero agregar los iconos al Project&lt;br /&gt;
&lt;br /&gt;
En el Codigo:&lt;br /&gt;
&lt;br /&gt;
 cola_empleados    queue, pre(que)&lt;br /&gt;
 nombre        string(30)&lt;br /&gt;
 entro          long&lt;br /&gt;
 entro_ico    long&lt;br /&gt;
 salio          long&lt;br /&gt;
 salio_ico    long&lt;br /&gt;
                         end&lt;br /&gt;
&lt;br /&gt;
En el list:&lt;br /&gt;
&lt;br /&gt;
primer campo: nombre&lt;br /&gt;
&lt;br /&gt;
segundo campo: entro, picture @p p, iconized, transparente&lt;br /&gt;
&lt;br /&gt;
tercer campo: salio, picture @p p, iconized, transparente&lt;br /&gt;
&lt;br /&gt;
En el init de la pantalla:&lt;br /&gt;
&lt;br /&gt;
 ?list{prop:iconlist,1} = &#039;~no.ico&#039;&lt;br /&gt;
 ?list{prop:iconlist,2} = &#039;~si.ico&#039;&lt;br /&gt;
&lt;br /&gt;
Donde cargo la cola y la muestro:&lt;br /&gt;
&lt;br /&gt;
 if condicion  (si NO hay entrada)&lt;br /&gt;
     que:entro_ico = 1    ! icono de no&lt;br /&gt;
 else&lt;br /&gt;
     que:entro_ico = 2    !icono de si&lt;br /&gt;
 end&lt;br /&gt;
 if condicion  (si NO hay salida)&lt;br /&gt;
     que:salio_ico = 1    ! icono de no&lt;br /&gt;
 else&lt;br /&gt;
     que:salio_ico = 2    !icono de si&lt;br /&gt;
 end&lt;br /&gt;
 ! otras asignaciones&lt;br /&gt;
 add(cola_empleados)&lt;br /&gt;
 !&lt;br /&gt;
 display(?list)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Calcular Días Hábiles ==&lt;br /&gt;
&lt;br /&gt;
Ante todo necesitas una tabla de feriados, con al menos un campo llamado,&lt;br /&gt;
por ej., diaferiado y una clave por dicho campo.&lt;br /&gt;
&lt;br /&gt;
Luego podés hacer lo siguiente&lt;br /&gt;
&lt;br /&gt;
 habiles# = 0&lt;br /&gt;
 loop dia# = FechaInicial to FechaFinal&lt;br /&gt;
  if (Dia# % 7) = 0 then cycle. ! porque es domingo&lt;br /&gt;
  if (Dia# % 7) = 6 then cycle. ! porque es sabado&lt;br /&gt;
  !&lt;br /&gt;
  ! busco si es feriado&lt;br /&gt;
  !&lt;br /&gt;
  clear(feriado:record)&lt;br /&gt;
  feriado:diaferiado = dia#&lt;br /&gt;
  if access:feriado.fetch(Feriado:PorDia) = level:benign then cycle. !porque es feriado&lt;br /&gt;
  !&lt;br /&gt;
  habiles# += 1&lt;br /&gt;
 end!loop&lt;br /&gt;
 corridos# = fechafinal - fechainicial&lt;br /&gt;
&lt;br /&gt;
Si los cálculos que vas a realizar son muchos y continuos, sería conveniente&lt;br /&gt;
que la tabla de feriados la cargues en una queue y realices las búsquedas&lt;br /&gt;
sobre ella.&lt;br /&gt;
&lt;br /&gt;
Adrian Gallegos - Mega Sistemas S.R.L.&lt;br /&gt;
&lt;br /&gt;
Otra opción: Días Hábiles del mes - Rutina que quita los días sábados y domingos del mes&lt;br /&gt;
&lt;br /&gt;
CONTAR_DIAS ROUTINE&lt;br /&gt;
    LOC:DIAS = 0&lt;br /&gt;
    tope# = 1&lt;br /&gt;
    LOOP UNTIL DAY(LOC:FECHA) = tope#&lt;br /&gt;
    CASE  LOC:FECHA % 7&lt;br /&gt;
      of  0   ! Domingo&lt;br /&gt;
       LOC:FECHA = LOC:FECHA - 1&lt;br /&gt;
       CYCLE&lt;br /&gt;
      of  6    ! sabado&lt;br /&gt;
       LOC:FECHA = LOC:FECHA - 1&lt;br /&gt;
       CYCLE&lt;br /&gt;
      ELSE&lt;br /&gt;
       LOC:DIAS += 1&lt;br /&gt;
       LOC:FECHA = LOC:FECHA - 1&lt;br /&gt;
     END !CASE&lt;br /&gt;
   END !LOOP&lt;br /&gt;
   IF  LOC:FECHA % 7 = 0 or  LOC:FECHA % 7 = 6 THEN  !si el primero es feriado&lt;br /&gt;
         ! nada&lt;br /&gt;
          else&lt;br /&gt;
         LOC:DIAS  += 1&lt;br /&gt;
   END !IF&lt;br /&gt;
&lt;br /&gt;
Julio César Britez&lt;br /&gt;
&lt;br /&gt;
== Último día del mes y cantidad de días (Lunes, Martes, etc) entre 2 Fechas ==&lt;br /&gt;
Incluye el truco de saber el último día del mes: en la parte &amp;quot; Date(4,1,2005)-1 &amp;quot; significa que le resto 1 al primer día del mes siguiente, lo cual es una forma de obtener el último día del mes actual...&lt;br /&gt;
&lt;br /&gt;
 Loop Fecha# = Date(3,1,2005) TO (Date(4,1,2005)-1)&lt;br /&gt;
    EXECUTE (Fecha# % 7) + 1&lt;br /&gt;
          Domingo# +=1&lt;br /&gt;
          Lunes# +=1&lt;br /&gt;
          Martes# +=1&lt;br /&gt;
          Miercoles# +=1&lt;br /&gt;
          Jueves# +=1&lt;br /&gt;
          Viernes# +=1&lt;br /&gt;
          Sabado# +=1&lt;br /&gt;
    END&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Fecha en Español (por ejemplo en el Frame)==&lt;br /&gt;
Si quieres que funcione independientemente de como este configurado windows,&lt;br /&gt;
lo mejor es poner este embed, al final de WindowManager.Init&lt;br /&gt;
&lt;br /&gt;
 EXECUTE (TODAY() % 7) + 1&lt;br /&gt;
 Dia&amp;quot;= &#039;Domingo&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Lunes&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Martes&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Miercoles&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Jueves&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Viernes&#039;&lt;br /&gt;
 Dia&amp;quot;= &#039;Sabado&#039;&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
 EXECUTE (MONTH(TODAY()))&lt;br /&gt;
 Mes&amp;quot; = &#039;Enero&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Febrero&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Marzo&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Abril&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Mayo&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Junio&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Julio&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Agosto&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Septiembre&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Octubre&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Noviembre&#039;&lt;br /&gt;
 Mes&amp;quot; = &#039;Diciembre&#039;&lt;br /&gt;
 END&lt;br /&gt;
 AppFrame{Prop:StatusText,1} = CLIP(Dia&amp;quot;) &amp;amp; &#039; &#039; &amp;amp; DAY(TODAY()) &amp;amp; &#039; de &#039; &amp;amp;&lt;br /&gt;
 CLIP(Mes&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
 Dia&amp;quot; = Choose(((TODAY() % 7) + 1),&#039;Domingo&#039;,&#039;Lunes&#039;,&#039;Martes&#039;,&#039;Miercoles&#039;,&#039;Jueves&#039;,&#039;Viernes&#039;,&#039;Sabado&#039;)&lt;br /&gt;
&lt;br /&gt;
Javier A. Junca Barreto [http://www.sicya.com (SICyA Software - Colombia)]&lt;br /&gt;
&lt;br /&gt;
== Obtener la fecha del server ==&lt;br /&gt;
Este código lee la fecha del servidor, usando el truco de crear un archivo en el servidor y leer la fecha y hora de los atributos:&lt;br /&gt;
&lt;br /&gt;
 !Data&lt;br /&gt;
 LOC:TMP STRING(254),STATIC&lt;br /&gt;
 TMP FILE,DRIVER(&#039;Ascii&#039;),CREATE,NAME(LOC:TMP)&lt;br /&gt;
 RECORD  RECORD&lt;br /&gt;
 LIN STRING(1)&lt;br /&gt;
    .&lt;br /&gt;
    .&lt;br /&gt;
 FILS   QUEUE(File:queue),PRE(FIL)&lt;br /&gt;
       END&lt;br /&gt;
&lt;br /&gt;
 CODE&lt;br /&gt;
  LOC:TMP = PATH()&amp;amp;&#039;\TMP&#039;&amp;amp;RANDOM(10000,99999)&amp;amp;&#039;.TMP&#039;&lt;br /&gt;
  CREATE(TMP)&lt;br /&gt;
  IF NOT ERRORCODE()&lt;br /&gt;
    DIRECTORY(FILS,LOC:TMP,0)&lt;br /&gt;
    REMOVE(TMP)&lt;br /&gt;
    GET(FILS,1)&lt;br /&gt;
    IF TODAY() &amp;lt;&amp;gt; FIL:DATE OR ABS(CLOCK()-FIL:TIME) &amp;gt; 100&lt;br /&gt;
 !FECHA DIFERENTE O 1 SEGUNDO DE DESFASE&lt;br /&gt;
      SETTODAY(FIL:DATE)&lt;br /&gt;
      SETCLOCK(FIL:TIME)&lt;br /&gt;
    END&lt;br /&gt;
  ELSE&lt;br /&gt;
    REMOVE(TMP)&lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
Carlos Gutierrez&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Con SQL&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
La sugerencia de Carlos es muy buena. Si estás usando SQL o drivers ODBC, la otra opción es preguntarle la fecha al motor de base de datos.&lt;br /&gt;
&lt;br /&gt;
La forma genérica de hacerlo es:&lt;br /&gt;
 temp{prop:sql}=&#039;SELECT {fn curdate() }&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Con NET TIME&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Posteado por Diego Sánchez al foro.&lt;br /&gt;
 Run(&#039;NET TIME \\Server_Name /SET /Y&#039;)&lt;br /&gt;
Reemplazar  &amp;quot;Server_Name&amp;quot;  por el nombre del servidor o equipo del cual se desea obtener la hora&lt;br /&gt;
Fue posteado originalmente por un NICOLAS VEILLEUX nveilleux@nbautomation.com, en el foro comp.lang.clarion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Llamar a un Stored Procedure ==&lt;br /&gt;
El código sería mas o menos asi:&lt;br /&gt;
 L:Query = &#039;CALL NombreDelStored (&#039;&#039;&#039; &amp;amp; FORMAT(ParamFecha,@D12) &amp;amp; &#039;&#039;&#039;, &#039;&#039;&#039; &amp;amp;&lt;br /&gt;
 FORMAT(OtraFecha,@D12) &amp;amp; &#039;&#039;&#039;, &#039; &amp;amp; OtroParam1 &amp;amp;&#039;, &#039; &amp;amp; OtroParam2 &amp;amp;&#039;, &#039; &amp;amp;&lt;br /&gt;
 OtroParam3 &amp;amp;&#039;  )&#039;&lt;br /&gt;
&lt;br /&gt;
 ResSQL{prop:sql} = L:Query&lt;br /&gt;
 Loop Until Access:ResSql.Next()&lt;br /&gt;
    MiVariable = R:Campo1&lt;br /&gt;
    etc     = R:Campo2&lt;br /&gt;
 ....&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
En la tabla auxiliar ResSQL obtienes el resultado del último SELECT que&lt;br /&gt;
tenga el Stored Procedure.&lt;br /&gt;
&lt;br /&gt;
Para mas detalles ver el documento sobre SQL Embebido [http://templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
También recomiendo leer el help &amp;quot;MSSQL Accelerator Calling a Stored&lt;br /&gt;
Procedure&amp;quot;. Ahi está explicado además el uso de valores de retorno y parámetros de salida.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Encriptación básica ==&lt;br /&gt;
Encriptación / desencriptación básica de un campo usando el metodo XOR.&lt;br /&gt;
 !la primera vez encripta&lt;br /&gt;
 !al volver a aplicar el algoritmo con la misma&lt;br /&gt;
 !Clave de encriptado: desencripta&lt;br /&gt;
 X# = 1&lt;br /&gt;
 loop Y# = 1 to Len(Campo)&lt;br /&gt;
   Campo [Y#] = chr(bxor(val(Campo[Y#]), val(ClaveEncriptado[X#])))&lt;br /&gt;
   X# += 1&lt;br /&gt;
   if X# &amp;gt; len (ClaveEncriptado) then X# = 1.&lt;br /&gt;
 end&lt;br /&gt;
 display&lt;br /&gt;
&lt;br /&gt;
 !Campo y ClaveEncriptado son campos CString&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Generar un archivo de Texto a máxima velocidad==&lt;br /&gt;
Estas son las APIs para generar un archivo de texto sin necesidad de declararlo en el Diccionario.&lt;br /&gt;
&lt;br /&gt;
Además es muy rápido, ideal para exportaciones.&lt;br /&gt;
&lt;br /&gt;
En Global - Inside Global map:&lt;br /&gt;
&lt;br /&gt;
 MODULE(&#039;Windows API&#039;)&lt;br /&gt;
  _lcreat(*CSTRING,SIGNED),SIGNED,PASCAL,RAW&lt;br /&gt;
  _hwrite(SIGNED,*CSTRING,LONG),LONG,PASCAL,RAW&lt;br /&gt;
  _lclose(SIGNED),SIGNED,PASCAL&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Por ejemplo para guardar el contenido de un control Text&lt;br /&gt;
&lt;br /&gt;
 IF NOT FILEDIALOG(&#039;Guardar como&#039;,FileName,&#039;Text|*.TXT|Source|*.CLW&#039;,FILE:Save + FILE:LongName)&lt;br /&gt;
    CYCLE&lt;br /&gt;
 END&lt;br /&gt;
 F# = _lcreat(FileName,0)&lt;br /&gt;
 X# = _hwrite(F#,Texto,LEN(Texto))&lt;br /&gt;
 X# = _lclose(F#)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Efecto BLINK en un campo ==&lt;br /&gt;
Tienes que crear un timer en la ventana, para eso ponle cada cuanto se va a&lt;br /&gt;
ejecutar en la propiedad timer de la ventana. Son centesimas de seg, asi que&lt;br /&gt;
si le pones 50 por ejemplo tu campo va a titilar 2 veces por segundo.&lt;br /&gt;
&lt;br /&gt;
Luego cierra la ventana, vuelve a entrar y vas a encontrar un evento timer&lt;br /&gt;
de la ventana en los embeds.&lt;br /&gt;
&lt;br /&gt;
Window Events --&amp;gt; Timer&lt;br /&gt;
 if ?campo{prop:background} = COLOR:WHITE&lt;br /&gt;
    ?campo{prop:background} = COLOR:SILVER&lt;br /&gt;
 else&lt;br /&gt;
    ?campo{prop:background} = COLOR:WHITE&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Función para calcular dígito verificador en CUIT ==&lt;br /&gt;
- La siguiente función devuelve el numero de CUIT con el dígito verificador&lt;br /&gt;
correcto.&lt;br /&gt;
- El parámetro que recibe es el numero de CUIT a revisar incluyendo el&lt;br /&gt;
dígito verificador.&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  CuitCliente=&#039;20-15433984-6&#039;&lt;br /&gt;
  IF Cuit(CuitCliente)=CuitCliente THEN&lt;br /&gt;
    MESSAGE(&#039;Digito verificador correcto&#039;)&lt;br /&gt;
  ELSE&lt;br /&gt;
    MESSAGE(&#039;Digito verificador incorrecto&#039;)&lt;br /&gt;
  END&lt;br /&gt;
  ...&lt;br /&gt;
 &lt;br /&gt;
 Cuit         PROCEDURE(cuit1)&lt;br /&gt;
 cuit2        STRING(255)&lt;br /&gt;
 digver       LONG&lt;br /&gt;
 lon          LONG&lt;br /&gt;
 fac          LONG&lt;br /&gt;
 car          STRING(1)&lt;br /&gt;
   &lt;br /&gt;
  CODE&lt;br /&gt;
  cuit2=cuit1&lt;br /&gt;
  digver=0&lt;br /&gt;
  fac=2&lt;br /&gt;
  lon=LEN(CLIP(cuit2))&lt;br /&gt;
  LOOP i#=lon-1 TO 1 BY -1&lt;br /&gt;
    car=SUB(cuit2,i#,1)&lt;br /&gt;
    IF car&amp;lt;&#039;0&#039; OR car&amp;gt;&#039;9&#039; THEN&lt;br /&gt;
      CYCLE&lt;br /&gt;
    .&lt;br /&gt;
    digver=digver+(car*fac)&lt;br /&gt;
    fac+=1&lt;br /&gt;
    IF fac&amp;gt;7 THEN&lt;br /&gt;
      fac=2&lt;br /&gt;
    .&lt;br /&gt;
  .&lt;br /&gt;
  digver=11-(digver%11)&lt;br /&gt;
  IF digver&amp;gt;9 THEN&lt;br /&gt;
    digver=0&lt;br /&gt;
  .&lt;br /&gt;
  cuit2=SUB(cuit2,1,lon-1) &amp;amp; FORMAT(digver,@n01)&lt;br /&gt;
  RETURN(cuit2)&lt;br /&gt;
&lt;br /&gt;
Este codigo esta en la documentacion del template de Impresoras Fiscales&lt;br /&gt;
(BIGSYS TEMPLATES) del amigo Juan Carlos Rodríguez&lt;br /&gt;
&lt;br /&gt;
== Validar Email ==&lt;br /&gt;
Puedes hacerlo con MATCH, el cual devuelve 1 o 0 si el mail no es valido.&lt;br /&gt;
Ejemplo:&lt;br /&gt;
&lt;br /&gt;
 X# =  MATCH(UPPER(CLIP(locemail)),|&lt;br /&gt;
 &#039;^[-A-Z0-9._]+@{{[-A-Z0-9._]+.}+[A-Z][A-Z][A-Z]?[A-Z]?$&#039;, Match:Regular)&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Restar Horas==&lt;br /&gt;
Para sacar la diferencia entre horas es simplemente:&lt;br /&gt;
 resultado = hora2  - hora + 1&lt;br /&gt;
&lt;br /&gt;
El +1 es porque sino que faltaria un segundo cuando muestres el resultado (en formato @T6, por ej)&lt;br /&gt;
&lt;br /&gt;
Si Hora2 es del dia siguiente, la cuenta seria:&lt;br /&gt;
 resultado = (hora2 +(100*60*60*24)) - hora + 1&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
== Digito Verificador para 5 digitos ==&lt;br /&gt;
&lt;br /&gt;
Si tenes un numero de 5 digitos y deses verificar que el mismo es ingresado correctamente podes usar este codigo que genera un digito verificador&lt;br /&gt;
&lt;br /&gt;
Crea una funcion que tenga un parametro (numero a verificar) y retorne el digito verificador correspondiente ejem: DigitoV5(LONG xNumero),BYTE&lt;br /&gt;
&lt;br /&gt;
  loc:Numero = xNumero&lt;br /&gt;
 &lt;br /&gt;
  loc:Valor = (loc:Numero[1]*5) + |&lt;br /&gt;
              (loc:Numero[2]*4) + |&lt;br /&gt;
              (loc:Numero[3]*3) + |&lt;br /&gt;
              (loc:Numero[4]*2) + |&lt;br /&gt;
              (loc:Numero[5]*7)&lt;br /&gt;
 &lt;br /&gt;
  IF (loc:Valor%5) + 1 = 0 OR (loc:Valor%5) + 1 = 1&lt;br /&gt;
    loc:Digito = 0&lt;br /&gt;
  ELSE&lt;br /&gt;
    loc:Digito = 6 - ((loc:Valor%5) + 1)&lt;br /&gt;
  END&lt;br /&gt;
 &lt;br /&gt;
  RETURN loc:Digito&lt;br /&gt;
&lt;br /&gt;
Ruben Garcia [http://www.dipsarg.com (DiPS)]&lt;br /&gt;
&lt;br /&gt;
== Digito Verificador para Cualquier Longitud ==&lt;br /&gt;
&lt;br /&gt;
Si no sabes que longitud puede tener el numero a verificar podes probar verificarla con este codigo&lt;br /&gt;
&lt;br /&gt;
Crea una funcion cuyo parametro es el numero a verificar y retorne el digito verificador. Ej. DigitoV(STRING xNumero),BYTE&lt;br /&gt;
&lt;br /&gt;
  !Inicializa&lt;br /&gt;
  loc:Numero   = xNumero&lt;br /&gt;
  loc:Valor    = 0&lt;br /&gt;
  loc:Multiplo = 1&lt;br /&gt;
 &lt;br /&gt;
  !Barrido y calculo&lt;br /&gt;
  LOOP loc:Posicion = LEN(CLIP(loc:Numero)) TO 1 BY -1&lt;br /&gt;
    loc:Multiplo += 1&lt;br /&gt;
    IF loc:Multiplo &amp;gt; 7&lt;br /&gt;
      loc:Multiplo = 2&lt;br /&gt;
    END&lt;br /&gt;
    loc:Valor += loc:Numero[loc:Posicion] * loc:Multiplo&lt;br /&gt;
  END&lt;br /&gt;
 &lt;br /&gt;
  loc:Digito = loc:Valor % 11&lt;br /&gt;
 &lt;br /&gt;
  IF loc:Digito = 10&lt;br /&gt;
    loc:Digito = 0&lt;br /&gt;
  END&lt;br /&gt;
 &lt;br /&gt;
  RETURN loc:Digito&lt;br /&gt;
&lt;br /&gt;
Ruben Garcia [http://www.dipsarg.com (DiPS)]&lt;br /&gt;
&lt;br /&gt;
== Autoincremento Manual == &lt;br /&gt;
&lt;br /&gt;
Esto se utiliza cuando tenemos una tabla en la cual queremos manejar la clave de auto incremento &lt;br /&gt;
&lt;br /&gt;
 CLEAR(MASTER)&lt;br /&gt;
 SET(MAS:ClavePorID, MAS:ClavePorID)&lt;br /&gt;
 ACCES:MASTER.Previous()&lt;br /&gt;
 IF MAS:Id = 0 THEN &lt;br /&gt;
     MAS:Id = 1&lt;br /&gt;
 ELSE &lt;br /&gt;
     MAS:Id = MAS:Id +1 &lt;br /&gt;
 END &lt;br /&gt;
&lt;br /&gt;
!!!MAS:Id TENDRÍA EL VALOR DEL PROXIMO NUMERO.- &lt;br /&gt;
&lt;br /&gt;
Gracias [mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
Nota: El mecanismo descrito es &amp;quot;confiable&amp;quot; sólo para aplicaciones que usan TPS y en modo single-user. Para Multiusuario y SQL hay que tener cuidado con las lecturas simultáneas del último valor. &lt;br /&gt;
También puede simplificarse el &amp;quot;if ... then ... else ...&amp;quot; como &amp;quot;MAS:Id = MAS:Id +1&amp;quot; (si es cero, será 1, no hace falta chequearlo)&lt;br /&gt;
&lt;br /&gt;
== Desabilitar menu desde cualquier procedimiento ==&lt;br /&gt;
Una opcion seria usando NOTIFY.&lt;br /&gt;
En el Frame&lt;br /&gt;
 Window Events&lt;br /&gt;
    Notify&lt;br /&gt;
        DISABLE = VariableGlobal&lt;br /&gt;
&lt;br /&gt;
En cualquier procedimiento que se necesite deshabilitar un menu&lt;br /&gt;
&lt;br /&gt;
 VariableGlobal = Nro de Use del Menu&lt;br /&gt;
 NOTIFY (999, 1)&lt;br /&gt;
&lt;br /&gt;
Puede ser 999 o cualquier cosa ya que no estoy usando ese parametro.&lt;br /&gt;
(bueno, en realidad podria usar ese parametro en lugar de la global...)&lt;br /&gt;
1 es el Tread del Frame&lt;br /&gt;
&lt;br /&gt;
Como desde los otros procedimientos no existen los use del los items de menu&lt;br /&gt;
(o sea ?menuitem) lo que hay que hacer es ponerles un numero a cada uno.&lt;br /&gt;
Esto se logra poniendolos de esta manera ?use, numero en la definicion del&lt;br /&gt;
menu.&lt;br /&gt;
&lt;br /&gt;
[mailto:Fernando_Cerini@hotmail.com Fernando Cerini]&lt;br /&gt;
&lt;br /&gt;
==Formatear fechas en SQL ==&lt;br /&gt;
Les paso una función que utilizo para trabajar con las fechas en el SQL parecido al format de clarion. Es muy útil.&lt;br /&gt;
  &lt;br /&gt;
  CREATE FUNCTION dbo.FormatDateTime&lt;br /&gt;
  (&lt;br /&gt;
      @dt DATETIME,&lt;br /&gt;
      @format VARCHAR(16)&lt;br /&gt;
  )&lt;br /&gt;
  RETURNS VARCHAR(64)&lt;br /&gt;
  AS&lt;br /&gt;
  BEGIN&lt;br /&gt;
      DECLARE @dtVC VARCHAR(64)&lt;br /&gt;
      SELECT @dtVC = CASE @format&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;LONGDATE&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          DATENAME(dw, @dt)&lt;br /&gt;
          + &#039;,&#039; + SPACE(1) + DATENAME(m, @dt)&lt;br /&gt;
          + SPACE(1) + CAST(DAY(@dt) AS VARCHAR(2))&lt;br /&gt;
          + &#039;,&#039; + SPACE(1) + CAST(YEAR(@dt) AS CHAR(4))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;LONGDATEANDTIME&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          DATENAME(dw, @dt)&lt;br /&gt;
          + &#039;,&#039; + SPACE(1) + DATENAME(m, @dt)&lt;br /&gt;
          + SPACE(1) + CAST(DAY(@dt) AS VARCHAR(2))&lt;br /&gt;
          + &#039;,&#039; + SPACE(1) + CAST(YEAR(@dt) AS CHAR(4))&lt;br /&gt;
          + SPACE(1) + RIGHT(CONVERT(CHAR(20),&lt;br /&gt;
          @dt - CONVERT(DATETIME, CONVERT(CHAR(8),&lt;br /&gt;
          @dt, 112)), 22), 11)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;SHORTDATE&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          LEFT(CONVERT(CHAR(19), @dt, 0), 11)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;SHORTDATEANDTIME&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          REPLACE(REPLACE(CONVERT(CHAR(19), @dt, 0),&lt;br /&gt;
              &#039;AM&#039;, &#039; AM&#039;), &#039;PM&#039;, &#039; PM&#039;)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;UNIXTIMESTAMP&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CAST(DATEDIFF(SECOND, &#039;19700101&#039;, @dt)&lt;br /&gt;
          AS VARCHAR(64))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;YYYYMMDD&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 112)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;YYYY-MM-DD&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(10), @dt, 23)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;YYMMDD&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(VARCHAR(8), @dt, 12)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;YY-MM-DD&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          STUFF(STUFF(CONVERT(VARCHAR(8), @dt, 12),&lt;br /&gt;
          5, 0, &#039;-&#039;), 3, 0, &#039;-&#039;)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;MMDDYY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          REPLACE(CONVERT(CHAR(8), @dt, 10), &#039;-&#039;, SPACE(0))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;MM-DD-YY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 10)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;MM/DD/YY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 1)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;MM/DD/YYYY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(10), @dt, 101)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;DDMMYY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          REPLACE(CONVERT(CHAR(8), @dt, 3), &#039;/&#039;, SPACE(0))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;DD-MM-YY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          REPLACE(CONVERT(CHAR(8), @dt, 3), &#039;/&#039;, &#039;-&#039;)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;DD/MM/YY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 3)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;DD/MM/YYYY&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(10), @dt, 103)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;HH:MM:SS 24&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          CONVERT(CHAR(8), @dt, 8)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;HH:MM 24&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          LEFT(CONVERT(VARCHAR(8), @dt, 8), 5)&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;HH:MM:SS 12&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          LTRIM(RIGHT(CONVERT(VARCHAR(20), @dt, 22), 11))&lt;br /&gt;
  &lt;br /&gt;
      WHEN &#039;HH:MM 12&#039; THEN&lt;br /&gt;
  &lt;br /&gt;
          LTRIM(SUBSTRING(CONVERT(&lt;br /&gt;
          VARCHAR(20), @dt, 22), 10, 5)&lt;br /&gt;
          + RIGHT(CONVERT(VARCHAR(20), @dt, 22), 3))&lt;br /&gt;
  &lt;br /&gt;
      ELSE&lt;br /&gt;
  &lt;br /&gt;
          &#039;Invalid format specified&#039;&lt;br /&gt;
  &lt;br /&gt;
      END&lt;br /&gt;
      RETURN @dtVC&lt;br /&gt;
  END&lt;br /&gt;
  GO&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  Ejemplos:&lt;br /&gt;
  &lt;br /&gt;
  DECLARE @now DATETIME&lt;br /&gt;
  SET @now = GETDATE()&lt;br /&gt;
  &lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;LONGDATE&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;LONGDATEANDTIME&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;SHORTDATE&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;SHORTDATEANDTIME&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;UNIXTIMESTAMP&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;YYYYMMDD&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;YYYY-MM-DD&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;YYMMDD&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;YY-MM-DD&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;MMDDYY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;MM-DD-YY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;MM/DD/YY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;MM/DD/YYYY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;DDMMYY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;DD-MM-YY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;DD/MM/YY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;DD/MM/YYYY&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;HH:MM:SS 24&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;HH:MM 24&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;HH:MM:SS 12&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;HH:MM 12&#039;)&lt;br /&gt;
  PRINT dbo.FormatDateTime(@now, &#039;goofy&#039;) &lt;br /&gt;
  &lt;br /&gt;
Posteado al foro por Omar Squiabro&lt;br /&gt;
&lt;br /&gt;
== Anular Tecla Escape ==&lt;br /&gt;
&lt;br /&gt;
Hay veces que se necesita que el usuario salga de una FORM o de una ventana solo cuando pulse un determinado boton o se halla completado alguna condicion. Y en estos casos puede suceder que si el usuario pulsa la tecla ESC cause algun problema&lt;br /&gt;
&lt;br /&gt;
Primero hay que activar la alerta de la tecla esc en el INIT de la ventana&lt;br /&gt;
&lt;br /&gt;
  ALERT(EscKey)&lt;br /&gt;
&lt;br /&gt;
Despues en el evento alertkey&lt;br /&gt;
&lt;br /&gt;
  IF KEYCODE() = EscKey&lt;br /&gt;
    SELECT(?UnDeterminadoCampo)  !1= al primero&lt;br /&gt;
    RETURN Level:Notify          &lt;br /&gt;
  END&lt;br /&gt;
&lt;br /&gt;
Si el codigo embebido es puesto despues del codigo generado por clarion reemplazar el RETURN por CYCLE&lt;br /&gt;
&lt;br /&gt;
Ruben Garcia [http://www.programaya.com (DiPS)]&lt;br /&gt;
&lt;br /&gt;
== Convertir Número Hexadecimal a Binario ==&lt;br /&gt;
A veces, y sobre todo al trabajar con estados de puertos de comunicaciones, necesitamos convertir numeros hexadecimales a binario para establecer errores o tratar envios y recepciones.&lt;br /&gt;
Esta función hace justamente esto de forma sencilla.&lt;br /&gt;
&lt;br /&gt;
 HexaABinario         PROCEDURE(PAR:Nhexa)   ! (String),String&lt;br /&gt;
 HBinario   String(4),dim(16) !Equivalencias&lt;br /&gt;
 RetuBina   String(100)       !Variable Retorno&lt;br /&gt;
&lt;br /&gt;
  CODE&lt;br /&gt;
   HBinario[01] = &#039;0000&#039; !     0h&lt;br /&gt;
   HBinario[02] = &#039;0001&#039; !     1h&lt;br /&gt;
   HBinario[03] = &#039;0010&#039; !     2h&lt;br /&gt;
   HBinario[04] = &#039;0011&#039; !     3h&lt;br /&gt;
   HBinario[05] = &#039;0100&#039; !     4h&lt;br /&gt;
   HBinario[06] = &#039;0101&#039; !     5h &lt;br /&gt;
   HBinario[07] = &#039;0110&#039; !     6h&lt;br /&gt;
   HBinario[08] = &#039;0111&#039; !     7h&lt;br /&gt;
   HBinario[09] = &#039;1000&#039; !     8h &lt;br /&gt;
   HBinario[10] = &#039;1001&#039; !     9h&lt;br /&gt;
   HBinario[11] = &#039;1010&#039; !     Ah  65&lt;br /&gt;
   HBinario[12] = &#039;1011&#039; !     Bh  66&lt;br /&gt;
   HBinario[13] = &#039;1100&#039; !     Ch  67&lt;br /&gt;
   HBinario[14] = &#039;1101&#039; !     Dh  68&lt;br /&gt;
   HBinario[15] = &#039;1110&#039; !     Eh  69&lt;br /&gt;
   HBinario[16] = &#039;1111&#039; !     Fh  70&lt;br /&gt;
   CLEAR(RetuBina)&lt;br /&gt;
   PAR:NHexa = UPPER(PAR:NHexa) !Aseguro letras en mayusculas&lt;br /&gt;
   LOOP I# = 1 to LEN(CLIP(PAR:NHexa))&lt;br /&gt;
     IF NUMERIC(PAR:NHexa[I#]) THEN  !Si es numero es &amp;lt;= 9&lt;br /&gt;
        !Asigno equivalente&lt;br /&gt;
        RetuBina = CLIP(RetuBina) &amp;amp; HBinario[PAR:NHexa[I#]+1]&lt;br /&gt;
     ELSE&lt;br /&gt;
       !Asigno equivalente tomando,por ejemplo, 65 - 54 = 11 para &amp;quot;A&amp;quot;&lt;br /&gt;
        RetuBina = CLIP(RetuBina) &amp;amp; HBinario[VAL(PAR:NHexa[I#])-54]&lt;br /&gt;
     END&lt;br /&gt;
   END&lt;br /&gt;
   !Retorno la cadena binaria sin ceros a la izquierda&lt;br /&gt;
   RETURN(SUB(RetuBina, INSTRING(&#039;1&#039;,RetuBina), LEN(CLIP(RetuBina)))) &lt;br /&gt;
&lt;br /&gt;
Bueno, espero les sea de utilidad!&lt;br /&gt;
&lt;br /&gt;
Mario A. Wojcik&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Manuales&amp;diff=62</id>
		<title>Manuales</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Manuales&amp;diff=62"/>
		<updated>2015-03-07T22:36:00Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Texto reemplazado: «[http://www.evolutionconsulting.com.ar/download.htm (Evolution Consulting)]» por «[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los programadores Clarion reconocemos que existe una falencia importante en la cantidad de manuales disponibles para Clarion, eso es especialmente notable en nuestra lengua.&lt;br /&gt;
&lt;br /&gt;
Por eso es importante conocer los manuales diponibles y dónde descargarlos o acceder.&lt;br /&gt;
&lt;br /&gt;
== Clarion 5 Primeros pasos ==&lt;br /&gt;
&lt;br /&gt;
Una traducción del Getting Started de Clarion 5 realizado por Unisoft. &#039;&#039;&#039;Altamente recomendable.&#039;&#039;&#039; Sobre todo para los que principiantes que les cuesta leer en inglés.&lt;br /&gt;
&lt;br /&gt;
[http://www.lawebdelprogramador.com/cursos/enlace.php?idp=1066&amp;amp;id=16&amp;amp;texto=Clarion Manual primeros pasos Clarion 5]&lt;br /&gt;
&lt;br /&gt;
== Anti Manual de SQL ==&lt;br /&gt;
&lt;br /&gt;
De Mauricio Nicastro.&lt;br /&gt;
&lt;br /&gt;
Imposible empezar a incursionar en SQL sin leerlo.&lt;br /&gt;
&lt;br /&gt;
[[Anti Manual de SQL]]&lt;br /&gt;
&lt;br /&gt;
== Los mejores puntos embebidos ==&lt;br /&gt;
&lt;br /&gt;
De Mauricio Nicastro.&lt;br /&gt;
&lt;br /&gt;
Este tema tiene una sección propia en este Wiki, pero el documento tiene consistencia de manual, por eso lo incluyo en forma completa.&lt;br /&gt;
&lt;br /&gt;
[[Los mejores puntos embebidos]]&lt;br /&gt;
&lt;br /&gt;
== Guia de las mejores prácticas de Clarion ==&lt;br /&gt;
&lt;br /&gt;
De Cristian Olsen.&lt;br /&gt;
&lt;br /&gt;
[[Guia de las mejores prácticas de Clarion]]&lt;br /&gt;
&lt;br /&gt;
== SQL Embebido ==&lt;br /&gt;
Doc. que explica como usar sql embebido y un ejemplo de como crear un editor de SQL&lt;br /&gt;
	&lt;br /&gt;
[http://www.templatesclarion.com.ar/downloads/ (Templates Clarion)]&lt;br /&gt;
&lt;br /&gt;
== Migración TPS a SQL ==&lt;br /&gt;
Primeros pasos en la migración de TPS a SQL. Basado en una presentación del creador de los drivers, Scott Ferret. La cual tuve la suerte de presenciar y me tomé el atrevimiento de hacer algunos cambios...&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Funciones ODBC ==&lt;br /&gt;
Lista de funciones muy útiles de ODBC.&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Strings de Conexión ==&lt;br /&gt;
De diversas bases en formato DSNLess (sin necesidad de crear el DNS).&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Tipos de Datos SQL ==&lt;br /&gt;
Compatibilidad de tipos entre SQL y Clarion.&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Multithreading con Clarion6 ==&lt;br /&gt;
Uso correcto de variables y queues globales. Ejemplos de Secciones criticas, Mutexs y Semáforos. Incluye documentación de la charla presentada en CONDEV por Fernando Cerini&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Firebird ==&lt;br /&gt;
Primeros pasos en la instalación del Firebird. (Gracias Roque Delia)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Manuales&amp;diff=61</id>
		<title>Manuales</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Manuales&amp;diff=61"/>
		<updated>2015-02-28T14:53:01Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: Videos de Youtube ya no están disponibles&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Los programadores Clarion reconocemos que existe una falencia importante en la cantidad de manuales disponibles para Clarion, eso es especialmente notable en nuestra lengua.&lt;br /&gt;
&lt;br /&gt;
Por eso es importante conocer los manuales diponibles y dónde descargarlos o acceder.&lt;br /&gt;
&lt;br /&gt;
== Clarion 5 Primeros pasos ==&lt;br /&gt;
&lt;br /&gt;
Una traducción del Getting Started de Clarion 5 realizado por Unisoft. &#039;&#039;&#039;Altamente recomendable.&#039;&#039;&#039; Sobre todo para los que principiantes que les cuesta leer en inglés.&lt;br /&gt;
&lt;br /&gt;
[http://www.lawebdelprogramador.com/cursos/enlace.php?idp=1066&amp;amp;id=16&amp;amp;texto=Clarion Manual primeros pasos Clarion 5]&lt;br /&gt;
&lt;br /&gt;
== Anti Manual de SQL ==&lt;br /&gt;
&lt;br /&gt;
De Mauricio Nicastro.&lt;br /&gt;
&lt;br /&gt;
Imposible empezar a incursionar en SQL sin leerlo.&lt;br /&gt;
&lt;br /&gt;
[[Anti Manual de SQL]]&lt;br /&gt;
&lt;br /&gt;
== Los mejores puntos embebidos ==&lt;br /&gt;
&lt;br /&gt;
De Mauricio Nicastro.&lt;br /&gt;
&lt;br /&gt;
Este tema tiene una sección propia en este Wiki, pero el documento tiene consistencia de manual, por eso lo incluyo en forma completa.&lt;br /&gt;
&lt;br /&gt;
[[Los mejores puntos embebidos]]&lt;br /&gt;
&lt;br /&gt;
== Guia de las mejores prácticas de Clarion ==&lt;br /&gt;
&lt;br /&gt;
De Cristian Olsen.&lt;br /&gt;
&lt;br /&gt;
[[Guia de las mejores prácticas de Clarion]]&lt;br /&gt;
&lt;br /&gt;
== SQL Embebido ==&lt;br /&gt;
Doc. que explica como usar sql embebido y un ejemplo de como crear un editor de SQL&lt;br /&gt;
	&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.htm (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Migración TPS a SQL ==&lt;br /&gt;
Primeros pasos en la migración de TPS a SQL. Basado en una presentación del creador de los drivers, Scott Ferret. La cual tuve la suerte de presenciar y me tomé el atrevimiento de hacer algunos cambios...&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Funciones ODBC ==&lt;br /&gt;
Lista de funciones muy útiles de ODBC.&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Strings de Conexión ==&lt;br /&gt;
De diversas bases en formato DSNLess (sin necesidad de crear el DNS).&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Tipos de Datos SQL ==&lt;br /&gt;
Compatibilidad de tipos entre SQL y Clarion.&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Multithreading con Clarion6 ==&lt;br /&gt;
Uso correcto de variables y queues globales. Ejemplos de Secciones criticas, Mutexs y Semáforos. Incluye documentación de la charla presentada en CONDEV por Fernando Cerini&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;br /&gt;
&lt;br /&gt;
== Firebird ==&lt;br /&gt;
Primeros pasos en la instalación del Firebird. (Gracias Roque Delia)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html (Evolution Consulting)]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=60</id>
		<title>Portada</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=60"/>
		<updated>2015-02-28T14:49:49Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;¡Bienvenido!&lt;br /&gt;
 &lt;br /&gt;
Este Wiki tiene por objetivo ser una guía en idioma español de la herramienta de desarrollo de aplicaciones Clarion, agrupando manuales, trucos, ideas, código, templates gratuitos o simplemente recomendaciones para los usuarios de Clarion. La consigna es agrupar los documentos o respuestas que se han publicado en los foros de consulta en un lugar centralizado, donde los usuarios novatos (y los más avanzados también...) puedan tenerla más a mano y organizada.&lt;br /&gt;
&lt;br /&gt;
En el menú de la derecha puedes acceder a las distintas secciones del sitio, o utilizar el buscador situado en la esquina superior izquierda.&lt;br /&gt;
&lt;br /&gt;
¿Te interesaría colaborar como editor?&lt;br /&gt;
Envíame un e-mail a [mailto:jbrugger@clarionwiki.com.ar jbrugger@clarionwiki.com.ar] para gestionar el alta de la cuenta.&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Templates_gratuitos&amp;diff=59</id>
		<title>Templates gratuitos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Templates_gratuitos&amp;diff=59"/>
		<updated>2014-11-18T13:24:59Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Existen diversos templates adicionales para Clarion que extienden notablemente su funcionalidad.&lt;br /&gt;
&lt;br /&gt;
Esta sección debería incluir el nombre, una breve descripción del mismo, las versiones compatibles de Clarion y el sitio desde donde puede descargarse.&lt;br /&gt;
&lt;br /&gt;
== ABCFree ==&lt;br /&gt;
&lt;br /&gt;
Es el conjunto de templates y librerias gratuitas más interesante para Clarion.&lt;br /&gt;
Esta disponible en http://www.authord.com/Clarion . Frecuentemente actualizado y cubre todos los niveles de programación con Clarion: bajo y alto nivel. Fundamental&lt;br /&gt;
&lt;br /&gt;
== Botpl ==&lt;br /&gt;
Sitio web: http://comsoft7.com/Botpl.htm&lt;br /&gt;
&lt;br /&gt;
Incluye:&lt;br /&gt;
&lt;br /&gt;
AppSpecsControl, BarCodeLabelControl,BrowseSearch,LabelControl,ListHorzRuntime,ListVertRuntime, PerCentGraph,PerCentGraphVert,Bo_resc 32bit only.&lt;br /&gt;
&lt;br /&gt;
== Clarion Australia ==&lt;br /&gt;
http://www.comformark.com.au/&lt;br /&gt;
&lt;br /&gt;
Clarion Autralia&lt;br /&gt;
&lt;br /&gt;
== Clarion FreeImage Project ==&lt;br /&gt;
&lt;br /&gt;
http://www.clarionfreeimage.com/&lt;br /&gt;
&lt;br /&gt;
Conjunto de clases y un template que implementa la librería open source FreeImage para procesamiento de imágenes en Clarion 5.5 y 6.x.&lt;br /&gt;
Tiene una seccion[http://www.clarionfreeimage.com/related.html] con varias clases y ejemplos: escanear con eztwain, enumerar monitores, barras de progreso e iconos en Barras de estado, botones con alpha blend y smooth scrolling control&lt;br /&gt;
&lt;br /&gt;
== Evolution Consulting ==&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html Seccion Downloads]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html MENSAJES DE CLARION EN ESPAÑOL ]&lt;br /&gt;
&lt;br /&gt;
Traducción al español de todos los botones, mensajes, etc... que se utilizan en la generación de los Wizzards. Actualizado siempre a la última version de Clarion 6.1. Una herramienta indispensable para nuestra comunidad Latinoamericana.&lt;br /&gt;
&lt;br /&gt;
Para instalar simplemente copie los archivos al directorio Clarion6\LIBSRC.&lt;br /&gt;
&lt;br /&gt;
También agregamos la traducción del Calendario ABUTILUI&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html EVOLUTION MAIL TEMPLATE    (Clarion 5.0)   (Clarion 5.5)   (Clarion 6.1)   (Clarion 7.2)]&lt;br /&gt;
&lt;br /&gt;
El producto está compuesto por un Control Template para envío de mail y un Extension Template para enviar los WMF del preview por mail con selector de página. Permite guardar el wmf en un word y generar el attach automáticamente dentro de un mail o bien dejarlo en segundo plano del aplicativo.&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html EVOLUTION TOOLS (Clarion 5, 5.5 y 6.1) ]&lt;br /&gt;
&lt;br /&gt;
Incluye el Control Template tan solicitado &amp;quot;página de páginas&amp;quot; en los reportes.&lt;br /&gt;
&lt;br /&gt;
Evita el mensaje &#039;No hay registros para procesar&#039;&lt;br /&gt;
&lt;br /&gt;
STREAM y FLUSH Automático en los process.&lt;br /&gt;
&lt;br /&gt;
Control template que nos permite pegar un calendario en una windows. La diferencia de este template con otros free es que éste agrega el calendario dentro de la misma ventana como &amp;quot;Control Template&amp;quot;, los otros son simplemente procedimientos aparte.&lt;br /&gt;
&lt;br /&gt;
Enter por Tab mejorado.&lt;br /&gt;
&lt;br /&gt;
Imprimir Página Desde - Hasta desde Preview.&lt;br /&gt;
&lt;br /&gt;
Configuración de Impresora en Preview.&lt;br /&gt;
&lt;br /&gt;
Impresión Página Actual en Preview.&lt;br /&gt;
&lt;br /&gt;
Este template se irá actualizando periódicamente, se aceptan sugerencias...&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html ARBOL DE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Pequeño Utility template que genera el árbol de procedimientos en un archivo NombreAPP.TXT&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html CLARION BATCH COMPILER (beta 11) ]&lt;br /&gt;
&lt;br /&gt;
Este excelente producto de Cristian Olsen compila en modo Batch todos los APPs del sistema. Compatible con todas las versiones de Clarion&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html INFORMACION DE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Template muy útil para volcar información detallada de los procedimientos de un app, con nombre, tipo, prototipo, ultima modificación, si es local o externo, etc (Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html GRABAR TAB ELEGIDO ]&lt;br /&gt;
&lt;br /&gt;
Se agrega a los browses con múltiples tabs y graba como se lo utilizó la ultima vez para cuando se reingrese, se pare nuevamente en ese tab(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html TRACE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Este es mas complejo, es global y se indica un procedimiento que es le que recibirá el procedimiento y app por el que se está pasando, este procedimiento (que el usuario debe crear) es que debe grabar en un archivo deseado, el resultado. En mi caso graba en un txt, el procedimiento, app, fecha y hora, y tengo una variable en un INI para indicar si debe grabarse o no.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html CAMPOS OBLIGATORIOS ]&lt;br /&gt;
&lt;br /&gt;
Extensión que hace no se pueda salir de los campos obligatorios. Es global con opciones locales (se puede deshabilitar en cada procedimiento). Importante: Es necesario crear un alert key global para salir del procedimiento para dejar escapar al usuario en caso de necesidad.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html VARIOS ]&lt;br /&gt;
&lt;br /&gt;
Tiene 2 funciones, si se presiona CrtlAltP, indica en un message en que procedimiento estamos y en que APP está y una función que si estás parado en un campo con formato de fecha y presionas el + del teclado numérico asigna la fecha del día.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html DCT2SQL ]&lt;br /&gt;
&lt;br /&gt;
La última versión de uno de los templates mas populares para la generación de Scripts SQL a partir del DCT (Gracias Roberto Artigas)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html MCI ]&lt;br /&gt;
&lt;br /&gt;
Template que reproduce audio (Wav, Mp3) y video (Avi, Mpg) (Gracias Victor Pierri)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html Calendario + 18 funciones ]&lt;br /&gt;
&lt;br /&gt;
Template del estilo PopUp Calendario y un conjunto de 18 Funciones muy útiles (Ver mas info) Gracias Francisco J. Carabez&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html Print Driver ]&lt;br /&gt;
&lt;br /&gt;
Template para impresoras matriciales, traducido y mejorado por Ruben Caporossi . Simplemente se registra en Global Extensions del app y las funciones están disponibles&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html Esta página se actualiza constantemente...]&lt;br /&gt;
&lt;br /&gt;
== SICyA Software ==&lt;br /&gt;
http://www.sicya.com&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; SICyA Templates &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
AutoCompletar_SICyA - Control entry de autocompletado desde una tabla.&lt;br /&gt;
&lt;br /&gt;
Calendario_SICyA - Calendario con estilo XP con manejo de dominicales y feriados.&lt;br /&gt;
&lt;br /&gt;
LlamaProcedimiento_SICyA - Llama procedimientos con parámetros o en forma thread.&lt;br /&gt;
&lt;br /&gt;
VolumeDiscoDuro_SICyA - Captura Serial, nombre del Volumen y Tipo Archivos de un Disco&lt;br /&gt;
&lt;br /&gt;
Botones_SICyA - Extensión para tener Botones con un estilo propio en aplicaciones no XP.&lt;br /&gt;
&lt;br /&gt;
[http://www.sicya.com/download/SICyA_Templates_Build_051007.exe Descargar el template aqui...]&lt;br /&gt;
&lt;br /&gt;
== Solace ==&lt;br /&gt;
&lt;br /&gt;
http://www.solace-software.demon.co.uk/freetemplates.htm&lt;br /&gt;
&lt;br /&gt;
Enhanced standard HTML help template&lt;br /&gt;
&lt;br /&gt;
Colour all columns in a browse on a condition without having to individually specify each column&lt;br /&gt;
&lt;br /&gt;
Screen Resolution&lt;br /&gt;
&lt;br /&gt;
Make Directory&lt;br /&gt;
&lt;br /&gt;
Read Only Window&lt;br /&gt;
&lt;br /&gt;
Open Close Files in Source Template&lt;br /&gt;
&lt;br /&gt;
Add Wallpaper to every Window&lt;br /&gt;
&lt;br /&gt;
Override Recursive Insert Message &lt;br /&gt;
&lt;br /&gt;
Global extension to change the Font of every screen in your app.&lt;br /&gt;
&lt;br /&gt;
Global Extension to allow users to make all controls flat&lt;br /&gt;
&lt;br /&gt;
== tabajara ==&lt;br /&gt;
&lt;br /&gt;
http://www.tabajara.com/downloads.html&lt;br /&gt;
&lt;br /&gt;
Browser to HTML - Just populate a Button and you can export to HTML&lt;br /&gt;
&lt;br /&gt;
Browser to CSV - Just populate a Button, and Done! This way you can export to Excel.&lt;br /&gt;
&lt;br /&gt;
Files to CSV - Choose files to export data. (export files to CSV selecting from DCT)&lt;br /&gt;
&lt;br /&gt;
Report Green Bar - makes shadowed every other report detail.&lt;br /&gt;
&lt;br /&gt;
== xFunction ==&lt;br /&gt;
&lt;br /&gt;
Colección gratuita de templates de código de la empresa Sealsoft. Incluyen funciones para manejo de fechas, archivos y paths, y algunas otras. Puede descargarse de http://www.seal-soft.com&lt;br /&gt;
&lt;br /&gt;
== Locus Templates ==&lt;br /&gt;
&lt;br /&gt;
http://www.riebens.co.za/index.php?option=com_content&amp;amp;view=article&amp;amp;id=39&amp;amp;Itemid=183&lt;br /&gt;
&lt;br /&gt;
Excelente conjunto de templates que abarcan varias categorias: &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CONTROL TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* PageTree	Seleccionar una hoja de propiedades de un listbox tipo tree&lt;br /&gt;
* PopupDate	Seleccionar fecha desde un calendario&lt;br /&gt;
* PopupDirectory	Seleccionar directorio&lt;br /&gt;
* RichEdit	Completo editor de texto enriquecido (RTF) totalmente escrito en clarion con toolbar y tabulador.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PROCEDURES:&#039;&#039;&#039;&lt;br /&gt;
* QBEDialog	Crea Dialogo QBE (Query by Example).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CODE TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* CWPrintEngine	Imprimir un reporte creado con el CW Report Writer&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;EXTENSION TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* BrowseEdit	Edit in place para un browse box con validación de campos y lookup&lt;br /&gt;
* BrowseTotal	Totalizar campos en un browse box.&lt;br /&gt;
* BrowseValue	Crea un checkbox editable&lt;br /&gt;
* FormSplit	Divisores verticales u horizontales&lt;br /&gt;
* GetIniFile	Obtiene y guarda valores en un archivo ini.&lt;br /&gt;
* LimitStarts	Evita comenzar 2 MDI threads a la vez&lt;br /&gt;
* PopupToolbar	Toolbar ocultable &lt;br /&gt;
* ReportFilter	Seleccionar registros para imprimir y resaltar. Incluye un visor de reporte&lt;br /&gt;
* FILE MANAGER	Posibilita cambiar el dct, recompilar, y todos los archivos son actualizados automáticamente a la nueva version&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Templates_gratuitos&amp;diff=58</id>
		<title>Templates gratuitos</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Templates_gratuitos&amp;diff=58"/>
		<updated>2014-11-18T13:24:12Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Locus Templates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Existen diversos templates adicionales para Clarion que extienden notablemente su funcionalidad.&lt;br /&gt;
&lt;br /&gt;
Esta sección debería incluir el nombre, una breve descripción del mismo, las versiones compatibles de Clarion y el sitio desde donde puede descargarse.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ABCFree ==&lt;br /&gt;
&lt;br /&gt;
Es el conjunto de templates y librerias gratuitas más interesante para Clarion.&lt;br /&gt;
Esta disponible en http://www.authord.com/Clarion . Frecuentemente actualizado y cubre todos los niveles de programación con Clarion: bajo y alto nivel. Fundamental&lt;br /&gt;
&lt;br /&gt;
== Botpl ==&lt;br /&gt;
Sitio web: http://comsoft7.com/Botpl.htm&lt;br /&gt;
&lt;br /&gt;
Incluye:&lt;br /&gt;
&lt;br /&gt;
AppSpecsControl, BarCodeLabelControl,BrowseSearch,LabelControl,ListHorzRuntime,ListVertRuntime, PerCentGraph,PerCentGraphVert,Bo_resc 32bit only.&lt;br /&gt;
&lt;br /&gt;
== Clarion Australia ==&lt;br /&gt;
http://www.comformark.com.au/&lt;br /&gt;
&lt;br /&gt;
Clarion Autralia&lt;br /&gt;
&lt;br /&gt;
== Clarion FreeImage Project ==&lt;br /&gt;
&lt;br /&gt;
http://www.clarionfreeimage.com/&lt;br /&gt;
&lt;br /&gt;
Conjunto de clases y un template que implementa la librería open source FreeImage para procesamiento de imágenes en Clarion 5.5 y 6.x.&lt;br /&gt;
Tiene una seccion[http://www.clarionfreeimage.com/related.html] con varias clases y ejemplos: escanear con eztwain, enumerar monitores, barras de progreso e iconos en Barras de estado, botones con alpha blend y smooth scrolling control&lt;br /&gt;
&lt;br /&gt;
== Evolution Consulting ==&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html Seccion Downloads]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html MENSAJES DE CLARION EN ESPAÑOL ]&lt;br /&gt;
&lt;br /&gt;
Traducción al español de todos los botones, mensajes, etc... que se utilizan en la generación de los Wizzards. Actualizado siempre a la última version de Clarion 6.1. Una herramienta indispensable para nuestra comunidad Latinoamericana.&lt;br /&gt;
&lt;br /&gt;
Para instalar simplemente copie los archivos al directorio Clarion6\LIBSRC.&lt;br /&gt;
&lt;br /&gt;
También agregamos la traducción del Calendario ABUTILUI&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html EVOLUTION MAIL TEMPLATE    (Clarion 5.0)   (Clarion 5.5)   (Clarion 6.1)   (Clarion 7.2)]&lt;br /&gt;
&lt;br /&gt;
El producto está compuesto por un Control Template para envío de mail y un Extension Template para enviar los WMF del preview por mail con selector de página. Permite guardar el wmf en un word y generar el attach automáticamente dentro de un mail o bien dejarlo en segundo plano del aplicativo.&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html EVOLUTION TOOLS (Clarion 5, 5.5 y 6.1) ]&lt;br /&gt;
&lt;br /&gt;
Incluye el Control Template tan solicitado &amp;quot;página de páginas&amp;quot; en los reportes.&lt;br /&gt;
&lt;br /&gt;
Evita el mensaje &#039;No hay registros para procesar&#039;&lt;br /&gt;
&lt;br /&gt;
STREAM y FLUSH Automático en los process.&lt;br /&gt;
&lt;br /&gt;
Control template que nos permite pegar un calendario en una windows. La diferencia de este template con otros free es que éste agrega el calendario dentro de la misma ventana como &amp;quot;Control Template&amp;quot;, los otros son simplemente procedimientos aparte.&lt;br /&gt;
&lt;br /&gt;
Enter por Tab mejorado.&lt;br /&gt;
&lt;br /&gt;
Imprimir Página Desde - Hasta desde Preview.&lt;br /&gt;
&lt;br /&gt;
Configuración de Impresora en Preview.&lt;br /&gt;
&lt;br /&gt;
Impresión Página Actual en Preview.&lt;br /&gt;
&lt;br /&gt;
Este template se irá actualizando periódicamente, se aceptan sugerencias...&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html ARBOL DE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Pequeño Utility template que genera el árbol de procedimientos en un archivo NombreAPP.TXT&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html CLARION BATCH COMPILER (beta 11) ]&lt;br /&gt;
&lt;br /&gt;
Este excelente producto de Cristian Olsen compila en modo Batch todos los APPs del sistema. Compatible con todas las versiones de Clarion&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html INFORMACION DE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Template muy útil para volcar información detallada de los procedimientos de un app, con nombre, tipo, prototipo, ultima modificación, si es local o externo, etc (Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html GRABAR TAB ELEGIDO ]&lt;br /&gt;
&lt;br /&gt;
Se agrega a los browses con múltiples tabs y graba como se lo utilizó la ultima vez para cuando se reingrese, se pare nuevamente en ese tab(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html TRACE PROCEDIMIENTOS ]&lt;br /&gt;
&lt;br /&gt;
Este es mas complejo, es global y se indica un procedimiento que es le que recibirá el procedimiento y app por el que se está pasando, este procedimiento (que el usuario debe crear) es que debe grabar en un archivo deseado, el resultado. En mi caso graba en un txt, el procedimiento, app, fecha y hora, y tengo una variable en un INI para indicar si debe grabarse o no.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html CAMPOS OBLIGATORIOS ]&lt;br /&gt;
&lt;br /&gt;
Extensión que hace no se pueda salir de los campos obligatorios. Es global con opciones locales (se puede deshabilitar en cada procedimiento). Importante: Es necesario crear un alert key global para salir del procedimiento para dejar escapar al usuario en caso de necesidad.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html VARIOS ]&lt;br /&gt;
&lt;br /&gt;
Tiene 2 funciones, si se presiona CrtlAltP, indica en un message en que procedimiento estamos y en que APP está y una función que si estás parado en un campo con formato de fecha y presionas el + del teclado numérico asigna la fecha del día.(Gracias Gustavo Bocian y los amigos de BTB Soft)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html DCT2SQL ]&lt;br /&gt;
&lt;br /&gt;
La última versión de uno de los templates mas populares para la generación de Scripts SQL a partir del DCT (Gracias Roberto Artigas)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html MCI ]&lt;br /&gt;
&lt;br /&gt;
Template que reproduce audio (Wav, Mp3) y video (Avi, Mpg) (Gracias Victor Pierri)&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html Calendario + 18 funciones ]&lt;br /&gt;
&lt;br /&gt;
Template del estilo PopUp Calendario y un conjunto de 18 Funciones muy útiles (Ver mas info) Gracias Francisco J. Carabez&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html Print Driver ]&lt;br /&gt;
&lt;br /&gt;
Template para impresoras matriciales, traducido y mejorado por Ruben Caporossi . Simplemente se registra en Global Extensions del app y las funciones están disponibles&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[http://www.evolutionconsulting.com.ar/download.html Esta página se actualiza constantemente...]&lt;br /&gt;
&lt;br /&gt;
== SICyA Software ==&lt;br /&gt;
http://www.sicya.com&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; SICyA Templates &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
AutoCompletar_SICyA - Control entry de autocompletado desde una tabla.&lt;br /&gt;
&lt;br /&gt;
Calendario_SICyA - Calendario con estilo XP con manejo de dominicales y feriados.&lt;br /&gt;
&lt;br /&gt;
LlamaProcedimiento_SICyA - Llama procedimientos con parámetros o en forma thread.&lt;br /&gt;
&lt;br /&gt;
VolumeDiscoDuro_SICyA - Captura Serial, nombre del Volumen y Tipo Archivos de un Disco&lt;br /&gt;
&lt;br /&gt;
Botones_SICyA - Extensión para tener Botones con un estilo propio en aplicaciones no XP.&lt;br /&gt;
&lt;br /&gt;
[http://www.sicya.com/download/SICyA_Templates_Build_051007.exe Descargar el template aqui...]&lt;br /&gt;
&lt;br /&gt;
== Solace ==&lt;br /&gt;
&lt;br /&gt;
http://www.solace-software.demon.co.uk/freetemplates.htm&lt;br /&gt;
&lt;br /&gt;
Enhanced standard HTML help template&lt;br /&gt;
&lt;br /&gt;
Colour all columns in a browse on a condition without having to individually specify each column&lt;br /&gt;
&lt;br /&gt;
Screen Resolution&lt;br /&gt;
&lt;br /&gt;
Make Directory&lt;br /&gt;
&lt;br /&gt;
Read Only Window&lt;br /&gt;
&lt;br /&gt;
Open Close Files in Source Template&lt;br /&gt;
&lt;br /&gt;
Add Wallpaper to every Window&lt;br /&gt;
&lt;br /&gt;
Override Recursive Insert Message &lt;br /&gt;
&lt;br /&gt;
Global extension to change the Font of every screen in your app.&lt;br /&gt;
&lt;br /&gt;
Global Extension to allow users to make all controls flat&lt;br /&gt;
&lt;br /&gt;
== tabajara ==&lt;br /&gt;
&lt;br /&gt;
http://www.tabajara.com/downloads.html&lt;br /&gt;
&lt;br /&gt;
Browser to HTML - Just populate a Button and you can export to HTML&lt;br /&gt;
&lt;br /&gt;
Browser to CSV - Just populate a Button, and Done! This way you can export to Excel.&lt;br /&gt;
&lt;br /&gt;
Files to CSV - Choose files to export data. (export files to CSV selecting from DCT)&lt;br /&gt;
&lt;br /&gt;
Report Green Bar - makes shadowed every other report detail.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== xFunction ==&lt;br /&gt;
&lt;br /&gt;
Colección gratuita de templates de código de la empresa Sealsoft. Incluyen funciones para manejo de fechas, archivos y paths, y algunas otras. Puede descargarse de http://www.seal-soft.com&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Locus Templates ==&lt;br /&gt;
&lt;br /&gt;
http://www.riebens.co.za/index.php?option=com_content&amp;amp;view=article&amp;amp;id=39&amp;amp;Itemid=183&lt;br /&gt;
&lt;br /&gt;
Excelente conjunto de templates que abarcan varias categorias: &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CONTROL TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* PageTree	Seleccionar una hoja de propiedades de un listbox tipo tree&lt;br /&gt;
* PopupDate	Seleccionar fecha desde un calendario&lt;br /&gt;
* PopupDirectory	Seleccionar directorio&lt;br /&gt;
* RichEdit	Completo editor de texto enriquecido (RTF) totalmente escrito en clarion con toolbar y tabulador.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PROCEDURES:&#039;&#039;&#039;&lt;br /&gt;
* QBEDialog	Crea Dialogo QBE (Query by Example).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CODE TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* CWPrintEngine	Imprimir un reporte creado con el CW Report Writer&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;EXTENSION TEMPLATES:&#039;&#039;&#039;&lt;br /&gt;
* BrowseEdit	Edit in place para un browse box con validación de campos y lookup&lt;br /&gt;
* BrowseTotal	Totalizar campos en un browse box.&lt;br /&gt;
* BrowseValue	Crea un checkbox editable&lt;br /&gt;
* FormSplit	Divisores verticales u horizontales&lt;br /&gt;
* GetIniFile	Obtiene y guarda valores en un archivo ini.&lt;br /&gt;
* LimitStarts	Evita comenzar 2 MDI threads a la vez&lt;br /&gt;
* PopupToolbar	Toolbar ocultable &lt;br /&gt;
* ReportFilter	Seleccionar registros para imprimir y resaltar. Incluye un visor de reporte&lt;br /&gt;
* FILE MANAGER	Posibilita cambiar el dct, recompilar, y todos los archivos son actualizados automáticamente a la nueva version&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=MediaWiki:Sidebar&amp;diff=57</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=MediaWiki:Sidebar&amp;diff=57"/>
		<updated>2014-11-18T13:21:02Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
* Secciones&lt;br /&gt;
** manuales|Manuales&lt;br /&gt;
** Puntos Embebidos|Puntos embebidos&lt;br /&gt;
** Codigo Util|Código útil&lt;br /&gt;
** Recomendaciones|Recomendaciones y trucos&lt;br /&gt;
** Soluciones|Soluciones a Problemas Comunes&lt;br /&gt;
** Templates gratuitos|Templates Gratuitos&lt;br /&gt;
** Aplicaciones de Ejemplo|Aplicaciones de Ejemplo&lt;br /&gt;
** Comunidad Clarion|Comunidad Clarion&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=MediaWiki:Sidebar&amp;diff=56</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=MediaWiki:Sidebar&amp;diff=56"/>
		<updated>2014-11-18T13:20:47Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
* Secciones&lt;br /&gt;
** manuales|Manuales&lt;br /&gt;
** Puntos Embebidos|Puntos embebidos&lt;br /&gt;
** Codigo Util|Código útil&lt;br /&gt;
** Recomendaciones|Recomendaciones y trucos&lt;br /&gt;
** Soluciones|Soluciones a Problemas Comunes&lt;br /&gt;
** Templates Gratuitos|Templates gratuitos&lt;br /&gt;
** Aplicaciones de Ejemplo|Aplicaciones de Ejemplo&lt;br /&gt;
** Comunidad Clarion|Comunidad Clarion&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=55</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=55"/>
		<updated>2014-11-18T12:50:04Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento gratuitas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
[news://news.softvelocity.com/softvelocity.clarion.intl.spanish Grupo de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
=== Clarionhub (en inglés) ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionhub.com www.clarionhub.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://faq.clarionmag.com ClarionFAQ en Clarion Magazine]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Página de ayuda con Templates de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ Página que contiene Webinars y tutoriales. Muy útil.]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://evolutionconsulting.com.ar/download.htm Evolution Consulting - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=54</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=54"/>
		<updated>2014-11-18T12:48:35Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Soporte */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
[news://news.softvelocity.com/softvelocity.clarion.intl.spanish Grupo de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
=== Clarionhub (en inglés) ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionhub.com www.clarionhub.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php  Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://faq.clarionmag.com ClarionFAQ en Clarion Magazine]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Página de ayuda con Templates de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ Página que contiene Webinars y tutoriales. Muy útil.]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionwiki.com/ Wiki de Clarion en inglés]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://evolutionconsulting.com.ar/download.htm Evolution Consulting - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=53</id>
		<title>Portada</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=53"/>
		<updated>2014-11-12T17:06:51Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;¡Bienvenido!&lt;br /&gt;
 &lt;br /&gt;
Este Wiki pretende ser una guía en idioma español para los usuarios de Clarion.&lt;br /&gt;
&lt;br /&gt;
La idea del sitio es agrupar manuales, trucos, ideas, código, templates gratuitos o simplemente recomendaciones para los usuarios de Clarion. El objetivo es agrupar los documentos o respuestas que se han publicado en los foros de consulta en un lugar centralizado, donde los usuarios novatos (y los más avanzados también...) puedan tenerla más a mano y organizada.&lt;br /&gt;
&lt;br /&gt;
En el menú de la derecha puedes acceder a las distintas secciones del sitio, o utilizar el buscador situado en la esquina superior izquierda.&lt;br /&gt;
&lt;br /&gt;
¿Te interesaría colaborar como editor?&lt;br /&gt;
Envíame un e-mail a [mailto:jbrugger@clarionwiki.com.ar jbrugger@clarionwiki.com.ar] para gestionar el alta de la cuenta.&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=52</id>
		<title>Portada</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=52"/>
		<updated>2014-11-12T15:05:34Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;¡Bienvenido!&lt;br /&gt;
 &lt;br /&gt;
Este Wiki pretende ser una guía en idioma español para los usuarios de Clarion.&lt;br /&gt;
&lt;br /&gt;
La idea del sitio es agrupar manuales, trucos, ideas, código, templates gratuitos o simplemente recomendaciones para los usuarios de Clarion. El objetivo es agrupar los documentos o respuestas que se han publicado en los foros de consulta en un lugar centralizado, donde los usuarios novatos (y los más avanzados también...) puedan tenerla más a mano y organizada.&lt;br /&gt;
&lt;br /&gt;
En el menú de la derecha puedes acceder a las distintas secciones del sitio, o utilizar el buscador situado en la esquina superior izquierda.&lt;br /&gt;
&lt;br /&gt;
¿Te interesaría colaborar como editor?&lt;br /&gt;
Envíame un e-mail a [mailto:jbrugger@clarionwiki.com.ar] para gestionar el alta de la cuenta.&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=51</id>
		<title>Portada</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=51"/>
		<updated>2014-11-12T14:49:21Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;¡Bienvenido!&lt;br /&gt;
 &lt;br /&gt;
Este Wiki pretende ser una guía en idioma español para los usuarios de Clarion.&lt;br /&gt;
&lt;br /&gt;
La idea del sitio es agrupar manuales, trucos, ideas, código, templates gratuitos o simplemente recomendaciones para los usuarios de Clarion. El objetivo es agrupar los documentos o respuestas que se han publicado en los foros de consulta en un lugar centralizado, donde los usuarios novatos (y los más avanzados también...) puedan tenerla más a mano y organizada.&lt;br /&gt;
&lt;br /&gt;
En el menú de la derecha puedes acceder a las distintas secciones del sitio, o utilizar el buscador situado en la esquina superior izquierda.&lt;br /&gt;
&lt;br /&gt;
¿Te interesaría colaborar como editor?&lt;br /&gt;
Envíame un e-mail a jbrugger@clarionwiki.com.ar para gestionar el alta de la cuenta.&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=50</id>
		<title>Portada</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=50"/>
		<updated>2014-11-12T14:35:22Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Wiki Clarion en español ==&lt;br /&gt;
&lt;br /&gt;
Bienvenidos a este Wiki, que intenta ser una guía en idioma español para los usuarios de Clarion.&lt;br /&gt;
&lt;br /&gt;
La idea del sitio es agrupar manuales, trucos, ideas, código, templates gratuitos o simplemente recomendaciones para los usuarios de Clarion. El objetivo es agrupar los documentos o respuestas que se han publicado en los foros de consulta en un lugar centralizado, donde los usuarios novatos (y los más avanzados también...) puedan tenerla más a mano y organizada.&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=MediaWiki:Sidebar&amp;diff=49</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=MediaWiki:Sidebar&amp;diff=49"/>
		<updated>2014-11-12T14:31:42Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
* Secciones&lt;br /&gt;
** manuales|Manuales&lt;br /&gt;
** Puntos Embebidos|Puntos embebidos&lt;br /&gt;
** Codigo Util|Código útil&lt;br /&gt;
** Recomendaciones|Recomendaciones y trucos&lt;br /&gt;
** Soluciones|Soluciones a Problemas Comunes&lt;br /&gt;
** Templates Gratuitos|Templates Gratuitos&lt;br /&gt;
** Aplicaciones de Ejemplo|Aplicaciones de Ejemplo&lt;br /&gt;
** Comunidad Clarion|Comunidad Clarion&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=MediaWiki:Sidebar&amp;diff=48</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=MediaWiki:Sidebar&amp;diff=48"/>
		<updated>2014-11-12T14:30:03Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
* Secciones&lt;br /&gt;
** manuales|Manuales&lt;br /&gt;
** Puntos Embebidos|Puntos embebidos&lt;br /&gt;
** Codigo Util|Código útil&lt;br /&gt;
** Recomendaciones|Recomendaciones y trucos&lt;br /&gt;
** Soluciones|Soluciones a Problemas Comunes&lt;br /&gt;
** Templates Gratuitos&lt;br /&gt;
** Aplicaciones de Ejemplo&lt;br /&gt;
** Comunidad Clarion|Comunidad Clarion&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=47</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=47"/>
		<updated>2014-11-12T14:27:22Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Soporte ==&lt;br /&gt;
&lt;br /&gt;
=== Grupos de noticias ===&lt;br /&gt;
&lt;br /&gt;
Cualquier duda que tengas de Clarion podes recurrir al [news://news.softvelocity.com/softvelocity.clarion.intl.spanish Foro de soporte oficial en Español]&lt;br /&gt;
&lt;br /&gt;
Server: news.softvelocity.com&lt;br /&gt;
&lt;br /&gt;
Grupo: softvelocity.clarion.intl.spanish&lt;br /&gt;
&lt;br /&gt;
=== Foro Clarioneros ===&lt;br /&gt;
&lt;br /&gt;
[http://www.clarioneros.com www.clarioneros.com]&lt;br /&gt;
&lt;br /&gt;
== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php  Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://faq.clarionmag.com ClarionFAQ en Clarion Magazine]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Página de ayuda con Templates de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ Página que contiene Webinars y tutoriales. Muy útil.]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionwiki.com/ Wiki de Clarion en inglés]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://evolutionconsulting.com.ar/download.htm Evolution Consulting - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=46</id>
		<title>Portada</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Portada&amp;diff=46"/>
		<updated>2014-11-12T14:27:04Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Wiki Clarion en español ==&lt;br /&gt;
&lt;br /&gt;
Bienvenidos a este Wiki, que intenta ser una guía en idioma español para los usuarios de Clarion.&lt;br /&gt;
&lt;br /&gt;
La idea del sitio es agrupar manuales, trucos, ideas, código, templates gratuitos o simplemente recomendaciones para los usuarios de Clarion. El objetivo es agrupar los documentos o respuestas que se han publicado en los foros de consulta en un lugar centralizado, donde los usuarios novatos (y los más avanzados también...) puedan tenerla más a mano y organizada.&lt;br /&gt;
&lt;br /&gt;
== Secciones ==&lt;br /&gt;
    &lt;br /&gt;
[[Manuales]]   &lt;br /&gt;
    &lt;br /&gt;
[[Puntos Embebidos|Puntos embebidos]]&lt;br /&gt;
       &lt;br /&gt;
[[Codigo Util|Código útil]]   &lt;br /&gt;
    &lt;br /&gt;
[[Recomendaciones|Recomendaciones y trucos]]&lt;br /&gt;
&lt;br /&gt;
[[Soluciones|Soluciones a Problemas Comunes]]   &lt;br /&gt;
    &lt;br /&gt;
[[Templates gratuitos]]   &lt;br /&gt;
    &lt;br /&gt;
[[Aplicaciones de Ejemplo]]   &lt;br /&gt;
    &lt;br /&gt;
[[Sitios Web sobre Clarion]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ¿Cómo se edita una página Wiki? ==&lt;br /&gt;
&lt;br /&gt;
Para conocer cómo se edita/crea una página Wiki pueden leer directamente el tutorial en español desde la Wikipedia. Visiten por favor la siguiente dirección: &lt;br /&gt;
&lt;br /&gt;
[http://es.wikipedia.org/wiki/Wikipedia:C%C3%B3mo_se_edita_una_p%C3%A1gina  ¿Cómo se edita una páqina Wiki?]&lt;br /&gt;
&lt;br /&gt;
En este wiki, sólo los usuarios registrados pueden crear o editar páginas. Si desea colaborar como editor, por favor solicite la creación de su cuenta a jbrugger (arroba) dasu.com.ar&lt;br /&gt;
&lt;br /&gt;
Tenga en cuenta que NO debe hacer pruebas sobre este sitio, ya que el mismo forma parte de la comunidad de usuarios de Clarion y es consultado diariamente.&lt;br /&gt;
&lt;br /&gt;
== Importante ==&lt;br /&gt;
&lt;br /&gt;
Toda la información que se provee aquí debe ser de uso público y por favor, tengan en cuenta que va a ser utilizada por cualquier programador Clarion. Si ud. tiene algo que no desea compartir, o sólo está disponible por una suma de dinero, por favor no lo postee aquí.&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=45</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=45"/>
		<updated>2014-11-12T14:26:20Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php  Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://faq.clarionmag.com ClarionFAQ en Clarion Magazine]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Página de ayuda con Templates de Capesoft]&lt;br /&gt;
&lt;br /&gt;
[http://www.ClarionLive.com/ Página que contiene Webinars y tutoriales. Muy útil.]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionwiki.com/ Wiki de Clarion en inglés]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://evolutionconsulting.com.ar/download.htm Evolution Consulting - Downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.dasu.com.ar/clarion DASU]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=44</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=44"/>
		<updated>2014-11-12T14:11:56Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php  Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;br /&gt;
&lt;br /&gt;
[http://evolutionconsulting.com.ar/download.htm Evolution Consulting - Downloads]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=43</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=43"/>
		<updated>2014-11-12T14:11:40Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Repositorios de archivos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php  Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/D7.EXE.0 Par2.com Download Center]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=42</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=42"/>
		<updated>2014-11-12T14:11:27Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Repositorios de archivos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php  Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/wfdownloads/ ClarionDeveloper downloads]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/ftp/ Icetips FTP]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=41</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=41"/>
		<updated>2014-11-12T14:11:04Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento gratuitas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php  Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
== Repositorios de archivos ==&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=40</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=40"/>
		<updated>2014-11-12T14:10:33Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento gratuitas ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php  Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=39</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=39"/>
		<updated>2014-11-12T13:51:00Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://faq.clarionmag.com ClarionFAQ en Clarion Magazine]&lt;br /&gt;
&lt;br /&gt;
[http://www.nettalkcentral.com/ Página de ayuda con Templates de Capesoft]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=38</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=38"/>
		<updated>2014-11-12T13:50:42Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;br /&gt;
&lt;br /&gt;
[http://www.clariondeveloper.net/modules/smartfaq/ ClarionDeveloper FAQs]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
	<entry>
		<id>https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=37</id>
		<title>Comunidad Clarion</title>
		<link rel="alternate" type="text/html" href="https://clarionwiki.com.ar/index.php?title=Comunidad_Clarion&amp;diff=37"/>
		<updated>2014-11-12T13:50:25Z</updated>

		<summary type="html">&lt;p&gt;Jorge Brugger: /* Bases de conocimiento */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bases de conocimiento ==&lt;br /&gt;
&lt;br /&gt;
[http://www.schoeffler.biz/cwkb.php Clarion for Windows Knowledge Base]&lt;br /&gt;
&lt;br /&gt;
[http://www.clarionfaq.com ClarionFAQ]&lt;br /&gt;
&lt;br /&gt;
[http://www.icetips.com/articleindex.php Icetips Articles]&lt;br /&gt;
&lt;br /&gt;
[http://www.par2.com/CWS/C5LAUNCH.DLL/FAQS/THEFAQS.EXE.0 Par2.com Just the FAQs]&lt;/div&gt;</summary>
		<author><name>Jorge Brugger</name></author>
	</entry>
</feed>