Monday, February 05, 2007


TAtCommands

Aquest component gestiona els SMS mitjançant les comandes AT del modem.

unit AtCommands;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

const
  SIZEBUFFER_RX=1024;
  SIZEBUFFER_TX=1024;
  CR=$0D;
  LF=$0A;
  CTRLZ=26;

type TPortsAt = (COM1,COM2,COM3,COM4,COM5,COM6,COM7,COM8,COM9,COM10);
type TParity = (pNONE,pODD,pEVEN,pMARK,pSPACE);
type TStopBit = (sbONE,sbONE5,sbTWO);

type TPortConfig = class(TPersistent)
  private
    FBaudRate: integer;
    FBitsNumber: integer;
    FParity: TParity;
    FParityN: integer;
    FStopBit: TStopBit;
    FStopBitN: integer;
    procedure SetParity(AParity: TParity);
    procedure SetStopBit(AStopBit: TStopBit);
  public
    constructor Create;
  published
    property BaudRate: integer read FBaudRate write FBaudRate;
    property BitsNumber: integer read FBitsNumber write FBitsNumber;
    property Parity: TParity read FParity write SetParity;
    property StopBit: TStopBit read FStopBit write SetStopBit;
  end;

type
  TAtCommands = class(TComponent)
  private
    { Private declarations }
    FPortName: TPortsAt;
    FPortNumber: integer;
    HandlePort: Array[0..6] of THANDLE;
    FConfiguration: TPortConfig;
    FEnabled: boolean;
    FPhoneNumber: string;
    FDelayTime: DWORD;
    procedure SetPortName(APort: TPortsAt);
  protected
    { Protected declarations }
    function ReadByteSerialChannel(var b: BYTE): Integer;
    function WriteByteSerialChannel(b: BYTE): Integer;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function OpenSerialChannel: Integer;
    procedure CloseSerialChannel;
    procedure ClearInBuffer;
    procedure ClearOutBuffer;
    procedure SendAtCommand(AtComm: string);
    procedure ReadAnswer(var Ans: string);
    procedure SendCRLF;
    procedure SendCtrlZ;
    procedure SendMessage(msgtxt: string; var msgerr: string);
    procedure Delay(Ms: DWORD);
    procedure ReadMessage(index: integer; var msgtxt: string; var msgerr: string);
    procedure DeleteMessage(index: integer; var msgerr: string);
  published
    { Published declarations }
    property Configuration: TPortConfig read FConfiguration write FConfiguration;
    property PortName: TPortsAt read FPortName write SetPortName;
    property Enabled: boolean read FEnabled write FEnabled;
    property PhoneNumber: string read FPhoneNumber write FPhoneNumber;
    property DelayTime: DWORD read FDelayTime write FDelayTime;
  end;

procedure Register;

implementation

var
  cPortName: Array[0..10] of PChar=('COM1','COM2','COM3','COM4','COM5','COM6','COM7','COM8','COM9','COM10','');

constructor TPortConfig.Create;
begin
  FBaudRate := 9600;
  FBitsNumber := 8;
  FParity := pEVEN;
  FParityN := EVENPARITY;
  FStopBit := sbONE;
  FStopBitN := ONESTOPBIT;
end;

procedure TPortConfig.SetParity(AParity: TParity);
begin
  FParity := AParity;
  case FParity of
    pNONE: FParityN := NOPARITY;
    pODD: FParityN := ODDPARITY;
    pEVEN: FParityN := EVENPARITY;
    pMARK: FParityN := MARKPARITY;
    pSPACE: FParityN := SPACEPARITY;
  end;
end;

procedure TPortConfig.SetStopBit(AStopBit: TStopBit);
begin
  FStopBit := AStopBit;
  case FStopBit of
    sbONE: FStopBitN := ONESTOPBIT;
    sbONE5: FStopBitN := ONE5STOPBITS;
    sbTWO: FStopBitN := TWOSTOPBITS;
  end;
end;

constructor TAtCommands.Create(AOwner: TComponent);
begin
  FConfiguration := TPortConfig.Create;
  FEnabled := True;
  inherited Create(AOwner);
end;

destructor TAtCommands.Destroy;
begin
  FConfiguration.Free;
  inherited Destroy;
end;

procedure TAtCommands.SetPortName(APort: TPortsAt);
begin
  FPortName := APort;
  case APort of
    COM1: FPortNumber := 0;
    COM2: FPortNumber := 1;
    COM3: FPortNumber := 2;
    COM4: FPortNumber := 3;
    COM5: FPortNumber := 4;
    COM6: FPortNumber := 5;
    COM7: FPortNumber := 6;
    COM8: FPortNumber := 7;
    COM9: FPortNumber := 8;
    COM10: FPortNumber := 9;
  end;
end;

function TAtCommands.OpenSerialChannel: Integer;
var
  dcb: TDCB;
  cto: TCOMMTIMEOUTS;
label
  error;

