terça-feira, 24 de julho de 2012

Exemplo de Aplicação para dar um Zoom na Tela


Imaginem criar uma aplicação que possibilite "darmos" um zoom por onde o mouse passar. A idéia é passarmos o mouse em um determinado local da tela e ampliar a mesma. Com Delphi podemos fazer isso facilmente. Para demonstrarmos essa facilidade vamos criar uma aplicação exemplo, e detalharmos passo-a-passo como executar o zoom por onde o mouse passar. A imagem abaixo demonstra como deve ficar a interface gráfica da aplicação de exemplo.













Vamos ao código fonte do botão Click Here
// variaveis
var Srect,Drect,PosForme:TRect;
iWidth,iHeight,DmX,DmY:Integer;
iTmpX,iTmpY:Real;
C:TCanvas;
hDesktop: Hwnd;
Kursor:TPoint;

// Ampliar a tela se esse aplicativo não for um icone
If not IsIconic(Application.Handle) then begin

// Pega as coordenadas do mouse
GetCursorPos(Kursor);
hDesktop:= GetDesktopWindow;
// PosForm representa um retangulo com as coordenadas
// Form (image control) coordenadas
PosForme:=Rect(Form1.Left,
Form1.Top,
Form1.Left+Form1.Width,
Form1.Top+Form1.Height);

//Mostra a tela ampliada
//se o cursor do mouse sair do form
If not PtInRect(PosForme,Kursor) then begin
// O codigo abaixo para ampliar o que estiver selecionado a parte da tela que estiver selecionada
iWidth:=Image1.Width;
iHeight:=Image1.Height;
Drect:=Bounds(0,0,iWidth,iHeight);
iTmpX:=iWidth / (Slider.Position * 4);
iTmpY:=iHeight / (Slider.Position * 4);
Srect:=
Rect(Kursor.x,Kursor.y,Kursor.x,Kursor.y);
InflateRect(Srect,Round(iTmpX),Round(iTmpY));
//recebe a "alça de janela" (handle) do form
C:=TCanvas.Create;
try
C.Handle:=GetDC(GetDesktopWindow);
//Transfere a parte da imagem da tela para o TImage
Image1.Canvas.CopyRect(Drect,C,Srect);
finally
ReleaseDC(hDesktop, C.Handle);
C.Free;
end;
end;

// Garantir de processar todas as mensagens do windows
Application.ProcessMessages;
end;
É obvio que devemos aumentar a parte gráfica da aplicação para podermos visualizar melhor a parte da tela que esta sendo ampliada. Fica a dica, de mais uma funcionalidade que podemos disponibilizar em nosso sistemas.

sexta-feira, 29 de junho de 2012

Lendo e gravando arquivos de texto

Existem vários métodos em Delphi para gravar arquivos texto a partir de informações gravadas em bases de dados ou para ler arquivos texto e armazená-los em bases de dados. Esta dica apresenta um destes métodos: o uso de TextFiles.

TextFile é um tipo de dado pré-definido no Delphi e corresponde ao tipo Text do Turbo Pascal e do Object Pascal.

Inicialmente para acessar um arquivo de texto, você precisa definir uma variável tipo TextFile, no local que você achar mais apropriado, da seguinte forma:

var arq: TextFile;
Vamos precisar também de uma variável tipo string para armazenar cada linha lida do arquivo:

var linha: String;
Antes de se iniciar a leitura do arquivo, precisamos associar a variavel TextFile com um arquivo fisicamente armazenado no disco:

AssignFile ( arq, 'C:\AUTOEXEC.BAT' );
Reset ( arq );
A rotina AssignFile faz a associação enquanto Reset abre efetivamente o arquivo para leitura. AssignFile corresponde à Assign do Turbo Pascal. Em seguida é necessário fazer uma leitura ao arquivo, para isto utilizaremos a procedure ReadLn:

ReadLn ( arq, linha );
O comando acima lê apenas uma linha de cada vez, assim precisamos de um loop para efetuar várias leituras até que o arquivo acabe. Para verificar o fim do arquivo, utilizaremos a função Eof:

while not Eof ( arq ) do
Agora uma rotina quase completa para fazer a leitura de um arquivo texto. Esta rotina recebe como parâmetro o nome do arquivo que será lido:

procedure percorreArquivoTexto ( nomeDoArquivo: String );
var arq: TextFile;
linha: String;
begin
AssignFile ( arq, nomeDoArquivo );
Reset ( arq );
ReadLn ( arq, linha );
while not Eof ( arq ) do
begin
{ Processe a linha lida aqui. }
{ Para particionar a linha lida em pedaços, use a função Copy. }
ReadLn ( arq, linha );
end;
CloseFile ( arq );
end;
E também uma rotina quase completa para gravação de um arquivo texto. Esta rotina recebe como parâmetro o nome do arquivo que será gravado e uma tabela (TTable) de onde os dados serão lidos:

procedure gravaArquivoTexto ( nomeDoArquivo: String; tabela: TTable );
var arq: TextFile;
linha: String;
begin
AssignFile ( arq, nomeDoArquivo );
Rewrite ( arq );
tabela.First;
while not tabela.Eof do
begin
Write ( arq, AjustaStr ( tabela.FieldByName ( 'Nome' ).AsString, 30 ) );
Write ( arq, FormatFloat ( '00000000.00', tabela.FieldByName ( 'Salario' ).AsFloat ) );
WriteLn ( arq );
tabela.Next;
end;
CloseFile ( arq );
end;
Note nesta segunda rotina, a substituição de Reset por Rewrite logo após o AssignFile. Rewrite abre o arquivo para escrita, destruindo tudo que houver lá anteriormente .

Note também o uso de Write e WriteLn para gravar dados no arquivo texto.

Finalmente note o uso de AjustaStr e FormatFloat para garantir que campos string e numericos sejam gravados com um número fixo de caracteres. FormatFloat é uma rotina do próprio Delphi enquanto AjustaStr está definida abaixo:

function AjustaStr ( str: String; tam: Integer ): String;
begin
while Length ( str ) < tam do
str := str + ' ';
if Length ( str ) > tam then
str := Copy ( str, 1, tam );
Result := str;
end;
O uso da função AjustaStr é fundamental quando você estiver gravando arquivos texto com registros de tamanho fixo a partir de bases de dados Paradox que usualmente não preenchem campos string com espaços no final.

Nomes dos arquivos que estão sendo executados:

É comum e até relativamente fácil encontrarmos rotinas para listar todas as janelas abertas. Mas muitas vezes não é apenas o caption das janelas que queremos listar e sim o nome do arquivo executável.

Veja então uma rotina que cria uma lista de strings com esses nomes:

uses TLHelp32; // não esqueça de incluir esta unit

procedure ListProcess(List: TStrings);
   var
     ProcEntry: TProcessEntry32;
     Hnd: THandle;
     Fnd: Boolean;
begin
    List.Clear;
    Hnd := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
    if Hnd <> -1 then
    begin
       ProcEntry.dwSize := SizeOf(TProcessEntry32);
       Fnd := Process32First(Hnd, ProcEntry);
       while Fnd do
       begin
          List.Add(ProcEntry.szExeFile);
          Fnd := Process32Next(Hnd, ProcEntry);
      end;
      CloseHandle(Hnd);
    end;
end;

E para utilizar esta rotina é muito simples, veja:

procedure TForm1.Button1Click(Sender: TObject);
begin
      ListProcess(ListBox1.Items);
end;

Programar meu aplicativo para abrir arquivos a partir do Windows Explorer

Inclua na seção uses: Registry

Problema:

Criei um editor de textos no Delphi. Agora gostaria que o Windows Explorer usasse este editor para abrir arquivos com a extensão .dpg e .dan. Como fazer?

Solução:

Para fazer isto será necessária a criação de algumas chaves no Registro do Windows. O exemplo abaixo cria todas as chaves necessárias.

- Coloque um TButton e no evento OnClick dele coloque o código abaixo:

procedure TForm1.Button1Click(Sender: TObject);
var
Reg: TRegistry;
begin
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_CLASSES_ROOT;
Reg.LazyWrite := false;
{ Define o nome interno (ArquivoDaniel) e uma legenda que aparecerá no Windows Explorer (Arquivo do Daniel) }
Reg.OpenKey('ArquivoDaniel', true);
Reg.WriteString('', 'Arquivo do Daniel');
Reg.CloseKey;
{ Define o comando a ser executado quando abrir um arquivo pelo Windows Explorer (NomeDoExe %1). O símbolo %1 indica que o arquivo a ser aberto será passado como primeiro parâmetro para o aplicativo - ParamStr(1). }
Reg.OpenKey('ArquivoDaniel\shell\open\command', true);
Reg.WriteString('', ParamStr(0) + ' %1'); { NomeDoExe %1 }
Reg.CloseKey;
{ Define o ícone a ser usado no Windows Explorer:
0 - primeiro ícone do EXE
1 - segundo ícone do EXE, etc }
Reg.OpenKey('ArquivoDaniel\DefaultIcon', true);
Reg.WriteString('', ParamStr(0) + ',0'); { 0 = primeiro ícone }
Reg.CloseKey;
{ Define as extensões de arquivos que serão abertos pelo meu aplicativo }
{ *.dpg }
Reg.OpenKey('.dpg', true);
Reg.WriteString('', 'ArquivoDaniel');
Reg.CloseKey;
{ *.dan }
Reg.OpenKey('.dan', true);
Reg.WriteString('', 'ArquivoDaniel');
Reg.CloseKey;
finally
Reg.Free;
end;
end;
- Coloque um TMemo;

- No evento OnShow do Form coloque o código abaixo:

procedure TForm1.FormShow(Sender: TObject);
begin
{ Se o primeiro parâmetro for um nome de arquivo existente... }
if FileExists(ParamStr(1)) then
{ Carrega o conteúdo do arquivo no memo }
Memo1.Lines.LoadFromFile(ParamStr(1));
end;
*** Para testar ***

- Execute este programa;

- Clique no botão para criar as chaves no Registro do Windows;

- Feche o programa;

- Crie alguns arquivos com as extensões .dpg e .dan;

- Vá ao Windows Explorer e procure pelos arquivos criados;

- Experimente dar um duplo-clique sobre qualquer dos arquivos com uma das extensões acima.

Observações

Existem outros recursos que poderão ser configurados. Porém, para começar, este já é um bom exemplo.

