| Artículos | 01 MAR 2001

Borland Delphi

Tags: Histórico
Francisco Charte.
75- Notificación de cambios en un directorio
La API de Windows dispone de una serie de funciones que nos permiten solicitar una notificación cada vez que se efectúe un cambio en un directorio o en los archivos que éste contiene. El método consiste en solicitar la notificación, mediante la función FindFirstChangeNotification(), y quedar a la espera de que ésta se produzca, usando para ello la función WaitForSingleObject() u otra de la misma familia. Puesto que esta última función detendría la ejecución del programa si la utilizamos en el hilo de ejecución principal, lo habitual es que el proceso de espera se efectúe en un hilo (thread) independiente.
Esto no supone ningún problema en Delphi, basta con seleccionar la opción Thread Object del Depósito de objetos. Partiendo de un nuevo proyecto Delphi, seleccionaríamos la opción citada para añadir un nuevo módulo con una clase derivada de TThread. Podríamos llamarla TActualiza. En el método Execute de esta clase será donde solicitemos la notificación por primera vez, usando para ello la citada función FindFirstChangeNotification().
Esta llamada nos devuelve un identificador que guardaremos en una variable local. Seguidamente entramos en un bucle que se estará ejecutando indefinidamente. En su interior quedamos a la espera de que se produzca una notificación, usando para ello la función WaitForSingleObject(). Al pasar INFINITE como segundo valor, este hilo de ejecución quedará dormido sin límite de tiempo, hasta que en el directorio indicado en la llamada a FindFirstChangeNotification() se produzca algún cambio. En este momento llamamos de forma sincronizada a la función ActualizaLista, con el fin de poder acceder en ella a un control TFileListBox que estará mostrando el contenido del directorio que se está controlando. Por último, mediante una llamada a FindNextChangeNotification(), se solicita una nueva notificación cuando se produzca otro cambio, repitiéndose el proceso.
// Este método es el mundo de ejecución
// del nuevo hilo
procedure TActualiza.Execute;
Var // Identificador de la notificación
Id: LongInt;
begin
// Solicitamos una notificación de
// cambios de archivo en la unidad C:
Id := FindFirstChangeNotification(
‘C:\’, True, FILE_NOTIFY_CHANGE_FILE_NAME);

While True Do // Ejecutar siempre
Begin
// Esperamos que se produzca una
// modificación
WaitForSingleObject(Id,INFINITE);
// Actualizamos la lista
Synchronize(ActualizaLista);
// y esperamos la siguiente notificación
FindNextChangeNotification(Id);
End;
end;
En el formulario de este programa de prueba habrá que insertar el código necesario para crear un objeto TActualiza. El lugar apropiado para ello es el método asociado al evento OnCreate de la ventana. La creación la efectuaremos con la siguiente sentencia:

ActualizaVista :=
TActualiza.Create(False);
Observe que se pasa como parámetro al constructor el valor False, indicando que el nuevo hilo de ejecución no ha de iniciarse en estado de espera, sino directamente en estado de ejecución.

76- Cómo calcular la línea y columna del cursor en un texto
En Delphi existen controles visuales, como TMemo y TRichEdit, capaces de contener grandes cantidades de texto por los que el usuario puede desplazarse libremente utilizando teclado y ratón. Dichos componentes, sin embargo, no disponen de propiedades informativas que permitan saber en qué línea o qué columna concreta se encuentra el cursor en cada momento, aunque sí es posible saber el número de carácter absoluto, desde el principio del control, donde está el cursor.
Con la propiedad SelStart es posible determinar el número de carácter en que se encuentra el cursor o, para ser más exactos, donde comienza la selección de una porción de texto. La posición real del cursor en el texto será la indicada por SelStart más el valor de SelLength. Esta posición, sin embargo, es absoluta y no relativa a la línea actual, aunque es un dato que nos servirá para recuperar el número de línea. Con este fin enviaríamos al control el mensaje EM_LINEFROMCHAR facilitando como parámetro la posición absoluta. El valor devuelto es el número de línea comenzando a contar desde cero.
Para conocer el número de columna habrá que hacer algunos cálculos. Usando el mensaje EM_LINEINDEX, junto con el parámetro -1, obtendremos el número absoluto del primer carácter de la línea actual. Restando a la posición absoluta del cursor, obtenida antes con SelStart y SelLength, la posición de ese primer carácter, obtendremos la posición del cursor relativa a la línea.
Realmente, toda esta explicación es más extensa que el código que finalmente tenemos que escribir. Sería el siguiente:
procedure TForm1.ActualizaPosicion;
var
PosicionCursor,
NumeroCaracteres,
NumeroLinea,
NumeroColumna: integer;
begin
// Calculamos la posición
// absoluta del cursor
PosicionCursor :=
Memo1.SelStart +
Memo1.SelLength;

// Obtener el número de línea
NumeroLinea := SendMessage(
Memo1.handle,
EM_LINEFROMCHAR,
PosicionCursor, 0) + 1;

// y mostrarlo
Label1.Caption :=
IntToStr(NumeroLinea);

// Índice absoluto del primer
// carácter de la línea actual
NumeroCaracteres := SendMessage(
Memo1.handle,
EM_LINEINDEX, -1, 0);

// Calculamos la columna
NumeroColumna := PosicionCursor -
NumeroCaracteres + 1;

// y la mostramos
Label2.Caption :=
IntToStr(NumeroColumna);
end;
Para que este código sea funcional debe insertar en un formulario un control TMemo y dos TLabel. A continuación habría que llamar a este método desde los eventos OnKeyUp y OnMouseMove del TMemo, de tal manera que la posición se actualice cada vez que se mueva una tecla o el ratón.

77- Listas más atractivas
Las listas simples, representadas en Delphi con el control TListBox, por defecto muestran todos sus elementos en el mismo color que, además, suele ser el mismo color por defecto usado en cajas de texto, listas desplegables y otros controles similares. Dicho control, sin embargo, cuenta con una propiedad llamada Style que nos permite cambiar este estilo por defecto. Si elegimos el estilo lbOwnerDrawFixed, por ejemplo, el control generará un evento OnDrawItem cada vez que haya que dibujar un elemento, en lugar de dibujarlo él mismo.
Gracias a este mecanismo podemos personalizar la lista dibujando los elementos con diferentes tipos de letra, estilos y colores. Incluso podríamos añadir imágenes en la lista o cualquier otro elemento que sea posible dibujar sobre un TCanvas.
Puede ver el resultado con este sencillo ejemplo. Inserte en un formulario una lista, una caja de texto y un botón. Dé el valor citado a la propiedad Style de la lista, abra la página de eventos y haga doble clic sobre OnDrawItem, introduciendo el código siguiente:
procedure TForm1.ListBox1DrawItem(
Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
With (Control As TListBox) Do
Begin
// Si el número es menor que 0
If StrToInt(Items[Index]) < 0 Then
// lo mostramos en rojo
Canvas.Font.Color := clRed<

Contenidos recomendados...

Comentar
Para comentar, es necesario iniciar sesión
Se muestran 0 comentarios
X

Uso de cookies

Esta web utiliza cookies técnicas, de personalización y análisis, propias y de terceros, para facilitarle la navegación de forma anónima y analizar estadísticas del uso de la web. Consideramos que si continúa navegando, acepta su uso. Obtener más información