begin
  //Apertura del canal de comunicaciones
  HandlePort[FPortNumber]:=CreateFile(cPortName[FPortNumber],
                                GENERIC_READ or GENERIC_WRITE,
                                0,
                                NIL,
                                OPEN_EXISTING,
                                0,
                                0);
  if HandlePort[FPortNumber]=INVALID_HANDLE_VALUE then begin
    goto error;
  end;

  //Lectura de la configuración actual
  if not GetCommState(HandlePort[FPortNumber],dcb) then begin
    goto error;
  end;

  //Modificación de la configuración del canal
  dcb.BaudRate:=Configuration.FBaudRate;
  dcb.ByteSize:=Configuration.FBitsNumber;
  dcb.Parity:=Configuration.FParityN;
  dcb.StopBits:=Configuration.FStopBitN;
  if not SetCommState(HandlePort[FPortNumber],dcb) then begin
    goto error;
  end;

  //Asignación de buffers de entrada y salida
  SetUpComm(HandlePort[FPortNumber],SIZEBUFFER_RX,SIZEBUFFER_TX);

  //Assignación de timeouts
  GetCommTimeouts(HandlePort[FPortNumber],cto);
  cto.ReadIntervalTimeout:=0;
  cto.ReadTotalTimeoutMultiplier:=0;
  cto.ReadTotalTimeoutConstant:=300; //200
  cto.WriteTotalTimeoutMultiplier:=0;
  cto.WriteTotalTimeoutConstant:=0;
  setCommTimeouts(handlePort[FPortNumber],cto);

  //Borrado de buffers de entrada y salida
  PurgeComm(handlePort[FPortNumber],PURGE_TXCLEAR or
                              PURGE_RXCLEAR or
                              PURGE_TXABORT or
                              PURGE_RXABORT);
  Result:=0;
  Exit;

  error:
  Result:=GetLastError();
  CloseHandle(HandlePort[FPortNumber]);
end;

procedure TAtCommands.CloseSerialChannel;

begin
  PurgeComm(HandlePort[FPortNumber],PURGE_TXCLEAR or
                              PURGE_RXCLEAR or
                              PURGE_TXABORT or
                              PURGE_RXABORT);
  CloseHandle(HandlePort[FPortNumber]);
end;

procedure TAtCommands.ClearInBuffer;
begin
  PurgeComm(handlePort[FPortNumber],PURGE_RXCLEAR or
                              PURGE_RXABORT);
end;

procedure TAtCommands.ClearOutBuffer;
begin
  PurgeComm(handlePort[FPortNumber],PURGE_TXCLEAR or
                              PURGE_TXABORT);
end;

function TAtCommands.ReadByteSerialChannel(var b: BYTE): Integer;
var
  rx: Array[0..1] of BYTE;
  nBytes: DWORD;
  dwError: DWORD;
  comStat: TCOMSTAT;
label
  error;
begin
  nBytes:=0;
  ClearCommError(HandlePort[FPortNumber],dwError,@comStat);
  if dwError > 0 then begin
    goto error;
  end;
  if ReadFile(handlePort[FPortNumber],rx,1,nBytes,NIL)=False then begin
    goto error;
  end;
  if nBytes=0 then begin
    Result:=-1;
    Exit;
  end;
  b:=rx[0];
  Result:=0;
  Exit;
  error:
  Result:=GetLastError();
end;

function TAtCommands.WriteByteSerialChannel(b: BYTE): Integer;
var
  tx: Array[0..1] of BYTE;
  nB: DWORD;
  nBytes: DWORD;
  dwError: DWORD;
  comStat: TCOMSTAT;
label
  error;
begin
  nB:=1;
  tx[0]:=b;
  tx[1]:=0;
  nBytes:=0;
  repeat
    ClearCommError(HandlePort[FPortNumber],dwError,@comStat);
    if dwError > 0 then begin
      goto error;
    end;
    if (comStat.cbOutQue < nB) then begin
      if WriteFile(handlePort[FPortNumber],tx,nb,nBytes,NIL)=False then begin
        goto error;
      end;
      if nBytes=0 then begin
        goto error;
      end else begin
        dec(nB);
      end;
    end else begin
      goto error;
    end;
  until nb=0;
  Result:=0;
  Exit;
  error:
  Result:=GetLastError();
end;

procedure TAtCommands.SendAtCommand(AtComm: string);
var
  i: integer;
begin
  for i:=1 to Length(AtComm) do
  begin
    WriteByteSerialChannel(BYTE(AtComm[i]));
  end;
end;

procedure TAtCommands.SendCtrlZ;
begin
  WriteByteSerialChannel(CTRLZ);
end;

procedure TAtCommands.SendCRLF;
begin
  WriteByteSerialChannel(CR);
end;

procedure TAtCommands.ReadAnswer(var Ans: string);
var
  i: integer;
  b: byte;
  s: string;
begin
  i := 1;
  while ReadByteSerialChannel(b)=0 do
  begin
    s := s + char(b);
    Inc(i);
  end;
  ans := s;
end;

procedure TAtCommands.Delay(Ms: DWORD);
var
  StartTime: DWORD;
  Time: DWORD;
begin
  StartTime:=GetTickCount;
  while 1=1 do begin
    Time:=GetTickCount();
    if Time-StartTime > Ms then Exit;
    Application.ProcessMessages();
  end;
end;

procedure TAtCommands.SendMessage(msgtxt: string; var msgerr: string);
var
  r: integer;
  s: string;
begin
  if FEnabled then
  begin
    r := OpenSerialChannel;
    if r=0 then
    begin
      SendAtCommand('AT+CMGF=1');
      SendCRLF;
      Delay(FDelayTime);
      ReadAnswer(s);
      SendAtCommand('AT+CMGS="+34'+FPhoneNumber+'"');
      SendCRLF;
      Delay(FDelayTime);
      ReadAnswer(s);
      SendAtCommand(msgtxt);
      SendCtrlZ;
      Delay(FDelayTime);
      ReadAnswer(s);
      CloseSerialChannel;
    end
    else
    begin
      msgerr := Format('Error %d obrir port',[r]);
    end;
  end
  else
  begin
    msgerr := '';
  end;