domingo, 24 de junho de 2012

Obter a quantidade de registros total e visível de uma tabela

Inclua na seção uses: DbiProcs

Os componentes TTable e TQuery possuem a propriedade RecordCount que indicam a quantidade de registros da tabela.

No entanto esta propriedade é dependente de filtros, ou seja, se tivermos uma tabela com dez registros com campo "Codigo" de 1 a 10 e aplicarmos o filtro mostrado a seguir, a propriedade RecordCount retornará 5 e não 10.

Table1.Filter := 'Codigo <= 5';
Table1.Filtered := true;
Se quizermos obter a quantidade total de registros, independentemente de filtros, devemos usar uma API do BDE conforme abaixo:

var
Total: integer;
begin
Check(DbiGetRecordCount(Table1.Handle, Total));
ShowMessage('Total de registros: ' + IntToStr(Total));
end;

Observações


Para testar o exemplo acima, o Table1 precisa estar aberto.

Os limites do InterBase

Questões / Problemas / Resumo:

Na hora de se construir uma Base de Dados, temos que ter bastante atenção quanto as limitações do Sistema Gerenciador de Banco de Dados, se não levarmos em conta, poderemos ter varias surpresas desagraveis durante o desenvolvimento da mesma....

Descrição:
Os limites do InterBase

Traduzido por: Marcos Ribeiro

Por: Iván Pons

Na hora de se construir uma Base de Dados, temos que ter bastante atenção quanto as limitações do Sistema Gerenciador de Banco de Dados, se não levarmos em conta, poderemos ter varias surpresas desagraveis durante o desenvolvimento da mesma.

Muitas vezes podemos “ignorar” o problema, e buscarmos uma solução que nos permite sair do passo como está, porém em outros casos, nós nos encontramos com uma triste realidade de um Sistema, que não tem toda a potencia de que precisamos.

Por tudo isso, e a pesar de divulgar muitas vezes o InterBase como um sistema “maravilhoso”, devemos conhecer de antemão, até onde ele pode chegar:

1 - Número máximo de clientes conectados em um servidor

Não tem um número máximo de clientes que um Servidor do IB pode servir. Dependerá de uma combinação de fatores, incluindo capacidade do Sistema Operacional, Limitações de Hardware e o que cada cliente pode no servidor. Em uma aplicação “normal”, que executa interações humanas e um servidor médio, o IB pode responder tranqüilamente a mais de 150 clientes.

2 - Tamanho Máximo da Base de Dados

O tamanho máximo direcionado de um arquivo, em um único arquivo é de 2Gb no Windows95/98, 4Gb em NT4 e na maioria dos sistemas UNIX. As limitações dependem do Sistema Operacional. Em uma configuração de múltiplos arquivos, podem chegar a ter o tamanho de Terrabytes.

3 – Máximo número de arquivos por Base de Dados

Pode ser, 2 elevado a 16 (65.536), porque os arquivos estão numerados com um número de 16 bits. Os arquivos Shadow apontam para este limite. É o limite do InterBase, porém a maioria dos sistemas operacionais tem um limite menor de arquivos que podem ser usados simultaneamente por um único processo.

4 - Número Máximo de Tabelas em uma Base de Dados

Podem ser, 2 elevado a 16 (65.536), porque as tabelas estão enumeradas usando um número de 16 bits.

5 – Tamanho Máximo de Filas

64Kb. Os Blobs e Arrays contribuem cada um com 8Bytes. As tabelas de sistemas tem uma limitação de tamanho de coluna de 128 Kb.

6 – Número Máximo de Filas e Colunas por tabela

Pode ser, 2 elevado a 32 filas, e as filas estão numeradas com um inteiro de 32 bits, por tabela. O número de colunas em uma fila dependerá do tipo de dados usado. Assim, uma fila pode ter um tamanho de 64K, e poderíamos definir 16.384 colunas do tipo INTEGER (quatro bytes) em uma tabela.

7 – Número Máximo de Índices por tabela

Pode ser 2 elevado a 16 (65.356), porque estão enumerados com um inteiro de 16 bits.

8 – Número Máximo de Índices por Base de Dados

Pode ser 2 elevado a 32, porque se podem criar 216 tabelas por Base de Dados, e cada tabela pode chegar a ter 216 índices.

9 – Tamanho Máximo da Chaves de um Índice

Inicia com 256 bytes para uma chave simples de coluna, aumentando-se 200 para chaves de múltiplas colunas, restando 4 bytes por cada coluna adicional.

10 – Máximo número de eventos por Procedimento Armazenado

Não tem restrições para desenvolvimento, porém tem um limite prático, dado por um limite em tamanho do código de um Procedimento Armazenado em uma Trigger.

11 – Tamanho máximo do código de um Procedimento Armazenado em uma Trigger

48Kb de BLR (Linguagem compilada de um Procedimento Armazenado ou de uma Trigger.)

12 – Tamanho Máximo de um Blob

O tamanho máximo de um Blob dependerá do tamanho de página de uma Base de Dados. Assim:

1Kb de tamanho de página à 64Mb

2Kb de tamanho de página a 512Mb

4Kb de tamanho de página a 4Gb

8Kb de tamanho de página a 32 Gb

