Tricks

Redimensionar un control de texto con el tamaño de su contenido


En ocasiones, trabajando con WinForms, nos encontramos con un control contenedor de un texto variable en el que, o nos sobra espacio o nos falta. La clase Graphics de System.Drawing nos proporciona un método tremendamente útil para saber el tamaño, en píxels, de una cadena de texto.
Veremos a continuación cómo redimensionar de forma dinámica un control dependiendo del tamaño del texto contenido. Para ello crearemos, por ejemplo, un TextBox al que llamaremos txtPrueba, y en el que albergaremos un texto, por ejemplo “Más vale pájaro en mano, que ciento volando”.


txtPrueba.Text = "Más vale pájaro en mano que ciento volando";

A continuación, declararemos dos variables enteras, una para el alto y otra para el ancho.

// Declaramos una variable entera para almacenar el nuevo ancho y el nuevo alto
int nuevoAncho = 0;
int nuevoAlto = 0;

Es ahora donde instanciaremos la clase Graphics a partir del control TextBox, y extraeremos la fuente que está utilizando.

// Creamos un objeto de tipo Graphics a partir del TextBox
Graphics g = txt.CreateGraphics();

// Extraemos la fuente del TextBox
Font fuente = txt.Font;

Obtenemos, a partir del objeto Graphics, su alto y ancho a partir del método MeasureString, que no hace otra cosa que medir, en pixels, el tamaño que ocupa la cadena con la fuente indicada.


nuevoAncho = (int)g.MeasureString(txt.Text, fuente).Width;
nuevoAlto = (int)g.MeasureString(txt.Text, fuente).Height;

Por último, asignamos los nuevos valores de alto y ancho y refrescamos el control.


txt.Width = nuevoAncho;
txt.Height = nuevoAlto;

txt.Refresh();

A partir de estos conceptos básicos, se pueden encontrar multitud de utilidades a este proceso, como por ejemplo, redimensionar el desplegable de un ComboBox al tamaño del mayor de sus elementos.

Redimensión dinámica de imágenes


Siguiendo con la manipulación de imágenes en .NET, imaginemos que disponemos de una imagen de un tamaño considerable, bien en disco, bien en base de datos, y queremos enviarle al usuario un thumbnail de dicha imagen. ¡Ojo! No queremos mostrar la imagen completa con un estilo que modifique su alto y ancho, ya que con esto estaríamos enviando la imagen completa y luego modificaríamos su visualización en cliente, perdiendo el correspondiente (y valioso) ancho de banda.

En lugar de esto, sacrificaremos unos cuantos ciclos de CPU en pos de limitar el tráfico y realizaremos la operación de redimensionar la imagen en servidor para posteriormente enviarsela (más pequeñita o más grande) al cliente.
Para ello, nos crearemos una función llamada RedimensionarImagen que reciba tres parámetros: la imagen que queremos redimensionar, la nueva altura y la nueva anchura:


private System.Drawing.Bitmap RedimensionarImagen(System.Drawing.Image imagenOriginal, int alto, int ancho)
{

Lo primero que haremos será guardar el alto y el ancho de la imagen original.


int anchoOriginal = imagenOriginal.Width;
int altoOriginal = imagenOriginal.Height;

A continuación declaramos dos variables de tipo float que almacenaran el porcentaje de escalado al que se va a ver sometida la imagen.


float porcentajeEscaladoX = (float)ancho / (float)anchoOriginal;
float porcentajeEscaladoY = (float)alto / (float)altoOriginal;

El siguiente paso será definir una nueva altura para la imagen, multiplicando los valores originales por los factores que hemos obtenido en el paso anterior.


int nuevoAncho = (int)(anchoOriginal * porcentajeEscaladoX);
int nuevoAlto = (int)(altoOriginal * porcentajeEscaladoY);

Ya tenemos las dimensiones de nuestra nueva imagen, ahora necesitaremos crear una instancia.


System.Drawing.Bitmap nuevaImagen = new System.Drawing.Bitmap(nuevoAncho, nuevoAlto);

Ahora instanciamos una superficie de dibujo de GDI+ a partir de la imagen para tratar el tamaño.


System.Drawing.Graphics superficieGDI = System.Drawing.Graphics.FromImage((System.Drawing.Image)nuevaImagen);

Indicamos el modo de interpolación (en nuestro caso, Bicúbico Alta Calidad) y dibujamos la imagen con los nuevos valores de ancho y alto.


superficieGDI.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
superficieGDI.DrawImage(imagenOriginal, 0, 0, nuevoAncho, nuevoAlto);

Finalmente, liberamos el objeto GDI+ y devolvemos la imagen.


superficieGDI.Dispose();

return nuevaImagen;
}