end;

procedure TAtCommands.ReadMessage(index: integer; var msgtxt: string; var msgerr: string);
var
  r: integer;
  s: string;
begin
  if FEnabled then
  begin
    r := OpenSerialChannel;
    if r=0 then
    begin
      SendAtCommand('AT+CMGF=1');
      SendCRLF;
      Delay(FDelayTime);
      ReadAnswer(s);
      SendAtCommand('AT+CMGR='+IntToStr(index));
      SendCRLF;
      Delay(FDelayTime);
      ReadAnswer(msgtxt);
      CloseSerialChannel;
    end
    else
    begin
      msgerr := Format('Error %d obrir port',[r]);
    end;
  end
  else
  begin
    msgerr := '';
    msgtxt := 'Simulació';
  end;
end;

procedure TAtCommands.DeleteMessage(index: integer; var msgerr: string);
var
  r: integer;
  s: string;
begin
  if FEnabled then
  begin
    r := OpenSerialChannel;
    if r=0 then
    begin
      SendAtCommand('AT+CMGF=1');
      SendCRLF;
      Delay(FDelayTime);
      ReadAnswer(s);
      SendAtCommand('AT+CMGD='+IntToStr(index));
      SendCRLF;
      Delay(FDelayTime);
      ReadAnswer(s);
      CloseSerialChannel;
    end
    else
    begin
      msgerr := Format('Error %d obrir port',[r]);
end;
end
else
begin
msgerr := '';
end;
end;

procedure Register;
begin
RegisterComponents('Components Delphi', [TAtCommands]);
end;

end.


Entre les propietas que cal configurar hi ha PortName, que és el port que correspon al dispositiu que empleem. A Configuration en determinen els parámetres. PhoneNumber és la destinació del missatge. Escollim un DelayTime per control.lar el correcte funcionament, si fos necessari. A partir d'aquí enviem missatges amb SendMessage, els borrem amb DeleteMessage, i els llegim amb ReadMessage.



Tuesday, January 23, 2007



ColorButton i ColorSpeedButton

Aquests components són una modificació sobre els components Button i SpeedButton per poder canviar-los de color.

unit TtButton;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DsgnIntf,
  ShellAPI, StdCtrls, Buttons;

type
  TColorButton = class(TCustomControl)
  private
    { Private declarations }
    FCaption: string;
    FFont: TFont;
    FColor: TColor;
    FWidthTop,FWidthDown: integer;
    FGlyph: TBitmap;
    FParentColor: boolean;
    FBitmap: TBitmap;
    procedure SetCaption(Value: string);
    procedure SetFont(Value: TFont);
    procedure SetColor(Value: TColor);
    procedure SetParentColor(AParentColor: boolean);
  protected
    { Protected declarations }
    procedure SetGlyph(Value: TBitmap);
    procedure Paint; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure KeyPress(var Key: Char); override;
    procedure DoExit; override;
    procedure DoEnter; override;
    procedure Click; override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
    property Caption: string read FCaption write SetCaption;
    property Font: TFont read FFont write SetFont;
    property Color: TColor read FColor write SetColor;
    property Glyph: TBitmap read FGlyph write SetGlyph;
    property Action;
    property Anchors;
    property BidiMode;
    property Constraints;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property ParentBiDiMode;
    property ParentColor: boolean read FParentColor write SetParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Visible;
    property OnClick;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyUp;
    property OnKeyPress;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
  end;

type
  TColorSpeedButton = class(TGraphicControl)
  private
    { Private declarations }
    FCaption: string;
    FFont: TFont;
    FColor: TColor;
    FTopColor,FBottomColor: integer;
    FGlyph: TBitmap;
    FParentColor: boolean;
    FBitmap: TBitmap;
    procedure SetCaption(Value: string);
    procedure SetFont(Value: TFont);
    procedure SetColor(Value: TColor);
    procedure SetParentColor(AParentColor: boolean);
  protected
    { Protected declarations }
    procedure SetGlyph(Value: TBitmap);
    procedure Paint; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
    property Caption: string read FCaption write SetCaption;
    property Font: TFont read FFont write SetFont;
    property Color: TColor read FColor write SetColor;
    property Glyph: TBitmap read FGlyph write SetGlyph;
    property Action;
    property Anchors;
    property BidiMode;
    property Constraints;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property ParentBiDiMode;
    property ParentColor: boolean read FParentColor write SetParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property Visible;
    property OnClick;
    property OnDblClick;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
  end;

procedure Register;

implementation

constructor TColorButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FColor := clSilver;
  FFont := TFont.Create;
  FFont.Assign(Canvas.Font);
  TabStop := True;
  FWidthTop := 2;
  FWidthDown := 4;
  Width := 75;
  Height := 25;
  FGlyph := TBitmap.Create;
  FParentColor := False;
  FBitmap := TBitmap.Create;
end;

destructor TColorButton.Destroy;
begin
  FFont.Free;
  FGlyph.Free;
  FBitmap.Free;
  inherited Destroy;
end;

