Showing posts with label Components. Show all posts
Showing posts with label Components. Show all posts

Sunday, 14 March 2010

Showing the folder dialog in Delphi

Some time ago, I published one post showing the way we can open the folder dialog with Delphi. But this snippet of code doesn't work for Delphi 2010. Then, I found this little code that allows you to open the folder dialog with no problems.

unit folderDialog;

interface

uses
    SysUtils, ShlObj, Windows, ActiveX, Forms;

function GetFolderDialog2(const ACaption: string; out ADirectory: string): boolean;
function BrowseForFolder: string;

implementation

function BrowseForFolder: string;
begin
  GetFolderDialog('Add directory:', Result);
end;

function GetFolderDialog(const ACaption: string; out ADirectory: string): boolean;
const
  BIF_NEWDIALOGSTYLE       = $0040;
  BIF_NONEWFOLDERBUTTON    = $0200;
  BIF_USENEWUI             = BIF_NEWDIALOGSTYLE or BIF_EDITBOX;
var
  pWindowList: Pointer;
  tbsBrowseInfo: TBrowseInfo;
  pBuffer: PChar;
  iOldErrorMode: cardinal;
  pIemIDList: PItemIDList;
  pShellMalloc: IMalloc;
begin
  CoInitialize(nil);
  try
    Result := false;
    ADirectory := '';
    FillChar(tbsBrowseInfo, sizeof(tbsBrowseInfo), 0);
    if (ShGetMalloc(pShellMalloc) = S_OK) and Assigned(pShellMalloc) then
    begin
      pBuffer := pShellMalloc.Alloc(MAX_PATH);
      try
        with tbsBrowseInfo do
        begin
          hwndOwner := Application.Handle;
          pidlRoot := nil;
          pszDisplayName := pBuffer;
          lpszTitle := PChar(ACaption);
          ulFlags := BIF_USENEWUI or BIF_RETURNONLYFSDIRS or BIF_NONEWFOLDERBUTTON;
          lParam := 0;
        end;
        pWindowList := DisableTaskWindows(0);
        iOldErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
        try
          pIemIDList := ShBrowseForFolder(tbsBrowseInfo);
        finally
          SetErrorMode(iOldErrorMode);
          EnableTaskWindows(pWindowList);
        end;
        Result := Assigned(pIemIDList);
        if Result then
        begin
          ShGetPathFromIDList(pIemIDList, pBuffer);
          pShellMalloc.Free(pIemIDList);
          ADirectory := pBuffer;
        end;
      finally
        pShellMalloc.Free(pBuffer);
      end;
    end;
  finally
    CoUninitialize;
  end;
end;

end.

Now we can see the result after the execution of the code:


Friday, 29 January 2010

Batch Watermark with Delphi part I

As a novice photographer, always upload my pictures on flickr and the other day someone told me about putting watermarks to the pictures just in case (in order to protect my pictures). Well, said and done, here you can find one of my last applications: Thundax batch watermark. A simple application that lets you upload a set of jpeg images and a bitmap watermark and then embed the mark in each of the images by merging the pixels.

Imagine that we have this picture:


Saturday, 23 January 2010

Developing a simple MRU List

If you are developing an application and you need a simple MRU list, here I left my system. The MRU acronym stands for Most Recently Used, and that's very useful when we are working with documents and we want to open the last document opened. To implement this in our application in a simple way, we only need to do this:

In our MainMenu item we need to add 5 new subitems called MRU1 to MRU5 and a separator called separatorMRU.

After that, I've designed the following classes to accomplish my goal:

Friday, 8 January 2010

Review from the passing scene

In this article I'll be reviewing all the interesting posts I've published where the set up of the VLO framework is involved. From working with the canvas to using a Force-directed graph layout I'll show you the vast amount of information I've posted, and this will help me to think "Where the project is?" and "Where the project is going to?".

Tuesday, 5 January 2010

Thursday, 13 August 2009

Speech SDK con Delphi

