quarta-feira, 26 de outubro de 2011

Mostrando um formulário Modal usando Show

Um exemplo disso é quando você está mostrando um diálogo do progresso de uma operação.
O problema é que se você usa ShowModal todo o código da operação deve estar contido no form do diálogo de progresso. 

Para evitar isso use DisableTaskWindows and EnableTaskWindows.
Desta form seu diálogo vai agir como um formulário Modal e ao mesmo tempo permite executar o form da operação que está em progresso no diálogo.

procedure TForm1.ShowProgressDlg;
var
WindowList: Pointer;
begin
// Desabilita todos os formulários com exceção de FrmProgress
WindowList := DisableTaskWindows(FrmProgress.Handle);
try
FrmProgress.Show;
// Início do loop que executa a operação
FrmProgress.ProgressBar1.Position := FrmProgress.ProgressBar1.Position + 1;
// Fim do loop
finally
// Reabilita todos os formulários
EnableTaskWindows(WindowList);
FrmProgress.Close;
end; // try
end; // ShowProgressDlg

Mostrar um Form de Login antes do Form principal

  * Crie um novo Projeto. Este certamente terá o Form1.
  * Adicione um novo Form (Form2).
  * Coloque no Form2 dois botões TBitBtn.
  * Mude a propriedade Kind do BitBtn1 para bkOK.
  * Mude a propriedade Kind do BitBtn2 para bkCancel.
  * Vá no menu "Project/Options" na aba "Forms" e passe o Form2 de "Auto-create Forms" para "Available Forms".
  * Abra o arquivo Project.dpr (menu Project/View Source).
  * Altere o conteúdo deste arquivo conforme abaixo:
 
program Project1;
 
uses
  Forms, Controls,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};
 
{$R *.RES}
 
var
  F: TForm2;
 
begin
  F := TForm2.Create(Application);
  try
  if F.ShowModal = mrOK then begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
  end;
  finally
  F.Free;
  end;
end.
Observações
O Form2 do exemplo é o Form de Login. Este deverá ser preparado para que se possa escolher o usuário, digitar a senha, etc.

Seja você também um(a) Divulgador(a) FR Promotora e ganhe comissões vitalícias.

A FR Promotora Oferece para você a oportunidade de ganhar Dinheiro de forma inteligente e justa.


Como Divulgador você vai ganhar dinheiro com o seu trabalho e com o trabalho dos seus indicados.


Você vai ganhar 60% sobre a 1ª mensalidade dos seus indicados e 20% sobre a primeira mensalidade dos indicados deles.


A partir da 2ª mensalidade dos seus indicados e dos indicados deles, você ganhará de 8 a 17% vitalícios sobre as mensalidades deles.


Crie uma Renda superior a R$ 1.500,00

Já a partir do 3º mês de trabalho


Acesse e faça seu cadastro:



FR PROMOTORA – Desde 1998 apresentando soluções

CNPJ.: 02.773.549/0001-44

segunda-feira, 17 de outubro de 2011

Otimizando Aplicações Oracle


Melhorar a performance das aplicações Oracle depende também da forma com que você utiliza o banco e da arquitetura do servidor. Veja algumas técnicas interessantes...

UTILIZE ARRAY NA ESTRUTURA DE STORAGE DO SERVIDOR