procedure TColorButton.SetGlyph(Value: TBitmap);
begin
  FGlyph.Assign(Value);
  Invalidate;
end;

procedure TColorButton.SetParentColor(AParentColor: boolean);
begin
  FParentColor := AParentColor;
  Paint;
end;

const
  BORDER_FOCUS = 4;

procedure TColorButton.Paint;
var
  i: integer;
begin
  FBitmap.Width:=Width;
  FBitmap.Height:=Height;
  with FBitmap.Canvas do
  begin
    Font.Assign(FFont);
    if FParentColor=False then
      Brush.Color := FColor
    else
      Brush.Color := Parent.Brush.Color;
    FBitmap.Canvas.FillRect(ClientRect);
    if Focused then
    begin
      //external border
      Pen.Style := psSolid;
Pen.Color := clWhite;
      Pen.Width := 1;
   FBitmap.Canvas.MoveTo(1,1);
     FBitmap.Canvas.LineTo(Width-3,1);
FBitmap.Canvas.MoveTo(1,1);
   FBitmap.Canvas.LineTo(1,Height-1);
      Pen.Style := psSolid;
      Pen.Width := FWidthTop;
Pen.Color := clBlack;
   FBitmap.Canvas.MoveTo(0,0);
     FBitmap.Canvas.LineTo(Width,0);
FBitmap.Canvas.MoveTo(0,0);
   FBitmap.Canvas.LineTo(0,Height);
      Pen.Width := FWidthDown;
FBitmap.Canvas.MoveTo(0,Height);
   FBitmap.Canvas.LineTo(Width,Height);
     FBitmap.Canvas.MoveTo(Width,0);
FBitmap.Canvas.LineTo(Width,Height);
      //internal line
Pen.Color := clBlack;
      Pen.Width := 1;
      Pen.Style := psSolid;
      for i:=BORDER_FOCUS to Width-BORDER_FOCUS do
      begin
FBitmap.Canvas.MoveTo(i,BORDER_FOCUS);
      if (i mod 2)=0 then
        FBitmap.Canvas.LineTo(i+1,BORDER_FOCUS);
      end;
      for i:=BORDER_FOCUS to Height-BORDER_FOCUS do
      begin
FBitmap.Canvas.MoveTo(BORDER_FOCUS,i);
      if (i mod 2)=0 then
        FBitmap.Canvas.LineTo(BORDER_FOCUS,i+1);
      end;
      for i:=BORDER_FOCUS to Width-BORDER_FOCUS do
      begin
FBitmap.Canvas.MoveTo(i,Height-BORDER_FOCUS);
      if (i mod 2)=0 then
        FBitmap.Canvas.LineTo(i+1,Height-BORDER_FOCUS);
      end;
      for i:=BORDER_FOCUS to Height-BORDER_FOCUS do
      begin
FBitmap.Canvas.MoveTo(Width-BORDER_FOCUS,i);
      if (i mod 2)=0 then
        FBitmap.Canvas.LineTo(Width-BORDER_FOCUS,i+1);
      end;
    end
    else
    begin
      Pen.Width := 2;
Pen.Color := clWhite;
   FBitmap.Canvas.MoveTo(0,0);
     FBitmap.Canvas.LineTo(Width,0);
FBitmap.Canvas.MoveTo(0,0);
   FBitmap.Canvas.LineTo(0,Height);
     Pen.Color := clBlack;
      Pen.Width := 4;
FBitmap.Canvas.MoveTo(0,Height);
   FBitmap.Canvas.LineTo(Width,Height);
     FBitmap.Canvas.MoveTo(Width,0);
FBitmap.Canvas.LineTo(Width,Height);
    end;
    Brush.Style := bsClear;
    FGlyph.Transparent := True;
    if (FGlyph.Width<>0) and (FCaption<>'') then
    begin
      FBitmap.Canvas.TextOut((width - TextWidth(FCaption) - FGlyph.Width) div 2 + FGlyph.Width + 5, (height - TextHeight(FCaption)) div 2 , FCaption);
      FBitmap.Canvas.Draw((width - TextWidth(FCaption) - FGlyph.Width) div 2, (height - FGlyph.Height) div 2,FGlyph);
    end
    else
    if FGlyph.Width=0 then
    begin
      FBitmap.Canvas.TextOut((width - TextWidth(FCaption)) div 2, (height - TextHeight(FCaption)) div 2 , FCaption);
    end
    else
    begin
      FBitmap.Canvas.Draw((width - FGlyph.Width) div 2, (height - FGlyph.Height) div 2,FGlyph);
    end;
  end;
  Canvas.Draw(0,0,FBitmap);
end;

procedure TColorButton.SetCaption(Value: string);
begin
  FCaption := Value;
  Paint;
end;

procedure TColorButton.SetFont(Value: TFont);
begin
  FFont.Assign(Value);
  Paint;
end;

procedure TColorButton.SetColor(Value: TColor);
begin
  FColor := Value;
  Paint;
end;

procedure TColorButton.DoExit;
begin
  Paint;
end;

procedure TColorButton.DoEnter;
begin
  Paint;
end;

procedure TColorButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  FWidthTop := 4;
  FWidthDown := 2;
  SetFocus;
  Paint;
end;

procedure TColorButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  FWidthTop := 2;
  FWidthDown := 4;
  Paint;
end;

procedure TColorButton.Click;
begin
  inherited;
end;