O tamanho máximo de um segmento de um Blob é de 64Kb.

13 – Número máximo de tabelas em um Join

Não tem restrições, porém o tempo de resposta em uma tarefa de cruzar tabelas e exponencial em relação com o número de tabelas que participam em um JOINEI número máximo de tabelas em um JOIN, para que seja eficiente é sobre 16 tabelas, porém a realidade e experiência com nossas aplicações, com uma carga real de dados em nossas tabelas poderá ter um rendimento aceitável.

14 – Número máximo de consultas dentro de outras consultas

Não tem restrições, porém o limite prático dependerá do tipo de consulta de teremos.

15 – Número máximo de colunas para um índice composto

16

16 – Número de Procedimentos Armazenados na Trigger dentro de um PA em uma Trigger.

Em Windows 95/98/NT 750. Em plataformas Unix 1000.

17 – Tamanho máximo de chave em uma sentença SORT

32Kb

18 – Entre Datas

domingo, 10 de junho de 2012

Colocar os bitmaps na dll

Por vezes, quando iniciamos um projecto, temos uma preocupação: fazer uma aplicação pequena. Bem, a solução pode passar por colocar todos os bitmaps que vamos utilizar numa dll. Então vamos lá começar:

Deve usar o Image Editor, criar uma nova Resource File (.res), neste ficheiro vamos colocar os bitmaps e icons (ambos funcionam da mesma forma) que queremos na nossa aplicação, clique com a tecla direita do rato na nova resource file e crie um novo bitmap, depois desenhe ou cole do clipboard um bitmap, finalmente guarde o ficheiro com o nome images.res. Depois disto estar feito vá ao IDE do Delphi e no File menu clique New... e escolha DLL depois cole o código abaixo, não se esqueça de adicionar uma unit vazia ao projecto. Guarde o projecta da dll no mesmo directório do ficheiro image.res, finalmente faça o build da dll (não se esqueça, que não se pode correr (executar) uma dll!)

Código da Dll:

library ImageRes; {nome da dll}
uses DummyUnit; {DummyUnit é uma unit vazia, que é necessária}
{$R images.res} {nome da resource file, que deve estar no mesmo caminho da dll}
begin
end.
Código da DummyUnit:

unit DummyUnit;
interface
implementation
end.

Usar os bitmaps que estão na dll:
Estão aqui alguns exemplos como extrair os bitmaps da dll:

procedure TForm1.SpeedButton1Click(Sender:TObject);
var
      MyHandle :THandle; 
      Bmp : TBitmap; 
begin
      MyHandle := LoadLibrary('ImageRes.DLL'); {nome da dll construida acima} 
      Bmp := TBitmap.Create; 
      Bmp.Handle := LoadBitmap(MyHandle, 'BITMAP1'); {Bitmap1 é o nome do bitmap criado no ficheiro image.res} 
      SpeedButton1.Glyph.Handle := LoadBitmap(MyHandle,'BITMAP1'); {Carrega o Bitmap1 para o glyph do SpeedButton1} 
      Canvas.Draw(0,0,Bmp); {Desenha o bitmap no canvas da form} 
       Image1.picture.bitmap:=Bmp; {Carrega o bitmap para o componente Timage} 
       Bmp.Free; 
end;

quinta-feira, 24 de maio de 2012

Drag and Drop com ListView


Primeiro inclua em seu formulário dois TListView e preencha a propriedades DragMode com o valor dmAutomatic nos dois. Para facilitar nossas vidas, vamos criar um método genérico para realizar o drag and drop, com o seguinte código
procedure realizarDragAndDrop(Sender: TObject; Source: TObject);
var
itemAdicionado : TListItem;
Item : string;
itAdd : TListItem;
begin
if Source <> Sender then
begin
with (Source as TListview) do
begin
Item := Items[ItemIndex].Caption;
Items.Delete(ItemIndex);
itAdd := items[ItemIndex];
end;
itemAdicionado := (Sender as TListView).Items.AddItem(itAdd, 1);
itemAdicionado.Caption := item;
end;
end;

Agora, vamos partir do ponto que nossos listView só aceitam drag and drop de componentes listView, para isso, no evento onDragOver de cada listView vamos colocar o seguinte código

Accept := (Source is TListView);

Para finalizar, vamos fazer a chamada do método que realiza o drag and drop efetivamente. No evento onDragDrop de cada listView, basta fazer a chamada do nosso método realizarDragAndDrop da seguinte maneira

realizarDragAndDrop(Sender, Source);

Vale ressaltar que os parâmetros Sender e Source são parâmetros de entrada do evento onDragDrop de um listView que definem a origem e o destino do item que está sendo manipulado com o drag and drop.

Técnicas para Agilizar o Desenvolvimento


Nesse mini-artigo vou descrever algumas técnicas que considero importantes, no dia-a-dia para agilizar o nosso trabalho como desenvolvedores de software.
Utilizar atalhos: nada mais rápido e eficiente do que aproveitar dos recursos que o Delphi nos oferece para agilizar e facilitar nossa vida, um dos que utilizo com frequência: Detalhe importante, estou trabalhando com o Delphi XE. Galera do Delphi 7... vamos lá, vamos migrar para o XE2 nada melhor e mais produtivo!
> Ctrl + Shift + S = salvar, nunca é demais
> Ctrl + Shift + D = refactory para adicionar um field a classe
> Ctrl + Shift + V = declarar variáveis locais
> Ctrl + Alt + P = adicionar componentes
> Alt + F11 = use unit
> Ctrl + Shift + F11 = abrir o project options
> Ctrl + Shift + J = sync edit, poder editar vários objetos, propriedades etc ao mesmo tempo.