Bancos de dados, conceitualmente, utilizam intenso acesso à discos. Por esta razão e não só para o armazenamento de grandes massas de dados, os principais fabricantes de hardware disponibilizam unidades de "storage" de alto desempenho para serem integradas à servidores de dados.
Estas unidades SCSI utilizam um conceito extremamente moderno de "arrays" de disco, que são na verdade "condomínios" estruturados para conjugar diversos discos com o objetivo de ganhar segurança no armazenamento e performance no acesso para leitura e gravação.
Quanto maior a quantidade de discos, independentemente do seu tamanho, maior a possibilidade de performance. As controladoras de "array" permitem, inclusive, que se possa balancear segurança e performance, que são inversamente proporcionais.
Isso, por si só, não quer dizer que uma estrutura de "storage" super-dimensionada elimine a necessidade de um processador adequado ou de uma quantidade de memória física condizente com a utilização do equipamento. Pelo contrário, a questão "storage" precisa estar resolvida para que se possa planejar o processador e a quantidade de memória física necessários.
É comum em servidores com problemas de contenção de discos (fila de trabalho causada pela sobrecarga na utilização do "storage"), que o processador e a memória física sejam sub-utilizados, porque como a atividade está aguardando liberação do "storage", o processador e a memória acabam sendo requisitados pela velocidade em que a fila vai sendo liberada, muito abaixo do necessário.
É algo como olharmos o trânsito na saída do pedágio da Imigrantes num feriado de carnaval por exemplo. Antes do pedágio, dezenas de quilômetros de congestionamento. Após o pedágio,se existirem 10 postos de arrecadação, saem 10 veículos por vez... Se existirem 20 postos, saem 20 veículos por vez...
Quanto menos postos de arrecadação, mais a fila cresce potencialmente. O numero de postos de arrecadação corresponderia, numa analogia, ao número de discos do array.
Quanto mais lenta a liberação da fila, menos a estrada depois do pedágio (processador e memória física) é requisitada, a despeito dos quilômetros de congestionamento antes do pedágio...
Nestes casos, assim que se resolve o problema do "storage", ficam evidentes eventuais problemas de processador e de memória.

PADRONIZE AS DECLARACÕES SQL AO MÁXIMO

O Oracle trabalha todas as requisições de usuário na SGA (System Global Área), que é um pedaço da memória do servidor reservado para uso exclusivo do banco de dados.
Dentro da SGA, entre outras, o Oracle mantém uma área para compartilhamento de SQL, também chamado "pool compartilhado". Todas as declarações SQL são executadas dentro desse "pool".
Quando recebe uma declaração SQL, antes de carregá-la no "pool" o banco verifica se ela já existe. Se existir, a declaração já existente é executada. Isso aumenta a performance na resposta da declaração SQL. Desta forma, fazer várias declarações SQL idênticas, mas escritas de forma diferente, impede o banco de procurar respostas mais rápidas. Por exemplo:
SELECT * FROM CLIENTES WHERE CODIGO = 10;
Não é igual a
Select * from clientes where código = 10;
Se ambas as declarações forem escritas de forma idêntica, o tempo de resposta da segunda será menor. Agora imagine quantas vezes isso acontece dentro da sua aplicação. Percebeu quanto tempo pode ser economizado?

CRIE TABELAS DE ELEVADO CRESCIMENTO EM DATAFILES SEPARADOS

As tabelas da sua aplicação que potencialmente forem crescer muito rápido, isto é, tiverem uma elevada taxa de crescimento, você deve criar em DATAFILES separados, ou até mesmo em TABLESPACES separadas se preferir.
Isso irá diminuir consideravelmente a fragmentação das informações, e conseqüentemente melhorar a performance.

UTILIZE CORRETAMENTE ÍNDICES

A adequada utilização de índices contribui consideravelmente para melhorar o tempo de resposta das consultas SQL. Ao criar um índice, você dá ao banco a oportunidade de não ter que procurar informações na tabela inteira (operação chamada de "full scan") e de encontrá-las mais rapidamente através das estruturas dos índices.
Assim você deve criar índices:
- para indexar as colunas utilizadas nas cláusulas WHERE ou AND de uma declaração SQL;
- para indexar colunas que se referenciam a chaves-primárias de outras tabelas, ou seja, utilizadas em constraints foreign key;
Aqui uma consideração importante que você provavelmente vai ter dificuldade de encontrar em literaturas, mas que vivemos muito na "vida real".
O Oracle tem muita dificuldade em resolver através de índices a condição <> (diferente de). Assim, evite ao máximo usar esta condição em SELECTS que envolvam tabelas potencialmente grandes.

Pequenos segredos do Delphi


Irei falar sobre algumas palavras que vemos no Delphi e às vezes não sabemos de onde a mesma vem e nem o que existe por trás da mesma.
Mas também, falarei de algumas palavras chaves do Delphi.

Result


A primeira delas que veremos é a palavra Result. Quando implementamos uma função (método):


{...}


type


TForm1 = class(TForm)


private


{ Private declarations }


function Soma(pnSoma1, pnSoma2: Double): Double;


public


{ Public declarations }


end;


{...}


function TForm1.Soma(pnSoma1, pnSoma2: Double): Double;


begin


Result := pnSoma1 + pnSoma2;


end;