procedure TColorButton.KeyPress(var Key: Char);
begin
  FWidthTop := 4;
  FWidthDown := 2;
  Paint;
  if (Key=#13) or (Key=' ') then
     Click;
  FWidthTop := 2;
  FWidthDown := 4;
  Paint;
end;

constructor TColorSpeedButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FColor := clSilver;
  FFont := TFont.Create;
  FFont.Assign(Canvas.Font);
FTopColor := clWhite;
  FBottomColor := clBlack;
  Width := 22;
  Height := 22;
  FGlyph := TBitmap.Create;
  ParentFont := True;
  FCaption := '';
  FParentColor := False;
  FBitmap := TBitmap.Create;
end;

destructor TColorSpeedButton.Destroy;
begin
  FFont.Free;
  FGlyph.Free;
  FBitmap.Free;
  inherited Destroy;
end;

procedure TColorSpeedButton.SetGlyph(Value: TBitmap);
begin
  FGlyph.Assign(Value);
  Invalidate;
end;

procedure TColorSpeedButton.Paint;
begin
  FBitmap.Width:=Width; {Ajustamos nuestro bitmap}
  FBitmap.Height:=Height;
  with FBitmap.Canvas do
  begin
    Font.Assign(FFont);
    if FParentColor=False then
      Brush.Color := FColor
    else
      Brush.Color := Parent.Brush.Color;
    FBitmap.Canvas.FillRect(ClientRect);
    Pen.Width := 2;
    Pen.Color := FTopColor;
  FBitmap.Canvas.MoveTo(0,0);
    FBitmap.Canvas.LineTo(Width,0);
    FBitmap.Canvas.MoveTo(0,0);
  FBitmap.Canvas.LineTo(0,Height);
    Pen.Color := FBottomColor;
    Pen.Width := 4;
    FBitmap.Canvas.MoveTo(0,Height);
  FBitmap.Canvas.LineTo(Width,Height);
    FBitmap.Canvas.MoveTo(Width,0);
    FBitmap.Canvas.LineTo(Width,Height);
    FGlyph.Transparent := True;
    if (FGlyph.Width<>0) and (FCaption<>'') then
    begin
      FBitmap.Canvas.TextOut((width - TextWidth(FCaption) - FGlyph.Width) div 2 + FGlyph.Width + 5, (height - TextHeight(FCaption)) div 2 , FCaption);
      FBitmap.Canvas.Draw((width - TextWidth(FCaption) - FGlyph.Width) div 2, (height - FGlyph.Height) div 2,FGlyph);
    end
    else
    if FGlyph.Width=0 then
    begin
      FBitmap.Canvas.TextOut((width - TextWidth(FCaption)) div 2, (height - TextHeight(FCaption)) div 2 , FCaption);
    end
    else
    begin
      FBitmap.Canvas.Draw((width - FGlyph.Width) div 2, (height - FGlyph.Height) div 2,FGlyph);
    end;
  end;
  Canvas.Draw(0,0,FBitmap);
end;

procedure TColorSpeedButton.SetCaption(Value: string);
begin
  FCaption := Value;
  Paint;
end;

procedure TColorSpeedButton.SetFont(Value: TFont);
begin
  FFont.Assign(Value);
  Paint;
end;

procedure TColorSpeedButton.SetColor(Value: TColor);
begin
  FColor := Value;
  Paint;
end;

procedure TColorSpeedButton.SetParentColor(AParentColor: boolean);
begin
  FParentColor := AParentColor;
  Paint;
end;

procedure TColorSpeedButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  FTopColor := clBlack;
  FBottomColor := clWhite;
  Paint;
end;

procedure TColorSpeedButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  FTopColor := clWhite;
  FBottomColor := clBlack;
  Paint;
end;

procedure Register;
begin
  RegisterComponents('Components Delphi', [TColorButton]);
  RegisterComponents('Components Delphi', [TColorSpeedButton]);
end;

end.


La propietat Color fa que el botó canvïi de color.

Tuesday, January 16, 2007


WinLinks

Aquest component incorpora una sèrie de mètodes que ens permeten crear accesos directes a l'aplicació que el conté.

unit WinLinks;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ShlObj, ActiveX, ComObj;

const
  CSIDL_DESKTOP = 0;
  CSIDL_PROGRAMS = 2;
  CSIDL_STARTUP = 7;
  CSIDL_STARTMENU = 11;

type
  TWinLinks = class(TComponent)
  private
    { Private declarations }
    Path: string;
    Handle: HWnd;
    function CreateLink(appname: string; apppath: string): boolean;
  protected
    { Protected declarations }
    procedure CreateLinkType(linktype: integer);
  public
    { Public declarations }
    procedure CreateDesktopLink;
    procedure CreateStartMenuLink;
    procedure CreateStartUpLink;
    procedure CreateProgramsLink;
  published
    { Published declarations }
  end;

procedure Register;

function SHGetSpecialFolderPath(Handle: HWND; Path: PChar; Folder: Integer; Create: Bool): HRESULT; StdCall;

implementation

function SHGetSpecialFolderPath; External 'Shell32.DLL' Name 'SHGetSpecialFolderPathA';

function TWinLinks.CreateLink(appname: string; apppath: string): boolean;
var
  IShellLinkInterface: IShellLink;
  IPersistFileInterface: IPersistFile;
  ResultCode: HResult;
  WidePath: Array[0..1024] Of WideChar;
begin

  apppath := PChar(apppath);
  
  IShellLinkInterface := IShellLink(CreateCOMObject(CLSID_ShellLink));
  With IShellLinkInterface Do
  begin
    SetPath(pchar(appname));
    SetDescription(PChar(ChangeFileExt(ExtractFileName(appname),'')));
  end;

  StringToWideChar(apppath+'\'+ChangeFileExt(ExtractFileName(appname),'.lnk'), WidePath, 1024);
  ResultCode := IShellLinkInterface.QueryInterface(IPersistFile, IPersistFileInterface);

  If ResultCode <> S_OK Then // Si no fue posible
  begin
    Result := False;
    Exit;
  end;

  ResultCode := IPersistFileInterface.Save(WidePath, True);

end;

procedure TWinLinks.CreateLinkType(linktype: integer);
begin
  SetLength(Path, MAX_PATH+1);
  SHGetSpecialFolderPath(Handle, PChar(Path), linktype, False);
  CreateLink(Application.ExeName,Path);
end;

procedure TWinLinks.CreateDesktopLink;
begin
  CreateLinkType(CSIDL_DESKTOP);
end;

procedure TWinLinks.CreateStartMenuLink;
begin
  CreateLinkType(CSIDL_STARTMENU);
end;

procedure TWinLinks.CreateStartUpLink;
begin
  CreateLinkType(CSIDL_STARTUP);
end;

procedure TWinLinks.CreateProgramsLink;
begin
  CreateLinkType(CSIDL_PROGRAMS);
end;

procedure Register;
begin
  RegisterComponents('Components Delphi', [TWinLinks]);
end;

end.

Els mètodes són CreateDesktopLink, CreateStartMenuLink, CreateStartUpLink i CreateProgramsLink, que ens permeten crear respectivament un accés directe a l'escriptori, al menú Inici, al menú que fa que l'aplicació s'inicïi amb windows i a la secció programes del menú Inici.

Thursday, January 11, 2007


FloatEdit

Caixa d'edició que només permet l'entrada de números reals.

unit FloatEdit;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, DsgnIntf, ShellAPI;

type TFloatEditEd = class(TDefaultEditor)
  procedure ExecuteVerb(Index: integer); override;
  function GetVerb(Index: integer): string; override;
  function GetVerbCount: integer; override;
  end;

type
  TFloatEdit = class(TCustomEdit)
  private
    { Private declarations }
    FAlignment: TAlignment;
    FValue: double;
    lDelPressed: boolean;
    FVersion: string;
    FMaxIntValue: integer;
    FPrecission: integer;
    FSeparator: char;
    procedure SetAlignment(AAlignment: TAlignment);
    function GetValue: double;
    procedure SetValue(iNewVal: double);
    function GetAsFloat: double;
    procedure SetAsFloat(lnVal: double);
    function GetAsString: string;
    procedure SetAsString(strVal: string);
    procedure SetVersion(strVersion: string);
    procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
  protected
    { Protected declarations }
    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    property AsFloat: double read GetAsFloat write SetAsFloat;
    property AsString: string read GetAsString write SetAsString;
  published
    { Published declarations }
    property MaxIntValue: integer read FMaxIntValue write FMaxIntValue;
    property Precission: integer read FPrecission write FPrecission;
    property Value: double read GetValue write SetValue;
    property Alignment: TAlignment read FAlignment write SetAlignment default taRightJustify;
    property Anchors;
    property AutoSelect;
    property AutoSize default True;
    property BorderStyle;
    property Color;
    property Ctl3D;
    property DragCursor;
    property DragMode;
    property Enabled;
    property Font;
    property HideSelection;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property TabOrder;
    property Visible;
    (* General events properties *)
    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property Version: string read FVersion write SetVersion;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Components Delphi', [TFloatEdit]);
end;

constructor TFloatEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FAlignment := taRightJustify;
  FValue := 0;
  Text := '0';
  FSeparator := ',';
  FMaxIntValue := 2147483647;
  FPrecission := 2;
  lDelPressed := False;
  FVersion := '1.1';
end;

procedure TFloatEdit.SetAlignment(AAlignment: TAlignment);
begin
  if FAlignment <> AAlignment then
  begin
    FAlignment := AAlignment;
    if not (csDesigning in ComponentState) then
      RecreateWnd;
    if Focused then
      SelectAll;
  end;
end;

function TFloatEdit.GetValue: double;
begin
  Result := FValue;
end;

procedure TFloatEdit.SetValue(iNewVal: double);
begin
    Text := FloatToStr(iNewVal);
    FValue := iNewVal;
    if Focused then
    begin
      SelStart := Length(Text);
      SelectAll;
    end;
end;

procedure TFloatEdit.SetAsFloat(lnVal: double);
begin
  Value := lnVal;
end;

function TFloatEdit.GetAsFloat: double;
begin
  Result := Value;
end;

procedure TFloatEdit.SetAsString(strVal: string);
begin
  Value := StrToFloat(strVal);
end;

function TFloatEdit.GetAsString: string;
begin
  Result := FloatToStr(Value);
end;

procedure TFloatEdit.KeyPress(var Key: Char);
begin
  if not (Key in [#27, '0'..'9', #8, ',']) then begin
    Key := #0;
    MessageBeep(0);
    Exit;
  end
  else if (Key in ['0'..'9']) then
  begin
    if (Length(Copy(Text,Pos(',',Text)+1,Length(Text)-Pos(',',Text)+1))>FPrecission-1) and (Pos(',',Text)<>0) then
    begin
      Key := #0;
      MessageBeep(0);
      Exit;
    end
    else if Int(StrToFloat(Text+key))>FMaxIntValue then
    begin
      Key := #0;
      MessageBeep(0);
      Exit;
    end;
  end;
  inherited;
end;

procedure TFloatEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
  ClearSelection;
  inherited KeyDown(Key,Shift);
end;

procedure TFloatEdit.KeyUp(var Key: Word; Shift: TShiftState);
begin
  inherited KeyUp(Key,Shift);
  if Text='' then
  begin
    Text := '0';
    SelStart := Length(Text);
    SelectAll;
  end;
  FValue := StrToFloat(Text);
end;

procedure TFloatEdit.CreateParams(var Params: TCreateParams);
var
{$ifdef VER120}
  lnStyle: LongWord;
{$else}
  lnStyle: LongInt;
{$endif}
begin
  inherited CreateParams(Params);
  case Alignment of
    taLeftJustify:
      lnStyle := ES_LEFT;
    taRightJustify:
      lnStyle := ES_RIGHT
    else
      lnStyle := ES_CENTER;
  end (*case*);
  with Params do
    Style := Style or DWORD(lnStyle);
end;

procedure TFloatEdit.SetVersion(strVersion: string);
begin

end;

procedure TFloatEdit.CMEnter(var Message: TCMEnter);
begin
  if AutoSelect and not ReadOnly then
    SelectAll
  else
    if not ReadOnly then
    begin
      SelStart := Length(Text);
    end (*if*);
  Refresh;
  inherited;
end;

end.


La propietat Value conté el número introduït. MaxIntValue conté el màxim valor enter que és possible introduïr. Amb Precission determinem el màxim número de decimals permesos. Alignment permet alinear el text a la dreta o a l'esquerra.

Wednesday, January 10, 2007


SytemInfo

Mostra algunes propietats de sistema operatiu.

unit SystemInfo;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TSystemInfo = class(TComponent)
  private
    { Private declarations }
    FShortDate: string;
    FLongDate: string;
    FTime: string;
    FComputerName: string;
    FUserName: string;
    FCDRomDrive: string;
    function GetFirstCdRomDrive: string;
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner:TComponent); override;
  published
    { Published declarations }
    property ShortDate: string read FShortDate write FShortDate;
    property LongDate: string read FLongDate write FLongDate;
    property Time: string read FTime write FTime;
    property ComputerName: string read FComputerName write FComputerName;
    property UserName: string read FUserName write FUserName;
    property CDRomDrive: string read FCDRomDrive write FCDRomDrive;
  end;

procedure Register;

implementation

function TSystemInfo.GetFirstCdRomDrive: string;
var
  r: LongWord;
  Unidades: array[0..128] of char;
  pUnidad: pchar;
begin
  Result := '';
  r := GetLogicalDriveStrings(sizeof(Unidades), Unidades);
  if r = 0 then exit;
  if r > sizeof(Unidades) then
    raise Exception.Create(SysErrorMessage(ERROR_OUTOFMEMORY));
  pUnidad := Unidades; // Apunta a la primera unidad
  while pUnidad^ <> #0 do begin
    if GetDriveType(pUnidad) = DRIVE_CDROM then begin
      Result := pUnidad;
      exit;
    end;
    inc(pUnidad, 4); // Apunta a la siguiente unidad
  end;
end;

constructor TSystemInfo.Create(AOwner:TComponent);
var
  Buf: array[0..99] of char;
  size: dword;
begin
  inherited;
  GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SSHORTDATE,@Buf,100);
  FShortDate := Buf;
  GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SLONGDATE,@Buf,100);
  FLongDate := Buf;
  GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STIMEFORMAT,@Buf,100);
  FTime := Buf;
  size := 100;
  GetComputerName(Buf, size);
  FComputerName := Buf;
  GetUserName(Buf, size);
  FUserName := Buf;
  FCDRomDrive := GetFirstCdRomDrive;