Hoy os traigo un componente muy interesante, Speech SDK (Microsoft Speech Object Library), una API de windows que permite dictar texto por los altavoces del ordenador. Ésta idea me vino el otro día mientras miraba una película dónde uno de los testigos no quería que su voz se viera involucrada en la declaración. Para ello, utilizaron un ordenador, un software para la transcripción y unos altavoces. De ésta manera el testigo, escribía todo lo que quería decir y la voz del ordenador decía todas esas palabras y frases. Pues bien, después de investigar un poco y consultar las diferentes API's de las que dispone nuestro SO, ya sea Windows XP o vista, he encontrado la API Speech SDK que me permite hacer esta pijada.
  • Cómo lo instalo en Delphi?
He encontrado varios ejemplos de la instalación del componente pero solo para Delphi 6 y 7, y la verdad es que para Delphi 2007 o 2009, la cosa ha cambiado bastante. Pues bien, después de interminables pruebas, he conseguido realizar una mini aplicación que es capaz de decir lo que entro en un Edit box, y la verdad es que una vez lo tenemos todo instalado, solo es insertar el componente necesario y ejecutar uno de sus métodos.

Primeros pasos:

Una vez tengo abierto el delphi, creo un nuevo package (File -> New -> Package - Delhpi for win32), que en este caso voy a llamar TSpeechSDK50, ya que utilizaré la Microsoft Speech Object Library 5.0. Podría utilizar la 5.1, pero es la que me viene con el windows. En uno de los enlaces anteriores os he dejado la página de la descarga de ésta API.


Ahora viene la parte importante, tengo que importar la librería que necesito. Por lo tanto, vamos a Component -> Import Component, y dentro del asistente, selecciono Import a type Library. Ahora continuo con el asistente y selecciono la librería que me interesa:

Ahora en el siguiente paso, tenemos que seleccionar en que paleta queremos los componentes y sobretodo marcar la casilla "Generate Component Wrappers".


Ahora, para finalizar, importamos éste componente a nuestro package:

El proyecto quedará de la siguiente manera:

Ahora, tenemos en nuestro proyecto el fichero SpeechLib_TLB.pas:

Ahora que ya lo tenemos todo, viene la parte más importante, hacemos un Compile, un Build y un Install, y nos tiene que aparecer el siguiente mensaje indicando que se han instalado todos los componentes correctamente:

Bien, si ahora nos fijamos en nuestra paleta de componentes, veremos como han aparecido todos éstos componentes:



  • Creando la aplicación Thundax Speech Dictator
Ahora, solo tenemos que crear una pequeña aplicación donde utilizaremos éstos componentes. Aquí os dejo mi aplicación Thundax Speech Dictator, que tiene un TMemo el cual todas las palabras que contengan serán reproducidas por el altavoz. El idioma predefinido es el inglés, por lo tanto lo voy a dejar así. Si quisiéramos otros idiomas o voces, solo hay que descargarlos de la web de microsoft.

La nueva aplicación, también debe contener el fichero SpeechLib_TLB.pas ya que las declaraciones de diversas variables están contenidas dentro de ésta librería. Por lo tanto mi ejemplo tiene la siguiente forma:

El código fuente de la aplicación es aún más sencillo, solo tenemos que emplastar el componente TSPVoice y ejecutar su método Speak.

unit Unit3;

interface

uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls, SpeechLib_TLB, OleServer;

type
    TForm3 = class(TForm)
        Button1: TButton;
        SpVoice1: TSpVoice;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
    private
        { Private declarations }
    public
        { Public declarations }
    end;

var
    Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.Button1Click(Sender: TObject);
var
    iSpeechFlags: Integer;
begin
    if Memo1.Text = '' then
        exit;
    iSpeechFlags := SVSFlagsAsync or SVSFPurgeBeforeSpeak or SVSFIsXML;
    SpVoice1.Speak(Memo1.Text, iSpeechFlags);
end;

end.


Ahora, una vez tenemos la aplicación en funcionamiento, y le damos al Play, escucharemos el texto escrito en el TMemo:


En mi opinión, es una buena API, disponemos de muchas funcionalidades ya sea reproducir un texto o reconocer incluso las palabras que nosotros decimos. Solo hay que explorar un poco más la potencia de ésta API, incluyendo diferentes idiomas e incluso añadiendo diferentes voces. Todo ésto y más en Microsoft. Si probáis la aplicación en Windows XP o en Windows Vista, encontraréis bastante diferéncia, ya que la voz que podemos oir en windows vista, es de una mujer y se entiende mucho mejor.
  • Enlaces de interés:
Installing the Microsoft SAPI Speech SDK.
Text To Speech.
Speech Syntesis and Speech Recognition with Speech SDK.
Speech SDK 5.1.
Speaking some text.

Friday, 7 August 2009

unidades innecesarias en Delphi

Cuando nuestra aplicación va creciendo, vamos haciendo referencia a diferentes unidades en la sección uses de Delphi. Cada vez que añadimos un componente se añaden sus diferentes vínculos en ésta sección, pero cuando quitamos el componente, éstas no desaparecen. El problema que se nos plantea aquí es que si éstas unidades no desaparecen, el .dcu (Delphi compiled Unit) se carga en nuestra aplicación aunque no se utilice. Una de la soluciones que tenemos es utilizar la aplicación ICARUS de Peganza Software. El producto es totalmente libre, y mediante unos cuantos clicks, la aplicación es capaz de decirnos que unidades de nuestros uses no nos hacen falta y las podemos quitar de nuestro proyecto. Es como hacer referencia a una librería, por ejemplo una DLL, que no se utiliza nunca, pero que igualmente la tenemos dentro de nuestra aplicación.

Si queremos que nuestra aplicación esté limpia con sus referencias correspondientes, mejor utilizar una aplicación que nos informe de ésto. Con otros IDE's como Eclipse por ejemplo, ésto no pasa, ya que en el momento que uno de los imports no se utiliza aparece subrayado, e incluso podemos hacer botón derecho sobre el texto y eliminar los unused imports. Pero Delphi no tiene esta opción. Esperemos que en alguna versión posterior haya algo parecido.

Una vez instalada la aplicación, la iniciamos y nos aparece un asistente que nos guiará a través de la carga del proyecto y parametrizar las opciones más comunes:

Para hacer un pequeño test de la aplicación, he creado un proyecto Demo con los siguientes la siguiente lista de unidades en el uses:

unit Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, StdCtrls, ExtCtrls, TeeProcs, TeeDraw3D, IWVCLBaseControl,
  IWBaseControl, IWBaseHTMLControl, IWControl, IWHTMLControls;

type
  TForm3 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

end.

Si ahora ejecutamos el ICARUS con el proyecto obtenemos:

Aparece una lista con las unidades que no encuentra, y con las unidades que no son necesarias para nuestro proyecto:

== Messages unnecessary (used by unit with init)
== SysUtils unnecessary (has initialization, used by unit with init)
== Variants unnecessary (has initialization, used by unit with init)
== Classes unnecessary (has initialization, used by unit with init)
== Graphics unnecessary (has initialization, used by unit with init)
== Controls unnecessary (has initialization, used by unit with init)
== StdCtrls unnecessary (used by unit with init)
== Dialogs unnecessary (has initialization, used by unit with init)
== ExtCtrls unnecessary (has initialization, used by unit with init)
== DB unnecessary (has initialization, used by unit with init)
== ADODB unnecessary (has initialization)
En mi opinión, la aplicación es un poco liosa, y cuesta un poco encontrar la lista de los unnecessary units, pero en general si Peganza lo actualiza regularmente (la última actualización del software fue el 14 de julio del 2009) tendremos una aplicación muy buena para éste tipo de consultas.

  • Enlaces de interés:
Uses List analyzer for delphi.

HTML Display Components para Delphi