Et voilà!, hecho esto, obtendremos una imagen con el alto y ancho deseados.

Recuperar una contraseña almacenada automáticamente mediante Javascript


Últimamente existe una cruenta batalla en la plataforma Windows entre Internet Explorer y Firefox. Personalmente, yo no me decanto hacia uno ni otro: utilizo Opera desde su versión 6.05, allá por 2002. Indico que utilizo Opera porque es un navegador que posee una funcionalidad llamada “varita mágica”, que no es más que un gestor de contraseñas en las que, pulsando ALT+ENTER se introducen automáticamente el nombre de usuario y la contraseña de una web en la que se hayan almacenado estos datos previamente.

Esta “comodidad” tiene un precio: a veces, de tanto utilizar este sistema, se me olvida alguna contraseña a causa del desuso, lo que causa que mi navegador la conozca y yo no.

0811_01

Para paliar esta posibilidad, teniendo acceso a la página con el nombre de usuario y la contraseña, es posible averiguar el contenido del campo oculto entre asteriscos mediante una pequeña “treta” en Javascript. Lo primero que deberemos hacer será visualizar el código fuente de nuestra página (normalmente, haciendo click derecho sobre la misma y pulsando “Ver código fuente” o algo así, dependiendo del navegador).

Una vez visualizado, comprobamos la etiqueta que se muestra antes del campo que alberga la contraseña. En GMail, por ejemplo, “Contraseña”. Buscaremos este texto en el código fuente, obteniendo algo como lo que sigue: Como podemos observar, nos encontramos con un Input con un campo ID.

0811_02

El valor de esa variable, en nuestro caso “Passwd”, es lo que nos interesa. Volveremos a nuestra página, y escribiremos lo siguiente en nuestra barra de navegación:


javascript:alert((document.getElementById('Passwd')).value);

Lo que le estamos diciendo a nuestro navegador es: “Ejecuta el siguiente código javascript: muestrame una alerta con el valor del elemento cuyo ID es ‘Passwd'”.

0811_03

Acto seguido, se mostrará el contenido del campo en texto plano.

0811_04

Es ahora tarea del usuario el ejecutar este código lejos de la vista de un posible mirón y, por supuesto, en un PC no comprometido… 😉

Comentarios condicionales en Internet Explorer


Uno de los mayores dolores de cabeza de un programador web reside en la maximización de la compatibilidad entre navegadores. O dicho de otro modo: programar y -especialmente- maquetar una página que funcione perfectamente en todos los navegadores.

Hasta ahora, lo más común era controlar las diferencias (especialmente a nivel de css y javascript) entre Firefox e Internet Explorer. Lejos de acabar en debates sobre estas diferencias, nos centraremos en un nuevo dolor de cabeza que ha surgido hace relativamente poco: los problemas de compatibilidad entre versiones de Internet Explorer.

Pese a que la versión 6 de Internet Explorer está avocada a la extinción, aún hoy es requisito fundamental en la firma de muchos proyectos orientados a internet. Es por eso que algunos bugs de esta versión, o algunas funcionalidades que son tratadas de forma distinta, siguen dando quebraderos de cabeza.

Una de las posibilidades para solventar este problema reside en los comentarios condicionales.
(más…)

Concatenar campos nulos en una consulta SQL


Hay ocasiones en las que puede que se nos pidan consultas del siguiente tipo:

SELECT Nombre + ' ' + Apellido1 + ' ' + Apellido2 AS NombreCompleto FROM Usuario

Es decir: concatenar varios campos y devolverlo como uno solo. Ante esto existe un problema bastante común: ¿Qué ocurre cuando uno de estos campos es NULL?
Si uno de estos campos es NULL, por defecto el registro devolverá NULL. Esto es, si tenemos un usuario llamado Santiago, cuyo primer apellido es López y su segundo apellido no consta en la base de datos, el resultado de concatenar Santiago + López + NULL será NULL.

Una posible solución a este problema es utilizar condicionales dentro de la propia sentencia T-SQL, haciendo algo así:

SELECT U.IdUsuario, U.Nombre + ' ' + CASE 
     WHEN U.Apellido1 is NULL THEN '' 
     ELSE U.Apellido1 END + ' ' + CASE 
     WHEN U.Apellido2 is NULL THEN ' ' 
     ELSE U.Apellido2 END AS NombreCompleto
FROM Usuario U

Esto nos devolverá una columna “NombreCompleto” con los campos concatenados correctamente, sin temor a que éstos sean NULL.