end;

procedure Register;
begin
  RegisterComponents('Components Delphi', [TSystemInfo]);
end;

end.
 

La propietat CDRomDrive ens indica la unitat del CD. ComputerName ens dona el nom de la màquina. LongData i ShortDate els formats de data del sistam. Time el format de temps del sistema. Finalment, User, l'usuari actual del sistema operatiu. Lògicament es poden anar afegint tantes propietats com es vulgui per obtenir dades del sistema.

Tuesday, January 09, 2007


BlinkingLabel

Descendent del TLabel que canvia de color intermitentment

unit BlinkingLabel;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type
  TBlinkingLabel = class(TCustomLabel)
  private
    { Private declarations }
    Timer: TTimer;
    FBlinkingEnabled: boolean;
    FBlinkingInterval: integer;
    FBlinkingFirstColor: TColor;
    FBlinkingSecondColor: TColor;
    procedure RefreshLabel;
  protected
    { Protected declarations }
    procedure SetBlinkingEnabled(ABlinkingEnabled: boolean);
    procedure SetBlinkingInterval(ABlinkingInterval: integer);
    procedure OnTimer(Sender: TObject); virtual;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
    property BlinkingEnabled: boolean read FBlinkingEnabled write SetBlinkingEnabled default True;
    property BlinkingInterval: integer read FBlinkingInterval write SetBlinkingInterval default 500;
    property BlinkingFirstColor: TColor read FBlinkingFirstColor write FBlinkingFirstColor;
    property BlinkingSecondColor: TColor read FBlinkingSecondColor write FBlinkingSecondColor;
    property Align;
    property Alignment;
    property Anchors;
    property AutoSize;
    property BiDiMode;
    property Caption;
    property Color;
    property Constraints;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property FocusControl;
    property Font;
    property ParentBiDiMode;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowAccelChar;
    property ShowHint;
    property Transparent;
    property Layout;
    property WordWrap;
    property Visible;
    property OnClick;
    property OnDblClick;
    property OnDragOver;
    property OnDragDrop;
    property OnEndDock;
    property OnEndDrag;
    property OnMouseDown;
    property OnMouseUp;
    property OnStartDock;
    property OnStartDrag;
  end;