Desde la web de Dave Balwin, podemos descargar una serie de componentes gratuitos para delphi. El autor dispone de una serie de componentes para trabajar con HTML's utilizando las librerías de Indy. Des de el siguiente enlace, podréis descargar los diferentes componentes HTML: HTMLViewer.



En la web encontraremos los siguientes componentes:
  • ThtmlViewer
  • TFrameViewer
  • TFrameBrowser
Utilizando ésta gama de componentes, podremos cargar una página web en el componente y descargar la web como una imagen o realizar diversas peticiones.
  • Enlaces de interés.
Web page to Image File.


Tuesday, 4 August 2009

Dibujando ejes para mostrar un gráfico con Delphi

Muchas veces nos encontraremos con el diseño de diversas aplicaciones dónde tendremos que mostrar algún gráfico sobre un Canvas. Para hacer el gráfico más interesante y sin tener que recurrir a componentes de terceros como el TChart (que ya os explicaré un día como funciona éste componente), lo podemos hacer nosotros mismos, a mano!. En éste ejemplo, utilizaré un TImage (como siempre) para jugar con nuestro amigo TCanvas y dibujar las líneas horizontales y verticales. Dentro de las líneas centrales dibujaremos las marcas para cada valor y los valores múltiples de 5 los marcaremos con una marca de eje diferente. El ejemplo que vamos a realizar quedará como el que os muestro a continuación:


Si os fijáis, aparecen una serie de líneas verticales y horizontales en forma de parrilla y luego en el eje central aparecen las marcas diferenciando los números múltiples de 5. Mediante el Script que os muestro a continuación podemos ajustar todos éstos parámetros como queramos. Aquí os dejo el código fuente:

procedure TForm3.Button1Click(Sender: TObject);
begin
    DrawAxes();
end;

procedure TForm3.DrawAxes;

  procedure DrawLine(p1, p2: TPoint; color: TColor);
  begin
      Image2.Canvas.Pen.Width := 1;
      Image2.Canvas.Pen.Color := color;
      Image2.Canvas.MoveTo(p1.x, p1.y);
      Image2.Canvas.LineTo(p2.x, p2.y);
  end;

var
    i, partH: integer;
    partW : double;
    Center: TPoint;
begin
    partH := Image2.Height div 8;
    partW := Image2.Width / 100;
    Center := Point(image2.Height div 2, Image2.Width div 2);

    //Horizontal line --------------------------------
    for i := 1 to 8 do
        DrawLine(Point(0, i * partH), Point(Width, i * partH), clBlack);

    for i := 1 to 99 do
        if (i mod 5) = 0 then
            DrawLine(Point(Center.y - 4, i * 4), Point(Center.y + 5, i * 4), clRed)
        else
            DrawLine(Point(Center.y - 2, i * 4), Point(Center.y + 3, i * 4), clBlack);

    //Vertical line -----------------------------
    for i := 1 to 9 do
        DrawLine(Point(round(i * partW * 10), 0), Point(round(i * partW * 10), width), clBlack);

    for i := 1 to 110 do
        if (i mod 5) = 0 then
            DrawLine(Point(round(i * partW), Center.x - 4), Point(round(i * partW), Center.x + 5), clRed)
        else
            DrawLine(Point(round(i * partW), Center.x - 2), Point(round(i * partW), Center.x + 3), clBlack);
end;

Una vez configurada la parrilla, podemos dibujar cualquier cosa encima y referenciarnos a través de los ejes dibujados. Además podemos utilizar el código para crear un componente o algo por el estilo. vosotros mismos!.

Más componentes para Delphi

Aquí os dejo el enlace para la web de Carlos Barbosa, un desarrollador de software que ha publicado una serie de componentes para delphi con el código y totalmente libre. Aquí os dejo la lista de componentes, y el enlace de descarga de la web: download.
  • cbAsyncDirScan
  • cbAudioPlay
  • Delphi DirectDraw
  • Delphi DirectSound
  • DirNotify
  • DSMixer
  • Delphi Wavemix
  • Keyedit
  • Mailslot
  • Resizer Panel
  • Threaded Timer
  • WaveIO
  • WinGPack