Já parou para pensar de onde vem Result?


R. Eu já :-).


Result é uma variável. Cada função (ou método) declara implicitamente a variável Result, cujo, o tipo da variável é o mesmo tipo de retorno da função declarada. No exemplo acima, é do tipo Double. Result não é uma variável Local ela é semelhante a um parâmetro var oculto, já declarado no cabeçalho da function (isso ocorre nos bastidores).


Uma dica: O Delphi pode falhar ao inicializar a variável Result, principalmente em alguns casos envolvendo o retorno de String, Arrays Dinâmicos e Variant. Nesses casos, por segurança, deve-se inicializar a mesma com: String Vazia, Array Vazio e ou Unassigned (declarada na Uses Variants do Delphi 7).


Self


E Self?


R. Eu já (de novo) :-).


Self assim como Result é uma variável. Self só é visível em Métodos que pertencem a uma Classe e não é visível em Functions e Procedures normais. Self é um parâmetro oculto e tem como valor a Referência ao Objeto ou, se for o caso de um Método de Classe (Class methods) Self é a Referência da Classe.


No exemplo acima do método Soma, Self receberia o valor de: TForm1. Uma coisa interessante é, os métodos possuem um with Self do implícito no corpo do método, isto é, é por isso que quando fizemos o seguinte no corpo de um método não precisamos colocar Self:


function TForm1.Soma(pnSoma1, pnSoma2: Double): Double;


begin


Caption := 'Artigo escrito por AHR';


Close;


{...}


end;


Como o método está envolvido num with Self do implícito (como já explicado) não precisamos fazer:


Self.Caption, Self.Close, etc, etc.


Const


E const?


R. Você deve estar cansado de ler (Eu já)......


Const é uma palavra chave, não é uma variável inicializada implicitamente (pelo compilador) como Self e Result (explicados mais acima). A palavra Const não possui mistério algum para explicar. O que tem de mistério para explicar na palavra chave const é como a mesma se comporta conforme a sua declaração e se ligarmos (no Delphi 7) a diretiva de compilação {$J+} ou {$WRITEABLECONST ON}. Const pode ser de dois tipos:


Constantes (propriamente dita) ou Constantes Tipificadas.


Constantes (constantes mesmo!) é como estamos acostumados a trabalhar, isto é, não podemos modificar o seu valor dentro de rotinas, por que, o próprio compilador impõe essa restrição, onde, se você tentar mudar o valor da mesma, o compilador irá emitir uma mensagem de erro.


Constantes Tipificadas não é realmente uma constante, e sim, uma variável inicializada, isto é, o Delphi trata a mesma como sendo uma variável. Mas, existe uma diferença entre constantes tipificadas e variáveis normais locais, Constantes tipificadas mantém o seu valor entre as chamadas de rotinas, coisa que não acontece com uma variável local normal, onde, a mesma sempre será “inicializada” conforme o seu tipo.


Vamos aos exemplos para ficar mais claro:


implementation


{$J+}


// Ou {$WRITEABLECONST ON}


const constMesmo = 42;


constTipificada: Integer = 7;


consObjeto: TForm = nil;


{$J-}


// Ou {$WRITEABLECONST OFF}


{$R *.dfm}


No exemplo acima eu liguei a diretiva de compilação {$J+} (também poderia ser: {$WRITEABLECONST ON}), do qual indica que poderemos mudar o valor da “constante” (mas lembre-se, mesmo ligando a diretiva, ainda necessito especificar o Tipo para a mesma ser realmente Constante Tipificada):


procedure TForm1.Button1Click(Sender: TObject);


begin


//constMesmo := 10;


constTipificada := 10;


consObjeto := TForm1.Create(Self);


consObjeto.Name := 'TESTE';


ShowMessage(IntToStr(constTipificada));


ShowMessage(consObjeto.Name);


end;


Ao colocarmos o código no Evento OnClik do Botão (que foi adicionado no Form), podemos perceber que nem o compilador e muito menos em tempo de execução tivemos alguma mensagem de erro. Mas, como citado, só podemos modificar o valor de constTipificada e consObjeto, pois, ambas foram declaradas com o seu tipo, tornando assim, ambas como constantes tipificadas. Quis também usar um Objeto para vermos que também podemos fazer o uso de variáveis incializadas com Objetos.