procedure Register;

implementation

constructor TBlinkingLabel.Create(AOwner: TComponent);
begin
  FBlinkingEnabled := False;
  FBlinkingInterval := 500;
  FBlinkingFirstColor := clBlue;
  FBlinkingSecondColor := clRed;
  Timer := TTimer.Create(Self);
  Timer.Enabled := FBlinkingEnabled;
  Timer.Interval := FBlinkingInterval;
  Timer.OnTimer := OnTimer;
  inherited;
  RefreshLabel;
end;

destructor TBlinkingLabel.Destroy;
begin
  Timer.Free;
  inherited;
end;

procedure TBlinkingLabel.SetBlinkingEnabled(ABlinkingEnabled: boolean);
begin
  FBlinkingEnabled := ABlinkingEnabled;
  Timer.Enabled := ABlinkingEnabled;
end;

procedure TBlinkingLabel.SetBlinkingInterval(ABlinkingInterval: integer);
begin
  FBlinkingInterval := ABlinkingInterval;
  Timer.Interval := ABlinkingInterval;
end;

procedure TBlinkingLabel.OnTimer(Sender: TObject);
begin
  RefreshLabel;
end;

procedure TBlinkingLabel.RefreshLabel;
begin
  if Font.Color=FBlinkingFirstColor then
    Font.Color := FBlinkingSecondColor
  else
    Font.Color := FBlinkingFirstColor;
