martes, 11 de marzo de 2008

HotSpots en ImageMap …áreas circulares en una imagen que causan postbak al dar clic sobre ellas.

El control ImageMap es usado para desplegar una imagen clickeable en una página web que puede ser usada para hacer un PostBack al WebServer, o para abrir otra página siguiendo una URL.

A diferencia del control ImageButton, este permite definir regiones “hot-spots” de formas circulares CircleHotSpot, Rectangulares RectangleHotSpot, y Poligonales PolygonHotSpot que causan PostBack cuando el usuario da clic en ellas, mientras que en un ImageButton dando clic en cualquier parte de la imagen se hace un PostBack.

El primer HotSpot definido toma precedencia sobre los demás, por ejemplo si tenemos dos CircleHotSpot el primero con un radio menor al segundo y ambos con el mismo centro.

El círculo menor quedaría dentro del segundo pero su área clickeable siempre estaría activa y limitada por el área mayor.

Para el siguiente ejemplo, primero Agregaremos un ImageMap y un Label a nuestra página:

Como serán utilizadas varias zonas circulares o CircleHotSpot ara ello he creado un procedimiento que recibe las coordenadas en (x,y) del centro, el radio y la descripción en este caso el valor que será devuelto al hacer el PostBack.

public void zona_circular(int x, int y,int radio,string descripcion)

{

CircleHotSpot chs;

chs = new CircleHotSpot();

chs.X = x;

chs.Y = y;

chs.Radius = radio;

chs.PostBackValue = descripcion;

ImageMap1.HotSpots.Add(chs);

}

En el evento Load de la página, establecemos la imagen que será mostrada en el ImageMap1, el AlternateText que será el comentario mostrado cuando se posicione el Mouse sobre el control y el HotSpotMode que da el comportamiento para los objetos HotSpot de un ImageMap cuando se hace clic en ellos, en este caso es PostBack pero puede ser Inactive (sin comportamiento), Navigate (se desplaza a una URL).

ImageMap1.ImageUrl = "~/images/homer.jpg";

ImageMap1.AlternateText = "This is a picture of Homero";

ImageMap1.HotSpotMode = HotSpotMode.PostBack;

Después llamaremos a la función zona_circular(X,Y,Radio,Descripción); cuantas veces sea necesario de acuerdo a las zonas que deseemos definir:

zona_circular(124, 151, 6, "Left Eye Center");

zona_circular(133, 145, 35, "Left Eye");

zona_circular(193, 145, 6, "Right Eye center");

zona_circular(183, 173, 20, "Nose");

zona_circular(155, 233, 50, "Mouth");

Finalmente en el evento clic del ImageMap agregamos la siguiente línea:

Label1.Text = "You clicked the " + e.PostBackValue;

Con esta línea traemos el valor asociado al funcionamiento del Hotspot.

De esta forma cada vez que demos clic en un área hotspot como resultado tendremos en la etiqueta o label el valor del PostBack.

En las imagenes puede apreciarse el mensaje del PostBackValue en el label después de haber dado clic en los HotSpots del ImageMap.



DataSet, XML y Flash

En ocaciones tenemos registros leidos desde la base de datos y almacenados en un DataSet, y se nos ocurre que podremos mostrarla en una aplicacion de Macromedia Flash, pues bien, Flash no tiene un soporte nativo para base de datos, pero si la lectura de archivos XML.

Pues bien para crear un archivo XML desde el DataSet basta lo siguiente:

'Esta es una clase que facilita la conexion y la ejecusion de consultas
Dim Conn As New Conectividad()
'Mi Objeto DataSet
Dim ds As New DataSet
'Llenamos el DataSet con el resultado de la consulta
ds = Conn.Consulta("Select * from datos", strError)
'E invocando al metodo WriteXml podemos crear tan facilmente un archivo XML
ds.WriteXml(Server.MapPath("MyXML.XML"), XmlWriteMode.IgnoreSchema)

Una ves creado el archivo XML, en Flash bastará este script para leer y mostrar cada uno de los registros del XML

//Este va en el fotograma 1
//Variables globales para control de recorrido por el XML
_global.pos=0;
_global.limite=0;

