Professional Documents
Culture Documents
CURSO DE X++
ndice
ndice
CURSO DE X++ INTRODUCCIN MTODOS CONTENEDORES Y SUS FUNCIONES SENTENCIAS BSICAS DEL LENGUAJE X++ INSTRUCCIONES DE ACCESO A REGISTROS JOBS ESTNDARES PARA LOS MTODOS DE LAS TABLAS MTODOS DISPLAY Y EDIT MTODOS BSICOS EN TABLAS CONTROL DE TRANSACCIONES HERRAMIENTAS DE DESARROLLO PROGRAMACIN DE FORMULARIOS PASO DE PARMETROS ENTRE OBJETOS: LA CLASE ARGS PROGRAMACIN DE INFORMES PLANTILLAS DE INFORMES CLASES DESARROLLO CLIENTE / SERVIDOR 1 4 8 17 19 27 37 38 41 44 51 54 61 79 82 94 95 107
ndice
OTRAS HERRAMIENTAS DE DESARROLLO COMUNICACIN CON EL USUARIO LA CLASE RUNBASE MAPS ACCESO A CLAVES DE FUNCIN DESDE EL CDIGO GESTIN DE EXCEPCIONES ACCESO A MEN ITEMS DESDE EL CDIGO INDICACIN DE OPERACIONES EN EJECUCIN XCLASES PERSONALIZANDO FORMULARIOS LOOKUP DEFINIDO. FUNCIONES GENERALES
109 117 125 131 133 134 137 138 139 ERROR! MARCADOR NO
140
Introduccin
Introduccin
1.
1.1.
El entorno MorphX
Definicin
El entorno de desarrollo en Navision Axapta se llama MorphX. Podemos considerarlo un entorno integrado de desarrollo (Integrated Development Environment IDE), porque integra muchas funciones diferentes, como diseo, edicin, compilacin y depuracin en un entorno comn. En herramientas de desarrollo ms tradicionales, cada una de estas funciones operara como un programa independiente, cada uno con su propia interfaz. MorphX permite al usuario modificar de un modo sencillo los objetos de la interfaz grfica. Al mismo tiempo que ofrece al usuario avanzado las herramientas necesarias para modificar fcilmente la funcionalidad de la aplicacin o bien crear diseos completamente nuevos. El rbol de objetos de la aplicacin (Application Object Tree AOT) es el elemento central desde el que el programador puede crear nuevos objetos o bien modificar los existentes. El desarrollador puede crear nuevos objetos utilizando la tcnica de arrastre (drag-and-drop) y asignndoles propiedades. Para hacer el trabajo del desarrollador ms fcil y rpido, el sistema tiene valores por defecto para todas las propiedades de los objetos de la aplicacin. Dado que se trata de un sistema de desarrollo orientado a objetos, el concepto de herencia es fundamental. La herencia significa que lo que se ha definido en niveles inferiores del sistema es automticamente heredado en niveles superiores. Un ejemplo claro del concepto de herencia es la posibilidad que tiene el desarrollador de modificar y aumentar la funcionalidad del sistema escribiendo sus propios mtodos. En Navision Axapta, la herencia no se limita nicamente a las clases, sino que se extiende a todo el sistema. De este modo, los objetos heredan no slo variables y mtodos, sino tambin propiedades.
1.2.
1.2.1.
Clase de sistema
Una clase de sistema (system class) es una interfaz de funcionalidad definida en MorphX, por ejemplo para crear o ejecutar un formulario.
1.2.2.
Clase
Una clase (class) define las interfaces de un objeto. Ensea o explica como construir un objeto de un tipo particular.
Pgina 4 de 141
Introduccin
Una caracterstica esencial de una clase es que podemos crear nuevas instancias (objetos) de la clase. Los formularios, informes e incluso las tablas son ejemplos de clases: MorphX tiene una definicin de clase que define qu ocurre exactamente cuando un objeto de cada tipo es creado.
1.2.3.
Controles
Un control es un objeto grfico, como una caja de texto (text box), una casilla de verificacin (check box) o un botn de comando (command button) que podemos situar en un formulario o un informe cuando lo diseamos, para que nos muestre informacin, realice una accin o hacer el formulario o informe ms fcil de leer. Hay aproximadamente 20 controles diferentes y cada uno est definido por alrededor de 50 propiedades.
1.2.4.
Origen de datos
Un origen de datos (Data Source) contiene las variables de datos que utilizan un formulario o una consulta. Estas variables de datos pueden ser una o ms tablas, o campos individuales de las tablas.
1.2.5.
Diseos
Un nodo de diseos (Designs) proporciona acceso al usuario para definir el aspecto de un formulario o de un informe.
1.2.6.
Encapsulacin
La encapsulacin significa que los datos en el sistema son definidos dentro de los mtodos y solo pueden ser modificados desde los propios mtodos.
1.2.7.
Final
Final es un modificador de una clase o un objeto que indica que dicha clase o mtodo no puede ser ampliado o sobrecargado.
1.2.8.
Herencia
La herencia es un concepto fundamental en MorphX. Significa que lo que es definido en niveles inferiores del sistema es automticamente accesible, o lo que es lo mismo, heredado por los niveles superiores.
1.2.9.
Objetos
Los objetos son el concepto central de MorphX. Cualquier formulario y cualquier control es un objeto. La base de datos es tambin un objeto. En definitiva, cualquier cosa presente en el sistema es un objeto. Los objetos son creados a partir de las clases. Decimos por tanto que un objeto es una instancia de una clase.
Pgina 5 de 141
Introduccin
Los objetos proporcionan una forma lgica y conveniente de organizar los datos y los procedimientos. Los objetos estn encapsulados, lo que significa que contienen tanto su cdigo como sus datos. Para utilizar un objeto, debemos mantener una referencia a l mediante una variable del mismo tipo del objeto.
1.2.10. Mtodos
Los mtodos son tareas que podemos decir a un objeto que realice.
1.2.11. Propiedad
Las propiedades son datos que describen un objeto. Cada tipo de objeto tiene diferentes tipos de propiedades. Un mtodo tpicamente tiene unas pocas propiedades, una de las cuales, por ejemplo, define donde queremos que se ejecute. Por otra parte, un control tiene acerca de 50 propiedades que definen el color, el tamao, la posicin, etc.
1.2.12. Consulta
Una consulta es un mecanismo de filtrado para recuperar los datos que nos interesa ver a partir de las tablas de nuestra base de datos. Las consultas son utilizadas normalmente como el origen de datos en los formularios e informes.
2.
2.1.
El lenguaje X++
Introduccin
El lenguaje X++ es un lenguaje sencillo y fcil de aprender, para que pueda ser utilizado por la mayora de desarrolladores. Es un lenguaje orientado a objetos, para beneficiarse de las ventajas de las metodologas modernas de desarrollo de software, que se acopla perfectamente en aplicaciones cliente/servidor. Por ltimo, es un lenguaje interpretado, al estilo de Java, para obtener mximas capacidades dinmicas.
2.2.
a)
Caractersticas
Lenguaje simple, orientado a objetos y familiar
Las principales caractersticas de X++ son que se trata de un lenguaje sencillo que puede ser utilizado rpidamente, si se conoce la metodologa de la programacin orientada a objetos. Los conceptos fundamentales de X++ son asimilados rpidamente, por tanto los programadores pueden ser productivos desde el principio. X++ ha sido diseado desde su base para ser orientado a objetos. X++ proporciona una plataforma de desarrollo orientada a objetos limpia y eficiente. El lenguaje X++ utiliza principios de la programacin orientada a objetos como encapsulacin, herencia, clases, objetos, mtodos y propiedades.
Pgina 6 de 141
Introduccin
A pesar de que C++ y Java fueron rechazados como lenguajes para utilizar con MorphX, el aspecto de X++ es muy similar al de estos dos lenguajes, aunque se ha eliminado la complejidad innecesaria de estos lenguajes. Adems, como MorphX es una plataforma para construir complejos sistemas de gestin empresarial y contabilidad, el lenguaje X++ tambin incluye un gran nmero de comandos comunes de SQL como parte integrada del lenguaje. El hecho de que X++ tenga una sintaxis muy similar a lenguajes ya existentes como C++, Java o SQL hace que X++ sea un lenguaje familiar para la mayora de desarrolladores de software. Esto significa que pueden migrar rpidamente a este nuevo lenguaje. b) Lenguaje robusto
El lenguaje X++ ha sido diseado para crear software muy fiable. Proporciona comprobaciones muy amplias en tiempo de compilacin, seguidas de un segundo nivel de comprobaciones en tiempo de ejecucin. Las caractersticas del lenguaje dirigen a los programadores hacia unos hbitos de programacin fiable. El modelo de manejo de la memoria es extremadamente simple: los objetos son creados mediante un operador new. No existe un tipo de datos puntero definido por el programador de forma explcita, lo que implica que no necesitamos aritmtica de punteros ni tenemos la necesidad de realizar limpieza de punteros en memoria, con lo que resulta innecesarias las llamadas al mtodo finalize. Este sencillo modelo de manejo de memoria elimina gran cantidad de errores de programacin muy comunes entre los programadores de C y C++. Podemos desarrollar cdigo en el lenguaje X++ con la seguridad de que el sistema encontrar la mayora de los errores rpidamente y con la tranquilidad de que no tendremos problemas latentes no descubiertos hasta que nuestro cdigo est en circulacin en el mercado. c) Lenguaje de alto rendimiento
El rendimiento es siempre algo a tener en consideracin. El lenguaje X++ consigue un superior rendimiento adoptando un esquema de trabajo en el cual el intrprete puede trabajar a la mxima velocidad sin necesidad de comprobar el entorno en tiempo de ejecucin. El liberador de memoria automtico (automatic garbage collector), se ejecuta automticamente cuando es necesario, asegurando una probabilidad muy alta de que la memoria est disponible cuando se necesite, lo que se traduce en un mejor rendimiento. En general, los usuarios perciben que las aplicaciones interactivas responden ms rpidamente a pesar de que son interpretadas. d) Lenguaje interpretado y dinmico
En una plataforma interpretada como el lenguaje X++, la fase de enlazado de un programa es sencilla, incremental y ligera. De esta forma nos beneficiamos de unos ciclos de desarrollo y prototipado mucho ms rpidos, comparados con los pesados ciclos de compilacin, enlazado y pruebas tradicionales.
Pgina 7 de 141
Mtodos
Mtodos
1. Introduccin
Todo objeto puede identificarse por el estado en que se encuentra y por su comportamiento. En programacin, el estado de un objeto se define mediante variables, mientras que su comportamiento est definido por mtodos. Los mtodos actan sobre las variables del objeto haciendo evolucionar su estado. Las variables de un objeto slo son accesibles directamente por mtodos propios del objeto, nunca desde el exterior. En Axapta podemos encontrar mtodos en todos los objetos que componen la aplicacin, es decir, en: Tablas Formularios Informes Consultas Clases
En cada uno de estos objetos, los mtodos se crean del mismo modo que los elementos restantes de la aplicacin, es decir, utilizando el rbol de Objetos de la Aplicacin.
2.
Cabecera
Instrucciones
Pgina 8 de 141
Mtodos
2.1.
Cabecera
La cabecera de un mtodo tiene el siguiente aspecto (entre [] se muestran los valores opcionales):
Los modificadores y los parmetros se describen en apartados posteriores. El tipo de dato de retorno puede tomar los siguientes valores: Tipo de dato void : este trmino se utiliza cuando el mtodo no devuelve nada. anytype : significa que el mtodo puede devolver todos los tipos de datos (mediante distintas instrucciones de retorno en el cuerpo del mtodo) Siempre que un mtodo devuelva algn valor, se debe especificar el tipo del valor de retorno e incluir una instruccin de retorno (return ...).
2.2.
Cuerpo
El cuerpo de un mtodo tendr el siguiente aspecto: { [Declaracin de variables] [Declaracin de mtodos] [;] Instrucciones; }
Aunque no forma parte de la estructura de un mtodo, es recomendable aadir siempre una lnea con un punto y coma (;) antes del grupo de instrucciones. Esto es debido a que en algunas ocasiones, el compilador confunde una instruccin con la declaracin de una variable y devuelve un error de sintaxis en un mtodo cuyas instrucciones son completamente correctas. El nico modo de evitar este error es marcar el inicio del bloque de instrucciones con un punto y coma. Si revisamos algunos de los mtodos de la aplicacin estndar, observaremos que la mayora de ellos utilizan esta tcnica. La declaracin de variables y de mtodos se describe a continuacin. Las instrucciones se irn viendo a lo largo del curso.
Pgina 9 de 141
Mtodos
2.2.1.
Declaracin de variables
Una variable es un puntero a una posicin de memoria donde se almacena informacin de un tipo de datos especfico. Todas las variables deben ser declaradas antes de poder ser usadas. Hay que sealar que X++ no permite que la declaracin de variables se mezcle con otras instrucciones del lenguaje. En otras palabras, el lenguaje X++ requiere que las variables sean declaradas antes de cualquier otra instruccin. La sintaxis de la declaracin es la misma, tanto si es una variable simple o una variable de objeto. Las variables pueden ser declaradas de tres formas en X++: declaracin simple, declaracin con inicializacin y declaracin mltiple. a) Declaracin simple
La declaracin simple de variables es la ms utilizada, ya que es rpida y la mayora de variables son simples. La sintaxis es la siguiente: TipoDato IdentificadorVariable
TipoDato es cualquier tipo de datos del lenguaje X++. IdentificadorVariable es bsicamente un nombre cuyo primer carcter debe ser una letra que puede estar seguida por letras o nmeros. Como letras se consideran los caracteres a..z y el carcter subrayado (_). Para los tipos de datos, si se trata de un objeto de la aplicacin su nombre se escribir mezclando maysculas y minsculas, de manera que el primer carcter sea una mayscula as como la primera letra de cada palabra interna. Si se trata de un tipo de datos primitivo se escribir en minsculas. El nombre de una variable mezclar maysculas y minsculas, siendo la primera letra en minscula y el primer carcter de cada palabra interna en maysculas. A continuacin se muestran algunos ejemplos de declaracin de variables: int i; CustInvoiceJour custInvoiceJour;
La declaracin de variables de la mayora de tipos de datos de X++, exceptuando los objetos, tambin reserva un espacio de memoria para dichas variables. Cuando una variable es declarada adems se inicializa con un valor por defecto. b) Declaracin con inicializacin
En ocasiones nos interesa que una determinada variable tenga un valor distinto al valor por defecto, en el mismo instante en que la variable se crea. El lenguaje X++ permite la inicializacin de variables en la sentencia de declaracin. La inicializacin se lleva a cabo aadiendo una sentencia de asignacin a la declaracin de la variable.
Pgina 10 de 141
Mtodos
Un ejemplo de este tipo de declaracin sera el ejemplo siguiente, donde una variable real de nombre pi, es declarada e inicializada al valor del nmero Pi: real pi = 3.14159265359; Existe otra sintaxis para inicializar objetos, ya que estos son inicializados invocando el mtodo new de la clase. Un ejemplo de inicializacin sera el siguiente: Class classObject = new Class(); Lo que declarara un objeto llamado classObject de la clase Class y lo inicializara. c) Declaracin mltiple
A veces necesitamos varias variables del mismo tipo. En estos casos puede llegar a ser una prdida de tiempo tener que escribir el tipo de dato delante de cada variable que vayamos a declarar. Por este motivo, X++ nos permite declarar ms de una variable en la misma sentencia de declaracin. La sintaxis es la siguiente: TipoDato Variable {, Variable}
Un ejemplo sera de declaracin mltiple sera el siguiente: real a, b = 1.5; En esta sentencia se declaran dos variables de tipo real llamadas a y b, inicializando la variable b a 1.5. Dentro de un mtodo podemos hacer referencia al objeto al que pertenece el mtodo mediante la variable this. sta nos da acceso a todos los mtodos y propiedades de dicho objeto. Es utilizado normalmente como parmetro para los mtodos que necesitan una referencia al objeto.
2.2.2.
Declaracin de mtodos
Los problemas complejos del mundo real son a menudo ms fciles de resolver si los dividimos en problemas ms pequeos que puedan ser resueltos independientemente unos de otros. El lenguaje de programacin X++, nos permite introducir mtodos dentro de otros mtodos. Otros lenguajes como Java o C++ no soportan esta caracterstica. Aunque en la realidad no es una prctica comn. Los mtodos incrustados dentro de otros mtodos solo son visibles dentro del mbito en el cual son creados y definidos. Ejemplo void myMethod() { void myEmbeddedMethod() { Box(1, Este es un mtodo incrustado, 1); }
Pgina 11 de 141
Mtodos
myEmbeddedMethod(); } El mtodo llamado myEmbeddedMethod, tan solo estara visible desde el mbito en el que fue creado, es decir dentro del mtodo llamado myMethod.
2.2.3.
Las reglas relativas al mbito de las variables en X++ son muy sencillas, todos los mtodos tienen su propio mbito. Para usar datos de un mtodo a otro, o lo que es lo mismo, datos de mbitos diferentes, debemos trasladar los datos utilizando parmetros. Un mtodo puede tener uno o ms argumentos. Dentro del mbito de ese mtodo esos parmetros son tratados como variables locales, inicializadas con el valor que tena el parmetro en la llamada. Es importante sealar que todos los parmetros son pasados por valor. Esto significa que no podemos modificar el valor de la variable original, pero s el de la variable local en el mtodo, la cual es una copia de la original. A continuacin mostramos un ejemplo: void methodA(int i) { i = i + 1; print i; } void methodB() { int i = 3; print i; this.methodA(i); print i; } En este ejemplo el mtodo methodB tiene una variable local llamada i, la cual se utiliza como parmetro para llamar al mtodo methodA. El mtodo methodA utiliza un parmetro llamado i, por lo tanto tiene una variable local llamada i. Esta variable tiene el valor de la variable i del mtodo methodB, ya que ha sido utilizada como parmetro de la llamada. El resultado de invocar el mtodo methodB es la impresin del valor de la variable i del mtodo methodB antes y despus de la invocacin del mtodo methodA que imprime el valor de su variable local i. El resultado de la ejecucin es el siguiente: 3 4 3 Esto ilustra perfectamente que las dos variables i son distintas en cada mtodo y que el mtodo methodA no puede cambiar el valor de los parmetros fuera de su mbito.
Pgina 12 de 141
Mtodos
2.3.
Algunos ejemplos
La forma ms simple que puede tener un mtodo se muestra a continuacin: Ejemplo 1 void methodName() { } Este ejemplo muestra un mtodo que no devuelve nada (void) y que no utiliza parmetros (los parntesis estn vacos). Adems, el cuerpo del mtodo (entre llaves) est vaco. El ejemplo es una declaracin vlida de un mtodo, pero como no hay instrucciones en el cuerpo, el mtodo no har nada. Ejemplo 2 int methodName() { return 1 } Si el mtodo debe devolver algo, por ejemplo un entero, la declaracin debe parecerse al ejemplo 2. La palabra int antes del nombre del mtodo, indica que el mtodo devolver un entero y la instruccin return 1 en el cuerpo devuelve el valor entero 1 al elemento que ha llamado al mtodo. Esto significa que se puede utilizar el resultado de la llamada al mtodo en una expresin, asignacin o incluso como parmetro en una llamada a otro mtodo. Un mtodo un poco ms complejo (sin argumentos ni modificadores) es por ejemplo, el mtodo delete de la tabla de proveedores. Mtodo delete en la tabla VendTable void delete() { Address address; ttsbegin; //Comienza la transaccin super(); //Llamada al mtodo delete de la clase superior
//Selecciona todas las direcciones para ese proveedor while select address where address.AdrTableId == this.TableId && address.AdrRecId == this.RecId { address.delete(); //Llamada al mtodo delete } ttscommit; //Acepta la transaccin
Pgina 13 de 141
Mtodos
} En el ejemplo podemos ver la cabecera del mtodo sin modificadores ni argumentos. A continuacin tenemos la declaracin de una variable llamada address. Al lado de cada instruccin se ha descrito su funcin mediante un comentario. Una lnea de comentario se marca mediante los caracteres //, mientras que un bloque de comentarios debe enmarcarse entre los caracteres /* y */.
3.
3.1.
Parmetros
Definicin
En algunas ocasiones son necesarios datos externos para utilizarlos en un mtodo, y la nica forma de realizar esto es definiendo datos de entrada al mtodo conocidos como parmetros. Si se utilizan parmetros en un mtodo, el mtodo puede escribirse a menudo de una manera ms general, lo que significa que tendr que escribirse menos cdigo para llevar a cabo una tarea. Como se describe en un apartado anterior, los parmetros en los mtodos son declarados en la declaracin del mtodo. Posteriormente son utilizados cuando se realiza una llamada al mtodo. La lista de parmetros que se declara en la cabecera de un mtodo estar compuesta por uno o ms parmetros separados por comas. La declaracin de cada uno de los parmetros tiene la siguiente estructura: TipoDato NombreParmetro [=Expresin] Es decir, los parmetros se declaran como si se tratar de una declaracin normal de variables. Como ejemplo de un mtodo que devuelve algo y utiliza parmetros podemos ver la declaracin del siguiente mtodo de la tabla CustTable:
Boolean chekDimension(Dimension dimension) { } El mtodo checkDimension devuelve un booleano y utiliza un parmetro del tipo de datos extendido Dimension, que es un vector de cadenas de caracteres.
3.2.
Parmetros opcionales
Es posible inicializar los parmetros en la declaracin. Esto convierte al parmetro en un parmetro opcional, de modo que si no es utilizado en la llamada al mtodo se utiliza el valor de la inicializacin.
Pgina 14 de 141
Mtodos
Veamos un ejemplo: Sea una clase Human, cuyo mtodo new tiene el siguiente aspecto (cuando veamos las clases hablaremos con ms detalle de este mtodo, de momento simplemente indicaremos que permite crear e inicializar las variables de un objeto): void new (Date _birthdate) { birthdate = _birthdate; } Es decir, al crear un objeto de la clase Human, simplemente estamos asignando el valor del parmetro a la variable birthdate. A continuacin, definimos un mtodo que calcula la edad en aos a partir de una fecha que se puede especificar como parmetro. Este parmetro es opcional, es decir, si no pasamos una fecha en la llamada al mtodo tomar como fecha de clculo la fecha de hoy: real age(date _calcDate = today()) { return (_calcDate - this.birthdate)/365; } Veamos las distintas posibilidades de llamada al mtodo:
Human kid = new Human(1/1/90); // Crea un objeto de tipo Human print kid.age(); //Imprime la edad a fecha de hoy print kid.age(1/1/1991); //Imprime la edad a fecha 1/1/91
4.
Modificadores
Existen diferentes modificadores que pueden ser aplicados en la declaracin de mtodos. Son los siguientes: a) Static Crea un mtodo de clase que no puede operar sobre un objeto. b) Final Crea un mtodo que no puede ser sobrecargado por subclases. No puede ser aplicado a los mtodos new y finalize. c) Display Los mtodos de este tipo siempre devuelven un valor. Se utilizan para asignar un valor a un campo en un informe o en un formulario. El campo no puede ser modificado.
Pgina 15 de 141
Mtodos
d)
Edit Los mtodos de este tipo siempre devuelven un valor. Se utilizan para asignar un valor a un en un formulario, que puede ser modificado.
Tal y como se vio en un apartado anterior, los modificadores forman parte de la cabecera de un mtodo, y se utilizan justo antes del tipo de datos de retorno. Como ejemplo, veamos algunas cabeceras de mtodos: static void ClassNoChange() final int DontAlterMe() display int Value() El modificador final se ver ms adelante, en el captulo dedicado a clases. Los modificadores display y edit tienen dedicado su propio captulo. Los mtodos de tipo static se describen en el siguiente apartado.
5.
Mtodos estticos
Los mtodos estticos nunca operan sobre un objeto, es decir sobre una instancia de la clase en ejecucin. Podemos ver muy fcilmente con un ejemplo el significado de los mtodos estticos. Supongamos un mtodo exist que recibe como parmetro un cdigo de cliente y nos indica si el cliente existe o no. Si el mtodo actuara sobre un objeto, no tendra ningn sentido, ya que para ejecutar el mtodo debera existir el objeto y por lo tanto el resultado sera siempre s. La declaracin de este mtodo podra tener la siguiente cabecera: static Boolean exist (CustAccount _custAccount) Dado que un mtodo esttico no opera sobre un objeto, no podemos utilizar la variable this. Por otro lado, y dado que se trata de mtodos de clase, nunca pueden ser sobrecargados. Como regla general de diseo en un entorno orientado a objetos y cliente/servidor, un mtodo se declarar como esttico cuando no tiene acceso a los miembros (variables y mtodos) de la instancia y, por lo tanto no utiliza el puntero this, y no va a ser sobrecargado. Como los mtodos estticos no operan sobre los objetos, no pueden ser llamados como cualquier otro mtodo no esttico. Por lo tanto tenemos que llamarlos utilizando el operador de mbito (scope-operator) ::, como en el siguiente ejemplo: ClassName::myMethod() Dentro de una clase, es posible declarar un mtodo esttico y un mtodo no esttico con el mismo nombre. Como por ejemplo: void myMethod() { // Instrucciones }
Pgina 16 de 141
Mtodos
static void myMethod() { // Instrucciones } En este caso tendramos dos mtodos con el mismo nombre, sin embargo como uno de ellos es esttico no se invocaran de la misma manera. Por ejemplo, className.myMethod() invocara el mtodo de la instancia actual de la clase, es decir el mtodo del objeto, mientras que ClassName::myMethod() invocara el mtodo esttico de la clase, con lo que no existe confusin posible.
En un entorno cliente/servidor, es interesante reducir al mximo el trfico en la red. Desde este punto de vista, resulta ms baratos llamar a un mtodo esttico de forma remota que instanciar un objeto y despus llamar a uno de sus mtodos.
2.
Pgina 17 de 141
Mtodos
3.
Descripcin Eliminacin de un nmero especfico de elementos de un contenedor. El primer entero especifica la posicin inicial a partir de la que se van a eliminar elementos. El segundo indica el nmero de elementos a borrar. Devuelve un contenedor.
ConFind ( container, element, Localiza la primera ocurrencia del elemento pasado como .) parmetro entre los elementos de un contenedor. Devuelve 0 si no ha encontrado el elemento, o el n de posicin que ste ocupa en el contenedor. ConIns element) (container, int, Inserta un elemento en un contenedor, en la posicin que le pasamos como parmetro. Devuelve el nuevo contenedor. Devuelve el nmero de elementos que tiene el contenedor. Devuelve un contenedor vaco. Devuelve el elemento del contenedor que ocupa la posicin que le hemos pasado como parmetro. int, Reemplaza el/los elemento/s del contenedor a partir de la posicin que se le pasa como parmetro. Si deseamos reemplazar varios elementos los pondremos seguidos de comas. Devuelve el contenedor con los elementos reemplazados.
ConPoke element)
(container,
Pgina 18 de 141
2.
Operadores
Significado
Igual a Distinto de Mayor que Mayor o igual que Menor que Menor o igual que No
Operador
== != > >= < <= !
Operador
&& ||
Significado
Funcin Y Funcin O
3.
3.1.
Sentencias condicionales
Instruccin IF
Normalmente queremos hacer diferentes cosas con datos distintos. Para hacer esto posible, necesitamos decidir en funcin de una condicin. Una instruccin if evala una condicin y ejecuta un conjunto de instrucciones dependiendo del valor lgico de esa condicin. La instruccin if es la instruccin de bifurcacin ms simple que ofrece el lenguaje X++, y est definida de la siguiente forma: if ( expresin ) instrucciones [ else instrucciones ]
Pgina 19 de 141
La expresin entre parntesis (la condicin), puede ser cualquier expresin que pueda evaluarse a verdadero o falso. Hay que recordar que cualquier nmero diferente de 0 y cualquier cadena de caracteres no vaca se interpreta como un valor cierto, mientras que solo vamos a considerar como valor falso cuando tengamos un nmero igual a 0 o cadena de caracteres vaca. A continuacin presentamos dos ejemplo de instruccin if: Sin Else 1) if (a>4) print a; 2) if (Debtor.NameRef == Uptown Radio) print Great music; 3) if (bankAccountTrans) { sentencias} 4) if (!this.validation()) { throw error("@SYS18447"); }
Con Else 1) if (a>4) print a; else print 4 es mayor que a; 2) if (BankAccountTable::Find(AccountId).Name) print Cuenta existente; else print No existe la cuenta;
3.2.
Instruccin SWITCH
La sentencia switch es una sentencia de bifurcacin mltiple. Eso significa que podemos seguir ms de dos caminos utilizando esta sentencia, en contraste con la instruccin if. En una instruccin switch, normalmente queremos que ocurra algo por defecto, si no se elige ninguna de las alternativas correspondientes a los distintos caminos posibles a seguir. Por tanto, existe un camino por defecto que se sigue si no se ha elegido ninguno de los otros posibles.
Pgina 20 de 141
Dependiendo de una condicin que se evala, la ejecucin del programa salta al camino correcto y contina la ejecucin desde all. Si queremos que la ejecucin se pare en algn lugar determinado dentro de la instruccin switch debemos utilizar la sentencia break. La sintaxis es la siguiente: switch (Expresin) { case Expresin {, Expresin}: Instrucciones; [break;]
case ...
[defaut Instrucciones; ] }
Un ejemplo de una instruccin switch, en comparacin con una instruccin if, sera el siguiente: Ejemplo instruccin switch switch (i) { case 10: // Instrucciones A; break; case 20: // Instrucciones B; break; default: // Instrucciones C; break; } Ejemplo instruccin if if (i==10) // Instrucciones A; else if (i==20) // Instrucciones B;
Pgina 21 de 141
else //Instrucciones C; Como podemos ver, en estos casos la instruccin switch es mucho ms intuitiva y fcil de entender que la instruccin if. Es importante sealar que si no utilizramos la instruccin break, la ejecucin del programa continuara con las instrucciones correspondientes a los siguientes caminos de ejecucin definidos en la instruccin switch. Ejemplos de Switch 1) switch (budget.tableId) { case tablenum(LedgerBudget): return new BudgetExpansion(budget); case tablenum(ForecastSales),tablenum(ForecastPurch): return new ForecastExpand(budget); case tablenum(ProjBudgetEmpl): return new BudgetExpansion(budget); case tablenum(ProjBudgetCost): return new BudgetExpansion(budget); case tablenum(ProjBudgetRevenue): return new BudgetExpansion(budget); } 2) switch (f) { case 2 : label = rd.lookupLabel(literalStr("@SYS53635")); break; case 3 : label = rd.lookupLabel(literalStr("@SYS3794")); break; case 4 : label = rd.lookupLabel(literalStr("@SYS50253")); break; case 5 : label = rd.lookupLabel(literalStr("@SYS477")); break; case 6 : label = rd.lookupLabel(literalStr("@SYS6437")); break;
Pgina 22 de 141
3.3.
Operador ternario: ?
A veces necesitamos elegir entre dos expresiones dependiendo de alguna condicin concreta. Eso puede realizarse utilizando la instruccin if estndar antes comentada. Esto nos obligara a realizar dos grupos de instrucciones, sin embargo el operador ternario (?) se puede ahorrrar cdigo. La sintaxis de este operador se presenta a continuacin: Expresin ? Expresin : Expresin
Si la primera expresin es verdadera, devolveramos la expresin situada inmediatamente detrs del smbolo ?, por el contrario, si es falsa devolveramos la expresin situada detrs de los dos puntos (:). La funcionalidad es similar a la de la instruccin if, pero mientras que en sta podemos elegir entre dos grupos de instrucciones, con el operador ternario podemos elegir entre dos expresiones. Las ventajas del operador ternario con respecto a la instruccin if se ilustran en el siguiente ejemplo: Operador ternario int result; int choose = 3; ; result = choose > 3 ? 100 : 50; Instruccin if int result; int choose = 3; if (choose > 3) result = 100; else result = 50; Como podemos ver con el operador ternario el cdigo es ms corto y adems podemos devolver el resultado de una manera directa, lo que hace aconsejable su utilizacin en determinadas ocasiones.
4.
4.1.
Sentencias de repeticin
Instruccin WHILE
A menudo necesitamos repetir algo mientras que una expresin sea verdadera. Si por ejemplo, estamos leyendo un fichero de texto, debemos seguir leyendo mientras haya ms texto en el fichero, es decir, antes de alcanzar el fin del fichero.
Pgina 23 de 141
Una instruccin while slo se ejecuta si la condicin es verdadera. Esto significa que una instruccin while puede ejecutarse varias veces, una vez o incluso ninguna, dependiendo de la condicin inicial. La sintaxis es la siguiente: while ( Expresin ) Instrucciones
Ejemplos de la instruccin while. 1) int n = 10; while (n > 1) { // Instrucciones n = n - 1; } 2) while (queryCust.next()) { Sentencias } 3) while select custInvoiceJour ==
4.2.
Instruccin DO WHILE
La instruccin dowhile tiene la misma funcionalidad bsica que la instruccin while, pero se diferencia en que la condicin se comprueba despus de las instrucciones. Esto significa que una instruccin dowhile al menos se ejecuta una vez, aunque puede hacerlo varias veces dependiendo de la condicin. La sintaxis es la siguiente: do { { Instrucciones } } while ( Expresin ) A continuacin presentamos un ejemplo de instruccin dowhile. int n = 1; do { // Instrucciones n = n + 1; } while (n < 1)
Pgina 24 de 141
En este caso el conjunto de instrucciones situadas dentro del cuerpo de la instruccin dowhile se ejecutara una vez.
4.3.
Instruccin FOR
La instruccin for es una instruccin while extendida, que resulta especialmente til cuando estamos trabajando con vectores (arrays), ya que la condicin es una variable que se va incrementando en cada iteracin. Realmente, la instruccin for aade funcionalidad a la instruccin while, ya que nos da la posibilidad de asignar un valor inicial a la variable de control de la condicin y de definir una instruccin de incremento o decremento de dicha variable. En cualquier otro aspecto, una instruccin for puede ser considerada de la misma forma que una instruccin while. La sintaxis es la siguiente: for ( Inicializacin; Expresin; Actualizacin ) Instrucciones Es importante sealar que la inicializacin y la actualizacin son dos instrucciones regulares de X++, pero el uso normal de esas instrucciones en la sentencia for es inicializar y actualizar la variable de control respectivamente. Vamos a mostrar a continuacin un ejemplo que compara el uso de las instrucciones for con las instrucciones while. Instruccin for int i; for (i=1; i<=100; i=i+1) { print i; } Instruccin while int i; i = 1; while (i<=100) { print i; i=i+1; } Como podemos apreciar, conseguimos ahorrarnos algo de cdigo en el caso de la instruccin for, aunque el funcionamiento es totalmente anlogo.
Ejemplos de For:
Pgina 25 de 141
1) for (i=0; i<dictEnum.values(); i++) { sentencias } 2) for (i=1; i<=conlen(c); i++) { sentencias }
Pgina 26 de 141
2.
Instruccin SELECT
La mayora de los procesos que se programan suponen la manipulacin de los datos almacenados en las tablas y, por lo tanto, el acceso a la base de datos. Por esta razn, existe en X++ la instruccin select, que es probablemente la instruccin ms potente y ms ampliamente utilizada en el lenguaje. La instruccin select tiene como propsito buscar y manipular los datos de la base de datos. Para ello utiliza una variable de tipo tabla, que debe ser declarada antes de que pueda ser ejecutada la instruccin select. El resultado de la seleccin de registros se devuelve en esta variable, que por lo tanto es utilizada para manipular los datos. Mediante una sentencia select recuperamos un grupo de registros de la base de datos, aunque en cada momento slo tenemos acceso a uno de ellos. Para manipular otros registros del grupo, debemos desplazarnos a travs de l mediante la instruccin next. Hablando tcnicamente, la instruccin select crea un cursor que puede avanzar al siguiente registro mediante la instruccin next. La sintaxis es la siguiente: InstruccinSelect = select Parmetros
Parmetros = [ [OpcionesBsqueda] [ListaCampos from] ] VariableTabla [InstruccinIndice] [Opciones] [InstruccinWhere] [instruccinJoin] OpcionesBsqueda nofetch = reverse | findfast | firstonly | forupdate | | * | IdentificadorCampo | count
maxof
group by ) IdentificadorCampo
{, IdentificadorCampo [Direccin]} InstruccionesIndice Direccin InstruccinWhere = asc = index idx | desc | index hint idx
= where Expresin
Pgina 27 de 141
InstruccinJoin Parmetros
= [ exist
not exist
outer ] join
select * from myTable order by TableCode where TableCode > 100; } En el anterior ejemplo, seleccionamos todos los registros de la tabla llamada MyTable que tienen un valor mayor que 100 en el campo TableCode, y devolvemos el primero de ellos en la variable myTable.
Cuando deseamos acceder nicamente a un nmero reducido de campos de la tabla es ms apropiado, desde el punto de vista de la eficiencia del sistema, especificar la lista de campos que acceder a registros completos. Por lo tanto, y segn la nota anterior, en el ejemplo siguiente, el mtodo methodA sera mucho ms eficiente que el mtodo methodB: void methodA { CustTable custTable; ; select * from custTable;
Pgina 28 de 141
while (custTable.accountNum) { print custTable.accountNum; next custTable; } } Tambin podemos utilizar la sentencia next sin necesidad de tener una instruccin select previa. En estos casos se comporta como si hubiramos realizado un select implcito sin clusula where. Por ejemplo: Ejemplo 1 { MyTable myTable; next myTable; } Ejemplo 2 { MyTable myTable; select * from myTable; } En ambos casos el resultado sera el mismo. Tendramos el primer registro de la tabla MyTable en la variable myTable.
2.1.
Opciones de bsqueda
Al describir la sentencia select, se han nombrado una serie de opciones de bsqueda que se describen a continuacin: reverse: los registros son devueltos en orden inverso firstfast: esta opcin acelera la captura de los registros. En realidad, devuelve la primera fila ms rpidamente, pero el tiempo total de acceso puede ser mayor. Esta opcin suele utilizarse en actualizaciones de dilogos. firstonly: slo devuelve el primer registro que cumple la condicin de seleccin. forupdate: selecciona los registros para ser actualizados. Es decir, los registros accedidos son modificados y posteriormente se actualiza la base de datos. Dependiendo del gestor de base de datos, los registros pueden quedar bloqueados de forma que otros usuarios no puedan acceder simultneamente. nofetch: indica que los registros no van a ser accedidos por el momento. Se utiliza cuando el resultado de la seleccin se pasa a otro objeto de la aplicacin.
Pgina 29 de 141
2.2.
Opciones de clculo
Las posibles opciones de clculo que presenta la sentencia select se describen a continuacin: sum: suma avg: media minof: mnimo maxof: mximo count: nmero de registros Todas estas funciones realizan el clculo sobre las filas agrupadas segn la sentencia group by.
Si deseamos realizar un clculo sobre un campo de una tabla, es mucho ms eficiente utilizar las opciones de clculo de la instruccin select que seleccionar el grupo de registros, recorrerlos uno a uno y realizar el clculo en nuestro cdigo. La razn de esto es fcil de entender si tenemos en cuenta que la instruccin select la ejecuta el servidor de base de datos. En SQL estndar, si ningn registro de la tabla cumple las condiciones de seleccin, el resultado es una fila, cuya columna count vale 0 y las restantes funciones de clculo devuelven NULL. Dado que Axapta no soporta el concepto de valores NULL, si ningn registro cumple las condiciones de seleccin, no devuelve ninguna fila al usuario. Sin embargo, si la nica funcin de clculo que se ha utilizado es count, se devolver una fila (como indica el lenguaje SQL estndar) con valor 0 en el campo utilizado en la funcin count. Si la instruccin select contena una lista de campos, stos tomarn el valor NULL en el sentido en que lo toma Axapta. En Axapta, cada tipo de datos tiene asignado un valor que se interpreta como valor NULL bajo determinadas circunstancias:
Pgina 30 de 141
En la mayora de los casos, para saber algn registro cumple las condiciones de seleccin, se consulta si el valor del campo RecId del registro es no nulo.
2.3.
select * from table index tableIdx order by TableCode where TableCode > 100; } En este ejemplo seleccionaramos todos los registros de la tabla que tuvieran un valor mayor que 100 en el campo TableCode, ordenados por ese campo y utilizando como ndice el definido en la tabla de nombre tableIdx.
2.4.
OtherTable tableB;
Pgina 31 de 141
join tableB where tableA.TableCode == tableB.TableCode //Se especifica la relacin entre tablas Esta instruccin obtendra todos los registros de la unin de las tablas tableA y tableB, que tuvieran un valor mayor de 100 en el campo FieldValue. La relacin entre las tablas se realiza con la igualdad de la instruccin tableA.TableCode == tableB.TableCode, siendo estos los campos comunes entre ambas tablas. Pueden definirse distintos tipos de relaciones entre tablas, que se corresponden con los tipos de uniones definidos en la creacin de formularios: join: Selecciona los registros de la tabla principal que tienen registros asociados en la tabla relacionada. Es decir, en el resultado tendremos un registro principal por cada registro relacionado. Corresponde con la opcin InnerJoin en la construccin de formularios. exist join: Selecciona un registro de la tabla principal si existen registros relacionados en la tabla asociada. Este tipo de unin se diferencia del anterior en que slo devuelve el primer registro que encuentra en la tabla relacionada. not exist join: Selecciona los registros de la tabla principal que no tienen registros asociados en la tabla relacionada. outer join: Selecciona registros de la tabla principal tengan o no registros asociados en la tabla relacionada.
3.
Ejemplos de SELECT
Todos los ejemplos usan la tabla Custtable, por lo tanto comenzamos declarando una variable de cliente pero, lgicamente, puedes usar la tabla que se quiera. Para ilustrar el trabajo de las sentencias select, asume que la tabla de clientes slo tuviera 5 registros (muchos campos han sido quitados): AccountNo 100 200 300 4000 5000 NameRef Radio Uptown CBS Walt Disney Ford Motor Company Pentagon Balance $ 10,000 $ 20,000 $ 30,000 $ 5,000 $ 1,000,000 Invoice No Blocked No No No
void SelectRecordExamples() {
Pgina 32 de 141
CustTable custtable;
// Un cliente con el cdigo > 100 select * from Custtable where AccountNo > 100;
// El cliente con el menor nmero > 100 es encontrado, // este es , CBS con el nmero 200. select * from Custtable order by AccountNo where AccountNo > 100; next Custtable; // El cliente siguiente en ser ledo, por Ejemplo Walt Disney
// El cliente con el mayor nmero de cuenta // (mayor de 100) es encontrado: Pentagon select * from Custtable order by AccountNo DESC where AccountNo > 100; next Custtable; // El siguiente registro ledo es (DESC) = Ford Motor
// El cliente con el mayor nmero de cuenta es: Pentagon select reverse Custtable order by AccountNo;
// EL cliente con el menor nombre y nmero de cuenta // en el intervalo ]100;1000[ es encontrado. Este es CBS. select * from Custtable order by NameRef where AccountNo > 100
Pgina 33 de 141
// La seleccin COUNT retorna el nmero de clientes accountnumbers (clientes): 5 select count(AccountNo) from CustTable; print Custtable.AccountNo; // Imprime el resultado del count // (el cual est en AccountNo)
/* Retorna la suma de los balances para los clientes no bloqueados. El resultado es: SUM: $1,060,000 */ select sum(Balance) from Custtable where Blocked == DebCreBlocked::No; }
Una nota para el siguiente comando: Hay que darse cuenta que cuando el comando NEXT es usado sin estar precedido de un select, es tratado como si hubiera un comando SELECT implcito sin una clusula Where. Ejemplo: { MyTable T; // declara una instancia de MyTable Next T; // recupera el primer registro, si lo hay, de la tabla MyTable }
Esto equivale a:
{ MyTable T; // declara una instancia para MyTable Select T; // recupera el primer registro, si lo hay, de la tabla MyTable
Pgina 34 de 141
} En el ltimo ejemplo, una llamada a NEXT retornara el segundo registro del resultado. Field Select Nota que tambin es posible usar una sentencia select en un lookup en un campo: despus de un sentencia select que va a buscar un registro en una tabla, puedes escribir .nombre de campo para referenciarte a un campo de una tabla. Debajo encontrars ejemplos de esta seleccin de campos. Nota, que esas selecciones deben ser usadas en las expresiones! Void selectFieldExample () { //imprime el campo NameRef para el cliente seleccionado (el cual es CBS) print (select Custtable order by NameRef).NameRef; Usa el campo de balance para el cliente con una cuenta 5000 (Pentagon). //Imprime un mensaje. if ((select Custtable where AccountNo == 5000).Balance > 500000) print This customer has a balance above $500,000; } Date cuenta de la diferencia entre la seleccin normal y la de seleccin de campo. La se seleccin de campo opera directamente sobre la tabla mientras que la seleccin opera sobre una variable de la tabla.
4.
Instruccin WHILESELECT
La instruccin whileselect itera sobre un grupo de registros, que cumplen ciertas condiciones de seleccin, de manera que es posible realizar operaciones sobre cada registro. La ventaja de la instruccin whileselect, es que es capaz de desplazarse automticamente por todos los registros seleccionados (por tanto no necesitamos la instruccin next) y ejecuta instrucciones para cada uno de estos registros. Esta versin de instruccin de seleccin de registros es la ms utilizada en MorphX. Cuando estamos manipulando datos utilizando esta sentencia, normalmente debemos utilizar el concepto de transaccin para asegurarnos la integridad de los mismos. La sintaxis es la siguiente:
Pgina 35 de 141
while { }
InstruccinSelect
while select * from table order by TableCode where TableCode > 100 { print table.TableCode; } } En este ejemplo seleccionaramos todos los registros de la tabla que tuvieran un valor mayor que 100 en el campo tableCode, ordenados por ese campo e imprimiramos su valor.
5.
Instruccin DELETE_FROM
Podemos utilizar la instruccin delete_from para borrar todos los registros que cumplan una determinada condicin. Esta instruccin es equivalente a ejecutar una instruccin whileselect y realizar el borrado en cada uno de los registros. Instruccin whileselect { MyTable myTable;
while select myTable where ... { myTable.delete(); } } Instruccin delete_from { MyTable myTable;
Pgina 36 de 141
delete_from myTable where ...; } Como se aprecia en el ejemplo, utilizando la instruccin delete_from en lugar de la whileselect, podemos economizar instrucciones de cdigo X++ y conseguir el mismo efecto.
JOBS
Un job es una porcin de cdigo la cual es ejecutada secuencialmente (desde arriba hasta abajo). Por defecto la siguiente lnea se encuentra en la parte superior de un nuevo job: Static void jobname (Args a) { } Los jobs que vers durante esta clase se parecern a este de aqu, excepto el nombre del job, el cual le dars t. Para aadir comentarios en el editor de texto se hace utilizando: //Este es un comentario de una sola lnea /* Para comentarios de ms de una lnea mejor utilizar esto*/ En ambos casos el texto cambiar de color a VERDE.
Pgina 37 de 141
2.
Mtodo FIND
El mtodo find nos sirve para encontrar un registro determinado de una tabla, a partir de un valor del campo que sea la clave principal de la misma. Se trata de un mtodo esttico y que recibe los siguientes parmetros de entrada:
La clave de la tabla Un booleano opcional utilizado para indicar si se van a realizar una actualizacin del registro seleccionado El mtodo find de todas las tablas sigue la misma estructura. Veamos un ejemplo: Ejemplo static CustTable find(CustAccount boolean { CustTable custTable; ; custAccount, _forUpdate = false)
Pgina 38 de 141
if (custAccount) { custTable.selectForUpdate(_forUpdate); select firstonly custTable index hint AccountIdx where custTable.accountNum == custAccount; } return custTable; } El hecho de que find sea un mtodo esttico nos facilita la tarea de buscar un registro de la tabla desde cualquier lugar del sistema, sin necesidad de tener una instancia de la tabla CustTable. La forma de ejecutar el mtodo sera por lo tanto la siguiente:
CustTable::find(customer) Donde customer sera una variable del tipo CustAccount que contendra el valor de la clave del registro que queremos buscar.
3.
Mtodo EXIST
El mtodo exist es un mtodo que nos indica si un registro determinado existe en la tabla, a partir de un valor del campo que sea la clave principal de la misma. Se trata de un mtodo esttico que tiene como parmetro de entrada el siguiente:
La clave de la tabla Ejemplo static boolean exist(CustAccount custAccount) { return (custAccount && CustTable::find(custAccount).recID != 0); } En el ejemplo se puede observar que se realiza una llamada al mtodo find. Resulta evidente que es mucho ms eficaz reutilizar el cdigo existente que reescribir la instruccin de seleccin.
4.
Mtodo TXTNOTEXIST
El mtodo TxtNotExist nos devuelve un texto esttico que utilizamos como mensaje de error. Ejemplo static str 80 txtNotExist()
Pgina 39 de 141
{ return "@SYS9779"; } La etiqueta del ejemplo corresponde al texto La cuenta %1 no existe. Siempre que introduzcamos una cadena de texto en el cdigo deberemos utilizar etiquetas.
5.
Mtodo CHECKEXIST
El mtodo checkExist nos indica si un registro determinado existe en la tabla, a partir de un valor del campo que sea la clave principal de la misma. Si el registro no existe, devuelve un mensaje de error. Se trata de un mtodo esttico que recibe el siguiente parmetro de entrada:
La clave de la tabla Ejemplo static boolean checkExist(CustAccount custAccount) { if (custAccount && !CustTable::exist(custAccount))
return checkFailed(strfmt(CustTable::txtNotExist(),custAccount)); return true; } Como se observa en el ejemplo, el mtodo checkExist hace uso de los mtodos exist y txtNotExist descritos anteriormente. Tambin hace referencia a un metodo de la clase Global checkFailed
Pgina 40 de 141
1.
Mtodos DISPLAY
El modificador display se utiliza para indicar que el valor de retorno del mtodo va a ser mostrado en un formulario o en un informe. Podemos utilizar este modificador en los mtodos de: Tablas Formularios Origen de datos de formularios Informes Diseo de informes
Siempre que sea posible, es aconsejable escribir los mtodos display en tablas, porque de esta forma puede utilizarse el mismo cdigo en varios formularios o informes.
1.1.
1.2.
Pgina 41 de 141
En los casos en que sea necesario realizar clculos costosos, es recomendable utilizar otro formulario para mostrar los valores calculados que se muestre al pulsar un botn. De este modo, slo se realizarn los clculos cuando el usuario lo solicite explcitamente. Veamos ahora cmo se utilizan los mtodos display. Una vez que se ha creado el mtodo, ste se utilizar en un control que se muestre en un formulario o en un informe. La forma de realizarlo es independiente del lugar donde se haya escrito el mtodo. Es necesario que el tipo de control y el tipo de retorno del mtodo sean idnticos. Esto significa que si, por ejemplo, tenemos en el formulario un control del tipo RealEdit, el mtodo display que estemos utilizando debe devolver un valor de tipo real. En un formulario, la propiedad DataSource indica donde est situado el mtodo, y la propiedad DataMethod indica el nombre del mtodo. Si la propiedad DataSource no tiene valor, el sistema asume que el mtodo ha sido definido en el formulario. En la siguiente figura se muestra la ventana de propiedades de un control de tipo real de un formulario:
En un informe, la propiedad DataMethod tambin indica el nombre del mtodo display. Si la propiedad Table no tiene valor, el sistema asume que el mtodo ha sido definido en el informe o en la clase de sistema ReportRun, donde tambin existen mtodos display. Por el contrario, cuando la propiedad Table tiene valor, el sistema busca el mtodo display en la tabla correspondiente. Si la propiedad ExtendedDataType tiene valor, el formato, el texto de ayuda, etc., se obtendrn del tipo de datos correspondiente. Si el mtodo display devuelve un vector, la propiedad ArrayIndex a 0 indica que todos los elementos del vector deben ser mostrados en el informe. Si, por ejemplo, ponemos la propiedad ArrayIndex a 2, solo el elemento nmero 2 del vector es mostrado.
Pgina 42 de 141
2.
Mtodos EDIT
El modificador edit es una extensin del modificador display, de forma que los controles que utilizan un mtodo edit, adems de mostrar un valor aceptan la entrada de datos por parte del usuario. Puede utilizarse en mtodos de los siguientes elementos: Tablas Formularios Orgenes de datos de los formularios
2.1.
3.
Resumen del aspecto de los parmetros para los mtodos display y edit
Boolean Set <Tipo de datos> valor Boolean Set <Tipo de datos> Ninguno Mtodo en formulario valor Boolean Set <Tipo de origen Mtodo en el origen de <Tipo de origen de datos> de datos> Origen de datos datos de un formulario Origen de datos <Tipo de datos> valor Mtodo en un informe Ninguno No aplicable No aplicable
Pgina 43 de 141
2.
Mtodos de sistema
Los mtodos de sistema son ejecutados cuando se utiliza la tabla, por ejemplo, cuando introducimos, actualizamos o borramos datos. El cuerpo de estos mtodos inicialmente nicamente contiene una llamada al mtodo super(). En captulos posteriores se describir con ms detalle este mtodo. De momento nos basta con saber que corresponde al comportamiento predeterminado del sistema. Cuando se aade cdigo X++ a los mtodos definidos por el sistema, se sobrecarga este comportamiento. A continuacin se presentan la lista de mtodos de sistema de una tabla. En apartados posteriores se describirn con ms detalle los ms importantes. Mtodo Caption Se ejecuta cuando... se muestra la cabecera de un formulario. El texto se genera a partir de las propiedades de la tabla.
Clear
Delete
se elimina un registro.
HelpField
se muestra en la barra de estado el texto de ayuda de un campo, por ejemplo cuando pasamos al campo siguiente en un formulario.
InitValue
Pgina 44 de 141
Insert
Merge
PostLoad
se carga un registro.
RenamePrimaryKey
ReRead
se relee un registro.
ToolTipField
ToolTipRecord
se va a mostrar un consejo para el campo actual. El mtodo super() realiza una llamada a Caption.
Update
ValidateDelete
se va a borrar un registro.
ValidateField
ValidateWrite
2.1.
Pgina 45 de 141
2.1.1.
Mtodos
Los mtodos de validacin en tablas son los siguientes:
a)
ValidateField Se ejecuta cuando movemos el cursor desde un campo del formulario a otro, es decir, cuando abandonamos un campo. Devuelve un dato de tipo booleano. Si el resultado es falso, el cursor permanecer en el campo. La llamada al mtodo super() comprueba las relaciones de validacin, es decir, relaciones en un campo donde la propiedad Validate tiene valor afirmativo. Por lo tanto, debemos respetar la tarea realizada por dicho mtodo super(). No deben codificarse validaciones que puedan realizarse con alguna propiedad. As, evitaremos escribir cdigo en el mtodo ValidateField si las condiciones pueden comprobarse con la propiedad Validate de una relacin.
b)
ValidateWrite Se ejecuta antes de insertar o actualizar un registro en la tabla. Devuelve un dato de tipo booleano. Si devuelve falso, el registro no se inserta o actualiza. La llamada al mtodo super() examina todos los campos para comprobar el valor de la propiedad Mandatory. Por lo tanto, debemos respetar la tarea realizada por dicho mtodo super(). Evitaremos introducir cdigo que compruebe si un campo tiene valor, siempre que podamos utilizar la propiedad Mandatory.
c)
ValidateDelete
No hay que olvidar, que a menudo tambin queremos comprobar ciertas condiciones antes de borrar un registro de una tabla. Para hacer esto, utilizamos el mtodo ValidateDelete(). ValidateDelete() se llama automticamente desde formularios y es utilizado para comprobar si el registro actual puede ser borrado. La llamada al mtodo super() comprueba si hay registros relacionados en tablas con DeleteActions del tipo Restricted. Si ese es el caso, el mtodo super() devuelve falso. Por lo tanto, debemos respetar la tarea realizada por dicho mtodo. Siempre que podamos utilizar un DeleteAction, evitaremos introducir cdigo en el mtodo ValidateDelete.
Pgina 46 de 141
2.1.2.
Para mantener una buena estructura de programacin, es recomendable que el cdigo para las comprobaciones no se site directamente en estos mtodos de validacin. Es ms conveniente que creemos mtodos de comprobacin que sern llamados desde los mtodos de validacin anteriormente descritos. Ejemplo de mtodo de validacin Boolean validateWrite() { Boolean ret;
return ret; } Cuando no se cumple alguna de las condiciones, el mtodo de comprobacin debe realizar dos cosas: presentar al usuario un mensaje de error devolver el valor falso como resultado El mtodo CheckFailed(Mensaje de error) escribe la cadena de texto que recibe como parmetro en la ventana de informacin (Infolog) y devuelve el valor falso. Por lo tanto, mediante la utilizacin de este mtodo, conseguimos simultneamente los dos objetivos. Ejemplo de utilizacin de CheckFailed Boolean checkSomething () { Boolean ret;
if (!something) { ret = checkFailed(Something is wrong); } return ret; } Podramos utilizar la estructura anterior, pero existen casos en los que nos interesa comprobar la misma condicin Something, presente en el mtodo CheckSomething(), sin presentar ningn mensaje al usuario. En este caso necesitaramos un mtodo adicional, que comprobara la condicin pero que no mostrara ningn mensaje.
Pgina 47 de 141
Sin embargo, esto no sera muy eficiente, porque estaramos duplicando el cdigo de comprobacin, por lo tanto es ms recomendable crear un mtodo llamado Something(), al que podremos llamar cuando queramos, que se encargar de realizar dicha comprobacin. Deberemos, adems, cambiar el mtodo CheckSomething(), para que realice una llamada a este nuevo mtodo. El mtodo CheckSomething() lo utilizaremos nicamente cuando queramos mostrar un mensaje al usuario. Ejemplo de validacin completa Boolean something () { if (!something) { return false; } return true; }
if (!something()) { ret = checkFailed(Something is wrong); } return ret; } Podemos considerar un estndar de nomenclatura de Axapta, la utilizacin del prefijo Check, en el nombre de todos aquellos mtodos que hagan una llamada al mtodo global CheckFailed(). De esta forma sabremos qu mtodos presentan mensajes en la ventana Infolog.
2.2.
Pgina 48 de 141
El mtodo InitValue se ejecuta cuando aadimos un nuevo registro. Tambin es llamado automticamente desde los formularios. Por lo tanto, utilizaremos el mtodo para asignar valores iniciales o por defecto en un nuevo registro. Ejemplo void initValue() { CustParameters custParameters;
super(); this.languageId = CustParameters::languageId(); this.currency = CompanyInfo::find().currencyCode; } Hay que sealar que la llamada al mtodo super() no hace nada. b) Insert El mtodo Insert se ejecuta cuando se introduce un nuevo registro en la tabla. Es muy importante asegurar cualquier transaccin relacionada para asegurar la integridad de la base de datos. Las tcnicas de control de transacciones se vern en un captulo posterior. Ejemplo void insert() { this.setNameAlias(); super(); } Si el registro no puede ser insertado en la tabla, la llamada al mtodo super() devuelve un error. c) Update El mtodo Update se ejecuta antes de modificar un registro existente en la tabla. En este caso, tambin es muy importante controlar cualquier transaccin relacionada para asegurar la integridad de la base de datos. Ejemplo void update() { CustTable this_Orig = this.orig();
ttsbegin; this.setNameAlias();
Pgina 49 de 141
super(); this.setAccountOnVend(this_Orig); if (this_Orig.custGroup != this.custGroup) ForecastSales::setCustGroupId(this.accountNum, this_Orig.custGroup, this.custGroup); ttscommit; } En el ejemplo se utiliza el mtodo orig(). ste mtodo nos da acceso al registro antes de la actualizacin. d) Delete El mtodo delete se ejecuta cuando se elimina un registro. Es muy importante asegurar cualquier transaccin relacionada para asegurarnos la integridad de la base de datos. Supongamos dos tablas relacionadas llamadas TableA y TableB. Si en TableA hemos definido un DeleteAction de tipo cascada (Cascade) con respecto a TableB, cuando se borre un registro de TableA se borrarn los registros relacionados en TableB. Por razones de rendimiento, se debe evitar escribir cdigo en el mtodo Delete de dichas tablas relacionadas (en el ejemplo, TableB). Si no se ha aadido cdigo, los borrados en cascada pueden ser realizados rpidamente por el sistema gestor de base de datos utilizando directamente instrucciones de borrado SQL. Sin embargo, si aadimos cdigo en esas tablas (lo que puede ser necesario en algunas ocasiones), el sistema crea una instruccin while select y ejecuta el mtodo Delete en todas las tablas hijas relacionadas. De esta forma el rendimiento es menor que cuando utilizamos directamente instrucciones de borrado en SQL.
Pgina 50 de 141
Control de transacciones
Control de transacciones
1. Introduccin
Una transaccin es una unidad lgica de trabajo. Las transacciones son operaciones de todo o nada, que aseguran la integridad de los datos en las actualizaciones ms compelas. Consideremos el caso en el que queremos actualizar un grupo de registros. Si el sistema se estropea o el proceso es cancelado durante la operacin, algunos registros pueden haber sido actualizados y otros no. Si realizamos la actualizacin dentro de una transaccin, el sistema nos garantiza que o bien se actualiza completamente la totalidad de los registros o no se realiza ninguna operacin. Es decir, la actualizacin nicamente se consigue cuando la transaccin finaliza con xito. El uso de transacciones nos asegura, en caso de fallo del sistema, la recuperacin de los datos en su estado inicial, mediante un retroceso (rollback). Otro aspecto a tener en cuenta es que podra darse el caso de que dos procesos estuvieran accediendo a un mismo registro. Supongamos que el proceso A lee un registro y a continuacin un proceso B lee el mismo registro. En un instante posterior, el proceso A actualiza el registro y a continuacin el proceso B realiza la misma operacin. En este caso, los cambios realizados por el proceso A se perderan. La solucin a este problema es bloquear los registros o las tablas durante las transacciones de actualizacin (insert, update y delete). Esto podemos hacerlo mediante la sentencia select forUpdate.
2.
Instrucciones TTS
Las instrucciones tts se utilizan para marcar el inicio y el final de una transaccin.
2.1.
Instruccin TTSBEGIN
Utilizamos la sentencia ttsbegin para marcar el comienzo de una transaccin. Esto nos asegura la integridad de datos y garantiza que todas las actualizaciones realizadas hasta la finalizacin de la transaccin son consistentes, o por el contrario no se realiza ninguna. La instruccin ttsbegin no tiene ningn sentido si no tenemos una instruccin de final de transaccin.
2.2.
Instruccin TTSCOMMIT
Utilizamos la sentencia ttscommit para indicar que una transaccin ha finalizado con xito. Esta instruccin termina una transaccin y lleva a cabo todas las actualizaciones realizadas. MorphX garantiza que una transaccin terminada con la instruccin ttscommit ser realizada por completo.
Pgina 51 de 141
Control de transacciones
2.3.
Instruccin TTSABORT
La sentencia ttsabort nos permite desechar todos los cambios realizados en la transaccin actual de una manera explcita. Esto trae como consecuencia la finalizacin de la transaccin y la vuelta de la base de datos a la situacin inicial, justo antes de comenzar la transaccin. Por lo tanto, es como si no hubiramos realizado ningn cambio. Normalmente, utilizaremos esta sentencia si detectamos que el usuario quiere detener la tarea actual. El uso de la instruccin ttsabort, nos asegura que la base de datos ser consistente. A menudo, la mejor solucin es utilizar las sentencias de gestin de excepciones en lugar de utilizar la sentencia ttsabort.
2.4.
Anidamiento de transacciones
Las instrucciones entre las sentencias ttsbegin y ttscommit, pueden incluir uno o ms bloques de transacciones, es decir podemos anidar dichas transacciones. A continuacin presentamos un ejemplo: Ejemplo de transacciones anidadas ttsbegin; // Instrucciones ttsbegin; // Instrucciones ttscommit; // Instrucciones ttscommit; En estos casos es importante sealar, que la transaccin que realmente importa es la ms externa, es decir la que abrimos en primer lugar. De forma que nada se actualiza hasta que finaliza con xito la ltima instruccin ttscommit.
3.
3.1.
Pgina 52 de 141
Control de transacciones
3.2.
Pgina 53 de 141
Herramientas de desarrollo
Herramientas de desarrollo
1. El editor
El editor de cdigo se puede abrir pulsando dos veces con el ratn sobre el nombre de un mtodo, o bien seleccionando la opcin Edit del men contextual de dicho mtodo.
Icon
Description Crea un Nuevo mtodo o Job. Puedes tener varios mtodos/jobs abiertos al mismo tiempo en el editor. Cada mtodo tiene su propia pestaa con el nombre del Job como ttulo. Salva el cdigo. Si cierras el Job, el sistema te preguntar si quieres guardar los cambios. Ejecuta el Job. El Job es tambin compilado. Un Job con un error de compilacin no funcionar. Sita un punto de interrupcin que el Debugger reconoce. Compila el cdigo. El compilador chequea los errores que hay ahora en el cdigo. La ventana de mensaje nos mostrar si el error es, por ejemplo, de sintaxis, coherencia, ... Propiedades de los mtodos. Te da el perfil de parmetros de un mtodo. Muestra el editor de etiquetas. Esto te da el texto de la etiqueta de la etiqueta que est seleccionada. Este icono te dar una lista completa de todas las etiquetas disponibles. Ejecuta un script, por Ejemplo, para transformar una parte seleccionada del cdigo en un comentario., o para insertar una cabecera en el Job incluyendo informacin sobre cuando y por quin ha sido editado el Job. Ayuda. Mira entre otras cosas una lista de teclas de acceso rpido. Hay tecla de acceso rpido para listas por ejemplo, tablas clases, o Enums.
Pgina 54 de 141
Herramientas de desarrollo
Click en el botn derecho del ratn en cualquier lugar de la ventana del editor para recibir este men. Adems de repetir varias funciones en la barra de estado del editor, el men incluye un nmero de funciones. Usa este men para mostrar, por ejemplo, tablas, clases y Enums cuando ests escribiendo cdigo en el editor. Usando las teclas de acceso rpido. (como las descritas arriba) para acceder a la misma lista a travs del teclado.
El nombre del mtodo seleccionado se muestra dentro de una solapa. El editor facilita el trabajo con varios mtodos a la vez, ya que cada vez que editamos un mtodo de la misma clase, se crea una nueva solapa en la misma ventana. Por otro lado, permite utilizar las funciones de edicin estndar de Windows tales como copiar, cortar y pegar. La opcin IntelliSense resulta de gran ayuda al desarrollador, ya que cada vez que ste introduce el nombre de un objeto, le muestra su lista de miembros (variables y mtodos). De este modo, el programador no necesita recordarlos. Esta opcin est activa por defecto, pero puede desactivarse desde la ventana de opciones de desarrollo. Esta lista se presenta tambin, si el desarrollador marca el objeto con el ratn y selecciona la opcin Buscar propiedades/mtodos del men contextual o bien pulsa el botn de la barra de herramientas del editor. El resultado se muestra en la figura 1.
Pgina 55 de 141
Herramientas de desarrollo
Si situamos el cursor sobre un objeto que no dispone de miembros, el sistema muestra un mensaje de ayuda emergente con informacin sobre el tipo de objeto, tal y como muestra la figura 2.
Esta informacin tambin puede obtenerse mediante la combinacin de teclas CTRL+SPACE. El men contextual nos ofrece otras opciones de bsqueda, como Buscar etiqueta/texto que abre el generador de etiquetas. Este mismo resultado se obtiene pulsando sobre el botn de la barra de herramientas del editor.
Por ltimo, la opcin Buscar definicin ejecutada sobre un mtodo, abre este mtodo en una nueva ventana del editor. El editor tambin nos ofrece la posibilidad de utilizar la tecla F1 para obtener ayuda sensible al contexto. Si marcamos con el ratn un elemento cuya informacin de ayuda se encuentra en la Documentacin de sistema o bien en la Documentacin de la aplicacin y pulsamos F1, se mostrar esta ayuda. As, por ejemplo si marcamos una variable perteneciente a una clase de sistema y pulsamos F1, obtendremos ayuda acerca de esta clase. Si F1 se pulsa en un elemento del que no se dispone informacin, obtendremos ayuda acerca del uso del editor de texto. El men contextual nos ofrece otras utilidades como las listas de objetos. As, encontramos las siguientes opciones: Enumerar tablas Enumerar clases Enumerar tipos
Pgina 56 de 141
Herramientas de desarrollo
Cada una de estas opciones muestra la lista de objetos correspondiente, de la cual podemos seleccionar el que nos interese. En la figura siguiente podemos ver el resultado de seleccionar la opcin Listar enumeraciones. Como vemos, tenemos acceso a los elementos del enumerado seleccionado. Para salir del editor podemos pulsar la tecla ESC. Si hemos realizado cambios, el sistema preguntar si queremos guardar dichos cambios.
2.
El generador de etiquetas
Cuando tengamos la necesidad de introducir algn texto en nuestro cdigo lo haremos utilizando una etiqueta. Las etiquetas en Axapta son uno de los elementos fundamentales para asegurarnos que las aplicaciones realizadas sern multi-lenguaje, es decir, podremos elegir el idioma en el que queremos que aparezcan nuestros formularios, informes, cuadros de dilogo, etc. Para la creacin de etiquetas disponemos en Axapta de un generador de etiquetas que va a facilitar nuestro trabajo. Cuando pulsamos con el ratn sobre el botn , nos aparece esta herramienta, que nos permite buscar, crear e insertar etiquetas. Como hemos comentado en el apartado anterior, el generador de herramientas tambin se puede abrir mediante la opcin Buscar etiqueta/texto del men contextual.
Pgina 57 de 141
Herramientas de desarrollo
La lista desplegable Idioma seleccionado, muestra el lenguaje que se seleccion al poner en funcionamiento la aplicacin. Cuando comenzamos la bsqueda de una cadena de texto determinada, este parmetro determina el fichero de etiquetas en el cual se realizar la bsqueda. El cuadro de texto Bsqueda de etiqueta, nos permite introducir la cadena de texto que queramos buscar en el fichero de etiquetas. La bsqueda encuentra todas las instancias de la cadena de texto. El botn de comando Buscar ahora, comienza la bsqueda de la cadena de texto que se haya introducido en el cuadro de texto que acabamos de describir. La lista en el cuadro de dilogo muestra el resultado de la bsqueda de la cadena de texto. Se nos muestran los nombres de todas las etiquetas, por las que nos podemos desplazar utilizando los botones Siguiente y Anterior. La casilla de verificacin Mostrar todos los idiomas, muestra las traducciones de la etiqueta actual en todos los lenguajes disponibles en nuestra instalacin de Axapta. La lista desplegable Archivo de etiquetas, nos muestra los caracteres que identifican un archivo de etiquetas. El nombre de los archivos de etiquetas se compone del siguiente modo: Ax<identificador><idioma>.ald, donde ald es el acrnimo de application label data (datos de etiquetas de la aplicacin). En la aplicacin estndar, el identificador del archivo es SYS. En nuestros desarrollos podremos definir un archivo de etiquetas para el nivel en el que estemos trabajando o bien podemos utilizar otras tcnicas, tales como crear un archivo por cada aplicacin desarrollada.
Pgina 58 de 141
Herramientas de desarrollo
3.
El depurador
El depurador es una herramienta de desarrollo presente en el entorno MorphX, como sucede en la mayora de entornos de programacin. La utilizacin del depurador va a ser muy til en tareas relacionadas con la programacin de aplicaciones, como la deteccin de errores, optimizacin de cdigo, etc. Con el depurador podemos realizar distintas operaciones, que pueden ser ejecutadas desde los botones de la barra de herramientas o bien mediante una combinacin de teclas. Estas operaciones son las siguientes: Ejecutar cdigo Ejecutar paso a paso las lneas de cdigo Introducir puntos de ruptura (breakpoints) Abrir una ventana de variables, donde se muestra una lnea para cada variable con su nombre, tipo, mbito y valor Ver la pila de llamadas Ver el estado del sistema Mostrar los nmeros de lneas en el cdigo Cuando elegimos la opcin de ejecutar nuestro cdigo con informacin de depuracin, las lneas de cdigo se muestran en la ventana del depurador. Para poder poner en marcha el depurador de cdigo debemos introducir un punto de ruptura o breakpoint. Podemos introducir un punto de ruptura directamente desde el editor de cdigo situando el cursor en la lnea en la que queremos que se detenga la ejecucin y pulsando con el ratn en el botn hacerlo apretando la tecla F9. de la barra de herramientas. Tambin podemos
Cuando ejecutemos el cdigo, la ejecucin se detendr en el punto de ruptura y se abrir el depurador. La siguiente figura muestra la apariencia del depurador:
Figura 5. El depurador.
Pgina 59 de 141
Herramientas de desarrollo
En la ventana de variables podemos ver cmo cambia el valor de las variables a medida que vamos ejecutando el cdigo paso a paso. Tambin podemos poner una o ms variables a un valor especfico, introduciendo ste en la columna Valor.
Podemos activar la ventana de variables pulsando sobre el botn herramientas del depurador.
de la barra de
Cuando una lnea en la ventana de variables contiene un objeto compuesto, podemos situar el cursor en esa lnea y apretar la tecla ENTER. Se abrir una segunda ventana que mostrar el valor actual de cada uno de los elementos de dicho objeto.
Pgina 60 de 141
Programacin de formularios
4.
Seguimientos o trazas
Si se quiere realizar una traza del programa en ejecucin necesitas activar las trazas. Para hacer esto debes ir al men de herramientas, seleccionar opciones, y una vez dentro de opciones marcar la pestaa de desarrollo., Aqu ves un grupo de traza (Seguimiento), en el que hay 4 opciones: Seguimiento de la base de datos. Seguimiento de los mtodos. Seguimiento de cliente/servidor. Seguimiento ActiveX. Cuando seleccionas un seguimiento de los mtodos una pantalla aparecer tan pronto se active uno de los controloes a los que estoy siguiendo. Nota: Hay que darse cuenta de que si seleccionas seguimiento de mtodos conseguirs mucha informacin muy rpido porque Axapta muestra todos los mtodos que son llamados, como OnMouseMove o OnMouseLeave.
Programacin de formularios
1. Introduccin
Como ya hemos comentado, podemos introducir cdigo en lenguaje X++ en muchas partes del sistema. Los formularios no son una excepcin. Existen distintos mbitos en los formularios donde podemos aadir cdigo. Estos mbitos son los siguientes: Formulario propiamente dicho Origen de datos del formulario Controles del formulario Dependiendo de la funcionalidad que queramos implementar, escribiremos el cdigo en un mbito o en otro. No obstante, normalmente, se siguen las siguientes reglas: Codificamos en los mtodos del propio formulario, cuando queremos controlar la funcionalidad general del mismo. Codificamos en los mtodos del origen de datos, cuando queremos controlar la funcionalidad de los datos que aparecen en el formulario.
Pgina 61 de 141
Programacin de formularios
Codificamos en los controles, cuando queremos controlar la funcionalidad de alguno de los controles o elementos especficos que aparecen en el formulario.
Se debe tener en cuenta que el cdigo que se introduce en un formulario ser accesible nicamente desde el formulario. Cualquier funcionalidad que deba ser accesible desde otro elemento, debe codificarse fuera del formulario. La funcionalidad relacionada con los datos se codificar en la tabla siempre que sea posible. Si se trata de otro tipo de funcionalidad, puede implementarse una clase para ello.
2.
Se trata de una variable de tipo FormRun, que recibe el nombre de element y que referencia al objeto formulario. Nos permite acceder a los mtodos definidos a nivel de formulario. La variable element se utiliza normalmente en asignaciones como la que mostramos a continuacin: Tb. Existe la variable form notifyDate = element.design().control(Control::NotifyDate); b) Tabla
Por cada uno de los orgenes de datos del formulario, disponemos de una variable llamada como stos, que nos referencia la tabla que utilizamos en dicho origen de datos. Por ejemplo, suponiendo que el origen de datos del formulario se llamara DatosFormulario, tendramos una variable con ese nombre que hara referencia a la tabla. En realidad, en un momento dado esta variable nos da acceso al registro activo de la tabla, de manera que podremos: 1. Llamar a un mtodo definido en la tabla. Por ejemplo: DatosFormulario.setDefault(ReadWrite::Write); 2. Hacer referencia a los campos individuales de la tabla. Por ejemplo: number = DatosFormulario.accountNo; c) Origen de datos
Pgina 62 de 141
Programacin de formularios
Tendremos tambin una variable llamada como el origen de datos del formulario con el sufijo _DS para hacer referencia a las propiedades y los mtodos de dicho origen de datos. Por ejemplo, en el caso de que nuestro origen de datos se llamara DatosFormulario, tendramos una variable llamada DatosFormulario_DS. Se trata de una variable de tipo FormDataSource que nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: DatosFormulario_DS.reSearch(); d) Consulta Existen dos variables que nos permiten acceder a la consulta de un formulario: Una variable de tipo Query llamada como el origen de datos del formulario con el sufijo _Q para hacer referencia a las propiedades y los mtodos de la consulta (query). Por ejemplo, en nuestro caso, tendramos una variable llamada DatosFormulario_Q. Esto nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: DatosFormulario_Q.levelNo(1); Una variable de tipo QueryRun llamada como el origen de datos del formulario con el sufijo _QR para hacer referencia a las propiedades y los mtodos de una instancia en ejecucin de la consulta de dicho origen de datos (queryRun). Por ejemplo, en nuestro caso, tendramos una variable llamada DatosFormulario_QR. Esto nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: DatosFormulario_QR.getNo(1); Es importante sealar que en versiones anteriores de Axapta, no existan las variables declaradas implcitamente para la consulta (_Q) y para la instancia en ejecucin de la consulta (_QR). Esto hace que nos podamos encontrar en muchos mtodos todava la forma tradicional de acceder a ellas desde cdigo. Para acceder a una consulta, debamos hacer una declaracin de variable, tras la cual podamos utilizar la variable declarada para acceder a los mtodos de dicha consulta. Por ejemplo, dentro de un origen de datos podramos acceder a su consulta de la siguiente forma: Ejemplo de declaracin de una consulta Query ; q = this.query(); q.levelNo(1); Para acceder a una instancia en ejecucin de una consulta, tambin debamos hacer una declaracin de variable. Siguiendo con el mismo ejemplo lo haramos de la forma siguiente: Ejemplo de declaracin de instancia en ejecucin de una consulta QueryRun ; qr = this.queryRun(); qr; q;
Pgina 63 de 141
Programacin de formularios
qr.getNo(1); En ambos casos la variable this hara referencia al objeto en ejecucin en ese momento, es decir, al origen de datos.
Siempre es ms aconsejable utilizar las variables implcitas declaradas por el sistema en lugar de definir nuevas variables, ya que de esta forma evitamos que existan variables iguales duplicadas en memoria.
3.
Es interesante recordar, que siempre que sea posible, se debe introducir el cdigo en la tabla de la que se obtienen los datos para el formulario. Los mtodos escritos en la tabla son accesibles desde cualquier formulario que utilice dicha tabla. En trminos de reutilizacin y herencia, aadir cdigo en los mtodos de un formulario es menos eficiente que introducirlo directamente en la tabla.
3.1.
Mtodos de sistema
El nodo contiene lo que se llaman mtodos virtuales, que son mtodos implementados en MorphX, pero que pueden ser sobrecargados para cambiar el comportamiento por defecto de los formularios. En estos mtodos la funcin llamada super() activa la ejecucin del mtodo implementado por MorphX.
3.1.1.
Lista de mtodos
Los formularios en MorphX tienen los siguientes mtodos de sistema:
Mtodo CanClose
Se ejecuta cuando... se cierra un formulario. Utilizaremos este mtodo, para aadir nuestras propias comprobaciones a las que realiza el sistema cuando cerramos un formulario. se cierra un formulario. Dependiendo del estado en el cual cierre el formulario, el mtodo Close se activa desde CloseCancel o desde CloseOK. el usuario pulsa con el ratn sobre el botn cancelar o cuando pulsamos le techa ESC. Cuando cerramos un formulario mediante el mtodo CloseCancel, no grabamos las modificaciones. el usuario pulsa con el ratn el botn Aceptar.
Close
CloseCancel
CloseOK
Pgina 64 de 141
Programacin de formularios
DoApply Finalize
el usuario cierra un formulario modal. se cierra el formulario. El objetivo de este mtodo es destruir el objeto y liberar la memoria. nos movemos al primer campo de un formulario. abrimos el formulario. nos movemos al ltimo campo de un formulario. nos movemos al siguiente campo dentro de un formulario. nos movemos al siguiente grupo de campos dentro de un formulario. nos movemos al campo anterior dentro de un formulario. nos movemos al grupo de campos anterior dentro de un formulario. abrimos el formulario, inmediatamente despus del mtodo Init, para mostrar el formulario. el usuario realiza alguna tarea en el formulario, como por ejemplo: utilizar la barra de herramientas, el men o el teclado.
Task
3.1.2.
A continuacin vamos a describir algunos de los mtodos ms utilizados en los formularios, que por su importancia merecen un tratamiento algo ms exhaustivo. a) Mtodo ClassDeclaration En este mtodo se definen las variables globales del formulario. Es decir, aqullas cuyo mbito es el formulario en su totalidad y, por lo tanto, pueden ser utilizadas en cualquier mtodo del formulario, de los orgenes de datos o de los controles. Como ejemplo, veamos el mtodo ClassDeclaration del formulario CustTable. Ejemplo de mtodo ClassDeclaration class FormRun extends ObjectRun { NumberSeq CustAccount FormStringControl FormStringControl } b) Mtodo Init numberSeq; numAllocated; contactPerson; contactPersonId;
Pgina 65 de 141
Programacin de formularios
Se ejecuta cuando abrimos el formulario. Se utiliza, bsicamente, para la inicializacin de variables. Debemos realizar una llamada al mtodo super(), ya que ste es el encargado de crear una instancia en ejecucin del formulario. Crea tambin el origen de datos, mediante una llamada al mtodo Init del origen de datos. Antes de la llamada al mtodo super(), podemos modificar el formulario mediante los mtodos de la clase FormBuild. Tras el mtodo super() y una vez creado el formulario, podemos inicializar variables. Como ejemplo, tenemos el mtodo Init del formulario CustTable. Ejemplo de mtodo Init void init() { super(); contactPersonId = element.control(control::ContactPersonId); TaxVATNumTable::enableLookupVatNum(vatNum); } c) Mtodo Run Se ejecuta cuando abrimos un formulario, inmediatamente despus del mtodo Init. La llamada al mtodo super() hace que la ventana aparezca en la pantalla, y realiza una bsqueda en la base de datos para obtener los datos que deben mostrarse en el formulario. La consulta la realiza activando el mtodo ExecuteQuery() del origen de datos. d) Mtodo Close Se ejecuta cuando cerramos un formulario. La llamada a super() cierra la ventana del formulario, realiza las actualizaciones en la base de datos y activa el indicador booleano Closed. Dependiendo del estado en el cual cierre el formulario, el mtodo Close se activa desde CloseCancel o desde CloseOK. Como ejemplo, tenemos el mtodo Close del formulario CustTable. Ejemplo de mtodo Close void close() { if (!custTable.recId && numberSeq) numberSeq.abort(); super(); }
Pgina 66 de 141
Programacin de formularios
3.2.
La inicializacin de las variables debe hacerse en el mtodo Init, haciendo uso de los mtodos de la clase de sistema FormRun. Suponiendo que en nuestro formulario tuviramos un control de tipo botn llamado ButtonName, tendramos el siguiente ejemplo, donde se asignara dicho botn a la variable button: Ejemplo button = element.design().control(Control::ButtonName); Una vez inicializada la variable, podemos cambiar las propiedades del control en cualquier momento utilizando sus propios mtodos. A continuacin mostramos un ejemplo de esto: Ejemplo button.enabled(false); A continuacin presentamos un ejemplo, donde podemos observar la asignacin de controles de un formulario a variables previamente declaradas.
Pgina 67 de 141
Programacin de formularios
Ejemplo de declaracin de controles class FormRun extends ObjectRun { FormCheckBoxControl FormStringControl FormDateControl } includeAll; interestNote; interestDate;
void init() { super(); includeAll = element.control(control::ShowOpen); interestNote = element.control(control::InterestNote); interestDate = element.control(control::InterestDate); } Por otra parte, si sabemos que no vamos a necesitar hacer referencia al control ms de una vez, podemos eliminar la variable y cambiar la propiedad de dicho control en una sola sentencia. Ejemplo element.design().control(Control::ButtonName).enabled(false);
4.
4.1.
4.1.1.
Mtodos de sistema
Lista de mtodos
Los orgenes de datos en los formularios tienen los siguientes mtodos de sistema: Mtodo Active Create Delete ExecuteQuery Se ejecuta cuando... el usuario cambia de registro activo. el usuario crea un nuevo registro. el usuario borra un registro. abrimos el formulario y el sistema accede a la base de datos para
Pgina 68 de 141
Programacin de formularios
recuperar la informacin que se va a mostrar al usuario. FindRecord FindValue se ejecuta desde el mtodo FindValue. el usuario pulsa con el ratn sobre el comando Buscar (Find) en el men contextual. nos movemos al primer registro. se abre el formulario. se crea un nuevo registro. Su propsito es dar valores iniciales al nuevo registro. nos movemos al ltimo registro. el usuario cambia de registro en un formulario que tiene su origen de datos enlazado con otro origen de datos. nos movemos al siguiente registro. nos movemos al registro anterior. el usuario activa el comando Imprimir (Print) en el men Archivo. el usuario activa el comando Filtrar (Filter). Refresca el contenido del registro activo sin leerlo desde el disco. Este mtodo no lo activa automticamente el sistema. el usuario pulsa con el ratn sobre el comando Eliminar filtro (Remove filter) en el men contextual. Se refresca el contenido del registro activo leyendolo de la base de datos. Este mtodo no lo activa automticamente el sistema. Vuelve a ejecutar el mtodo ExecuteQuery con la excepcin de que se preserva el filtro, el orden de los registros, etc. Este mtodo no lo activa automticamente el sistema. vamos a borrar un registro. vamos a actualizar un registro o escribir un nuevo registro. el usuario introduce un nuevo registro o actualiza uno existente.
Last LinkActive
RemoveFilter
Reread
Research
4.1.2.
Mtodos de validacin
Como hemos visto en la lista anterior, los orgenes de datos tienen sus propios mtodos de validacin. Estos mtodos son los siguientes: a) ValidateDelete Este mtodo se ejecuta justo antes de que un registro vaya a ser borrado. La llamada al mtodo super() invoca al mtodo ValidateDelete de la tabla asociada.
Pgina 69 de 141
Programacin de formularios
Utilizamos este mtodo cuando queremos aadir nuestras propias comprobaciones de validacin antes del borrado de los registros de la base de datos. b) ValidateWrite Este mtodo se ejecuta justo antes de que un registro vaya a ser escrito o actualizado. La llamada al mtodo super() invoca al mtodo ValidateWrite de la tabla asociada. Tambin utilizamos este mtodo cuando queremos aadir nuestras propias comprobaciones de validacin antes de la actualizacin o escritura de los registros en la base de datos. Como podemos apreciar, existe un paralelismo entre los mtodos de la tabla y los mtodos del origen de datos de un formulario. En realidad, los mtodos de validacin del origen de datos llaman a los de la tabla asociada. A partir de esto podemos llegar a la conclusin de que introduciremos los mtodos de validacin en un sitio o en otro dependiendo de nuestro objetivo. Supongamos que tenemos varios formularios que trabajan con los mismos datos. Cada uno de ellos tendr su propio origen de datos, pero todos esos orgenes de datos tendrn asociada la misma tabla. Si nosotros queremos validar el borrado o la escritura de los registros en todos los formularios, ser ms conveniente hacer la comprobacin directamente en los mtodos de validacin de la tabla, ya que solo tendramos que escribir el cdigo una vez. Esta validacin sera efectiva en todos los orgenes de datos que tuvieran dicha tabla asociada. Por el contrario, vamos a considerar que en un formulario especfico necesitamos realizar una validacin especial cuando queremos insertar un registro. Esta comprobacin ser ms conveniente hacerla sobre los mtodos de validacin del origen de datos de dicho formulario. No sera vlido hacerlo en los mtodos de la tabla, porque de esta forma estaramos forzando a todos los formularios a realizar esta validacin. A continuacin, vamos a ver cual es la secuencia de ejecucin de mtodos cuando intentamos escribir o actualizar un registro desde un formulario. Podemos verlo de manera grfica en el siguiente esquema:
Pgina 70 de 141
Programacin de formularios
1.
Se ejecutara el mtodo ValidateWrite del origen de datos del formulario. Este a su vez llamara al mtodo ValidateWrite de la tabla asociada. Se ejecutara le mtodo Write del origen de datos del formulario. Se llamara al mtodo Insert o al mtodo Update de la tabla asociada al formulario, dependiendo de si la operacin a realizar en una insercin o una actualizacin de registro.
2. 3.
En la programacin de los mtodos de validacin de los orgenes de datos debemos seguir la misma estructura estndar que se sigue en los mtodos de validacin de las tablas.
4.1.3.
A continuacin vamos a describir algunos de los mtodos ms utilizados en los orgenes de datos de los formularios, que por su importancia merecen un tratamiento algo ms exhaustivo. a) Mtodo Init Se ejecuta cuando abrimos un formulario. La llamada al mtodo super() crea la consulta para cargar los datos en el formulario. Tras esta llamada deben aadirse, en caso de que sea necesario, las sentencias de modificacin de la consulta. Como ejemplo, presentamos el mtodo Init del origen de datos del formulario CustTrans. Ejemplo de mtodo Init void init() { super(); dataSource = this.query().dataSourceNo(1); criteriaOpen = dataSource.addRange(fieldnum(CustTrans,open)); } b) Mtodo ExecuteQuery El mtodo ExecuteQuery se ejecuta cuando abrimos un formulario para ver sus datos. La llamada al mtodo super() ejecuta la consulta generada por el mtodo Init y muestra los registros. Si deseamos modificar los criterios de seleccin, debemos insertar las sentencias correspondientes antes de la llamada a super(). Como ejemplo, presentamos el mtodo ExecuteQuery del origen de datos del formulario CustTrans. Ejemplo de mtodo ExecuteQuery
Pgina 71 de 141
Programacin de formularios
void executeQuery() { switch (includeAll.value()) { case (1) : { criteriaOpen.value('1'); break; } case (0) : { criteriaOpen.value('0..1'); break; } } super(); } En este ejemplo, vemos que el mtodo puede servirnos para establecer dos criterios distintos de seleccin en la consulta antes de la llamada al mtodo super(). c) Mtodo Active Se ejecuta cada vez que cambia el registro activo. Esto sucede cuando pasamos de un registro a otro y tambin cuando pasamos de un formulario a otro. La llamada a super() hace que el nuevo registro pase a ser el registro actual. Como ejemplo, presentamos el mtodo Active del origen de datos del formulario Unit. Ejemplo de mtodo Active int active() { int ret; ; ret = super(); Unit_Unit.allowEdit(!Unit.recId); return ret; } d) Mtodo LinkActive
Pgina 72 de 141
Programacin de formularios
El mtodo LinkActive se ejecuta cuando el usuario cambia de registro en un formulario que tiene su origen de datos enlazado con otro origen de datos. Este mtodo solo es utilizado cuando se ha establecido un enlace entre dos orgenes de datos, poniendo la propiedad LinkType a valor Yes en el origen de datos. La llamada al mtodo super() activa el mtodo ExecuteQuery del origen de datos enlazado con el origen de datos principal. Como ejemplo, presentamos el mtodo LinkActive del origen de datos SalesLine del formulario SalesTable. Ejemplo de mtodo LinkActive void linkActive() { super(); if (!salesLine) element.setCaptionText(); } e) Mtodo Reread La llamada al mtodo super() vuelve a leer el registro actual de la base de datos. El sistema no activa este mtodo de forma automtica. f) Mtodo Research La llamada al mtodo super() refresca la recuperacin de registros de la base de datos, definida por la consulta que se genera automticamente en el mtodo Init. Corresponde a una llamada al mtodo ExecuteQuery con la excepcin de que se mantienen ciertas cosas, como los filtros, el orden de los registros, etc. El sistema no activa este mtodo de forma automtica. Para comprender bien el funcionamiento del mtodo Research, vamos a ver las diferencias existentes entre dicho mtodo y el mtodo ExecuteQuery. Si queremos refrescar el contenido del formulario con los registros que han sido insertados desde un mtodo al cual hemos llamado, debemos utilizar el mtodo Research. Por el contrario, si queremos cambiar la consulta para mostrar otros registros, quizs basados en un filtro modificado, debemos utilizar el mtodo ExecuteQuery. g) Mtodo Refresh La llamada al mtodo super() actualiza la pantalla, refrescando el contenido del registro activo sin leerlo desde el disco. El sistema no activa este mtodo de forma automtica. Nosotros podemos utilizarlo, por ejemplo, si necesitamos actualizar los datos dentro de una operacin ms compleja.
Pgina 73 de 141
Programacin de formularios
h)
Mtodo Write El mtodo Write se ejecuta cuando el usuario introduce un nuevo registro o actualiza uno ya existente. Este mtodo es el equivalente a los mtodos Insert y Update de las tablas, realizando una u otra operacin dependiendo de que exista ya el registro sobre el que vamos a escribir o no. La llamada al mtodo super() activa el mtodo ValidateWrite, y en el caso de que ste devuelva verdadero, gestiona la accin de escritura sobre la base de datos. Como ejemplo, presentamos el mtodo Write del origen de datos del formulario LedgerJournalTable. Ejemplo de mtodo Write void write() { super(); if (newJournalNum) { ledgerJournal.usedVoucher(); ledgerJournal = null; newJournalNum = false; } }
i)
Mtodo Delete El mtodo Delete se ejecuta cuando el usuario borra un registro en el origen de datos. La llamada al mtodo super() activa el mtodo ValidateDelete y en el caso de que ste devuelva verdadero, gestiona la accin de borrado sobre la base de datos, realizando una llamada al mtodo Delete de la tabla. Como ejemplo, presentamos el mtodo Delete del origen de datos del formulario LedgerJournalTable. Ejemplo de mtodo Delete void delete() { this.returnJournalNum(); super(); }
Pgina 74 de 141
Programacin de formularios
Es muy importante destacar que en un formulario los orgenes de datos enlazados son tratados como un nico origen de datos. Es decir, las operaciones de seleccin, actualizacin y creacin de registros desde el formulario se realizan sobre todas las tablas enlazadas. El mtodo Init se ejecuta tambin en todos los orgenes de datos. Por otro lado, los mtodos de notificacin (como el mtodo Active) se ejecutan tambin en todos los orgenes de datos.
4.2.
El nombre de las variables que corresponden a rangos de seleccin suele empezar con la palabra criteria. A continuacin deben inicializarse las variables de referencia. Para ello debe aadirse cdigo al mtodo del origen de datos. Las sentencias correspondientes deben insertarse despus de la llamada al mtodo super(), ya que ste es el encargado de crear la consulta. Hacer esto es equivalente a inicializar dichas variables antes de la llamada al mtodo super() en el mtodo Run. Ejemplo void init() { super(); dataSource = CustTrans_Q.dataSourceNo(1); criteriaOpen = dataSource.addRange(fieldnum(CustTrans,open)); }
Pgina 75 de 141
Programacin de formularios
Una vez inicializadas las variables, podremos modificar el rango de seleccin de registros. Esto se realiza antes de la llamada al mtodo super() del mtodo ExecuteQuery. Ejemplo void executeQuery() { criteriaOpen.value('0..1'); super(); } Como ya mencionamos anteriormente, en versiones ms antiguas de Axapta, no existan las variables declaradas implcitamente para las consultas. En ese caso habra que acceder a la consulta mediante mtodos de las clases de sistema, tal y como muestra el ejemplo: Ejemplo void init() { super(); dataSource = this.query().dataSourceNo(1); criteriaOpen = dataSource.addRange(fieldnum(CustTrans,open)); } Como podemos apreciar, sustituiramos la variable CustTrans_Q por this.query(), donde this hara referencia al origen de datos del formulario y query() sera el mtodo que nos devuelve la consulta de dicho origen de datos.
5.
Este mtodo existe en los controles de tipo CheckBox, Button, CommandButton y MenuItemButton. Se ejecuta cuando el usuario pincha sobre el control correspondiente.
Pgina 76 de 141
Programacin de formularios
En los botones de tipo MenuItemButton, la llamada al mtodo super() ejecuta el men item correspondiente. En el caso de los botones CommandButton, se ejecuta el comando asociado al botn. En los botones de tipo Button, la llamada a super() no realiza ninguna accin. b) Mtodo Lookup
Este mtodo existe en los controles de tipo StringEdit, IntEdit, RealEdit y DateEdit. Se ejecuta cuando el usuario pulsa el botn de lookup. Normalmente se aade cdigo a este mtodo cuando el desarrollador desea que se abra una ventana de bsqueda distinta de la ventana estndar.
6.
La secuencia de ejecucin de mtodos es la siguiente: 1. 2. 3. 4. 5. 6. Mtodo constructor New. Mtodo Init del formulario. Mtodo Init del origen de datos del formulario. Mtodo Run del formulario. Mtodo ExecuteQuery del origen de datos del formulario. Mtodo NextField del formulario.
A continuacin, vamos a ver la secuencia de ejecucin que tiene lugar cuando cerramos un formulario. Podemos apreciarla en el siguiente esquema:
Pgina 77 de 141
Programacin de formularios
La secuencia de ejecucin de mtodos es la siguiente: 1. Mtodo CloseCancel del formulario. 2. Mtodo CanClose del formulario. 3. Mtodo Close del formulario. Por ltimo, vamos a ver qu mtodos se ejecutan cuando salimos de un control de un formulario:
La secuencia de ejecucin de mtodos es la siguiente: 1. 2. 3. 4. 5. 6. Mtodo Leave del control. Mtodo Validate del control. Mtodo Modified del control. Mtodo Validate del origen de datos del formulario. Mtodo ValidateField de la tabla. Mtodo Modified del origen de datos del formulario.
Pgina 78 de 141
2.
La clase Args
La clase Args es una clase de sistema que nos permite pasar argumentos a los objetos de la aplicacin. Podemos encontrar ayuda acerca de esta clase en el nodo Documentacin del sistema del rbol de Objetos de la Aplicacin. A continuacin, se presenta la lista de mtodos de la clase Args. Para cada mtodo se describe su utilizacin en el objeto invocante y en el invocado.
Nombre del mtodo Void new object p2) Int finalize() Object caller (Object p1) (AnyType
En el objeto invocado
El destructor Almacena informacin sobre Utiliza el valor de retorno qu objeto ha creado el para determinar desde nuevo objeto. donde fue llamado el objeto actual. Obtiene el nombre del origen de datos del formulario que ha hecho la llamada.
TableId dataset()
Pgina 79 de 141
Slo es usado por la clase ClassFactory. Almacena una referencia a Usado por la un objeto. ClassFactory para objetos nuevos. clase crear
Almacena un parmetro (una Se usa para recuperar un cadena). parmetro del objeto invocante. Almacena un valor Se usa para recuperar un enumerado del tipo valor enumerado del objeto especificado en el mtodo invocante. ParmEnumType. Define el tipo de enumerado Se usa para determinar el que va a ser pasado en el tipo de enumerado usado mtodo ParmEnum. por el objeto invocante.
Object parmObject (Object Almacena un objeto que va a Se usa para recuperar un p1) ser pasado como parmetro. objeto del objeto invocante. Common record (common Almacena un registro. p1) Se usa este mtodo para recuperar el registro activo del objeto invocante.
Todos los formularios, informes y consultas utilizan la clase Args como su primer argumento en el constructor. El modo preferido para usar la clase Args es construir un objeto de tipo Args, asignarle un nombre y entonces pasarle el objeto Args al formulario o a un mtodo de la clase ClassFactory. Veamos, a continuacin, un ejemplo de utilizacin de la clase Args para pasar parmetros a un formulario creado desde el cdigo. Ejemplo: void method1() { Args args; fr;
FormRun ;
args = new Args(CustTable); fr = ClassFactory.formRunClass(args); fr.init(); fr.run(); } Algunos mtodos de la clase Args corresponden con propiedades de los men items. En la tabla siguiente se define esta correspondencia:
Pgina 80 de 141
Supongamos que abrimos un formulario desde un men item. Veamos cmo recuperar los parmetros de entrada. Para ello, presentamos el mtodo ExecuteQuery del origen de datos de un formulario. En este mtodo, se modifica el rango de seleccin de registros de la consulta en funcin de los parmetros especificados en el men item. Ejemplo: void ExecuteQuery() { switch (element.Args().ParmEnum()) { case (PastFuture::Past): criteriaPastFuture.value(..+date2StrDMY(today())); break;
Pgina 81 de 141
Programacin de informes
Programacin de informes
1. Introduccin
Los informes se utilizan para obtener copias impresas de la informacin almacenada en la base de datos del sistema. Como en otros elementos de Axapta, podemos introducir cdigo en los informes para ampliar su funcionalidad. Existen distintos mbitos en los informes donde podemos aadir cdigo: Informe propiamente dicho Consulta del origen de datos del informe Secciones del informe Dependiendo de la funcionalidad que queramos implementar en el informe, escribiremos el cdigo en un mbito o en otro. No obstante, normalmente, se siguen las siguientes reglas: Codificamos en los mtodos del propio informe, cuando queremos controlar la funcionalidad general del mismo. Codificamos en los mtodos de la consulta del origen de datos, cuando queremos controlar la funcionalidad de los datos que aparecen en el informe. Codificamos en las secciones del informe, cuando queremos controlar la funcionalidad de alguna de las secciones o el comportamiento de alguno de los elementos especficos que aparecen en el informe.
Como ya se vio en el captulo de programacin de formularios, se debe tener en cuenta que el cdigo que se introduce en un informe ser accesible nicamente desde dicho informe.
2.
Pgina 82 de 141
Programacin de informes
Una variable llamada element de tipo ReportRun referencia al objeto informe al completo. b) Tabla
Por cada uno de los orgenes de datos del informe tendremos una variable con el nombre del origen de datos, que nos referencia la tabla asociada a dicho origen de datos. En realidad, en un momento dado esta variable nos da acceso al registro activo. Suponiendo que tuviramos un origen de datos que se llamara DatosInforme, tendramos una variable con ese nombre que hara referencia a la tabla. Esta variable nos permite hacer dos cosas: 1. Llamar a un mtodo definido en la tabla. Por ejemplo: DatosInforme.insert(); 2. Hacer referencia a los campos individuales de la tabla. Por ejemplo: number = DatosInforme.accountNo; c) Consulta Existen dos variables que nos dan acceso a la consulta de un informe: Una variable llamada QUERY de tipo Query, que hace referencia a las propiedades y los mtodos de la consulta del informe. Esto nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: query.levelNo(1); Una variable llamada QUERYRUN de tipo QueryRun, que hace referencia a las propiedades y mtodos de una instancia en ejecucin de la consulta del informe. Esto nos da la posibilidad de ejecutar directamente sus mtodos. Por ejemplo: queryRun.getNo(1); A pesar de que se existen estas variables, declaradas automticamente por el sistema, podemos acceder a los elementos que referencian de la forma tradicional, es decir, desde cdigo haciendo uso de los mtodos de la clase de sistema ReportRun. As, por ejemplo, desde un mtodo del informe podemos acceder a la consulta del siguiente modo: Ejemplo de acceso a una consulta Query ; q = this.query(); q.levelNo(1); Ejemplo de acceso a la instancia en ejecucin de una consulta QueryRun ; qr; q;
Pgina 83 de 141
Programacin de informes
qr = this.queryRun(); qr.getNo(1); En ambos casos la variable this hara referencia al objeto en ejecucin en ese momento, es decir, al informe.
En cualquier caso, siempre es ms aconsejable utilizar las variables implcitas declaradas por el sistema en lugar de definir nuevas variables, ya que de esta forma evitamos que existan variables iguales duplicadas en memoria.
3.
3.1.
Lista de mtodos
En un informe podemos encontrar los siguientes mtodos de sistema:
Finalize
Prompt
Se ejecuta para solicitar al usuario que elija el medio (papel, pantalla, archivo) y otra informacin de impresin.
Init
Run
Fetch
Send
Se ejecuta para enviar los registros recuperados por la consulta a las distintas secciones del informe.
SetTarget
cuando
Pgina 84 de 141
Programacin de informes
GetTarget
cuando
PrinterSettings
Se ejecuta cuando seleccionamos la opciones de impresin en un men o a travs del formulario SysPrintForm.
Caption
Se ejecuta cuando se pone en marcha el informe y determina el ttulo de la ventana de visualizacin preliminar del informe.
CreateProgressForm
Se ejecuta cuando se crea una ventana que indica el progreso en la construccin del informe.
ProgressInfo
3.2.
Pgina 85 de 141
Programacin de informes
} c) Mtodo Prompt El mtodo Prompt se ejecuta para solicitar al usuario que elija el medio de impresin. Se muestra un dilogo en pantalla, donde podemos elegir entre las distintas opciones de impresin. Si el programador no quiere que aparezca este dilogo, el mtodo Prompt puede sobrecargarse, de manera que no realice la llamada a super(). No hay que confundir este mtodo con el mtodo del mismo nombre de una consulta. Como ejemplo, tenemos el mtodo Prompt del informe Cheque. Ejemplo de mtodo Prompt boolean prompt() { boolean ret; ; if (chequeCopy) ret = true; else ret = super(); return ret; } d) Mtodo Run El mtodo Run se ejecuta cuando abrimos un informe, inmediatamente despus del mtodo Init, para poner en funcionamiento el informe. La versin no sobrecargada de este mtodo realiza cinco tareas en la siguiente secuencia: 1. 2. 3. 4. 5. Llamar al mtodo Prompt Crear un diseo bsico para el informe, si an no existe Organizar los campos en el informe Llamar al mtodo Fetch Llamar al mtodo Print
Antes de la llamada al mtodo super() podramos hacer algunas tareas habituales, como por ejemplo modificar la consulta del informe. Como ejemplo, tenemos el mtodo Run del informe ForecastSalesActual. Ejemplo de mtodo Run public void run() { ReportStringControl ReportStringControl ctrlBudget; ctrlActual;
Pgina 86 de 141
Programacin de informes
3.3.
El orden en el que se ejecutan los mtodos es el siguiente: 1. Se activa el mtodo Init del informe, para inicializarlo. 2. Se activa el mtodo Run del informe. 3. Se activa el mtodo Prompt del informe, para permitir al usuario interactuar con l. 4. Se activa el mtodo Fetch del informe. 5. Se activa el mtodo Print del informe.
3.4.
Pgina 87 de 141
Programacin de informes
Cuando imprimimos un informe, el primer diseo es el utilizado por defecto. Sin embargo, en tiempo de ejecucin podemos abrir un diseo especfico en funcin de alguna condicin. Para ello utilizaremos el mtodo design() de la clase ReporRun. Como ejemplo, veamos parte del mtodo Init del informe SalesInvoice, correspondiente a las facturas de venta: Ejemplo void { super(); ... switch(SalesParameters::find().prePrintLevelInvoice) { case(PrePrintLevel::BlankPaper): element.design('BlankPaper'); break; case(PrePrintLevel::SemiPrePrinted): element.design('SemiPrePrinted'); break; case(PrePrintLevel::PrePrinted): element.design('PrePrinted'); break; } ... } init()
3.5.
Pgina 88 de 141
Programacin de informes
QueryRun qr = new QueryRun(report); // Abrir el dilogo prompt if (qr.prompt()) { while (qr.next()) { file = qr.get(file); send(file): } } Si slo queremos imprimir registros que satisfacen condiciones especiales, que sean difciles de expresar como un rango en la consulta, debemos escribir el cdigo situado arriba, y solo permitir la llamada al mtodo Send si la restriccin (expresada como una funcin con el mismo nombre en el ejemplo de abajo) se satisface. while (qr.next()) { file = qr.get(file); if (restriccin()) send(file); } A continuacin presentamos un ejemplo del mtodo Fetch del informe Cheque. Ejemplo de mtodo fetch boolean fetch() { QueryRun ; query = new QueryRun(this); if (query.prompt() && element.prompt()) { query.setRecord(tmpCheque); while (query.next()) { tmpChequePrintout = query.getNo(1); this.send(tmpChequePrintout); } return true; query; // Para todos los orgenes de datos // Para todos los orgenes de datos // el usuario no ha pulsado el botn de cancelar
Pgina 89 de 141
Programacin de informes
} return false; } El mtodo Send es una conexin entre la consulta y la parte visual del informe. El mtodo Send enva los registros recogidos a las secciones del cuerpo (body sections) del informe. Podemos ver un esquema del flujo de informacin en los informes en el dibujo siguiente:
En la figura podemos ver cmo los datos se envan desde la tabla a la consulta del formulario mediante el mtodo Fetch, y despus como se enlazan esos datos con los controles del diseo del informe mediante el mtodo Send.
4.
Mtodos en la consulta
En la Gua del desarrollador de Axapta podemos encontrar la lista completa de mtodos de las consultas. En este apartado vamos a ver nicamente los ms importantes. a) Mtodo ClassDeclaration En ste mtodo se definen las variables globales de la consulta, que sern accesibles nicamente por sus mtodos. b) Mtodo Init El mtodo Init incializa la consulta del informe cuando sta se ejecuta. c) Mtodo Prompt
Pgina 90 de 141
Programacin de informes
La ejecucin de este mtodo presenta un dilogo en pantalla, donde el usuario podr determinar los rangos de seleccin de registros, el orden en que stos deben presentarse, etc. La llamada al mtodo super(), abre el formulario definido en la propiedad Form de la consulta. Por defecto, esta propiedad toma el valor SysQueryForm. Si el programador no quiere que aparezca este dilogo, el mtodo Prompt puede sobrecargarse, de manera que no realice la llamada a super(). Como ejemplo, tenemos el mtodo Prompt del informe Cheque. Ejemplo de mtodo Prompt boolean prompt() { boolean ret; ; ret = true; return ret; } d) Mtodo Run El mtodo Run se ejecuta cuando ejecutamos la consulta de un informe desde el Arbol de Objetos de la Aplicacin. //No muestra la ventana
5.
Prlogo (Prolog)
Aparece al principio de un informe. Se utiliza para mostrar elementos, como por ejemplo el logotipo, el ttulo del informe, o la fecha actual. El prlogo se imprime antes que el encabezado de pgina, en la primera pgina del informe.
Aparece al principio de un nuevo grupo de registros. Se utiliza para mostrar elementos, como por ejemplo el nombre de un grupo.
Pgina 91 de 141
Programacin de informes
Aparece en la parte central de un informe. Una seccin puede contener un encabezado, un cuerpo y un pie. Es importante sealar, que la estructura de los orgenes de datos se ve reflejada en la estructura de las secciones.
Cuerpo (Body)
Aparece en la parte central de un informe. Un cuerpo contiene controles o una seccin. Los controles muestran la informacin de los campos de los orgenes de datos.
Pie (Footer)
Aparece al final de un grupo de registros. Se utiliza para mostrar, por ejemplo, subtotales.
Aparece al final de cada pgina de un informe. Se utiliza para mostrar, por ejemplo, nmeros de pgina.
Eplogo (Epilog)
Aparece al final de un informe. El eplogo se imprime justo despus del pie de pgina de la ltima pgina del informe.
Podemos utilizar secciones programables para aadir cualquier tipo de informacin personalizada a nuestros informes. Para activar una seccin programable, lo hacemos mediante la llamada explcita al mtodo execute.
Por lo tanto, la estructura de un informe sera la siguiente: [Prolog] [Page Header] [Section Group] [Header] [Body] [Footer] [Section Group] [Header] [Body] [Footer] [Page Footer] [Epilog] En cualquier lugar del informe podemos definir Secciones programables. De la misma manera, en cualquier seccin del diseo de un informe, podemos crear mtodos de tipo display, que nos permitiran producir la informacin que quisiramos mostrar en dicho informe.
Pgina 92 de 141
Programacin de informes
En el diseo de un informe, debajo de cada seccin, existe un mtodo llamado ExecuteSection. Cuando ejecutamos el mtodo super(), dentro de un mtodo de este tipo, se imprime la informacin de dicho sector. En determinadas situaciones, nos interesa controlar si la informacin de una seccin queremos que se imprima o no, de acuerdo con algn criterio que nosotros mismos definimos. Esto se consigue haciendo que la llamada al mtodo super() se realice dentro de una instruccin condicional. Tambin podemos utilizar el mtodo ExecuteSection para esconder o mostrar controles de un informe en tiempo de ejecucin. Otra utilidad comn de los mtodos ExecuteSection es insertar un salto de pgina. Por ejemplo, para insertar un salto de pgina entre el prlogo y las pginas siguientes, debemos insertar la instruccin element.newPage() despus de la llamada al mtodo super() en el mtodo ExecuteSection del prlogo.
6.
Pgina 93 de 141
Plantillas de informes
Plantillas de informes
1. Definicin
La idea bsica de una plantilla es muy simple. Imaginemos que tenemos 20 informes para una determinada compaa, que comparten el mismo diseo bsico. Si definimos el diseo bsico en una plantilla slo lo realizaremos una vez, y despus el mismo diseo podr ser compartido por todos los informes de dicha compaa. Cuando creamos un informe utilizando una plantilla, estamos determinando unas caractersticas por defecto. La plantilla contiene informacin sobre las secciones que contiene un nuevo informe y sobre el diseo de cada una de las partes del informe. Una plantilla puede contener un prlogo, una cabecera de pgina, un pie de pgina, un eplogo, y secciones programables. Estas secciones pueden ser aadidas al diseo que MorphX genera basndose en nuestro diseo especfico. Por ejemplo, nuestra plantilla contiene un pie de pgina que aade un nmero de pgina a todas las pginas de nuestro informe. Si nosotros decidimos hacer una modificacin en el diseo, tan slo lo tendremos que hacer una vez en la plantilla, y automticamente todos los 20 informes sern modificados. Esto es cierto nicamente cuando utilizamos un informe basado en un diseo especifico (AutoDesignSpecs). Si nuestro informe utiliza un diseo personalizado (Design), los cambios realizados en la plantilla no los veremos en nuestro informe. Cuando nosotros creamos un diseo personalizado, MorphX realiza una copia de la plantilla y la coloca en el nodo diseo de nuestro informe, por esta razn no se actualiza cuando se modifica la plantilla.
2.
3.
Pgina 94 de 141
Clases
Clases
DEFINICIN: Una clase es un constructor software que define unos datos (estado) y unas acciones (comportamiento) de los objetos concretos que posteriormente son creados en a partir de esa clase. Las propiedades son los datos para la clase y los mtodos son la secuencia de sentencias que operan con los datos. Normalmente las propiedades son propias de un objeto, es decir, todos los objetos construidos a partir de la definicin de la clase tendrn su propia copia de las propiedades. Estos distintos objetos son conocidas como instancias. Una clase no es un objeto. Una clase puede ser considerada como un anteproyecto, que define como un objeto podr comportarse cuando el objeto sea creado desde las especificaciones dictadas por la clase. Nosotros obtenemos objetos concretos para instanciar una clase definida previamente. As como nosotros podemos construir muchas casas de un mismo arquitecto, nosotros podemos instanciar muchos objetos de una misma clase. A continuacin podemos ver una declaracin bsica de una clase muy simple llamada Point: Class Point { double x; double y; } Esta declaracin simplemente define una plantilla de cmo objetos de tipo Point pueden ser instanciados. //instancia de una propiedad // instancia de una propiedad
1.
Objetos
Casi todo puede ser considerado como objeto. Coge, por ejemplo, una botella de agua mineral. Tiene un estado y varios mtodos. Puedes usar el mtodo vaciar agua para cambiar el estado del objeto. Hay menos agua en la botella cuando finaliza la accin. Activas los mtodos y el estado del objeto cambia de acuerdo a ello. El estado recuerda el efecto de la operacin que has activado. Otro ejemplo es el de un coche a control remoto. El coche consiste en funcionalidad y datos. Los datos estn influidos por los mtodos o la funcionalidad. Velocidad, direccin, rotacin, y, as sucesivamente, son datos o variables. Accedes a los mtodos del coche cuando usas el control remoto. Por ejemplo mandas un mensaje de moverse hacia delante, el cual sabes que es un mtodo (funcionalidad) que pertenece al objeto coche. El mensaje es interpretado por el coche que activa el mtodo de moverse hacia delante, el cual resulta en un movimiento de las ruedas y un movimiento hacia delante. El control remoto es el manipulador que utilizas para acceder al objeto, o apuntar al objeto. El cdigo es as: ClassName Myhandle=new ClassName();
Pgina 95 de 141
Clases
ClassName
Myhandle
ClassName
Un Ejemplo de datos en el coche podra ser tambin la energa de las bateras. No sabes cuanta energa puede quedarle a la batera, antes preguntas al objeto, en otras palabras, debes comprobar la batera. Slo el objeto conoce esos datos. Tienes que conocer los objetos mtodos del objeto, antes de poder activarlos y poder tener algn manejo para poder acceder a ellos. El coche podra tener un mtodo llamado fuel, el cual utilizas para cambiar el estado de la batera. No puedes acceder a los mtodos del coche sin el control remoto. Los objetos interactan con otros en la aplicacin. Uno objeto interacta con otros objetos envindole un mensaje, el cual invoca una operacin en el objeto que la recibe. El objeto recibiente sabe como reaccionar a este mensaje, y diferentes objetos pueden fcilmente reaccionar de forma distinta ante el mismo mensaje.
2.
2.1.
Mtodos de la clase
ClassDeclaration.
En este mtodo es donde podemos escribir la declaracin de las variables. Por defecto este mtodo est vaco. Tambin en este mtodo es donde se le asigna un nombre a la clase. Ejemplo: class CustOverdueExpense { CustPaymExpense LedgerAccount LedgerJournalTrans } custPaymExpense; ledgerAccount; ledgerJournalTrans;
Pgina 96 de 141
Clases
2.2.
New.
Este constructor es llamado automticamente cuando el objeto es creado por el operador new. Suele ser utilizado para inicializar las propiedades en el objeto nuevo. A continuacin vemos un ejemplo de la utilizacin del mtodo new en la clase Point: Void new(double a=10, double b=10) {//Constructor que inicializa a un valor por defecto x = a; y = b; } Al mtodo new en una clase se llama constructor. Cuando nosotros creamos una instancia de un objeto de la clase Point, el constructor es invocado para ejecutar cualquier inicializacin que sea necesaria. En este caso, modifica la instancia de la variable a un estado inicial. Los mtodos constructores pueden o no recibir parmetros, pero nunca devuelven un valor. En el ejemplo de abajo podemos ver como podemos crear e inicializar un objeto de la clase Point, inicializndolo con los valores por defecto o inicializndolo a unos valores especficos. Point lowerleft; Point upperRight;
lowerleft = new Point(); //valores por defecto. upperRight = new Point(100.0, 200.0); // valores especficos.
2.2.1.
En ocasiones una clase necesita utilizar instancias de otros objetos, y debe en su constructor crearse instancias de dichos objetos. A continuacin podemos ver un ejemplo de cmo la clase rectangle utiliza dos objetos de tipo Point. Class Rectangle { Point lowerleft; Point upperRight;
2.3.
Finalize.
Pgina 97 de 141
Clases
Cuando el manejo de un objeto no puede agregarse a un objeto, el objeto ya no podr extenderse. Si quieres terminar un objeto, usa el mtodo llamado FINALIZE. El mtodo libera el espacio que estaba ocupado por el objeto. Un manipulador siempre apuntar a algo, pero puede usarse el valor Null para interrumpir el enlace del manipulador del objeto con el objeto. Esto no har desaparecer el objeto. El ejemplo siguiente describe la diferencia entre dos acciones: Class1 oh; oh = new Class1(); objecthandle Su = Null; Or: Su.finalize(); // The object is terminated, and any code in Finalize is executed //Objecthandle of the oh type is created //Object of the type Class1 is created and attached //to the
Se puede usar el mtodo Finalze para optimizar las acciones teardown. ste fragmento de cdigo ilustra como activar el mtodo finalize en una clase. Observa que Finalize en X++ no es llamado automticamente por el sistema. Se debe explictar la llamada al mtodo finalize para ejecutar los estados que hay en l. // From any method in a class { ... if (Condition) this.Finalize(); ... } Aunque el mtodo finalize no contiene ningn cdigo, la ejecucin del mtodo tiene un efecto importante. Cuando llamas a Finalize, MorphX cierra el objeto. Esto significa que usando finalize un objeto se puede quitar a s mismo de la memoria.
3.
Mtodo main
Este mtodo es utilizado para ejecutar una clase. No es un mtodo de la clase, si no que cuando nosotros queremos ejecutar una clase a travs de una llamada de menu item, nos crearemos un mtodo main pasndole como parmetro un objeto de tipo Args. Este mtodo tiene 3 peculiaridades: 1.- Es un mtodo esttico.
Pgina 98 de 141
Clases
2.- Recibe un nico parmetro de tipo args. 3.- No devuelve ningn parmetro, es de tipo void. El perfil de este mtodo es el siguiente. void static main (args _args); Una clase puede ser ejecutada a travs de un men item de tipo Action o sobre la misma clase pulsando Open (botn derecho del ratn o en la barra de herramientas). Normalmente este mtodo suele contener la creacin de la instancia de la clase y las llamadas a los mtodos prompt y run de la clase. Ejemplo: static void { CustInvoiceJour CustInvoice ; custInvoiceJour = args.record(); custInvoice = new CustInvoice(custInvoiceJour, CustParameters::find().creditMaxCheck); custInvoice.run(); } custInvoiceJour; custInvoice; main(Args args)
4.
Donde ClaseDefinidaPorUsuario es el nombre del objeto de la aplicacin en el rbol de la Aplicacin de Axapta. Usando esto se pueden declarar variables como stas. Access A1; //Un objeto-acceso es declarado pero NO inicializado Access A2,A3; //Dos objetos accesos son declarados, pero no inicializados. Access A4 = new Access(); //Un objeto acceso es declarado E inicializado //(sin parmetros)
Pgina 99 de 141
Clases
Una variable es una referencia, o puntero, a una parte de la memoria que contiene el objeto almacenado. Pero desde la variable solo es una referencia (Object andel), debes asignar espacio para el objeto antes de que puedas usarlo para contener datos. En los ejemplo de arriva, el objeto A4 es declarado usando el nuevo mtodoen la Access-class(new access()) como una inicializacin, la memoria es tambin asignada. Los otros objetos-accesos(A1,A2 y A3) son slo declarados y por lo tanto slo (nulos) punteros. Como los objetos A1-A3 son declarados, pueden apuntar a cualquier objeto asignado, o ellos mismos pueden saignarse invocando el mtodo new en ellos. En la siguiente ejemplo, la memoria es asignada para A2 y A3 y A1 es asignada para referenciar al objeto A4: A2 = new Access(); A3 = new Access(); A1 = A4;
5.
Herencia
X++ implementa lo que se conoce como un modelo de herencia simple. Una nueva clase slo puede ser subclase de otra clase. Si nosotros extendemos una clase, nosotros heredamos todos los mtodos y variables de la clase madre, la cual se llama superclase. La sintaxis que denota que una clase es hija de una superclase es la siguiente: Class Nombre de la clase hija extends nombre de la superclase La anterior sera la definicin que debera a parecer en la declaracin de clase de la clase hija. A continuacin presentamos un ejemplo que crea una nueva clase que es una variante de la clase Point, esta nueva clase vamos a llamarla 3DPoint: class Point { real x; // instancia de la variable. Real y; // instancia de la variable. ; New(real _x, real _y) { // el constructor inicializa las variables x e y. x = _x; y = _y; } } class 3DPoint extends Point { real z; // la coordinada z del punto.
Clases
New(real _x, real _y, real _z) { super(_x, _y); // inicializa las instancias z = _z; } } Como podemos observar la clase 3DPoint ha aadido una nueva instancia de variable para la coordinada z del punto. Las instancias x e y son heredadas de la clase Point por lo que no necesitamos declararlas en la clase 3DPoint.
5.1.
Sobrecarga de mtodos
Cuando nosotros estamos trabajando con mtodos en una subclase, es decir, una clase que hereda mtodos y propiedades de otras clases, podemos alterar la funcionalidad del mtodo de la clase principal. Para hacer esto debemos crearnos en la subclase un mtodo con el mismo nombre y parmetros que el mtodo de la clase principal. Por ejemplo, supongamos que tenemos dos clases llamadas ClassA y ClassB, de forma que la segunda es una subclase de la primera. Definimos los siguientes mtodos: ClassA void myMethod(int i) { // Intrucciones clase A } ClassB void myMethod(int i) { // Instrucciones clase B } En este caso la clase ClassB es una subclase de la clase ClassA, por lo tanto hereda el mtodo myMethod. Sin embargo como en la clase ClassB se define un mtodo con el mismo nombre y el mismo nmero de argumentos, haramos caso omiso del mtodo de la clase principal. Si se llamara al mtodo myMethod de la clase ClassB ejecutara su propio mtodo, es decir, las instrucciones de la clase B, en lugar del mtodo de la clase principal. Esto es lo que llamamos sobrecargar un mtodo. Si no estamos interesados en perder por completo la funcionalidad del mtodo de la clase principal, pero nos interesa aadirle funcionalidad, podemos hacer una llamada al mtodo de la clase principal mediante la sentencia super()dentro del mtodo de la clase hija. Por ejemplo: ClassB void myMethod(int i) {
Clases
super(); // Instrucciones clase B } En este caso cuando realizramos una llamada al mtodo myMethod de la clase hija se ejecutara, mediante la llamada super(), el mtodo de la clase principal, con lo que se ejecutaran las instrucciones de la clase A y despus se ejecutara el resto del mtodo, es decir, las instrucciones de la clase B. Por otra parte, con este funcionamiento existe el peligro de que, al sobrecargar un mtodo, alteremos su funcionalidad de manera incorrecta. Por lo tanto, para protegernos de este tipo de situaciones, X++ proporciona el modificador final, que evita que un mtodo pueda ser sobrecargado. Por ejemplo: final void myMethod() { // Instrucciones } Existen no obstante algunos mtodos que no pueden utilizar el modificador final, como son los que se invocan cuando se crea o destruye un objeto, y otros que no lo necesitan ya que nunca pueden ser sobrecargados, como son los mtodos estticos.
5.2.
Clases
Como podemos ver, todas las clases hijas contienen el mtodo hello( ), el cual anula al mtodo hello( ) de la clase madre. Esto es importante para ver como trabaja la herencia controlada por constructor. En la clase PT_ConstructMain, nosotros utilizamos el mtodo run( ) para llamar al mtodo constructor( ) de la clase PT_Construct. Class PT_ConstructMain { void run( ) { PT_Constructor constructor; PT_Type type; ; // ** Llama al mtodo PT_ConstructDoNotKnow.hello() constructor = PT_Constructor::construct(PT_Type::DoNotKnow); constructor.hello();
// ** Llama al mtodo PT_ConstructTeacher.hello() constructor = PT_Constructor::construct(PT_Type::Teacher); constructor.hello(); } } Si observamos el mtodo PT_Constructor.construct( ), que abajo se detalla, podemos observar que dependiendo el parmetro que se le pasa al mtodo, l devuelve una de las instancias de las clases hijas. Static PT_Constructor construct(PT_Type type) { switch (Type) {
Clases
case (PT_Type::DoNotKnow) : return new PT_ConstructDoNotKnow(); break; case (PT_Type::Student) : return new PT_ConstructStudent(); break; case (PT_Type::Teacher) : return new PT_ConstructTeacher(); break; } }
5.3.
Polimorfismo
Imagina dos objetos diferentes: un coche controlado por control remoto y un helicptero tambin controlado por control remoto. El mismo control remoto es usado para ambos objetos, pero la forma en la que interpretan los mensajes recibidos es diferente. El mismo mensaje: Moverse hacia delante es enviado a ambos objetos. El coche slo debe activar las ruedas para moverse, mientras que el helicptero debe empezar un proceso ms complicado incluyendo el rotor para moverse hacia delante. El objeto del coche y del helicptero son instancias de dos clases diferentes, pero estas dos clases heredan el mtodo de movimiento de la misma clase padre. El mtodo es abstracto en la clase padre, lo cual significa que puede ser implementado indiferentemente en las diferentes clases hijas. Lo que es importante para comprender es que la interpretacin mandada del mensaje descansa en el objeto. Lo que es tambin importantes que necesitas un manejador para acceder a la funcionalidad de los objetos. En este ejemplo el manejador es el control remoto, el cual ilustra que se puede usar el mismo manejador para distintos objetos, pero no puedes usar el mismo manejador par los dos objetos al mismo tiempo. (A menudo un mtodo con el mismo nombre es implementado diferente en otra clase. Pero cada clase conoce como implementar el mtodo en su propia y nica forma. Este concepto es el que se denomina polimorfismo. La idea bsica de polimorfismo es que diferentes mtodos se pueden llamar de acuerdo a contextos diferentes. Una funcin debe tener un tipo de parmetros que determine el tipo de argumento cuando la funcin es llamada o diferentes funciones pueden ser llamadas correspondiendo a diferentes argumentos o el polimorfismo puede implementar alguna herencia. El polimorfismo proporcinala habilidad de escribir programas que son independientes del formulario de los datos a travs de los cuales ellos operan, as permiten un diseo prximo al del mundo real.) Finalmente, una ventaja de la encapsulacin es algo llamado polimorfismo. Simplemente esto significa que ms de una clase de objeto puede (solucionar) una solicitud. El solicitante no conoce y no le preocupa qu clase de objeto ha (solucionado) una solicitud en particular.
Clases
5.4.
Encapsulation
En las clases de Axapta, las variables de miembro estn siempre protegidas, tanto es, que no se puede acceder a ellas directamente. Tan solo se puede acceder a ellas dentro de un objeto. Para acceder a las variables debes escribir un mtodo de acceso. De este modo, el mtodo de acceso es la nica interfaz a las variables de miembro. Un ejemplo tpico de un mtodo de acceso para conseguir un valor es: \Classes\CustVendVoucher\InvoiceNum: InvoiceNum InvoiceNum() { return InvoiceNum; } Un ejemplo tpico de un mtodo de acceso para acceder a un valor es \Classes\CustVendVoucher\SetApprovedBy: void SetApprovedBy(EmployeeNum _ApprovedBy) { ApprovedBy = _ApprovedBy; } En lugar de crear un mtodo separado para obtener un valor, puedes hacerlo de igual forma que este ejemplo desde \Classes\Info\DoxRefCreate: boolean DoxRefCreate(boolean _DoxRefCreate = DoxRefCreate) { DoxRefCreate = _DoxRefCreate; return DoxRefCreate; } En el ltimo ejemplo desde que hay un pequeo gasto de memoria y tiempo cuando movemos los datos desde una variable a otra es recomendado usar la tcnica del siguiente ejemplo cuando las variables contiene una enorme cantidad de datos (como contenedores grandes o campos memo): container Code(container _Code = conNull()) {
Clases
5.5.
Recoleccin de objetos
Los objetos necesitan ser asignados o colocados, necesitan tambin ser re asignados para preservarlos en memoria. En otros lenguajes esto est hecho explcitamente, pero en X++ est hecho automticamente. MorphX controla el uso de objetos (el nmero de referencias en un trozo asignado de memoria), y cuando no objetos tienen asignado ninguna porcin de memoria, la memoria es liberada. Este mecanismo es conocido como coleccin de basura. En el ejemplo precedente, asignando null a A2 podra tambin reasignar la memoria asignada y llamar al mtodo finalize en la clase. Asignando Null a A1 podra no reasignar porque A4 hara an referencia a l. Asignando nulas a ambas (A1 y A4) podras reasignar memoria.
Desarrollo Cliente/Servidor
Los objetos creados desde la clase residirn donde se haya especificado. Si se escoge called from, el objeto residir en el entorno donde se invoque al constructor (new) (cliente o servidor). Las clases que heredan de otras tambin heredan la propiedad RunOn. Si est establecida a Client o Server no se puede modificar, pero si se trata de Called from s puede modificarse.
1.2.
Mtodos.
Los mtodos estticos de clase as como los mtodos de las tablas pueden cambiar su comportamiento aadiendo el modificador client o server en su declaracin como se muestra en el siguiente ejemplo. server static boolean myMethod() { ... } El mtodo anterior ser siempre ejecutado en el servidor. Por defecto los mtodos estticos de las clases son ejecutados all donde indique la propiedad Run On de la clase en la que se ha declarado el mtodo. Los mtodos dinmicos se ejecutan siempre all donde la clase se ha declarado que resida (a travs de la propiedad Run On). A los mtodos estticos de clase se les puede especificar comportamiento called from indicando en su declaracin que pueden ser ejecutados tanto en el cliente como en el servidor: client server static boolean myMethod() { ... }
Desarrollo Cliente/Servidor
Los mtodos de las tablas, se ejecutan desde all donde son llamados, aunque por definicin, los mtodos insert / doInsert, update / doUpdate y delete / doDelete se ejecutan en el servidor.
2.
Al tener esta opcin activada, cada vez que compilemos se generaran o actualizaran las referencias cruzadas de aquellos nodos del AOT que compilemos, con lo que siempre dispondremos de las referencias cruzadas actualizadas. Pero al mismo tiempo, la compilacin se volver ms costosa. Por lo tanto, Si se va a desarrollar en Axapta, se recomienda no activar esta casilla y realizar una actualizacin de las referencias cruzadas de todo el AOT de forma peridica. La herramienta para generar las referencias cruzadas de todo el sistema la vamos a encontrar en el men herramientas (tools) / desarrollo (development) / referencias cruzadas, donde accedemos a un dialogo donde podemos indicar que operacin deseamos realizar con las referencias cruzadas. Otro punto de acceso a la herramienta referencias cruzadas mucho ms utilizado est en el men contextual del AOT a travs de la entrada Adds-Ins / Referencia cruzada. A partir de esta entrada es posible no solo actualizar las referencias cruzadas para el nodo sobre el que estamos situados, sino tambin consultar dichas referencias cruzadas segn las distintas modalidades que pasamos a detallar.
Si seleccionamos la opcin Nombres, nos muestra una lista de objetos de aplicacin con el nombre del elemento y la posibilidad de ver a que elementos hace referencia el elemento actual.
Si seleccionamos la opcin Ruta de acceso (Path), nos muestra la misma lista pero nombrando la ruta de acceso en el rbol de objetos de la aplicacin del elemento actual.
Y seleccionando el botn Utilizado por nos muestra una ventana, como la mostrada a continuacin, con informacin de los elementos que hacen referencia al elemento actual.
2.
Visual MorphXplorer
Utilizaremos el Visual MorphXplorer para visualizar el mdulo de datos de Axapta mediante el dibujo de diagramas de relacin de entidades. Todos los comandos de visualizacin se encuentran disponibles en el men contextual del objeto actual. Utilizaremos las fichas General y Colores para asignar un ttulo a cualquier diagrama y para definir su propia configuracin de color. Antes de comenzar a realizar un diagrama, ser necesario actualizar el sistema de referencias cruzadas, puesto que la informacin para la realizacin de estos diagramas se obtiene de esta herramienta. En el Visual MorphXplorer nosotros podemos representar las relaciones entre tablas con la siguiente informacin: Las relaciones 1:n de la tabla actual. Las relaciones n:1 de la tabla actual. Las clases que utiliza la tabla actual. Los maps en que la tabla actual forma parte. Ejemplo: Diagrama de relacin entre tablas.
pr2
*
AccountNum
AccountNum
pr2
78
pr2
Tambin podemos representar relaciones entre clases. En un diagrama de clases podemos representar: Que clases utiliza la clase activa. Que clases utilizan la clase activa. Que clase es la superclase de la clase activa. Que clases son hijas de la clase activa. Ejemplo: diagrama de relacin entre clases.
RunBase 512 ChequeDelete DialogField
dialogFromChequeNum
Called
43
Called
115
Client
2.1.
2.1.1.
2.1.2.
2.2.
1. Hacer clic con el botn derecho del ratn en cualquier parte libre de la ventana del Visual MorphXplorer. 2. Seleccionar la opcin Organizar el men contextual. Todas las tablas, clases y relaciones son de nuevo organizadas acorde con el algoritmo de mejor situacin. Podemos situar los distintos elementos del grfico seleccionndolos y arrastrndolos hasta la posicin que deseamos. Al realizar esta accin, la herramienta recoloca el resto de objetos del grfico segn este algoritmo de mejor situacin.
2.3.
3.
rbol de jerarqua
El rbol de jerarqua ofrece una vista diferente de los elementos del rbol de objetos. La vista est clasificada por los diferentes tipos de datos. En la imagen de abajo podemos ver el rbol de jerarqua.
A continuacin se muestra un ejemplo, donde podemos ver la definicin de una clase, de qu clase es hija, y que mtodos estn reescritos. De la misma forma tambin podemos ver los campos y mtodos de una tabla.
4.
Herramienta de bsqueda
El aspecto de la ventana de la herramienta Buscar... es similar a Buscar archivos y carpetas de Windows, aunque dispone de algunas optimizaciones especificas para el entorno Axapta.
La ficha Filtro, es una mejora particular de esta herramienta, se utiliza para filtros avanzados del resultado de la bsqueda. Escriba el cdigo X++ en el campo Origen. El cdigo se evala para cada nodo encontrado y debe devolver un valor lgico que ser
verdadero si el nodo se va a incluir en el resultado de la bsqueda y falso si no se va a incluir. Se puede detener una bsqueda haciendo clic en el botn Detener (si se encuentra activado) o pulsando Ctrl+Interrumpir. El botn Detener se activa si se buscan slo mtodos (predeterminado) que contengan algo de texto, que utilicen la seleccin y si se han seleccionado algunos de los "nodos raz": AOT, Tablas, Clases, Formularios, Informes, Consultas, Mens, Menu items.
5.
5.1.
Otros
Herramientas de comprobacin de cdigo (Best Practices)
Esta herramienta hace una comprobacin del cdigo desarrollado para ver si se adapta a los estndares de Axapta. La utilizacin de esta herramienta no garantiza que todo el cdigo comprobado cumpla con los estndares de Axapta. Esta herramienta la podemos encontrar en el men contextual del rbol de objetos (AOT), seleccionando la opcin Add-ins / Optimizacin / Comprobar optimizacin. Nosotros podemos ejecutar la opcin Comprobar optimizacin en cualquier nodo el entorno de desarrollo. Basndonos en las directrices descritas en este documento, el resultado nos dar unos consejos sobre como ejecutar nuestro cdigo. A continuacin se detallan una serie de limitaciones de la herramienta: El procedimiento de comprobacin revisa un mtodo cada vez. No tiene perspectiva general. Es un anlisis esttico. No podemos ver la diferencia entre un mtodo del cliente llamado una vez y un mtodo del servidor llamado 1000 veces. No se aprecia como una tabla temporal reside en el servidor como una tabla ordinaria, aunque no debe ser el caso. Actualmente se considera una llamada a queryRun.next() como una llamada al servidor, pero debe considerarse como una llamada al cliente y al servidor, si la queryRun es instanciada desde el cliente y est accediendo a una tabla ordinaria. Tampoco se debe considerar si la tabla temporal reside en cualquier otra parte. No podemos ver si un objeto de una clase llamada es instanciado en un nivel y en otro nivel es pasado como parmetro a un mtodo ejecutable, el cual a su vez llama a mtodos de dicho objeto.
5.2.
Herramientas de comparacin
Esta herramienta realiza comparaciones entre objetos del rbol de objetos. La podemos encontrar en el men contextual del rbol de objetos (AOT), pinchando en la opcin Add-ins / comparar.
Para realizar la comparacin entre dos objetos deberemos seguir los siguientes pasos: 1. Seleccionar los dos objetos que deseamos comparar. Tambin podemos seleccionar un slo objeto para realizar comparaciones entre dos diseos o niveles. 2. Abrir el men contextual y escoger la opcin Comparar. 3. Verificar que los objetos seleccionados, son los que queremos para realizar la comprobacin. 4. Pulsar el botn Comparar. Ahora el sistema realizar la comparacin, y ampliar el cuadro de dilogo mostrado anteriormente con dos paneles ms, como se puede ver en la imagen siguiente.
El panel de la izquierda muestra las diferencias entre los dos objetos en una estructura de rbol que puede estar expandido. Y en el panel de la derecha muestra el contenido del nodo actual seleccionado. Las diferencias encontradas son indicadas usando colores, tanto en los iconos de la estructura en rbol como en el contenido del nodo actual. El panel sombreado con las marcas de comprobacin indica que hay diferencias en la hija del nodo. Como podemos ver en el cuadro de dilogo, un objeto est pintado de rojo y el otro objeto est pintado de azul. Cuando existen diferencias el icono del mtodo, control o propiedad etc. est pintado de los dos colores (rojo y azul), si pinchamos sobre este icono nos aparecern en rojo las lneas de cdigo, propiedades o controles que son del objeto rojo, en azul las lneas, propiedades o controles que son del objeto azul y en negro las lneas, controles o propiedades que son idnticos. Si nos aparece el icono con una marca roja, quiere decir que ese mtodo, control o propiedad es del objeto rojo, y si por el contrario aparece con una marca azul, significa que es del objeto azul.
5.3.
Sustitucin
Esta herramienta nos permite cambiar un texto por otro, por ejemplo, cambiar el nombre de un tipo de datos, o el nombre de un campo de una tabla, etc.
La podemos encontrar en el men contextual del rbol de objetos (AOT), pinchando en la opcin Add-ins, y despus sustituir sintcticamente.
5.4.
El examinador de tablas
Una vez ya hayamos creado un tipo de interfaz e introducidos datos en una tabla, podemos utilizar el examinador de tablas para facilitar una visin de los datos existentes en la base de datos.
Para abrir el examinador de tablas se siguen los siguientes pasos: 1. Sobre el objeto tabla que queremos ver los datos, abrir el men contextual del rbol de objetos de la aplicacin. 2. Activamos la opcin Add-ins / examinador de tablas. El examinador de tablas nos mostrar los datos de todos los campos de la tabla, excepto los de tipo container. A travs de esta herramienta podemos editar y eliminar registros. Podemos utilizar el examinador de tablas en cualquier sitio donde una tabla sea utilizada como origen de datos: en un formulario, en un informe o en una consulta. Tambin podemos utilizar el examinador de tablas para ver el contenido de las tablas del sistema.
Used by maps
Used by
AOD
Update Crossreference
Crossreference
One
2.
Vetanas
En Navision Axapta una de las formas ms fciles para mostrar informacin al usuario es usando una ventana. El comando crea una ventana de cualquier dimensin y posicin en la pantalla, usando el siguiente cdigo: Window x1, y1 [at x2, y2]; Donde x1 es el nmero de caracteres que se pueden poner en la ventana desde la derecha, y1 es el nmero de caracteres que puedes situar en la ventana de arriba abajo. Puedes emplazar la ventana en un lugar de la pantalla que quieras usando la sintaxis at x2, y2. Por ejemplo, un comando de ventana puede ser el siguiente:
Window 10,5 at 10,20 Crea una ventana, la cual tiene 10 caracteres de ancho y 5 caracteres de alto. La ventana est situada en la pantalla 10 caracteres a la derecha y 20 caracteres abajo. Nota: En lugar de usar valores positivos tambin se pueden utilizar valores negativos. Esto emplaza en partir de la esquina inferior derecha. En la posicin at, en lugar de la superior izquierda. Si se usan valores negativos para la posicin de la ventana siempre la ventana va a ser creada en la esquina inferior derecha.
3.
Informacin de salida
Axapta nos ofrece distintas posibilidades a la hora de mostrar mensajes al usuario.
3.1.
El sistema InfoLog
El sistema Infolog corresponde a la ventana informativa que utiliza el sistema para mostrar los mensajes de informacin, aviso y error que se generan durante el uso de la aplicacin. En realidad, es ms que una ventana. Se trata de un registro donde se van grabando los diferentes mensajes.
3.1.1.
Usa infolog.errorsPerBatch para fijar el nmero mximo de errores. Si el actual nmero de errores excede el mximo, un texto dice que puede haber ms errores de lo que pueden ser mostrados.
3.1.2.
a)
Como parmetro de entrada recibe la cadena correspondiente al mensaje. Como valor de retorno, devuelve una excepcin de tipo info. b) EXCEPTION warning(Str) Nos permite presentar un mensaje de aviso.
Como parmetro de entrada recibe la cadena correspondiente al mensaje. Como valor de retorno, devuelve una excepcin de tipo warning. c) EXCEPTION error(Str) Nos permite presentar un mensaje de error. Como parmetro de entrada recibe la cadena correspondiente al mensaje. Como valor de retorno, devuelve una excepcin de tipo error.
d)
boolean checkFailed(Str)
El mtodo CheckFailed retorna un valor booleano y es usado para los avisos (warnings). Como info, warning y error,checkFailed toma tres argumentos: Una string Que es aadida al log (histrico).
Una ruta al sistema de ayuda interno de Axapta Que puede ser usado para abrir el visor de la ayuda y presentar un texto aclaratorio mayor. Este argumento es opcional. Una accin de Infolog Que puede ser usada para iniciar una accin, por Ejemplo para accionar el editor de X++. Este argumento es opcional.
3.2.
La sentencia throw
Esta sentencia pertenece al sistema de gestin de excepciones de Axapta, que se describe en un captulo posterior. En estos momentos, nos basta con saber que podemos utilizarla para presentar un mensaje de error al usuario y abortar la ejecucin del cdigo. La sentencia throw error muestra al usuario el mensaje de error especificado en su argumento: throw error("No existen registros");
4.
Informacin de entrada
Adems de los formularios, bsicamente Axapta nos ofrece dos posibilidades para solicitar informacin al usuario.
4.1.
La clase Box
Hay varias limitaciones cuando usamos el comando imprimir. El espacio est limitado, un comando de pausa es necesario para ver lo que se escribe. Una caja (Box) est diseada para arreglar estos problemas. Crear una caja es como esto: Box::info (Text1,Text2,Text3); Tres parmetros son adjuntados para el mtodo de Info en una clase de caja, Text1 es el texto que se muestra en la caja, text2 es el texto que se muestra en la etiqueta de la caja, y el texto 3 es el texto que se muestra como texto de ayuda en el final de la pantalla. No son obligatorios el segundo y tercer parmetro. La caja es usada para mostrar en el ejemplo de arriba es una de las de tipo info, la cual es especificada detrs de los dos puntos. Alternativamente, para crear mensajes de usuario, usa la Stop o la caja de Warning. Los siguientes parmetros son los mismos. Los tipos de cajas mencionadas no son interactivos. Tan solo pueden ser usadas para mensajes para el usuario; no pueden recibir ninguna instruccin del usuario. Examina el AOT y expande las clases y despus el nodo Box para ver una lista de todos los tipos de Box que hay disponibles en X++. Los tipos de cajas que no estn descritos arriba tienen todos algn nmero de botones. El sistema acta de acuerdo con el botn que pulse el usuario. Una caja del tipo YesNO es creada de la siguiente manera: Box::yesno(Text1, DialogButton::No, text2,text3); Como se ha mencionado previamente, hay tres textos el cual solo es obligatorio el primero. En adicin, un cuarto parmetro: DialogButton necesita ser especificado. El parmetro DialogButton controla qu botn se encuentra seleccionado por defecto, antes de que el usuario haga su eleccin. Elige la opcin apropiada para ser ejecutada si el usuario solo selecciona con el botn Enter del teclado.
El DialogButton es un Base Enum Ejemplo de cajas: { ; Box::Info(Information \n new line,title,helptext); Print any2int(box::yesno(Is this a yes/no box, dialogbutton::no,title,helptext))at 10,11; Pause; }
Tipo de Dilogo
Valor Enumerado/ Cuando utilizarlo Nombre del mtodo InfoBox El usuario debe ser informado de algo, y debe pulsar Ok. El usuario debe ser advertido de algo, y debe pulsar Ok. Se le presenta una eleccin al usuario y debe pulsar S o No. La aplicacin se detiene, posiblemente porque algn error ha ocurrido, o algo serio va a ocurrir, y el usuario debe pulsar Ok. Se le presenta una eleccin al usuario y debe pulsar S, No o Cancelar. Se le presenta una eleccin al usuario y debe pulsar Si a todo, No a todo y Cancelar
Informacin
Advertencia
WarnBox
S/No
YesNoBox
Stop
StopBox
S/No/Cancelar
YesNoCancelBox
S/No/No a todo/Cancelar
YesNoNoAllCancelarBox Se le presenta una eleccin al usuario y debe pulsar Si, No, No a todo y Cancelar YesYesAllNoCancel Se le presenta una eleccin al usuario y debe pulsar S, S a todo, No, Cancelar Se le presenta una eleccin al usuario y debe pulsar Se le presenta una eleccin al usuario y debe pulsar Aceptar o Cancelar.
S/S a Todo/No/Cancel
S/No/FormularioAxapta
YesNoAxaptaFromBox
Aceptar / cancelar
OkCancelBox
La clase Box hace uso de la clase de sistema DialogBox. Sin embargo, nunca debemos utilizar esta ltima directamente.
4.2.
La clase Dialog
La clase Dialog nos permite presentar al usuario un tipo especial de formulario para que introduzca algunos valores. Tpicamente se utiliza para obtener del usuario determinados parmetros necesarios para la ejecucin de un programa. Esta clase presenta al usuario una ventana estndar.
Esta clase se utiliza cuando el dilogo no es muy complejo. Si se hace necesario un dilogo complejo es aconsejable disear un nuevo formulario para este propsito. Internamente, la clase Dialog construye un formulario en tiempo de ejecucin. Los mtodos ms comnmente utilizados de la clase Dialog son: a) Mtodo addField
Se utiliza para aadir un campo al dilogo. Como resultado devuelve un objeto de la clase DialogField. b) Mtodo addGroup Se utiliza para aadir un grupo de campos al dilogo. c) Mtodo run
Este mtodo dibuja el dilogo en la pantalla y permite al usuario que introduzca los valores. Si el usuario pulsa Aceptar el valor de retorno ser true, y si pulsa Cancelar el resultado ser false. De la clase DialogField se utiliza el mtodo value() para asignar valores al campo y recuperar el dato introducido por el usuario. Ejemplo:
DialogAccountId.Value("456"); DialogAccountId.Active(false);
DialogFromChequeNum.Value(FromChequeNum); DialogNumOfCheque.Value(NumOfCheque);
La clase RunBase
La clase RunBase
1. Introduccin
La clase RunBase es una de las clases de sistema ms importantes en Axapta. Nos permite la creacin de clases ejecutables con apenas unas pocas lneas de cdigo. Cuando definimos una clase como hija de RunBase, automticamente estamos heredando toda su funcionalidad, lo que nos facilita mucho la creacin de dichos procesos ejecutables. El funcionamiento bsico de esta clase es el siguiente: 1. Se muestra un dilogo al usuario. Mediante la creacin de una instancia de la clase DialogRunBase. 2. El usuario introduce una serie de valores o parmetros. 3. Se analizan los parmetros. 4. Se ejecuta el proceso a realizar por la clase. Este ser, por tanto, el comportamiento general de cualquier clase que herede de la clase RunBase, las particularidades de cada una de las clases las conseguiremos sobrecargando mtodos.
2.
La clase RunBase
En este mtodo, se define adems una macro que nos va a servir para almacenar los valores que el usuario introduce en el cuadro de dilogo. De este modo, cada vez que ejecutemos la clase, aparecern en el cuadro unos valores predeterminados, que sern los ltimos valores que introdujo el usuario. b) Dialog En este mtodo creamos el dilogo que queremos que se muestre al usuario. La llamada a este mtodo se realiza automticamente desde el mtodo prompt(). Ejemplo Object dialog() { DialogRunbase ; dialog = new DialogRunbase("@MCP254", this); dialogCustFormat = dialog.addField(TypeId(CustFormat)); dialogCustFormat.value(custFormat); dialogFileName = dialog.addField(TypeId(FileNameSave)); dialogFileName.lookupButton(2); dialogFileName.value(fileName); return dialog; } En este ejemplo, se creara un cuadro de dilogo con dos controles, uno de tipo CustFormat y otro de tipo FileNameSave. c) GetFromDialog En este mtodo obtendramos los valores que el usuario introduce en el cuadro de dilogo para asignarlos a las variables globales definidas en ClassDeclaration. Ejemplo private boolean getFromDialog() { ; fileName = dialogFileName.value(); custFormat = dialogCustFormat.value(); return true; } En este mtodo tomaramos los valores de los campos del cuadro de dilogo y lo asignaramos a las variables. d) Pack dialog;
La clase RunBase
En este mtodo es donde se almacena la informacin del trabajo que estamos ejecutando en ese momento, para su posterior utilizacin en sucesivas ejecuciones. Ejemplo public container pack() { return [#CurrentVersion, #CurrentList]; } e) UnPack En este mtodo se proporciona al usuario la informacin guardada en la ltima ejecucin, para utilizarla como valores por defecto del cuadro de dilogo. Ejemplo public boolean unpack(container packedClass) { Integer version; ; version = conpeek(packedClass, 1); switch (version) { case #CurrentVersion : [version, #CurrentList] = packedClass; break; default : return false; } return true; } f) Description En este mtodo se realiza una descripcin de la tarea que realiza esta clase. Esto es un estndar, por lo que es aconsejable que en todas las clases que hereden de RunBase exista dicho mtodo. Ejemplo static ClassDescription description() { return "@MCP254"; }
La clase RunBase
Se debe poner el texto de descripcin en una etiqueta. De esta forma nos aseguramos que dicha descripcin est disponible en todos los lenguajes soportados por el sistema. g) Run Este mtodo es el ms importante dentro de la clase, ya que constituye el cuerpo principal, es decir, el trabajo o la tarea que vamos realizar. Ejemplo void run() { if (answer) // Instrucciones; else // Instrucciones; } Donde ejecutaramos unas instrucciones u otras en funcin de los valores introducidos por el usuario en el cuadro de dilogo. h) Main Este mtodo es el primero que se ejecuta en cualquier clase ejecutable, y desde l se llama a los dems mtodos. Es por tanto, el mtodo que controla la ejecucin de la clase. Se trata de un mtodo esttico que siempre presenta la estructura que se muestra en el ejemplo siguiente. Ejemplo static void main(Args a) { MyClass ; myClass = new MyClass(); if (myClass.prompt()) myClass.run(); } myClass;
3.
La clase RunBaseBatch
La clase RunBaseBatch es una clase que hereda de la clase RunBase, cuya principal caracterstica, es que permite la creacin de procesos de ejecucin por lotes (batch). Por lo tanto, utilizaremos la clase RunBase en aquellas tareas que no necesiten procesamiento por lotes y la clase RunBaseBatch en aquellas tareas que si lo necesiten.
La clase RunBase
La clase RunBaseBatch es una clase utilizada como base para la realizacin de clases que lleven consigo funcionalidad de alto nivel. Este tipo de clases tiene normalmente una estrecha relacin con funciones de men y pueden ser activadas directamente por el usuario. Si queremos crear una clase ejecutable por lotes, debemos crearla de forma que herede de RunBaseBatch. Los mtodos que debemos sobrecargar en este tipo de clases son los mismos que en el caso de las clases RunBase, pero adems debemos sobrecargar el mtodo siguiente: a) CanGoBatch Este mtodo aade un botn al cuadro de dilogo que permite la ejecucin de la tarea a realizar mediante un proceso por lotes. La codificacin del mtodo es muy sencilla, simplemente debemos devolver un valor verdadero si queremos permitir que el proceso pueda ser ejecutado mediante un proceso batch. Ejemplo protected boolean canGoBatch() { return true; }
4.
La clase RunBaseReport
La clase RunBaseReport es una clase que tambin hereda de la clase RunBase, cuya principal caracterstica es que permite la creacin de informes personalizados mediante cdigo. Utilizaremos esta clase cuando necesitemos un informe que presente al usuario un cuadro de dilogo especfico para la introduccin de datos a dicho informe. Primero debemos crear en el Arbol de Objetos de la Aplicacin (AOT), el diseo del informe. Seguidamente, debemos crear la clase RunBaseReport que se encargar de dotar de funcionalidad adicional a ese informe. Los mtodos que debemos sobrecargar en esta clase son los mismos que en el caso de las clases RunBase, pero adems debemos sobrecargar los mtodos siguientes: a) InitParmDefault Este mtodo inicializa los parmetros del informe con valores por defecto. Debemos sobrecargarlo, solamente cuando queramos modificar dichos parmetros por defecto. Si sobrecargamos el mtodo, debemos realizar la llamada al mtodo super(). Como ejemplo mostramos el mtodo InitParmDefault de la clase CustInvoiceVolumeReport. Ejemplo void initParmDefault() { ; reportBy = AccountVATNum::VATNum;
La clase RunBase
LastValueElementName Este mtodo se utiliza para enlazar el diseo del informe creado en el Arbol de Objetos de la Aplicacin con la clase RunBaseReport. Como ejemplo mostramos el mtodo LastValueElementName de la clase CustInvoiceVolumeReport. Ejemplo private ReportName lastValueElementName() { return reportStr(CustInvoiceVolume); }
Maps
1. Definicin
En ocasiones podemos encontrar tablas en la aplicacin que sean muy similares. stas pueden tener varias columnas que contengan el mismo tipo de informacin, pero cuyo nombre sea diferente. Tambin puede ser usual tener clases que procesen de igual forma datos de distintas tablas. Si utilizamos el mismo nombre para las columnas, podemos reutilizar el cdigo que procese los datos de distintas tablas, pero hay que procurar mantener nombres coherentes a las columnas para hacer la aplicacin ms fcil de mantener. MorphX posee una poderosa caracterstica llamada map que permite cubrir estos dos requerimientos. Un map permite acceder a campos de distintas tablas si los campos son de tipos similares, aunque tengan nombres distintos. Cada tabla puede ser objeto de un map. Normalmente, si se tiene acceso a una tabla desde distintos maps, cada map accede a distintos subgrupos de campos de la tabla. Supongamos un map Address que puede ser utilizado para acceder a dos tablas: CompanyInformation y CustomerAddress. Supongamos que las tablas contienen campos similares a los siguientes:
City PostalCode
Para acceder a las tablas CompanyInformation y CustomerAddress a travs del map tenemos que utilizar como nombre del campo los definidos por el map.
2.
Creacin.
El proceso de creacin de un map es muy similar al de una tabla. Desde el men contextual Tablas pulsamos el botn New y Map.
2.1.
Campos.
Al igual que en las tablas, en los maps tenemos una nodo Fields desde el cual podemos aadir campos al map, as como un nodo Group para definir grupos de campos.
2.2.
Para asociar los campos del map a los de la tabla expandimos cualquiera de las tablas. Tendremos una entrada por cada campo definido en el map. Abrimos las propiedades de cualquiera de ellos y establecemos la asociacin: Si repetimos el proceso para cada una de las tablas ya tenemos definido el map.
2.3.
Mtodos en maps
En un map podemos encontrar los mismos mtodos que en las tablas, y tambin es posible definir mtodos nuevos. Para utilizar estos mtodos ser necesario referenciar al map, al igual que referenciamos a las tablas, con la particularidad de que un map no contiene informacin. Para que el map contenga informacin, y por tanto tenga utilidad su uso, primero hay que asignarle la informacin de una tabla que tenga definido un mapping en el map. Es decir, de alguna forma, se tratara de realizar una conversin de los datos de la tabla al mapping (se realiza con una simple asignacin entre variables), y utilizar al map para trabajar con estos datos.
Gestin de excepciones
Gestin de excepciones
MorphX tiene construido un sistema de manejo de excepciones. Esto permite capturar errores durante la ejecucin de un programa, y controlar el comportamiento del sistema ante ellos. Para utilizar el manejo de excepciones, se tienen que especificar las sentencias a controlar mediante el uso de try y catch. Toda sentencia try tiene asociada al menos una sentencia catch, donde las excepciones son capturadas. Cuando es lanzada una excepcin dentro de una transaccin, la transaccin es automticamente abortada. Este comportamiento se aplica tanto a las excepciones definidas por el usuario como a las propias del sistema.
1.
A veces cuando escribimos una porcin de cdigo, t conoces que se pueden dar ciertos errores (excepciones). Para prevenir al sistema de un bloqueo cuando se produce una excepcin, se pueden usar dos comandos que identifican y renen las excepciones. Puedes decirle al sistema que de un mensaje de error al usuario ayudndole a corregir el error, o puedes decirle al sistema que reintente la operacin. Los dos comandos que se pueden utilizar son el try y catch. Ejemplo: Quieres crear un nuevo cliente, pero quieres liberar el nmero en la secuencia numrica, si no tienes xito salvando el cliente. Adems de esto no permites un cliente con un nmero menor de 500. Static void TTSStatement (args a) { CustTable custtable; NumberSeq numberseq; Num Number; ; try { tts begin; numberSeq = NumberSeq::newGetNumFromCode (Cust_1); number = numberSeq.num(); custTable.CustGroup = 20; custTable.Name = Martin Hansen; custTable.AccountNum = number; custTable.insert(); if (number < 500) { throw (exception::Error) }
Gestin de excepciones
catch (exception::Deadlock) { numberSeq.abort(); retry; } } Como pueden ocurrir multitud de distintas exceciones, un nmero de Enums excepciones estn disponibles en el kernel:
Exception
Exception::info Exception::warning
Description
Muestra un mensaje de informacin al usuario.
Indica que se ha producido una situacin excepcional. El usuario deber llevar a cabo alguna accin pero las consecuencias no son fatales. Indica que existe un bloqueo en la base de datos debido a que diversas transacciones estn esperandose unas a otras. Normalmente no requieren intervencin por parte del usuario, y solo ser necesario reintentar la operacin. Indica que ha ocurrido un error fatal y que la transaccin ha sido abortada. Usada para mostrar errores internos de desarrollo de Navision Axapta. Indica que el usuario ha pulsado Break o CTRL+C. Ha ocurrido un error en la clase DDE-kernel. (Se ha recibido una comunicacin de error de DDE desde el sistema operativo).
Exception::deadlock
2.
Sentencia throw
Tambin es posible que nosotros lancemos excepciones en nuestro cdigo al detectar algn error en el proceso. Esto es posible a travs de la sentencia throw: Throw error (Mensaje del error); Se puede obtener una descripcin ms amplia del cdigo en la Ayuda en lnea de Axpata, en el Manual del Desarrollador de Axapta. sta sentencia puede incluirse en cualquier mtodo de la aplicacin, aunque es usual incluirlo en una seccin try, de manera que podamos controlar totalmente el comportamiento del sistema ante la excepcin producida. Ejemplo: try
Gestin de excepciones
Las excepciones definidas por el sistema vienen recogidas en el enumerado exception, y pueden ser: Info Warning Muestra un mensaje de informacin al usuario. Indica que se ha producido una situacin excepcional. El usuario deber llevar a cabo alguna accin pero las consecuencias no son fatales. Indica que existe un bloqueo en la base de datos debido a que diversas transacciones estn esperandose unas a otras. Normalmente no requieren intervencin por parte del usuario, y solo ser necesario reintentar la operacin. Indica que ha ocurrido un error fatal y que la transaccin ha sido abortada. Indica que el usuario ha pulsado BREAK o CTRL+C. Ha ocurrido un error en la clase DDE-kernel. (Se ha recibido una comunicacin de error de DDE desde el sistema operativo).
Deadlock
Error
Break Ddeerror
3.
Retry
Inserta el comando retry en la seccin del catch para decirle al sistema que ejecute la seccin del try de nuevo. Usa el retry con precauciones para no crear un bucle infinito. El comando es usado tpicamente para situaciones de bloqueo.
. . . . // Seleccin del registro taxReportVoucher . . . . Nombre del informe // Creacin de un objeto MenuFunction mf = new MenuFunction(ReportStr(TaxReporting), MenuItemType::Output); Tipo de menu item
//Obtener los argumentos que le vamos a pasar al informe. A.caller(this); A.record(taxReportVoucher); Report = mf.create(A); Report.run(); }
2.
xClases
1. X-Classes
En el nodo de clases, debajo del nodo de System Documentation (documentacin del sistema) encontraremos las X-Clases. Las X-Clases se proporcionan con una variedad de mtodos para ejecutar formularios, informes, consultas, ceacin de tablas y dems. Varias de estas clases son heredadas de varias de las clases de sistema y extendidas con funcionalidad aadida.
X-CLASS xApplication
XclassFactory
ClassFactory
Xcompany
Company
Xinfo
Info
Xrecord
Xref
Xsession
Session
DESCRIPTION Retorna informacin concerniente a la Compaa, Systemdate, etc... Los mtodos pueden ser sobreescritos. Son usados cuando quieres ejecutar formularios, informes o consultas. Los mtodos pueden ser sobreescritos. Retornando informacin de la compaa Los mtodos pueden ser sobrescritos. Usados para mostrar informacin, avisos y mensajes de error al usuario. Los mtodos pueden ser sobreescritos. Cuando ests creando una nueva tabla, la tabla hereda ste mtodo de sta clase. Los mtodos no pueden ser sobreescritos. Usada para actualizar las referencias, cuando compilan un objeto. Retorna informacin concerniente a la fecha hora usuario y dems del Login. Los mtodos pueden ser sobreescritos.
Cuando intentas abrir las X-Classes no podrs abrir el cdigo, pero en lugar de ello un archivo mostrar informacin acerca el mtodo especfico o las clase.
2. Class Factory
La clase xClassFactory contiene mtodos para ejecutar formularios, consultas e informes. Usa esta clase para ejecutar formularios, informes y consultas. El sistema usa esta clase para sobrescribir la funcionalidad de la ejecucin de los formularios, informes o consultas. Por ejemplo puedes mostrar una caja de informacin (Info Box) con el nombre del formulario, cada vez que el formulario es ejecutado.
La clase global es la clase que contiene las funciones estndar en el ambiente de desarrollo de X++. Si quieres aadir o cambiar un mtodo al mbito global de Navision Axapta es hecho en esta clase. S cuidadoso de no cambiar la funcionalidad de este mtodo ya que tiene influencia sobre Navision Axapta como plan global.
Lo segundo que haremos es crear un formulario que nos muestre la informacin que queremos que aparezca en el lookup y este formulario tiene que tener la propiedad Frame del diseo como "Border" para ser visto como lookup . Para que este valor nos sea devuelto, y se quede la informacin en el formulario principal, debemos anular el mtodo Init del formulario, y la forma en la que lo haremos ser la siguiente (siendo el nombre del control el control del campo que queremos que nos devuelva al formulario principal): public void init() { super(); element.selectMode(element.control(Control::nombre del control);
Funciones Generales
Funciones Matemticas: abs, acos, asin, atan, decround,exp,frac,power,trunc. Funciones de conversin: any2date, any2int, str2int, str2date, etc. Conseguir identificadores: ClassIdGet, ClassNum, FeatureKeyNum, FieldNum, etc. Manipulacin de datos del container: ConDel, ConFind, ConIns, ConPeek, etc. Funciones financieras: Cterm, Dbd, Dg, Fv, Idg, Syd, etc. Informacin acerca del nuevo ambiente: CurExt, CurUserId, SessionId. Funciones de fechas: DayName, DayOfMth, DayOfWk, SystemDateGet, SystemDateSet,etc Funciones string: StrAlpha, StrCmp, StrDel, StrFind, StrFmt, StrKeep, StrLwr, StrPrompt, StrRem.