Delphi paso a paso (VI): Controles (IV)

Anuncio
Delphi paso a paso (VI): Controles (IV)
Por Vladimir Algara
Para seguir avanzando en el mundo de los controles y retomar el hilo desde donde se abandonó
en la entrega anterior, expondré el objetivo del presente artículo.
Hasta lo visto, cualquier ejemplo analizado se ha desarrollado y resuelto en una sola ventana,
pero en ningún caso se ha recurrido a mostrar una segunda (o más) en la que seguir
completando los datos de la original.
Partiendo del ejemplo del número anterior, en el que se manipulaban un montón de ListBox y al
final se mostraba un archivo BMP, dividiremos la ventana para que, en la primera, efectivamente,
se permita movernos por los directorios, elegir el/los archivos oportunos, poner una máscara que
filtre el contenido del ListBox de archivos, etc., y la segunda dejarla, exclusivamente, para la
visualización y manipulación del archivo gráfico.
De acuerdo a esta lógica, por un lado se abordará la manipulación de la ventana de arranque de
la aplicación, que es la que se ve en la figura 1, y por otro la gestión del BMP, la de la figura 2.
Figura 1. Aspecto de la primera ventana.
La ventana de la figura 1 apenas merece explicación respecto a lo expuesto en la entrega del
mes pasado, pues, básicamente, lo único que se ha hecho con ella ha sido quitarle controles, y
los que han sobrevivido quedaron suficientemente explicados allí. La de la figura 2, si bien posee
el mismo control para visualizar la imagen, ha crecido en su casuística, pues ha pasado a tener
en cuenta qué archivo gráfico se ve, si hay otros más susceptibles de mostrarse, si se quiere
asignar un tamaño determinado o si se quiere ajustar la imagen al recinto definido (bien
expandiendo, bien reduciendo el BMP).
1
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
Figura 2. Aspecto de la segunda ventana.
Básicamente, todo esto se controlará por medio de las propiedades Stretch y AutoSize. Ambas
almacenan un valor lógico, para activarlas o desactivarlas, y su significado es:
-
Stretch (ajuste): Amoldar la figura al recinto especificado, de tal manera que si la figura es
más pequeña que el recinto, ésta se agrandará, agregando pixeles al original para que ocupe
totalmente la superficie, y si es más grande que el recinto se eliminarán pixeles hasta que
quepa. La distorsión de la imagen se ve tanto más acentuada cuanto menos se parezcan las
proporciones de la imagen al recinto predefinido.
-
AutoSize (tamaño automático): Permite supeditar el recinto fijado al tamaño real de la
imagen, de tal manera que si el archivo BMP es menor o mayor que la pantalla de
visualización (cosa bastante habitual), el control que alberga la imagen se queda con el nuevo
tamaño. Esto es así mientras dure la sesión en la que estemos trabajando y, dado que en
nuestro recinto vamos a tener que visualizar cualquier cantidad de imágenes, será bueno
almacenar las coordenadas y dimensiones originales para poder restaurarlas cuando lo
creamos necesario.
Además, y dado que vamos a jugar con las coordenadas del BMP, se habilita un conjunto de
botones de radio (RadioButtons) para ajustar (hacer Stretch), visualizar al tamaño real (no hacer
Stretch) o personalizar el tamaño del BMP. Si lo que se pretende es definir las dimensiones de la
imagen, es lógico pensar en dos controles de edición donde indicar el ancho y el alto (estos
controles deberán estar habilitados cuando queramos personalizar, y deshabilitados en el resto
de los casos.
Situaciones
Antes de pasar a examinar las características de cada uno de los elementos que completarán el
ejemplo, paso a enumerar los casos que nos vamos a encontrar, según la operación que se
desee hacer con el BMP y el tamaño original de éste.
-
Para BMPs más pequeños que el recinto de visualización. Tanto ajustar como mostrar en
2
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
tamaño original no forzarán a que haya barras de desplazamiento que permitan recorrer el
BMP en su totalidad, pues, al ser más pequeño, lo contemplaremos completo. Sin embargo,
cuando se fijan las dimensiones, sí habrá que tener en cuenta que el resultado final exceda
del habitáculo predefinido.
-
Para BMPs más grandes que el recinto de visualización. En este caso ajustar no fuerza el
redimensionamiento, pero sí la vista a tamaño original, que forzará a que existan barras de
desplazamiento para recorrer el BMP en su totalidad. Por otra parte, la lógica a seguir
cuando se trata de fijar las dimensiones es idéntica a la anterior.
De acuerdo a lo expuesto, las situaciones en las que se puede encontrar un BMP es alguna de
las de la tabla 1. En dicha tabla también puede verse en qué manera afecta a los estados de
dos de las propiedades más importantes de una imagen, la propiedad Stretch y la propiedad
AutoSize.
Tipo
Ajustado
BMP pequeño Sí
BMP pequeño No
BMP pequeño No
BMP grande
Sí
BMP grande
No
BMP grande
No
Tabla 1: Estado de Stretch y
Tanaño Original Personalizado
No
No
Sí
No
No
Sí
No
No
Sí
No
No
Sí
AutoSize según aspecto de BMP.
Stretch
true
false
false
true
false
false
AutoSize
false
false
true
false
true
true
Separación de bienes
Una vez vistas las situaciones posibles, tomemos el ejemplo del número anterior y dividámoslo
en las dos partes, las comentadas más arriba. Para ello:
1.- Se recupera el proyecto del ejemplo del mes anterior.
2.- Se salva con otro nombre para no perder la información que éste poseía (nunca se sabe
hasta dónde habremos de dar marcha atrás).
3.- Se crea un nuevo form que, a todos los efecto, se trata de la nueva ventana que será
invocada desde la principal. Para ello se elige el icono de la barra de herramientas
destinada a tal fin, o se procede a su creación mediante el ítem New del menú File. Esta
última operación nos obliga a elegir entre los distintos tipos de ventanas disponibles, de las
cuales se elegirá la más sencilla de todas, la de tipo form, tal y como se indica en la figura
3.
3
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
Figura 3: Creación de una nueva ventana
Una vez en posesión de dos ventanas, una con todos los controles y otra con ninguno,
basta con mandar cosas de un sitio a otro. La forma más fácil consiste en visualizar el
código asociado a las ventanas actuales. En él se puede observar que cada una de las
ventanas tiene una carpeta en la que se almacena su propio código, cuando pinchemos
sobre la carpeta Unit1 estaremos accediendo al form1, cuando lo hagamos sobre la
carpeta Unit2 estaremos accediendo al form2, y así sucesivamente para el resto de
ventanas y sus unidades asociadas a ellas. En las figuras 4 y 5 se ilustra lo que quiero
decir,. En la parte de la izquierda de cada figura se ve el editor de código fuente, donde una
de las unidades (Units) se llaman LB4 y la otra VerBMP; dependiendo de que una esté
pinchada o lo esté la otra se visualiza, en la parte de la derecha, su ventana asociada.
Figura 4: Ventana principal (form) y código asociado LB4 (unit)
4
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
Figura 5: Ventana para la visualización del BMP (form) y código asociado VerBMP (unit)
Una vez en esta situación bastará con ir a la fuente desde donde queremos copiar (o cortar en
este caso), que es LB4, marcar los controles deseados y llevarlos al portapapeles; cambiamos
de ventana, activando aquélla que va a recibir los controles almacenados en el portapapeles y
nos los traemos desde allí.
Nota: para cambiar entre código fuente basta con pinchar en la carpeta deseada. Para visualizar
la ventana asociada al código elegido se hace mediante el oportuno icono de la barra de
herramientas, la opción Toggle Form/Unit del menú View o la pulsación de la tecla [F12].
En este punto ya nos encontramos con dos ventanas, cada una con la separación que hemos
venido predicando. Ahora basta dejarla bonita redimensionando los controles al tamaño que
mejor nos parezca y consiguiendo un aspecto similar al que ofrecen las figuras 1 y 2.
Nuevos controles
Como ya se ha adelantado, se han introducido dos controles de lo que aún no hemos visto nada,
los RadioButton Groups y los Controles de Edición con Máscara.
Un RadioButton Group es un conjunto de RadioButtons con la característica de ser, dentro del
grupo, mutuamente excluyentes entre sí. Existe en la carpeta Standard la posibilidad de elegir
RadioButton individuales, pero cuando queremos agruparlos de manera lógica, lo más eficaz es
recurrir a este otro tipo de agrupación. El RadioButton Group se encuentra en la carpeta
Standard y los iconos que los representan (no seleccionado y seleccionado) son los de la figura
6.
Figura 6: Iconos para RadioButton Group
5
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
Propiedades de los RadioButton Group
Como viene siendo habitual, hacemos un rápido recorrido por eventos y propiedades no vistos
por el momento, y que están íntimamente ligados a los RadioButton Groups.
Caption. Es la propiedad de los literales. Con ella se pone un encabezamiento que indica
qué tipo de asociación se ha hecho para el RadioButton Group. En nuestro caso se ha
puesto la descripción: Presentación
Columns. Cantidad de columnas dentro de la agrupación. Dado que podemos especificar
un número arbitrario de elementos, esta propiedad fija la forma en que se van a presentar
en pantalla. Lo habitual es que haya una sola columna y que los elementos se presenten
como en la figura 2, pero si hubiésemos querido que su presentación fuera horizontal
hubiera valido con asignar un 3 al dato Column (nuestro ejemplo tiene tres RadioButton
dentro del grupo).
ItemIndex. Una agrupación siempre tendrá dos o más elementos, de los cuales uno será el
que esté inicialmente marcado (y desmarcado el resto). Sabiendo que estos controles se
rellenan siguiendo la misma lógica que en los ListBox, el primero de los RadioButtons se
reconoce por el índice 0, el segundo por el 1 y así sucesivamente. En nuestro ejemplo
partimos de que queremos ver el BMP a tamaño real (segunda posición) por lo que en la
propiedad ItemIndex ponemos un 1.
Items. Elementos con los que el RadioButton Group será rellenado. Este dato alberga un
objeto de la clase TString por lo que disponemos de la posibilidad de ir añadiendo en forma
de lista la relación de ítems que se quieren mostrar.
Propiedades de los Controles de Edición
El Control MaskEdit se encuentra en la carpeta Adittional y los iconos que los representan (no
seleccionado y seleccionado) son los de la figura 7.
Figura 7: Iconos para Controles de Edición con Máscara
Los controles de edición con máscara (MaskEdit) también disponen de sus particularidades:
AutoSelect. Propiedad que permite seleccionar automáticamente el contenido del control de
edición cada vez que éste recibe el foco. En nuestro ejemplo se ha cambiado a false, pues
el valor por defecto es true.
AutoSize. Propiedad que permite redimensionar el control de edición a medida que su
contenido se va haciendo mayor.
CharCase. Tipo de caracteres a utilizar. El valor ecNormal, que es la opción por defecto,
escribe según cómo se tenga el bloqueo de mayúsculas, ecUpperCase en mayúculas y
ecLowerCase minúsculas.
EditMask. Tipo de máscara que se va a utilizar. Son muchas las máscaras disponibles, y su
misión es forzar la escritura como al programador le convenga. Por ejemplo, se podría
forzar a escribir siempre números, o con un formato genérico para números de teléfono o
6
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
para NIF. El que nosotros utilizaremos será el de los números, impidiendo así que se
escriba otra cosa que no sean dígitos (además, se impide que el número exceda de tres
cifras). Para eso hay que asociar a EditMask la máscara 999 y a MaxLenght el valor 3. Las
posibles máscaras se definen o se eligen en la ventana de la figura 8, la cual aparece tras
pinchar en el botón de puntos suspensivos asociado a la propiedad EditMask.
Figura 8: Ventana para la definición de máscaras de edición
MaxLenght. Longitud máxima permitida a la hora de teclear.
Text. Contenido inicial del control. Nuestro ejemplo parte de un valor vacío para los
controles de edición X e Y.
PasswordChar. Carácter que se utiliza para encriptar lo que se escribe. En nuestro caso no
se quiere encriptar nada, por lo que se deja a #0, valor por defecto.
Ejemplo de visualización de BitMaps
Los pasos a seguir para obtener las ventanas del ejemplo han sido:
1.- Hacer la separación de bienes antedicha
2.- Instanciar la segunda ventana una vez que se pulse el botón de Ver o se haga doble clic
sobre el ListBox (habremos de asociar el código del fuente 1 tanto al evento OnClick del
botón como al OnDblClick del ListBox).
// --- Fuente 1 --------------------------------------------------------procedure TForm1.VerBmp(Sender: TObject);
var
nPos: integer;
begin
nPos := ListBox2.ItemIndex;
DlgVerBMP.Show;
DlgVerBMP.cLista := ListBox2.Items;
DlgVerBMP.nPosicion := nPos;
DlgVerBMP.Imagen.Picture.LoadFromFile( ListBox2.Items[nPos] );
end;
7
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
Como se puede apreciar, se hace una llamada al método Show, encargado de visualizar la
ventana no modal, sobre una variable llamada DlgVerBMP.
DlgVerBMP.Show;
La variable DlgVerBMP es el nombre que se le dio a la ventana VerBMP en su propiedad
Name, y que Delphi se ha encargado de especificar como variable a través del código
generado automáticamente (ver fuente 2)
// --- Fuente 2 --------------------------------------------------------. . .
type
TDlgVerBMP = class(TForm)
Cerrar: TBitBtn;
RadioGroup1: TRadioGroup;
ScrollBox1: TScrollBox;
Imagen: TImage;
GBCoord: TGroupBox;
X: TMaskEdit;
Y: TMaskEdit;
LabelX: TLabel;
LabelY: TLabel;
procedure Presenta(Sender: TObject);
procedure Activar(nPos: Integer);
procedure Tamano(Sender: TObject);
procedure Recordar(Sender: TObject);
procedure CambiaBMP(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
DlgVerBMP: TDlgVerBMP;
. . .
A continuación se asigna a la variable cLista (inventada por nosotros) la totalidad de los
ítems del ListBox de archivos y la posición que ocupa el elegido (se verá más adelante por
qué), para terminar por cargar la imagen (mediante el método LoadFromFile) en el recinto
destinado a tal fin.
3.- Importante. Añadir en el apartado uses de LB4 la unidad que contiene la segunda ventana.
Si no se hace esto el compilador no podrá unir la información de una unidad con la de otra,
dando el consecuente error y no pudiendo realizar la llamada a una ventana desde otra. En
definitiva, en el apartado uses hay que añadir, a la lista que Delphi incorpora
automáticamente, el literal VerBMP.
uses
Windows,
Messages,
. . .
VerBMP;
4.- Sopesando los pasos dados, se puede asegurar que lo menos intuitivo es lo de especificar
en el apartado uses la unidad que se quiere utilizar, pero explicado el concepto, parece
8
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
claro que una aplicación con multitud de ventanas, no tiene por qué invocar a todas desde
todos los sitios, de ahí que haya que fijarlo ese sitio y esas ventanas allí donde se
necesiten, todo ello de acuerdo al diseño dado a la aplicación y de las necesidades a
resolver.
Una vez que vemos que todo funciona correctamente hasta el paso 3 (se puede compilar y
ejecutar el ejemplo), podemos empezar a utilizar las nuevas funcionalidades conseguidas
con los controles estudiados más arriba, de ahí que ubiquemos un RadioButton Group y un
MaskEdit.
5.- Determinamos qué hacer cuando se elija alguno de los RadioButton, de acuerdo al evento
OnClick de este tipo de controles. En el fuente 3 se ve el código usado para ajustar la
imagen, mostrarla a tamaño original o personalizar sus dimensiones.
// --- Fuente 3 --------------------------------------------------------procedure TDlgVerBMP.Presenta(Sender: TObject);
var
nPos: Integer;
begin
nPos := RadioGroup1.ItemIndex;
Activar( nPos );
case nPos of
0 : Imagen.Stretch := True;
1 : Imagen.Stretch := False;
2 : X.SetFocus();
end;
end;
Lo primero que hace el procedimiento es provocar una llamada a Activar, pasándole como
parámetro el ítem que ha sido pulsado en el RadioButton Group. Después se discierne, en
una estructura case, cómo obrar para el ítem 1, 2 ó 3 (valores 0, 1 y 2, respectivamente,
en nPos). Para el ítem 1 se pone el dato Stretch a true, para el ítem 2 se modifica a false y
para el ítem 3 se le da el foco al control de edición X.
Pero pasemos a comprender qué hace el procedimiento Activar. Siempre que no se esté
personalizando el tamaño final del BMP (ítems 1 y 2), los controles de edición X e Y, los
literales y la caja que los abarca deberían estar inhabilitados, pasando a estar disponibles
solamente cuando se elija el ítem 3. Al tratarse de un código que se repite para cada
operación se ha optado por aislarlo en un procedimiento específico. En el fuente 4, y de
acuerdo al valor recibido como parámetro, se activan o desactivan dichos controles.
Cuando nPos sea 0 ó 1, el dato Enabled debería estar a false, por lo que se podría
ensayar algo como lo que sigue:
if (nPos = 0) or (nPos = 1) then
begin
GBCoord.Enabled := false;
LabelX.Enabled := false;
LabelY.Enabled := false;
X.Enabled := false;
Y.Enabled := false;
end
else
begin
GBCoord.Enabled := false;
9
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
LabelX.Enabled := false;
LabelY.Enabled := false;
X.Enabled := false;
Y.Enabled := false;
end;
Pero resulta algo excesivo cuando se puede recoger el valor false o true en una variable y
ser esa variable la que se encargue de modificar el contenido del dato Enabled.
if (nPos = 0) or (nPos = 1) then
lValor := false
else
lValor := true;
GBCoord.Enabled := lValor;
LabelX.Enabled := lValor;
LabelY.Enabled := lValor;
X.Enabled := lValor;
Y.Enabled := lValor;
o, como se hace en el fuente 4, obviar la estructura if y asignar directamente a la variable.
// --- Fuente 4 --------------------------------------------------------procedure TDlgVerBMP.Activar( nPos: Integer );
var
lValor : Boolean;
begin
lValor := not ((nPos = 0) or (nPos = 1));
GBCoord.Enabled := lValor;
LabelX.Enabled := lValor;
LabelY.Enabled := lValor;
X.Enabled := lValor;
Y.Enabled := lValor;
if not lValor then
begin
if nPos = 1 then Imagen.AutoSize := True
else Imagen.AutoSize := False;
Imagen.Width := XOrig;
Imagen.Height := YOrig;
end;
end;
Hasta aquí tenemos asegurado la activación y la desactivación de controles de acuerdo al
RadioButton elegido, así como el comportamiento de Stretch y AutoSize en los distintos
casos. Aún nos queda tomar como buenos los datos que se introduzcan en los controles de
edición y asignárselos al ancho y alto de la imagen.
6.- Asignación de los valores tecleados. Ante tal tesitura podemos elegir entre dos caminos. El
primero consiste en introducir los valores y, una vez que se consideren aceptables pulsar un
botón que actualice lo que se acaba de teclear. El segundo, más funcional, consiste en
actualizar el alto y ancho a medida que las nuevas dimensiones están siendo introducidas en
los controles de edición.
Por ejemplo, si queremos asignar unos valores de 300x459, a medida que escribamos se
10
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
irá asignando un valor de 3, luego un 30 y luego un 300 para el ancho, y un valor de 4, de
45 y de 459 al alto. Eso, efectivamente, es más funcional, pero puede darse el caso que un
gráfico tenga unas dimensiones de 0x0, lo cual no es representable. Por lo tanto, y para
llevar a cabo este redimensionamiento dinámico, protegeremos los valores muy pequeños y
sólo empezaremos a mostrar la imagen a partir de un rango mínimo (que en el ejemplo del
fuente 5 se ha fijado en 20).
El fuente 5, para que sea invocado a cada pulsación en los controles de edición, habrá de
especificarse en el evento OnChange de ambos EditMask.
// --- Fuente 5 --------------------------------------------------------procedure TDlgVerBMP.Tamano(Sender: TObject);
var
nValorX, nValorY : Integer;
nCod : Integer;
begin
Val( Trim(X.Text), nValorX, nCod );
Val( Trim(Y.Text), nValorY, nCod );
if (nValorX > 20) and (nValorY > 20) then
begin
Imagen.Stretch := True;
Imagen.Autosize := True;
Imagen.Width := nValorX;
Imagen.Height := nValorY;
end;
end;
El contenido de un control de edición es siempre de tipo carácter, y se recoge por medio
del dato Text de dicho control. Por lo tanto, para saber qué dato tiene almacenado el
control y así poder fijar la coordenada X (ancho) diremos:
Trim(X.Text)
Donde Trim() es la función que se encarga de quitar los blancos sobrantes
Una vez obtenida la cadena de caracteres que contiene el valor tecleado la convertimos a
un número que podemos manipular, por ejemplo, para comparación, sumas, restas, etc.
Esta operación se hace mediante el uso del procedimiento Val():
Val( cCadena, nValor, nCod )
Donde cCadena es la cadena alfanumérica a convertir, nValor una variable numérica
pasada por referencia y donde se recoge el valor convertido y nCod un código de error que
se rellena cuando la operación de conversión ha fallado.
De acuerdo con los valores de los controles X e Y, modificamos el alto y el ancho (datos
Width y Height, respectivamente) y alteramos AutoSize para que pase a valer true, pero
sólo cuando ambos controles superen las 20 unidades; por lo que la imagen más pequeña
será de 21x21 pixeles y la más grande de 999x999 pixeles.
Pero esta asignación a los datos Width y Height hace que la imagen pase a tener,
11
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
efectivamente, esos nuevos valores, lo que hará que si queremos ver la imagen tal y como
es en realidad no podamos dar marcha atrás. La solución pasa por recordar en alguna
variable los valores originales, y restaurarlos cuando hagan falta.
Eso se ha hecho en las variable XOrig e YOrig. Alterando la definición de la clase podemos
acceder o añadir datos públicos a esa clase (podía haberse hecho en los privados, pues
cualquier referencia a ellos se hace desde métodos de la propia clase). Como se ve en el
fuente 6, se ha hecho necesario guardar, además, una copia de los ítems del ListBox de
archivos y del ítem elegido (estos dos sí han de ser públicos, pues se accede a ellos desde
fuera de procedimientos propios de la clase).
// --- Fuente 6 --------------------------------------------------------type
TDlgVerBMP = class(TForm)
Cerrar: TBitBtn;
RadioGroup1: TRadioGroup;
ScrollBox1: TScrollBox;
Imagen: TImage;
GBCoord: TGroupBox;
X: TMaskEdit;
Y: TMaskEdit;
LabelX: TLabel;
LabelY: TLabel;
procedure Presenta(Sender: TObject);
procedure Activar(nPos: Integer);
procedure Tamano(Sender: TObject);
procedure Recordar(Sender: TObject);
procedure CambiaBMP(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
XOrig: Integer;
YOrig: Integer;
cLista: TStrings;
nPosicion: Integer;
end;
Ya se dispone de un lugar donde almacenar los valores que, en un determinado momento,
puede resultar ventajoso tenerlos; ahora sólo falta saber cuándo y/o dónde asignarle el
valor. Pueden ser varios los sitios donde hacerlo, aunque sí parece lógico que la asignación
se haga una sola vez. Para resolver esta cuestión se va a recurrir a los eventos
contemplados para la ventana. Los eventos que se pueden interceptar son los de
movimiento, redimensionado, activación, desactivación de ventana, etc. El que en definitiva
nos va a valer para nuestra operativa será el de creación de la ventana, identificado con
OnCreate.
El sencillo código del fuente 7 será el que se asocie a la creación de la segunda ventana.
// --- Fuente 7 --------------------------------------------------------procedure TDlgVerBMP.Recordar(Sender: TObject);
begin
XOrig := Imagen.Width;
YOrig := Imagen.Height
12
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
end;
Es decir, al ancho original (XOrig) le asignamos el ancho del control (Witdh) tal y como se
ve al aparecer la segunda ventana, y en el alto original (YOrig) almacenamos el alto del
control (Height).
7.- Para terminar, y siempre con el afán de dar más funcionalidad al ejemplo que nos ocupa, se
ha implementado una rutina que nos permite recorrer todos los archivos que estén
almacenados en el ListBox de archivos.
De nuevo nos encontramos ante dos posibles soluciones al problema. Por un lado está la
ubicación de dos botones que permitan avanzar y retroceder a través de la lista, por otro se
pueden utilizar el botón derecho e izquierdo del ratón para ir uno hacia adelante o uno hacia
atrás, respectivamente. Este último, aparte de no saturar la ventana con controles, nos
permite introducirnos en una nueva operativa, en la que va a entrar en juego las pulsaciones
en los botones del ratón.
Como siempre, habrá que determinar cuál es el evento que queremos interceptar, y luego
programarlo. Las pulsaciones del ratón que queremos procesar, a priori, parece lógico que
sean las que se efectúan dentro de la imagen, ignorando aquéllas que se hagan en
cualquier otro control. Si ahora consultásemos los posibles eventos relacionados con el
ratón, aparecería una lista como la de abajo.
OnClick
OnDblClick
OnMouseDown
OnMouseMove
OnMouseUp
Los dos primeros (OnClick y OnDblClick) los descartamos, pues sólo controlan que se
pulse y se suelte el botón principal (una o dos veces). OnMouseMove está pensado para la
gestión de cualquier movimiento del ratón. Por último OnMouseUp y OnMouseDown nos
informan que un determinado botón se soltó o se pulsó (respectivamente).
Para comprender cómo se puede advertir que se utilizó el botón principal o el auxiliar, basta
con echar un vistazo al código del fuente 8, generado automáticamente por Delphi
// --- Fuente 8 --------------------------------------------------------procedure TDlgVerBMP.CambiaBMP( Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer
);
Comentemos los parámetros recibidos de manera automática por el procedimiento. Como
siempre, Sender es el control que ha llamado al procedimiento y se utiliza cuando dicho
procedimiento es común a más de un control. La variable Button es la encargada de
almacenar el botón pulsado, pudiendo consultar su contenido según las constantes
predefinidas (mbLeft, mbRight y mbMiddle). La variable Shift guarda información acerca de
la tecla auxiliar presionada en el teclado, esto es, [Shift], [Alt] y/o [Ctrl], también de acuerdo
13
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
a constantes predefinidas (ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle y ssDouble). X e
Y son las coordenadas de pantalla donde se pulsó o se soltó el botón del ratón. De todas
ellas nos bastará con manipular el dato Button, aunque igualmente podríamos haber
involucrado alguna pulsación de teclado, y por tanto de parámetro Shift.
En el fuente 9, una vez comprendidos los parámetros manipulables, vemos cómo hacer la
operación de avance y retroceso entre imágenes.
// --- Fuente 9 --------------------------------------------------------procedure TDlgVerBMP.CambiaBMP( Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer
);
begin
if Button = mbLeft then
if nPosicion > 0 then nPosicion := nPosicion - 1
else nPosicion := 0;
if Button = mbRight then
begin
nPosicion := nPosicion + 1;
if nPosicion >= cLista.Count
then nPosicion := cLista.Count - 1;
end;
Imagen.Picture.LoadFromFile( cLista[ nPosicion ] );
end;
Como primera medida se comprueba, por medio de la variable Button, si se pulsó el botón
izquierdo del ratón. Si no, se comprueba si ha sido el botón derecho:
if Button = mbLeft then
. . .
if Button = mbRight then
. . .
Sea como fuere, se manipula el dato nPosicion (una de las variables públicas de la clase ver fuente 5-) decrementando o incrementando su valor, teniendo cuidado de no sobrepasar
el límite inferior (0) ni el superior (número total de elementos del ListBox de archivos menos
1). Sabiendo ya el nuevo valor de nPosicion, capturamos el elemento que se corresponde
en el ListBox y que, previamente, hemos almacenado en cLista.
cLista[ nPosicion ]
Conocido ya el elemento que nos interesa lo cargamos, como ya hemos hecho antes, por
medio del método LoadFromFile() del control Imagen.
Ese será el código que asociaremos al evento OnMouseUp, pero hay que decir que
igualmente se lo podemos asociar a OnMouseDown.
Un saludo.
14
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - © Grupo EIDOS
Descargar