Utilizarmos as macros: tenho certeza que pouco utilizam, mas caso seja necessário remover parte de um código em várias linhas, no caso em que o Ctrl + Shift + J não pode nos ajudar, tentem usar as macros, com certeza é muito produtivo.

Utilizar o Together, ou Model View: nada melhor que visualizarmos a hierarquia de nossas classes com ele. Ao visualizarmos apenas o código fonte fica complicado de identificar quem herda de quem e qual a relação entre as classes. Confesso que essa foi a ultima barreira que venci, pois não era acostumado a essa ferramenta, mas depois que passei a usar vejo que é muito útil.

Formatar Edit Estilo Moeda

Tenho observado que vários colegas tem problemas na formatação de campos no estilo moeda. Esta rotina mostra como o campo Edit funciona como nos caixas eletrônicos, ou seja, a digitação vem da direita para a esquerda.
Para isso, insira no seu form um edit e no evento OnKeyPress inclua o seguinte código:

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
     if NOT (Key in ['0'..'9', #8, #9]) then
     key := #0;
     //Função para posicionar o cursor sempre na direita
     Edit1.selstart := Length(Edit1.text);
end;

No evento onChange insira o seguinte código

procedure TForm1.Edit1Change(Sender: TObject);
var
   s : string;
   v : double;
   I : integer;
begin
   //1º Passo : se o edit estiver vazio, nada pode ser feito.
   If (edit1.Text = emptystr) then
      Edit1.Text := '0,00';

   //2º Passo : obter o texto do edit, SEM a virgula e SEM o ponto decimal:
   s := '';
   for I := 1 to length(edit1.Text) do
   if (edit1.text[I] in ['0'..'9']) then
      s := s + edit1.text[I];

   //3º Passo : fazer com que o conteúdo do edit apresente 2 casas decimais:
   v := strtofloat(s);
   v := (v /100); // para criar 2 casa decimais

   //4º Passo : Formata o valor de (V) para aceitar valores do tipo 0,10.
   edit1.text := FormatFloat('###,##0.00',v); 
   edit1.SelStart := 0;
end;

sábado, 19 de maio de 2012

Criando diretório

Para criar um diretório você precisa usar a função ForceDirectories, o exemplo a baixo testa se não existe um diretório e cria o diretório apartir de uma variável string testando se o diretório já existe

Unit

FileCtrl

procedure TForm1.Button1Click(Sender: TObject);
var
     Dir: string;
begin
     Dir := 'C:\APPS\SALES\LOCAL';

     if not DirectoryExists(Dir) then
     ForceDirectories(Dir);
     Label1.Caption := Dir + ' foi criado';
end;

sexta-feira, 11 de maio de 2012

Como passar parâmetros entre 2 forms

Suponha que você esteja no Form1 e precise chamar o Form2 passando dois parametros ("Aden" e "Rodrigues").
1. Crie as variáveis de instancia do Form2 que receberão os dois parâmetros.
2. Reescreva o Construtor desse form, de forma receber os parametros e atribui-los às suas variáveis de instância:
type
TForm2 = class(TForm)
private
Parametro1 : String;
Parametro2 : String;
public
constructor Create(AOwner : TComponent; pParm1, pParm2 : String);
end;

var
Form2: TForm2;

implementation

Constructor TForm2.Create(AOwner : TComponent; pParm1, pParm2 : String);
begin
inherited Create(AOwner);
Parametro1 := pParm1;
Parametro2 := pParm2;
end;

Agora no seu form1, abra o form2 com a seguinte sintaxe:

With TForm2.Create(self, 'Aden', 'Rodrigues') do
Begin
ShowModal;
Free;
End;

Obs: Não deixe o delphi criar automaticamente o formulário. Crie-o (e destrua-o) manualmente.

Definir o tamanho do papel em TPrinter


Esta procedure configura o tamanho do papel em Run-Time para ser utilizado com o objeto TPrinter; Esta procedure deve ser chamada antes de aplicar o método Printer.BeginDoc.

procedure TForm1.SetPrinterPage(Width, Height : LongInt);
var
   Device : array[0..255] of char;
   Driver : array[0..255] of char;
   Port   : array[0..255] of char;
   hDMode : THandle;
   PDMode : PDEVMODE;
begin
     Printer.GetPrinter(Device, Driver, Port, hDMode);
     If hDMode <> 0 then
     begin
          pDMode := GlobalLock( hDMode );
          If pDMode <> nil then
          begin
               pDMode^.dmPaperSize   := DMPAPER_USER;
               pDMode^.dmPaperWidth  := Width;
               pDMode^.dmPaperLength := Height;
               pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE;
               GlobalUnlock( hDMode );
          end;
     end;
end;

sexta-feira, 4 de maio de 2012

Como descobrir o código de uma tecla pressionada?

Na maioria dos componentes existem eventos que ocorrem quando o teclado é acionado

Ex:

Num Form existe os eventos:

1º OnKeyDown => Quando a tecla é apertada.

2º OnKeyUp => Quando a tecla é solta

3º OnKeyPress => Quando a tecla e apertada.

Os três devolvem uma variável chamada Key;

Os dois primeiros Key é uma word, no terceiro Key é um char.

Para você saber o nº de um tecla é só colocar no evento

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:TShiftState);
Begin
ShowMessage('O nº da tecla: '+Char(ORD(Key))+' é => '+IntToStr(key));
End;

Assim você sabe o valor de cada tecla e pode testar se ela foi acionada.

O legal não é testar este valor e sim trabalhar com a Virtual Key Code

Exemplo:

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
Begin
IF Key=VK_Return Then ShowMessage('Você apertou o enter');
End;


Esse VK_Return é da Virtual Key Code, você terá que pesquisar no Help, Segue abaixo as outras teclas:

VK_LBUTTON Left mouse button
VK_RBUTTON Right mouse button
VK_CANCEL Control+Break
VK_MBUTTON Middle mouse button
VK_BACK Backspace key
VK_TAB Tab key
VK_CLEAR Clear key
VK_RETURN Enter key
VK_SHIFT Shift key
VK_CONTROL Ctrl key
VK_MENU Alt key
VK_PAUSE Pause key
VK_CAPITAL Caps Lock key
VK_KANA Used with IME
VK_HANGUL Used with IME
VK_JUNJA Used with IME
VK_FINAL Used with IME
VK_HANJA Used with IME
VK_KANJI Used with IME
VK_CONVERT Used with IME
VK_NONCONVERT Used with IME
VK_ACCEPT Used with IME
VK_MODECHANGE Used with IME
VK_ESCAPE Esc key
VK_SPACE Space bar
VK_PRIOR Page Up key
VK_NEXT Page Down key
VK_END End key
VK_HOME Home key
VK_LEFT Left Arrow key
VK_UP Up Arrow key
VK_RIGHT Right Arrow key
VK_DOWN Down Arrow key
VK_SELECT Select key
VK_PRINT Print key (keyboard-specific)
VK_EXECUTE Execute key
VK_SNAPSHOT Print Screen key
VK_INSERT Insert key
VK_DELETE Delete key
VK_HELP Help key
VK_LWIN Left Windows key (Microsoft keyboard)
VK_RWIN Right Windows key (Microsoft keyboard)
VK_APPS Applications key (Microsoft keyboard)
VK_NUMPAD0 0 key (numeric keypad)
VK_NUMPAD1 1 key (numeric keypad)
VK_NUMPAD2 2 key (numeric keypad)
VK_NUMPAD3 3 key (numeric keypad)
VK_NUMPAD4 4 key (numeric keypad)
VK_NUMPAD5 5 key (numeric keypad)
VK_NUMPAD6 6 key (numeric keypad)
VK_NUMPAD7 7 key (numeric keypad)
VK_NUMPAD8 8 key (numeric keypad)
VK_NUMPAD9 9 key (numeric keypad)
VK_MULTIPLY Multiply key (numeric keypad)
VK_ADD Add key (numeric keypad)
VK_SEPARATOR Separator key (numeric keypad)
VK_SUBTRACT Subtract key (numeric keypad)
VK_DECIMAL Decimal key (numeric keypad)
VK_DIVIDE Divide key (numeric keypad)
VK_F1 F1 key
VK_F2 F2 key
VK_F3 F3 key
VK_F4 F4 key
VK_F5 F5 key
VK_F6 F6 key
VK_F7 F7 key
VK_F8 F8 key
VK_F9 F9 key
VK_F10 F10 key
VK_F11 F11 key
VK_F12 F12 key
VK_F13 F13 key
VK_F14 F14 key
VK_F15 F15 key
VK_F16 F16 key
VK_F17 F17 key
VK_F18 F18 key
VK_F19 F19 key
VK_F20 F20 key
VK_F21 F21 key
VK_F22 F22 key
VK_F23 F23 key
VK_F24 F24 key
VK_NUMLOCK Num Lock key
VK_SCROLL Scroll Lock key
VK_LSHIFT Left Shift key (only used with GetAsyncKeyState and GetKeyState)
VK_RSHIFT Right Shift key (only used with GetAsyncKeyState and GetKeyState)
VK_LCONTROL Left Ctrl key (only used with GetAsyncKeyState and GetKeyState)
VK_RCONTROL Right Ctrl key (only used with GetAsyncKeyState and GetKeyState)
VK_LMENU Left Alt key (only used with GetAsyncKeyState and GetKeyState)
VK_RMENU Right Alt key (only used with GetAsyncKeyState and GetKeyState)
VK_PROCESSKEY Process key
VK_ATTN Attn key
VK_CRSEL CrSel key
VK_EXSEL ExSel key
VK_EREOF Erase EOF key
VK_PLAY Play key
VK_ZOOM Zoom key
VK_NONAME Reserved for future use
VK_PA1 PA1 key
VK_OEM_CLEAR Clear key

terça-feira, 24 de abril de 2012

Como incrementar a Barra de Status

No formulário principal coloque uma statusbar com 3 panels,1 time e aplicationeventos e digite as funções abaixo ->

function mostrahora:string;
begin
    mostrahora:=timetostr(time);
end;

function mostradata:string;
var
    dthoje:tdatetime;
    diasemana:integer;
    strdiasemana:string;
begin
    dthoje:=date;
    diasemana:=dayofweek(dthoje);
    case diasemana of
      1:strdiasemana:='Domingo';
      2:strdiasemana:='Segunda-feira';
      3:strdiasemana:='Terça-feira';
      4:strdiasemana:='Quarta-feira';
      5:strdiasemana:='Quinta-feira';
      6:strdiasemana:='Sexta-feira';
      7:strdiasemana:='Sábado';
end;
mostradata:=strdiasemana+' '+datetostr(dthoje);
end;

// Selecione o aplicationeventos e na guia eventos do objeto inspector depois clique no evento OnHint e digite o código ->

procedure TFnomedoform.ApplicationEvents1Hint(Sender: TObject);
Begin
StatusBar1.Panels[2].Text:=Application.Hint;
// todos os hints do seu projeto apareceram no statusbar
end;

// agora faça com que suas funções apareçam o resultado

procedure TFnomedoform.Timer1Timer(Sender: TObject);
var
    presente:tdatetime;
    ano,mes,dia:word;
begin
   presente:=now;
   decodedate(presente,ano,mes,dia);
   case mes of
     1:STATUSBAR1.PANELS[1].TEXT:=' JANEIRO '+inttostr(ano);
     2:STATUSBAR1.PANELS[1].TEXT:='FEVEREIRO'+inttostr(ano);
     3:STATUSBAR1.PANELS[1].TEXT:='MARÇO '+inttostr(ano);
     4:STATUSBAR1.PANELS[1].TEXT:='ABRIL '+inttostr(ano);
     5:STATUSBAR1.PANELS[1].TEXT:='MAIO '+inttostr(ano);
     6:STATUSBAR1.PANELS[1].TEXT:='JUNHO '+inttostr(ano);
     7:STATUSBAR1.PANELS[1].TEXT:='JULHO '+inttostr(ano);
     8:STATUSBAR1.PANELS[1].TEXT:='AGOSTO '+inttostr(ano);
     9:STATUSBAR1.PANELS[1].TEXT:='SETEMBRO '+inttostr(ano);
     10:STATUSBAR1.PANELS[1].TEXT:='OUTUBRO '+inttostr(ano);
     11:STATUSBAR1.PANELS[1].TEXT:='NOVEMBRO '+inttostr(ano);
     12:STATUSBAR1.PANELS[1].TEXT:='DEZEMBRO '+inttostr(ano);
   end;
STATUSBAR1.PANELS[0].TEXT:=mostrahora();
STATUSBAR1.PANELS[1].TEXT:=mostradata();
end;

// ***** Viu como é fácil enfeitar seu projeto ******

Obter a célula de um StringGrid que está sob o cursor do mouse

Inclua na seção uses: Windows

procedure MouseCell(Grid: TStringGrid;
var Coluna, Linha: integer);
var
Pt: TPoint;
begin
GetCursorPos(Pt);
Pt := Grid.ScreenToClient(Pt);
if PtInRect(Grid.ClientRect, Pt) then
Grid.MouseToCell(Pt.X, Pt.Y, Coluna, Linha)
else begin
Coluna := -1;
Linha := -1;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
Coluna, Linha: integer;
begin
MouseCell(StringGrid1, Coluna, Linha);
if (Coluna >= 0) and (Linha >= 0) then
Caption := 'Coluna: ' + IntToStr(Coluna) + ' - ' +
'Linha: ' + IntToStr(Linha);
else
Caption := 'O mouse não está no StringGrid';
end;

sexta-feira, 20 de abril de 2012

Alternando Bitmaps no Fundo de um Form

Um leitor perguntou recentemente sobre imagens de fundo em Forms.... Apesar de já se ter escrito diversos artigos sobre este tópico, sua questão tinhas algumas novidades. Primeiramente, ele desejava que o fundo se alternasse periodicamente entre diferente

Essencialmente, a solução para isto seria a aplicação de outros artigos similares. Em primeiro lugar, para resolver a questão de se ter diversas imagens, os bitmaps devem ser carregados em um array quando o Form for criado. A mudança periódica da imagem s

Finalmente, para tratar do assunto "não leia as imagens do disco", recorremos aos resources. Um arquivo de resource é apenas um caminho para empacotar muito bem qualquer tipo de dados que será anexado ao executável durante o processo de Linkedição. Para o

BITMAP1 BITMAP IMAGE1.BMP

BITMAP2 BITMAP IMAGE2.BMP

BITMAP3 BITMAP IMAGE3.BMP

BITMAP4 BITMAP IMAGE4.BMP

BITMAP5 BITMAP IMAGE5.BMP

A primeira parte de cada linha é o identificador que você utilizará no código para capturar uma imagem em particular. A segunda parte é o tipo de resource (neste caso, bitmap). E a última parte é o nome do arquivo que deve ser utilizado para a imagem. Ist

{$R MYBMPS.RES}
Quando o executável está sendo linkeditado (um passo antes da compilação), o resource será automaticamente anexado ao executável. Para carregar as imagens do resource no array de bitmaps no programa, fiz simplesmente:

for a := 1 to NumBmps do
begin
Bmps[a] := TBitmap.Create;
Bmps[a].LoadFromResourceName(hInstance,'BITMAP'+IntToStr(a));
end;
É basicamente isto... A seguir a listagem da Unit principal:

unit Unit1a;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls;
const
NumBmps = 5;
type
TForm1 = class(TForm)
Timer1: TTimer;
Edit1: TEdit;
CheckBox1: TCheckBox;
ListBox1: TListBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
Bmps : Array[1..NumBmps] of TBitmap;
SelectedBmp : Integer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
{$R MYBMPS.RES}
procedure TForm1.FormCreate(Sender: TObject);
var
a : Integer;
begin
for a := 1 to NumBmps do
begin
Bmps[a] := TBitmap.Create;
Bmps[a].LoadFromResourceName(hInstance,'BITMAP'+IntToStr(a));
end;
SelectedBmp := 1;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
a : Integer;
begin
for a := 1 to NumBmps do Bmps[a].Free;
end;
procedure TForm1.FormPaint(Sender: TObject);
var
x,y,w,h : Integer;
begin
w := Bmps[SelectedBmp].Width;
h := Bmps[SelectedBmp].Height;
for x := 0 to (Width div w) do
for y := 0 to (Height div h) do
Canvas.Draw(x*w,y*h,Bmps[SelectedBmp]);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Inc(SelectedBmp);
if SelectedBmp > NumBmps then SelectedBmp := 1;
Paint;
end;
end.

domingo, 15 de abril de 2012

Como usar a cláusula UNION em um Query

O uso do componente TQuery gera muitas vantagens e economiza muitas linhas de programação. Mas muitas vezes nos deparamos com situações que parecem não ser resolvidas com sentenças SQL. Vejamos um exemplo:

Você possui 2 tabelas (VendasExternas e VendasInternas) e deseja fazer um resumo de todas as vendas de um vendedor chamado Marcos. Se você usar a sentença

SELECT Nome, Valor FROM VendasExternas, VendasInternas
WHERE Nome = 'Marcos'
você vai obter como resultado uma query com 4 campos (Nome, Valor, Nome_1 e Valor_1) e um resultado bem confuso para ser manipulado.

Para resolver o problema, você poderá usar a sentença

SELECT Nome, Valor FROM VendasExternas
WHERE Nome = 'Marcos'
UNION ALL
SELECT Nome, Valor FROM VendasInternas
WHERE Nome = 'Marcos'
A sentença acima pede para que sejam identificados as vendas de Marcos na tabela VendasExternas, as vendas de Marcos na tabela VendasInternas e que o resultado da primeira seja unido com o resultado da segunda produzindo uma query com apenas 2 colunas.

quinta-feira, 12 de abril de 2012

Visualizar imagem no dbgrid

Para visualizar uma imagem em um DBGrid, você vai ter que criar um descendente dele que aceite essas figuras. O código está abaixo:

unit DBPicGrd;

interface

uses
DBGrids, DB, DBTables, Grids, WinTypes, Classes, Graphics;

type
TDBPicGrid = class (TDBGrid)
protected
procedure DrawDataCell(const Rect: TRect; Field: TField; State:
TGridDrawState); override;
public
constructor Create (AOwner : TComponent); override;
published
property DefaultDrawing default False;
end;

procedure Register;

implementation

constructor TDBPicGrid.Create (AOwner : TComponent);
begin
inherited Create (AOwner);
DefaultDrawing := False;
end;

procedure TDBPicGrid.DrawDataCell (const Rect: TRect; Field: TField;
State: TGridDrawState);
var
bmp : TBitmap;
begin
with Canvas do
begin
FillRect(Rect);
if Field is TGraphicField then
try
bmp := TBitmap.Create;
bmp.Assign (Field);
Draw (Rect.Left, Rect.Top, bmp);
finally
bmp.Free;
end
else
TextOut (Rect.Left, Rect.Top, Field.Text);
end;
end;

procedure Register;
begin
RegisterComponents ('Custom', [TDBPicGrid]);
end;
end.

domingo, 8 de abril de 2012

Consultar por mês de um campo data

Problema:

Tenho um cadastro de clientes com Codigo, Nome, DataNasc, etc.

Preciso fazer uma consulta onde apareceão apenas os clientes que fazem aniversário em determinado mês. Como fazer?

Solução:Use uma Query como abaixo:

- Coloque no form os seguintes componentes:

* TQuery

* TDataSource

* TDBGrid

* TEdit

* TButton

- Altere as propriedades dos componentes como abaixo:

* Query1.DatabaseName = (alias do BDE)

* DataSource1.DataSet = Query1

* DBGrid1.DataSource = DataSource1

- Coloque o código abaixo no evento OnClick de Button1:

Query1.Close;
Query1.SQL.Clear;
Query1.SQL.Add('select * from dCli');
Query1.SQL.Add('where extract(month from DataNasc) = :Mes');
Query1.ParamByName('Mes').AsInteger := StrToInt(Edit1.Text);
Query1.Open;
- Execute. Digite um número de 1 a 12 no Edit e clique no botão.

Observações

Os números de 1 a 12 representam, respectivamente