//Nuevo Objeto XML
var obj_xml:XML = new XML();
obj_xml.ignoreWhite = true;
//Esta Funcion sera invocada cuando se intente cargar un archivo XML
obj_xml.onLoad = function(exito) {
//La variable exito sera "true" si se cargo bien y "false" si el archivo no //existe o no se pudo cargar por errores en su estructura
if (exito) {
//Numero de registros
_global.limite=obj_xml.firstChild.childNodes.length;
//modelo, des y precio son los nombres de las instancias de componentes TextInput
modelo.text=obj_xml.firstChild.childNodes[_global.pos].childNodes[1].firstChild.nodeValue;
des.text=obj_xml.firstChild.childNodes[_global.pos].childNodes[3].firstChild.nodeValue;
precio.text=obj_xml.firstChild.childNodes[_global.pos].childNodes[2].firstChild.nodeValue;

//img es una instancia del componente Loader, al cual le indicamos la ruta de la //imagen a mostrar
img.contentPath=obj_xml.firstChild.childNodes[_global.pos].childNodes[4].firstChild.nodeValue;
img.load();
} else {
trace("Error"); //Que indique que hubo un error si no cargo el archivo
}
};


//Esta es la función que invoca la carga del archivo
function cargarXML() {
obj_xml.load("myXML.XML");
}

//Cargamos la funcion al iniciar
cargarXML();


Si deseamos un recorrido por cada uno de los registros deberemos incluir un boton de avance y otro de retroceso y escribir el siguiente script

//Boton retroceso
on (release) {
//Llamamos a la función de carga del archivo XML
_global.pos--;//Disminuimos la posicion actual
if (_global.pos<0) //Si se paso del indice 0
_global.pos=0; //Lo ponemos en 0
cargarXML(); //Cargamos el archivo nuevamente, pero con la posicion indicada
}

//Boton Avanzar
on (release) {
//Llamamos a la función de carga del archivo XML
_global.pos++;//aumentamos la posicion actual
if (_global.pos>_global.limite - 1) //Si nos pasamos del limite
_global.pos=_global.limite-1;// Ponemos el indice en el ultimo registro
cargarXML(); //Cargamos nuevamente el archivo
}

Espero y alguna ves les sea util este sencillo ejercicio

lunes, 10 de marzo de 2008

Desde el sotano....tool tips dinámicos

Cuando utilizamos un ToolTip en Visual Studio, solo puede ser utilizado directamente sobre un control de Windows Forms, por ejemplo un TextBox, una Label, un Button, etc., ya que solo acepta dos parámetros; el control y la cadena de Texto que mostrará.

toolTip1.SetToolTip(listBox1, “Este es mi Tip”);

Sin embargo, si se deseará que el ToolTip cambiará para cada elemento de un ListBox o de un ComboBox, no es tan sencillo ya que no acepta en sus parámetros un evento como SelectedIndex o SelectedValue.

En un “googlazo” me encontre con un algoritmo que mostraba como realizarlo. Ahora solo faltaba tomar la información de una Base de Datos y que el ToolTip cambiará para cada elemento de la lista. Y esto fue lo que sucedió:

1.- Se considera de antemano que se tiene listo todo el formulario completo, de acuerdo a las necesidades. Así mismo una Base de Datos, por ejemplo, un directorio telefónico. Entre esos controles se encuentra un ListBox, el cual fue llenado en su propiedad DataSource una consulta hecha a la Base de Datos. Digamos una lista de nombres, y que se desea mostrar en el ToolTip su telefono.

2.- Una vez tomado de la Caja de Controles un ToolTip, nos dirigimos al evento SelectedIndexChanged del listBox1 y comenzamos a codificar:

private void lst_users_SelectedIndexChanged(object sender, EventArgs e)
{

/*Creamos un nuevo DataTable auxiliar y en el almacenamos el DataSource que contenga el listBox, convirtiendolo previamente*/
DataTable dt_aux_u = (DataTable)this.lst_users.DataSource;

/*Se prepara una variable de tipo de string que almacenará el texto del ToolTip*/
string telefono = "";

/*En una variable de tipo entero, se almacena el indíce del elemento seleccionado de la lista, previamente convirtiendolo a entero*/
int index = (int)this.lst_users.SelectedIndex;

/*Si el indice del elemento seleccionado se encuentra entre el rango de la lista*/
if (index >= 0 && index <>
{

/*La variable telefono almacena del DataTable el valor donde la fila con valor index y la columna “telefono” coincida. Esto esta basado en la Base de Datos*/
telefono = dt_aux_u.Rows[index][“telefono"].ToString();

//Si lo seleccionado no contiene nada
if (telefono =="")
{

//Se prepara un texto especial, para que el ToolTip no se muestre vacio

telefono = "Esta persona no tiene telefono";
}
}

/*Al final, establecemos el ToolTip con el control Windows Forms y la Variable*/
this.toolTip1.SetToolTip(this.lst_users, telefono);
}

3.- Cabe determinar que es necesario tener funcionando primero el acceso a la Base de Datos y el llenado del listBox correctamente, ya que la informacion para llenar el Tooltip lo tomamos del DataSource del control.

Esperando que sea util, así comentarios y sugerencias.

Dr. Omm

viernes, 7 de marzo de 2008

Imprimir WindowsForms con vista previa en Visual Basic.NET.

En ocasiones tenemos la tarea de imprimir una pantalla o el área cliente de un formulario en tiempo de ejecución con información y controles.

La forma más fácil de hacerlo es utilizando el control PrintForm.

Para utilizarlo antes debemos descargar el PrintFormComponent 1.0 ó la versión más reciente ya que no viene por default. La versión utilizada en el ejemplo siguiente puede ser descargada del siguiente sitio:

http://msdn2.microsoft.com/en-us/vbasic/aa701261.aspx

Existen dos archivos de descarga llamados:

PrintFormSetup.exe y PrintFormSetup.msi descargamos el .PrintFormSetup.msi y lo instalamos.

Una vez instalado creamos un proyecto de Visual Basic para WindowsForms y seguimos los pasos siguientes:

1. ir al cuadro de herramientas principal en la sección Impresión donde podremos visualizar los controles, PagesetupDialog, PrintDialog, PrintDocument.. entre otros pero notar que no existe uno llamado PrintForm.

2. Dar clic derecho con el mouse y luego en Elegir elementos..

3. En la lista de componentes del NET Framework buscar y seleccionar PrintForm.

4. Aceptar y ver el control PrintForm que ha sido agregado al cuadro de herramientas en la sección Impresón.

Imprimir un Formulario windowsForm:

En el evento clic de un botón, colocar el siguiente código

PrintForm1.Print()

Propiedad PrintAction

Determina si la salida es enviada directamente a la impresora, si se debe mostrar la imagen en una ventana de vista previa, o guardar la imagen como un archivo PostScript encapsulado.

Los valores que admite la propiedad PrintAction son tres opciones :

  • Printing.PrintAction.PrintToPreview : Ventana de vista previa
  • Printing.PrintAction.PrintToFile : Imprimir a un archivo
  • Printing.PrintAction.PrintToPrinter : Imprimir

Pre visualizar un WindowsForm antes de imprimirlo utilizando PrintAction:

With PrintForm1

.PrintAction = Printing.PrintAction.PrintToPreview

.Print(Me, PowerPacks.Printing.PrintForm.PrintOption.CompatibleModeClientAreaOnly)

End With

Imprimir hacia un archivo con la propiedad PrintAction

With PrintForm1
            .PrintAction = Printing.PrintAction.PrintToFile
            .PrintFileName = Ruta
            .Print()
End With 

Imprimir formulario scrollable

Por defecto, el printForm sólo imprime la parte visible del formulario

Si un usuario ha cambiado de tamaño el formulario en tiempo de ejecución, el resultado puede no ser el esperado.

El procedimiento siguiente muestra cómo imprimir el área cliente del Form desplegable incluso si se ha cambiado de tamaño en tiempo de ejecución.

Private Sub Button1_Click( _ByVal sender As System.Object, _ByVal e As
System.EventArgs)Handles Button1.Click
         With PrintForm1
            .PrintAction = Printing.PrintAction.PrintToPrinter
             .Print(Me, PowerPacks.Printing.PrintForm.PrintOption.Scrollable)
        End With
 End Sub 

Esta es la vista previa de un formulario antes de imprimirlo.

Desde el sotano... historia de una tabla autoreferenciada

Corrian los tiempos en que diseñaba una Base de Datos para un sistemita. La idea era una tabla que almacenará un catálogo de servicios con una descripción, un precio, etc. Al principio, no representaba mucho reto... era relativamente fácil la creación y edición de esta para después realizar las altas, bajas, consultas y modificaciones.

Pero sucedió lo que a muchos desarrolladores les tiene que pasar algún día. Los requerimientos cambiarón... y una sola tabla no sería suficiente. Ahora era necesario catálogar esos mismos servicios, y tal vez lo primero que viene a la cabeza es crear una tabla mas con los catálogos y relacionarlos con la tabla de servicios.

Sin embargo, en el caso de este desarrollador que se había dormido en sus clases de Base de Datos en los temas de Joins, SelfJoins, RigthJoins, etc., era algo que le complicaba su trabajo..., tener que crear esa clase de consultas SQL me ponía en un aprieto.

Tenía que encontrar una manera de resolver el problema sin complicar el acceso a los datos, sobre todo pensando a futuro que las consultas SQL podrían tardarse mucho en ejecutarse debido a la enorme cantidad de datos que algún día manejaría.

Así que, al método de prueba y error, se modificó el diseño de la tabla agregando dos columnas mas:



La columna TIPO y TIPO_RELACION resolvía mi problema. La idea era que cuando se agregará un cátalogo, este tendría automáticamente en su campo TIPO las letras CT que lo identifican como catálogo y en el campo TIPO_RELACION la letra T (o cualquier otra, incluso sin letra) concatenandole el ID del registro, que mas adelante sería utilizado.



Agregado el catálogo, ahora era posible agregar un servicio que pertenecierá a ese catálogo, relacionado por el campo TIPO_RELACION. La imágen muestra el registro 13, donde se agregó un catálogo, con TIPO CT y TIPO_RELACION C13. Posteriormente, agregando mediante el sistema un servicio, este pertenece al catálogo anterior, colocando en su campo TIPO C13. De esta manera "apuntamos" el servicio a directamente con el catálogo que lo contendrá. Cabe mencionar que el campo TIPO_RELACION se quedo vació ya que este servicio no contendrá a nadie mas.



Fue así como conseguí, de pura casualidad una tabla autoreferenciada... o eso me lo dijo un cuate... e investigando me di cuenta que es algo muy útil, pero pocas veces utilizadas en las Bases de Datos. Analizando este método nos dimos cuenta que no solo se aplica en un solo nivel, si no que incluso se presta perfectamente para mas niveles de jerarquía, como por ejemplo, clasificar los catálogos, en otro catálogo, o incluso los servicios, podrían contener en su interior mas servicios y variantes... y a su vez estos. Un estilo de árbol jerarquíco cuya implementación es mas barata que utilizar un sin fín de tablas y relacionarlas todas entre ellas.

Al final, las tablas autoreferenciadas me han funcionando muy bien, sin ninguna clase de problemas hasta la fecha.

jueves, 6 de marzo de 2008

Instalación de Mambo

Mambo es un sistema de portales CMS basado en el lenguaje de programaciónPHP y base de datos SQL de código abierto. Basa todo su aspecto en templates o themes.

Su Instalacion es bien sensilla de realizar

Como requisitos previos a la instalacion, debemos contar con Servidor Web (Apache o IIS), PHP y una Base de Datos (PostgreSQL, MySQL). Teniendo todo esto instalado, creamos una nueva base de datos con el nombre que deseen, la dejan en blanco (no crear ninguna tabla).

Nos descargamos el MAMBO teniendo el .gz o el .zip y lo descomprimimos en la carpeta default de tu servidor Web (C:/inetpub/wwwroot en windows, /var/www/ en linux). Todo lo anterior representa la parte dificil de la instalacion de Mambo.

Abrimos nuestro navegador (IE, Firefox, Opera, etc) y tecleamos la siguiente direccion http://localhost/mambo-version.

La instalacion se muestra como un asistente del tipo siguiente, siguiente, siguiente durante la cual nos pide el usuario y password de la base de datos, el nombre de la base de datos, el nombre del portal, nombre y contraseña para crear el usuario administrador, despues de completar todos los pasos hay que borrar la carpeta instalation y con eso es suficiente para crear un portal de manera rapida, sensilla.

Les dejo un pantallazo de el Mambo instalado en mi maquina