Además encontraréis en VideoJuegos creados por el, en la misma web, en el siguiente enlace: Games.

Aquí os dejo la imagen de alguno de sus componentes:



Delphi Max Components

Hoy os traigo varios enlaces sobre componentes gratuitos para delphi. Muchos de ellos incluso disponen del código fuente para que hagamos con ellos lo que queramos. En éste post os hablaré de MaxComponents, una empresa privada sobre tecnologías de la información. Fue fundada por Gábor Sas en 1996 y se especializó en el desarrollo de componentes VCL para Delphi. En su página web podremos encontrar varios componentes gratuitos muy interesantes, aquí os dejo la lista:
  • TmxExports 2.39
  • TmxProtector 1.32
  • TmxStorage 1.21
  • TmxCalendar 2.10a
  • TmxXPButton 1.02
  • TmxInsertSymbolDialog 1.10
  • TmxCaptionBarButtons 1.22
  • TmxWebUpdate 1.21
  • TmxOneInstance 1.21
  • TmxFlatPack 1.29
  • mxDebugger 1.02
  • TmxNativeExcel 1.26
  • TmxLinkLabel 1.13
  • TmxOutlookBar 1.55
  • TmxPluginLoader 1.70
  • TmxTipDialog 2.13
Todos válidos para D5, D6, D7, D2005, D2006, D2007 y D2009. Aquí os dejo también alguna de las imágenes de sus componentes:
Podréis descargar todos los componentes en el siguiente enlace: Download.

Thursday, 30 July 2009

Wuul Software

Hoy os traigo un enlace interesante de una web llamada Wuul Software, donde el autor ha dejado bastantes aplicaciones Open Source y de libre descarga hechas en Delphi (incluye código fuente) y que son muy interesantes. Aquí os dejo la lista de aplicaciones:
La verdad es que no tienen desperdicio y os aconsejo echarles un vistazo e incluso mirar el código fuente. Aquí os dejo algunas imágenes de sus aplicaciones:


Tuesday, 28 July 2009

Mostrar el Dialogo de carpetas

Con delphi no tenemos ningún dialogo para mostrar solo las carpetas. Disponemos de los componentes TDialog que nos permiten abrir ficheros, seleccionarlos o abrir otros tipos de dialogo como los de colores, fuentes, etc. Para cargar solo el dialogo de carpetas, lo tenemos que hacer como siempre se ha hecho, utilizando la Win32 API Shell objects Interface Unit (ShlObj). En ésta unit encontraremos toda la información para ejecutar nuestro dialogo. Aquí os dejo el código fuente sacado de Scalabium Software y unas imágenes de muestra del dialogo.

Con el siguiente código fuente, obtendremos el dialogo mostrado a continuación:




uses
SysUtils
, ShlObj;

function BrowseCallbackProc(hwnd: HWND; uMsg: UINT; lParam: LPARAM; lpData: LPARAM): Integer; stdcall;
begin
if (uMsg = BFFM_INITIALIZED) then
SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
BrowseCallbackProc := 0;
end;

function GetFolderDialog(Handle: Integer; Caption: string; var strFolder: string): Boolean;
const
BIF_STATUSTEXT = $0004;
BIF_NEWDIALOGSTYLE = $0040;
BIF_RETURNONLYFSDIRS = $0080;
BIF_SHAREABLE = $0100;
BIF_USENEWUI = BIF_EDITBOX or BIF_NEWDIALOGSTYLE;
var
BrowseInfo: TBrowseInfo;
ItemIDList: PItemIDList;
JtemIDList: PItemIDList;
Path: PAnsiChar;
begin
Result := False;
Path := StrAlloc(MAX_PATH);
SHGetSpecialFolderLocation(Handle, CSIDL_DRIVES, JtemIDList);
with BrowseInfo do
begin
hwndOwner := GetActiveWindow;
pidlRoot := JtemIDList;
SHGetSpecialFolderLocation(hwndOwner, CSIDL_DRIVES, JtemIDList);
pszDisplayName := StrAlloc(MAX_PATH);
lpszTitle := PChar(Caption);
lpfn := @BrowseCallbackProc;
lParam := LongInt(PChar(strFolder));
end;
ItemIDList := SHBrowseForFolder(BrowseInfo);
if (ItemIDList <> nil) then
if SHGetPathFromIDList(ItemIDList, Path) then
begin
strFolder := Path;
Result := True
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
s := 'C:\';
if GetFolderDialog(Application.Handle, 'Select a folder', s) then
Edit1.text := s;
end;