Mesmo ligando as diretivas acima, constMesmo é constante mesmo, isto é, não podemos modificar o seu valor, se tentarmos, receberemos uma mensagem de erro do compilador do Delphi. Para fazermos o teste, basta retirarmos o comentário de constMesmo.


Vamos colocar um novo botão no Form para testarmos outro aspecto das constantes tipificadas, que é (como já citado) o fato de Constantes tipificadas manterem o seu valor entre as chamadas de rotinas.


Exemplo:


procedure TForm1.Button2Click(Sender: TObject);


begin


ShowMessage(IntToStr(constTipificada));


constTipificada := constTipificada + 10;


end;




Ao clicarmos novamente no Botão:




E se clicarmos novamente, irá sempre adicionar mais 10 (Dez) ao valor da constante tipificada, conforme o código do exemplo do Button2.


No Delphi 7 tanto {$J} como {$WRITEABLECONST OFF} por Default estão desligados, então (isso não acontecia em versões anteriores), sendo assim, constantes tipificadas são verdadeiramente constantes.


Class


A palavra chave Class também não tem mistérios. O que existe de diferente é a forma como a mesma pode ser declarada. Isto é, conforme a declaração podemos ter muitas nuances com a mesma palavra, exemplo:


type


TForm1 = class(TForm)


private


public


end;


{...}


É a forma normal que usamos no dia a dia, e estamos apenas indicando (a IDE fez este trabalho acima por nós) que TForm1 herda da Classe TForm.


Já:


TCustomForm = class;


É uma declaração antecipada (chamada de: Forward declarations), onde estamos apenas dizendo ao compilador que a classe será declarada mais adiante na rotina. Se olharmos o fonte da unit: Forms.pas veremos muitas declarações deste tipo.


Já:


TFormClass = class of TForm;


É uma declaração do tipo MetaClasse. Onde, uma MetaClasse é uma variável que pode armazenar uma referência da classe que poderá ser usada em qualquer expressão que exija a referência de classe, como ao chamar um construtor ou método de classe.


Observação: Citei em várias partes do Artigo Referência de Classe, não se preocupe, mais a frente eu explico com detalhes o que é uma Referência de Classe.


Já:


type


TAlgumaClasse = class


public


class function AlgumaFunction(Operation: string): Boolean; virtual;


class procedure AlgumaProcedure(var Info: TFigureInfo); virtual;


{...}


end;


O principal da declaração é:


class function AlgumaFunction(Operation: string): Boolean; virtual;


class procedure AlgumaProcedure(var Info: TFigureInfo); virtual;


O cabeçalho e o corpo da implementação devem começar com: class function.


Class method é um método que opera sobre a classe e não sobre a instância dessa classe. Eles podem ser executados sem a necessidade se criar o objeto da classe.


IS


O operador is não tem mistérios, is é uma palavra chave e ele apenas testa se o tipo de referência do objeto é igual a uma referência de classe e ou de uma das suas classes derivadas. Mas, nas internas o operador is chama o método InheritsFrom do Objeto para saber o seu tipo correto. A dica do operador is é, ao testar o objeto com is não é necessário usar o operador as, neste caso, faça um type casting simples para conseguir um melhor desempenho.


NIL


É um valor do tipo Pointer especial (Pointer(0)). Seu valor numérico é 0 (Zero). O uso mais comum para NIL é marcar variáveis do tipo Pointer e métodos para um valor desconhecido. Um exemplo seria o manipulador de eventos, onde, podemos atribuir o mesmo para nil:


Button1.OnClick := nil;


Não fizemos nada de mais no exemplo acima, apenas “matamos” o endereço do método.


Uma característica e curiosidade, o Delphi armazena um Array Dinâmico e String longa como um ponteiro nil.


with


O que with faz é apenas acrescentar uma referência de registro, Objeto, Classe e ou Interface ao escopo para resolver nomes de símbolo.


Diferença entre TStrings e TStringList


Já parou para pensar qual a real diferença entre TStrings e TStringList?


R. Eu já ;-).


Listas de Strings estão por toda a parte, na VCL, no Mar, no Ar e até mesmo em Marte! ;-). Brincadeiras a parte, elas estão por todo o lugar mesmo: Caixa de Listas, Controles de Edições, Controle de Menu, Listas de Strings, etc, etc. Apesar de serem fáceis de usar e bastante funcional, ela vitima muitos desenvolvedores com a seguinte pergunta:


E agora? Uso TStrings ou TStringList? No fundo, qual a diferença entre elas?


R.: A combinação de ambas!


TStrings é uma classe que define todo o comportamento associado a lista de Strings. Entretanto, TStrings não tem qualquer método e/ou recursos para realmente manter a lista de Strings. Os descendentes de TStrings é que são responsáveis por isso, neste caso, TStringList. Ok, Ok.... então agora não necessito mais usar TStrings e apartir de agora só usarei TStringList! Certo?


R.: Errado!


Fazendo isso você perde um poderoso recurso da Classe TStrings, que é o recurso de cópia de uma Lista de String para outra Lista de String, usando o método Assign. Diante disso, você deve declarar a variável como TStrings e na criação da mesma, criar usando a referência de classe TStringList, já que TStringList é herdada de TStrings.


Algo como:


procedure TForm1.FormCreate(Sender: TObject);


var


sStrings: TStrings;


begin


sStrings := TStringList.Create;


{...}


end;


Um exemplo do que estou falando seria observar o comportamento da Classe TCustomRadioGroup (Extctrls.pas), onde, o campo de armazenamento interno FItems é declarado como TStrings, mas, ao observarmos o constructor do mesmo, podemos ver que FItems é atribuída a uma ocorrência de TStringList.


A dica de TStrings x TStringList pode servir mais para os criadores de componentes!


Diferença entre Objetos e Classes


Um outro fato que eu vejo em alguns colegas, é a dúvida do que é uma Classe, Um Objeto e até mesmo um Componente?


Classes