end;

procedure Register;
begin
  RegisterComponents('Components Delphi', [TBlinkingLabel]);
end;

end.

Les propietats BlinkingFirstColor i BlinkingSecondColor indiquen els dos colors entre els quals s'alterna. La propietat BlinkingInterval indica el període de canvi en milisegons. Amb la propietat BlinkingEnabled activem o desactivem el canvi.

Monday, January 08, 2007


FormMemoryReg

Guarda en el registre la posició i tamany del formulari, per recuperar-les al tornar-lo a crear.

unit FormMemoryReg;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Registry, Menus;

type
  //save dimensions by form name
  TFormMemoryReg = class(TComponent)
  private
    { Private declarations }
    RegIniFile: TRegIniFile;
    FOwner: TForm;
    AN: string;
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;
  published
    { Published declarations }
  end;

procedure Register;

implementation

constructor TFormMemoryReg.Create(AOwner: TComponent);
var
  filename: string;
  fl: TStringList;
begin
  inherited Create(AOwner);
  FOwner := TForm(AOwner);
end;

procedure TFormMemoryReg.Loaded;
var
  fl: TStringList;
begin
  inherited Loaded;
  AN := ExtractFileName(Application.ExeName);
  AN := ChangeFileExt(AN,'');
  if not (csDesigning in ComponentState) then
  begin
    RegIniFile := TRegIniFile.Create('');
    RegIniFile.RootKey := HKey_Local_Machine;
    if not RegIniFile.OpenKey('Software\CompDelphi\'+AN+'\FormsMem',False) then
    begin
      RegIniFile.CreateKey('Software\CompDelphi\'+AN+'\FormsMem');
    end;
    FOwner.Top := RegIniFile.ReadInteger('',FOwner.Name+'t',FOwner.Top);
    FOwner.Left := RegIniFile.ReadInteger('',FOwner.Name+'l',FOwner.Left);
    FOwner.Height := RegIniFile.ReadInteger('',FOwner.Name+'h',FOwner.Height);
    FOwner.Width := RegIniFile.ReadInteger('',FOwner.Name+'w',FOwner.Width);
    RegIniFile.Free;
  end;

end;

destructor TFormMemoryReg.Destroy;
begin
  if not (csDesigning in ComponentState) then
  begin
    if FOwner.WindowState=wsNormal then
    begin
      RegIniFile := TRegIniFile.Create('');
      RegIniFile.RootKey := HKey_Local_Machine;
      RegIniFile.OpenKey('Software\CompDelphi\'+AN+'\FormsMem',False);
      RegIniFile.WriteInteger('',FOwner.Name+'t',FOwner.Top);
      RegIniFile.WriteInteger('',FOwner.Name+'w',FOwner.Width);
      RegIniFile.WriteInteger('',FOwner.Name+'l',FOwner.Left);
      RegIniFile.WriteInteger('',FOwner.Name+'h',FOwner.Height) ;
    end;
    RegIniFile.Free;
  end;
  inherited;
end;

procedure Register;
begin
  RegisterComponents('Components Delphi', [TFormMemoryReg]);
end;

end.

This page is powered by Blogger. Isn't yours?