Thursday, 25 June 2009

Implementando una HashTable en Delphi

Las tablas de dispersión (Hash Table) son muy utilizadas en el diseño de software cuando lo datos que tenemos son pocos y queremos un coste muy bajo a la hora de acceder a estos. Mediante esta estructura de datos, podremos insertar un objeto con un coste O(1) y sacarlo con un coste O(1) mediante una función de dispersión. Todos los conceptos matemáticos relacionados con esta estructura de datos ya los estudiamos en la universidad (muchas asignaturas hablan de esto, Matemática Discreta, Estructura de la Información, etc).
Aquí os propongo un ejemplo que he recuperado de StackFrame y que lo he adaptado para crear una THashTable eficiente y sin fugas de memoria. Como muchos de vosotros ya sabréis existen muchas estructuras de datos (no solo las listas que requieren un recorrido secuencial para obtener sus elementos) como Arboles Binarios, Colas enlazadas, Colas prioritarias, Tablas de dispersión, etc. Y es muy importante que tengamos en cuenta dichos elementos para que nuestra aplicación sea eficiente y que el acceso a los datos sea rápido según lo requiramos.
La parte más importante de la tabla de dispersión es la función de dispersión, que se monta a través de algún identificador. Este identificador pasa por una función matemática (Hash Function) el cual devuelve una posición en la tabla.

Un ejemplo seria el siguiente:


El ejemplo que os adjunto en este post, consiste en una tabla de longitud fija y cada posición de la tabla tiene asociado un TObjectList que irá creciendo en función de las colisiones que tengamos en la tabla. Es decir, cuando un identificador del objeto a almacenar tenga la misma posición que otro objeto, éste se almacenará detrás del primer elemento, y esto provoca una colisión. Por lo tanto, tenemos que asegurarnos que las colisiones sean muy pocas y la tabla quede bien balanceada para que la búsqueda de valores continúe siendo rápida.

THashTable:




//*****************************
//@Author : Jordi Coll
//HastTable
//*****************************

unit HashTable;

interface

uses
SysUtils, Variants, Classes, Controls, Contnrs;

type
THashItem = class(TObject)
private
FId: string;
FData: TObject;
public
constructor Create(Id: string; Data: TObject);
destructor Destroy(); override;
property Id: string read FId write FId;
property Data: TObject read FData write FData;
end;

type
THashTable = class
protected
FTableSize: integer;
function HashFunction(AId: string): integer; virtual;
public
FData: array of TObjectList;
constructor Create(tableSize: integer);
destructor Destroy(); override;
procedure Add(Id: string; Data: TObject);
function items(Id: string): TObject;
procedure Delete(AId: string);
procedure ClearAll;
end;

implementation

{ THashItem }

constructor THashItem.Create(Id: string; Data: TObject);
begin
FId := Id;
FData := Data;
end;

destructor THashItem.Destroy;
begin
inherited;
FreeAndNil(FData);
end;

{ THashTable }

procedure THashTable.ClearAll;
var
i: integer;
begin
for i := 0 to FTableSize - 1 do
FData[i].Clear;
end;

constructor THashTable.Create(tableSize: integer);
var
i: integer;
begin
FTableSize := tableSize;
SetLength(FData, tableSize);
for i := 0 to FTableSize-1 do
FData[i] := TObjectList.Create();
end;