Classes são (pelo menos pense assim) como um Super Registro, onde podemos declarar e descrever métodos, propriedades e campos. Quando declaramos uma classe em Delphi (como em quase toda linguagem de programação que conheço, seja: C#, C++, etc) definimos níveis diferentes de acesso aos “dados” contidos na classe, através de Private, Protected, Public, Published (ou até mesmo Automated). Uma classe (em Delphi) herda de outra classe, onde desta forma, herda todos os campos, métodos e propriedades. Se não declaramos uma classe ancestral o Delphi automaticamente coloca TObject como sendo a classe ancestral.


Quando cito e falo em Referências de Classes (citado algumas vezes nesse artigo) ela é na realidade uma expressão que denomina uma classe específica. Referências de Classes são ponteiros para a tabela de informações de tempo de execução (VMT). Quando testamos uma classe com o operador is (explicado acima) você está testando a referência de classe. Classes são sempre apenas para leitura e residem na memória de Leitura.


Objetos


Um objeto é a instância dinâmica de uma classe. É no objeto é que podemos “escrever” e executar operações, isto é, Objetos não são apenas para Leitura conforme a Classe. Você cria o objeto usando a referência da classe, chamando o seu constructor. Exemplo:


oObjeto := TMinhaClasse.Create;


Já a referência de Objeto é o trecho de memória onde o Delphi armazena os valores para todos os campos do Objeto, a referência de objeto é um ponteiro para o objeto. Quando criamos um Objeto dinamicamente, somos os responsáveis por liberar tal objeto, usando:


oObjeto.Free;


sempre envolto num bloco try...finally...end; o Delphi não possui coleta de Lixo automática (Garbage Collector) como acontece no .NET, JAVA, SmallTalk, etc.


Componentes


Explicar o que é um componente é o mais simples. Componente é tudo aquilo (se falando em Delphi, esqueça o COM - Component Object Model) que você pode manipular num formulário Delphi. Todo componente tem que obrigatoriamente herdar da Classe TComponent no seu mais alto nível ancestral.


Conclusão


A intenção do artigo era apresentar algumas palavras usadas no dia a dia do Delphi do qual não tínhamos certeza de onde as mesmas vinham e como se comportavam. Espero ter esclarecido algumas dúvidas e estou aberto à sugestão e/ou troca de idéias.

quarta-feira, 12 de outubro de 2011

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;

Código usados pelas impressoaras HP

Veja abaixo alguns códigos usados pelas impressoras HP:

RESET = 027/069
BOLD1 = 027/040/115/051/066
BOLD0 = 027/040/115/048/066
ITALIC1 = 027/040/115/049/083
ITALIC0 = 027/040/115/048/083
UNDERLINE1 = 027/038/100/049/068
UNDERLINE0 = 027/038/100/064
LPI6 = 027/038/108/054/068
LPI8 = 027/038/108/056/068
CPI5 = 027/040/115/053/072
CPI6 = 027/040/115/054/072
CPI8 = 027/040/115/056/072
CPI10 = 027/040/115/049/048/072
CPI12 = 027/040/115/049/050/072
CPI17 = 027/040/115/049/054/046/054/055/072
CPI20 = 027/040/115/050/048/072

Adicionando a soma de Fields no QRExpression do QuickReport

QRExpr1.Expression := Sum(Field1);
QRExpr2.Expression := Sum(Field2);
QRExpr3.Expression := Sum(Field1+Field2);

segunda-feira, 3 de outubro de 2011

Formatando 0000780 para 7,80

Para converter o conteuro 0000780 para, escreva o seguinte código:

procedure TForm1.Button1Click(Sender: TObject);
var
     conteudo: string;
     Valor: currency;
begin
     conteudo := '0000780';
     Valor := StrToFloat(conteudo) / 100;
      ShowMessage(Format('%m', [Valor]));
end;


Também daria para jogar para um componete TEdit. Ficaria Assim:

procedure TForm1.Button1Click(Sender: TObject);
var
     conteudo: string;
      Valor: currency;
begin
     conteudo := '0000780';
     Valor := StrToFloat(conteudo) / 100;
      edit1.text := Format('%m', [Valor]);
end;

Como criar um form completo com botões dinamicamente

Você pode criar qualquer componente do delphi de forma dinãmica, incluindo todos os componentes visuais(buttons, textedits, maskedits, labels). Para que serviria isso? Para muitas coisas, uma delas é que vocÊ pode criar qualquer controle em tempo de execução e depois de utiliza-lo descarrega-lo da memória...

Exemplo:  Como Criar um botão quando o mouse for pressionado e associar eventos nele....

É só colar dentro da unit da form....

=========inicio do copia e cola==========

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
  procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
  procedure FormCreate(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;

var
  Form1: TForm1;
  contador:integer;
implementation

{$R *.DFM}
uses stdctrls;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var b:tbutton;
begin
  b:=Tbutton.create(self);
  b.visible:=false;
  b.parent:=self;
  b.left:=x;
  b.top:=y;
  b.name:='Btn'+inttostr(contador);
  b.Caption:='Clique-me';
  inc(contador);
  b.visible:=true;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
contador:=1;
end;

end.
============fim do copia e cola==========

Se quiser associar um evento ao botao é só copiar os procedimento clicou e alterar

o procedmento mouse down para o que segue....

=======inicio do copia e cola

 procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var b:tbutton;
begin
  b:=Tbutton.create(self);
  b.visible:=false;
  b.parent:=self;
  b.left:=x;
  b.top:=y;
  b.name:='Btn'+inttostr(contador);
  b.Caption:='Clique-me';
  inc(contador);
  b.visible:=true;
  b.onclick:=clicou;
end;

procedure TForm1.clicou(sender: TObject);
begin
ShowMessage('Clicou!!!');
end;

=====fim do copia e cola======

Com isto concluimos que podemos criar qualquer coisa em tempo de execução com economia de memória. BAsta para isso dar o create da classe....

Para apagar o botao devemos ter cuidado para não apagar dentro do evento visto que

gerara uma exceção. Existe duas formas de se contornar isto, a primeira é fornecendo um atraso

e a segunda é atraves de uma API do windows mas isto fica para os proximos e-mails..

Como Criar Forms Em Tempo de Execução

Para você economizar memória, pode-se criar os forms de sua aplicação somente no momento da execução. Na criação do Form você define se ele é MODAL ou NÃO MODAL. Para Isso observe os seguintes códigos:

MODAL - Mostra form em modo exclusivo

procedure TForm1.Button1Click(Sender: TObject);
begin
Application.CreateForm(TForm2, Form2);{Carrega form na memória}
Form2.ShowModal;{Mostra form em modo exclusivo}
Form2.Free; {Libera Memória}
end;
NÃO MODAL - Mostra form em modo não exclusivo

procedure TForm1.Button1Click(Sender: TObject);
begin
Application.CreateForm(TForm2, Form2);{Carrega form na memória}
Form2.ShowModal;{Mostra form em modo exclusivo}
end;
No evento OnClose do Form2 coloque o seguinte código.

procedure TForm2.FormClose (Sender: Tobject; var Action : TCloseAction);
begin
Action:= caFree;
end;
Aliado a este código, deve deve alterar no delphi, no menu Options, opção Project. Mudando os forms a serem criados dinamicamente da coluna Auto-Create Forms para Avaliable Forms. a

A melhor maneira de liberar um form da memoria

Quando você usa Form.Free ou Form.Destroy, você está imediatamento solicitando a destruição do formulário. Com Form.Release, todas as mensagens pendentes no pool do formulário são postadas - exemplo: redesenho do formulário, movimento do mouse, pressionamento de tecla,...
 
Use assim:

FormXX := TFormXX.create ( application );
try
  FormXX.ShowModal
finally
  FormXX.Release;
  FormXX := nil;
end;

Adaptando para resoluções de video diferentes?

Sempre que procurei algo sobre esse tema, ia para no Tip da Borland #2861, que é a mesma informação do arquivo de help da Loyd’s. Esse texto tambem aparece nos bancos de dados da Q&A. Eu suponho que essa seja a informação definitiva. Encontreiuma informação que não foi mencionada aqui. Pela lista de correiros do Delphi-Talk havia mensagens de Brien King e MichaelNovak que discutiam esse assunto.

***

LOYD´S TIPS:

Resolução de Vídeo:

Quando criamos formulários, as vezes é útil escrever um código para que a tela e todos os seus objetos sejam mostrados nomesmo tamanho, não importando qual a resolução da tela. Aqui esta um código que mostra como isso é feito:

Implementation
const
ScreenWidth: LongInt = 800; {I designed my form in 800x600 mode.}
ScreenHeight: LongInt = 600;
{$R *.DFM}
procedure TForm1.FormCreate (Sender: Tobject);
begin
scaled := true;
if (screen.width <> ScreenWidth) then
begin
height := longint(height) * longint(screen.height) DIV ScreenHeight;
width := longint(width) * longint(screen.width) DIV ScreenWidth;
scaleyBy(screen.width, ScreenWidth);
end;
end;
Agora, você vai querer checar, se o tamanho dos fontes(de letra) estão OK. Antes de trocar p tamanho do fonte, você precisará ter

certeza de que o objeto realmente tem a propriedade fonte pela checagem da RTTI. Isso pode ser feito assim:

USES typinfo; {Add this to your USES statement.}
var
i:integer;
begin
for i := componentCount - 1 downto 0 do
with components[i] do
begin
if GetPropInfo(ClassInfo, ´font´) <> nil then
font.size := (NewFormWidth DIV OldFormWidth) * font.size;
end;
end;
{Esta é a maneira longa de fazer a mesma coisa}

var
i:integer;
p:PPropInfo;
begin
for i := componentCount - 1 downto 0 do
with components [i] do
begin
p := GetPropInfo (ClassInfo, ´font´);
if assigned (p) then
font.size := (NewFormWidth DIV OldFormWidth) * font.size;
end;
end;
Atenção: Nem todos os objetos tem a propriedade FONT. Isso deve ser o suficiente para você começar.

Atenção: A seguir, algumas dicas para ter em mente quando representar aplicações Delphi (formulários) em diferentes resoluçõesde Tela:

* Decida antecipadamente, na etapa de criação do formulário, se ele será escalável ou não. A vantagem de um não escalável é que nada muda em tempo de execução. A desvantagem é equivalente (seu formulário pode ser muito pequeno ou grande para alguns sistemas se nào for usada escala).

* Se você não for usar formulário escalável, configure o set scaled to False.

* Ou então, configure a propriedade scaled do formulário para True.

* Configure a propriedade AutoScroll para False. AutoScroll = True quer dizer "não mexa no tamanho do frame do formulário em tempo de execução", o que não parece bom quando o conteúdo do formulário muda de tamanho.

* Configure a fonte do formulário para uma True Type escalável, como a Arial MS. San Serif é uma boa alternativa, mas lembre que ainda é uma fonte bitmapped. Só a Arial dará uma fonte dentro de um pixel da altura desejada.ATENÇÃO: Se a fonte usada em uma aplicação não estiver instalada no computador, o Windows selecionará uma fonte alternativa da mesma família para utilizar. O tamanho dessa fonte pode não corresponder ao da fonte original, podendo causar problemas.

* Configure a propriedade position do formulário para uma opção diferente de poDesigned. poDesigneddeixa o formulário onde você o deixou ( no design Time), o que sempre termina fora da margem, à esquerda da minha tela 1280 x 1024 - e completamente fora da tela 640 x 480.

* Não amontoe controles no formulário - deixe pelo menos 4 pixels entre else, para que uma mudança de um pixel nas margens (devido a apresentação em escala) não mostre controles sobrepostos.

* Para labels de uma linha alinhadas ã esquerda ou à direita, configure o AutoSize para True. Para outras formas de alinhamento configure o AutoSize para False.

* Tenha certeza de que há espaço em branco suficiente num componente de labels para alterações no tamanho da fonte – um espaço de 25% do comprimento da linha de caracteres mostrada é um pouco a mais do que se precisa, mas é mais seguro. (Você vai precisar de um espaço equivalente a 30% de espansão para string labels se você pretende traduzir sua aplicação para outra linguagem). Se o Autosize estiver em False, tenha certeza de que realmente configurou o tamanho do label corretamente. Se o Autosize estiver em True, esteja certo de que há espaço suficiente para que o label se amplie.

* Em labels de múltiplas linhas ou de termos ocultos, deixe pelo menos uma linha em branco na base. Isso vai ser necessário para incluir o que estiver sobrando quando o texto for oculto de maneira diferente, pela mudança do tamanho da fonte com a escala. Não assuma isso porque está usando fontes grandes. Você não tem que deixar sobra de texto - as fontes (grandes) de outros usuários podem ser maiores que as suas!

* Tenha cuidado quando abrir um projeto em IDEs com resoluções diferentes. Assim que o formulário for aberto, sua propriedade Pixel per Inch será moditificada, e gravada para o DFM se você salvar o projeto. É melhor testar a aplicação rodando sozinho, e editar o formulário em apenas uma resolução. Editar em várias resoluções e tamanhos de fonte provoca problemas de fluxo e tamanho dos componentes.

*Falando em fluxo de componentes, não represente o formulário em escala muitas vezes, quando estiver sendo criado ou quando tiver sendo executado. Cada escala introduz erros de roundoff que se acumulam muito rapidamente, uma vez que as coordenadas são rigorosamente interias. Quando valores fracionários forem retirados das origens e tamanhos do controle com cada sucessiva representação em escala, os conttroles parecerão deslizar para noroeste e ficar menores. Se você quer deixar seus usuários representarem o formulários em escala quantas vezes quiserem, comece com um formulário recentemente criado para que erros de escala não se acumulem.

* Definitivamente, não mexa na propriedade Pixel pre Inch do formulário.

* Em geral, não é necessário criar formulários em uma resolução específica, mas é essencial que você os revise em 640 x 480 com fontes pequenas e/ou grandes, e em alta resolução com fontes pequenas e/ou grandes antes de liberar suas aplicações. Isso deverser parte de sua lista de conferência para testar a compatibilidade do sistema regularmente.

* Preste bastante atenção em todos os componentes que são basicamamente TMemo de uma linha - com oTDBLookupCombo. O controle de edição (multi-linhas) do Windows sempre mostra apenas linhas inteiras de texto. Se o controle for muito curto para sua fonte, um TMemo não mostrará coisa alguma, e um TEdit mostrará um pedaço do texto. É melhor fazer esses componentes um pouco maiores do que deixá-los um pixel menores e não aparecer nada do texto.

* Tenha em mente que toda representação em escala é proporcional à diferença da altura da fonte entre o modo de execução e o modo de desenho, NÃO à resolução ou ao tamanho do monitor. Lembre também que as origens dos seus controles serão alteradas quando o formulário for representado em escala. Você não pode aumentar componentes muito bem sem também movê-los um pouco, novamente.

Obtendo e modificando a posição do cursor em um TMemo

Modificando a posição:

ActiveControl:=Memo1;

MemoCursorTo(Memo1,2,3);

Obtendo a Posição:

GetMemoLineCol(Memo1,Linha,Coluna);