function THashTable.HashFunction(AId: string): integer;
var
i: integer;
h, x: longint;
begin
h := 0;
for i := 1 to Length(AId) do
begin
h := (h shl 8) + Ord(AId[i]);
x := h and $F000F000;
if x <> 0 then
h := h xor (x shr 21) xor x;
end;
result := h mod FTableSize;
end;

procedure THashTable.Add(Id: string; Data: TObject);
var
hash, i: integer;
list: TObjectList;
item: THashItem;
begin
hash := HashFunction(Id);
list := TObjectList(FData[hash]);
for i := 0 to list.Count - 1 do
begin
item := THashItem(list[i]);
if item.Id = Id then
begin
item.Data := Data;
exit;
end;
end;
list.Add(THashItem.Create(Id, Data));
end;

function THashTable.items(Id: string): TObject;
var
hash, i: integer;
list: TList;
item: THashItem;
begin
result := nil;
hash := HashFunction(Id);
list := TObjectList(FData[hash]);
for i := 0 to list.Count - 1 do
begin
item := THashItem(list[i]);
if item.Id = Id then
begin
result := item.Data;
break;
end;
end;
end;

procedure THashTable.Delete(AId: string);
var
hash, i: integer;
list: TObjectList;
begin
hash := HashFunction(AId);
list := TObjectList(FData[hash]);
for i := 0 to list.Count - 1 do
if THashItem(list[i]).Id = AId then
begin
list.Delete(i);
break;
end;
end;

destructor THashTable.Destroy;
var
i : integer;
begin
inherited;
for i := 0 to FtableSize - 1 do
FreeAndNil(FData[i]);
end;

end.





Ejemplo de utilización de la tabla:




procedure TForm3.Button1Click(Sender: TObject);
var
hash: THashTable;
obj: TTest;
sText: string;
i, j: integer;
hashItem: THashItem;
begin
memo1.clear;
FormCreate(Sender);
sText := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
hash := THashTable.Create(20);
for i := 0 to StrToInt(Edit1.text) do
begin
obj := TTest.CreateTest(i + 1, sText[1 + random(26)]);
hash.Add(IntToStr(obj.id), obj);
end;
for i := 0 to Length(hash.FData) - 1 do
begin
if hash.FData[i].Count <> 0 then
begin
sText := IntToStr(i);
for j := 0 to hash.FData[i].Count - 1 do
begin
hashItem := THashItem(hash.FData[i].Items[j]);
sText := sText + ' -> |' + IntToStr(TTest(hashItem.Data).Id) + ' - ' + TTest(hashItem.Data).value + '| ';
end;
AddPosShape(i + 1, hash.FData[i].Count);
memo1.lines.Add(sText);
end
else
memo1.lines.Add(IntToStr(i) + ' -> null');
end;

//Obtener un item
obj := TTest(hash.items('100'));
showMessage(IntToStr(obj.id) + ' - ' + obj.value);


hash.ClearAll;
FreeAndNil(hash);
end;




Programa de ejemplo, mostrando las diferentes entradas y colisiones:

Mediante esta pequeña herramienta que hice, podemos ver como mediante la función de dispersión se van almacenando los elementos de una manera balanceada evitando la agrupación masiva en uno de los registros de la tabla. De esta manera los datos quedan bien almacenados, aunque es solo un ejemplo, y realmente la tabla tendría que tener como menos colisiones mejor.

  • Otras implementaciones:
En el siguiente enlace, podemos encontrar otra implementación de Hash Table, creada por kktos. Este ejemplo lo podemos encontrar en SWAG, una página dedicada a contener un montón de ejemplos para Pascal. Si podéis pasar por ella, hay bastantes ejemplos y mucho código. Aunque es bastante vieja (del año 97), pero tiene cosas interesantes.

En la red, podemos encontrar incluso vídeos explicativos de diferentes universidades. Aquí os dejo uno sobre los HashTables de la universidad de California (Berkley):






  • Enlaces de interés:
Introducción a las HashTables.
Implementación de una HashTable en C.
Introducción Algorítmica : Hashing1, Hashing2.