Arquivo do mês: outubro 2007

Como retornar múltiplos resultados numa função?

Você já teve a necessidade de retornar múltiplos valores numa função? normalmente a primeira idéia é criar uma procedure com parâmetros passados por referência como abaixo:

procedure GetCalculo(const Valor1, Valor2:Double; var Soma, Media:Double);
begin
Soma := Valor1 + Valor2;
Media := Soma / 2;
end;

//Testando
procedure TForm1.Button1Click(Sender: TObject);
var
Soma, Media:Double;
begin
GetCalculo(100,50,Soma,Media);
ShowMessage(‘Soma: ‘+FloatToStr(Soma)+#13+’Media: ‘+FloatToStr(Media));
end;

Isso funciona perfeitamente, mas veja que precisei declarar as funções que vou receber. Agora imagina se fosse 10 valores no retorno! além da procedure ficar imensa você ainda teria que declarar as variáveis que seriam passadas como referência. Uma técnica mais elegante de fazer isso é criar um record e usar esse tipo na nossa função. Veja o exemplo acima alterado.

//definindo o tipo
type
TCalculo = record
Soma,
Media:Double;
end;

Form1 = Class(TForm)

implemetation

function TForm1.GetCalculo(const Valor1, Valor2:Double):TCalculo;
begin
//Repare que o result agora pode receber vários resutados
Result.Soma := Valor1 + Valor2;
Result.Media :=
Result.Soma / 2;
end;

//Testando
procedure TForm1.Button1Click(Sender: TObject);
var
Calculo: TCalculo;
begin
Calculo := GetCalculo(100,50);
ShowMessage(‘Soma: ‘+FloatToStr(Calculo.Soma)+#13+’Media: ‘+FloatToStr(Calculo.Media));
end;

Com eu falei, não existe muita diferença nessa técnica com a passagem por parâmetros se considerarmos o número de parâmetros, mas com certeza numa função que retorna vários resultados, a segunda opção tornará o seu código muito mais legível e elegante. Até a próxima.



Função para validar CPF no SQL Server

Olá pessoal, não sou DBA, muito menos um expert em PSQL, mas como diz o ditado “quem está na chuva é pra se molhar”. Então depois de um necessidade de ter uma validação de CPF no banco, criei essa function pra SQL Server, façam um bom proveito!

/*
Autor: Cristiano Martins Alves
Para testar: SELECT DBO.CPF_VALIDO(’16195473247')
*/
CREATE FUNCTION CPF_VALIDO(@CPF VARCHAR(11))
RETURNS CHAR(1)
AS
BEGIN
	DECLARE @INDICE INT,
	@SOMA INT,
	@DIG1 INT,
	@DIG2 INT,
	@CPF_TEMP VARCHAR(11),
	@DIGITOS_IGUAIS CHAR(1),
	@RESULTADO CHAR(1)

	SET @RESULTADO = ‘N’

	/*
	Verificando se os digitos são iguais
	A Principio CPF com todos o números iguais são Inválidos
	apesar de validar o Calculo do digito verificado
	EX: O CPF 00000000000 é inválido, mas pelo calculo
	Validaria
	*/

	SET @CPF_TEMP = SUBSTRING(@CPF,1,1)

	SET @INDICE = 1
	SET @DIGITOS_IGUAIS = ‘S’

	WHILE (@INDICE <= 11)
	BEGIN
		IF SUBSTRING(@CPF,@INDICE,1) @CPF_TEMP
		SET @DIGITOS_IGUAIS = ‘N’
		SET @INDICE = @INDICE + 1
	END;

	--Caso os digitos não sejão todos iguais Começo o calculo do digitos
	IF @DIGITOS_IGUAIS = ‘N’
	BEGIN
		--Cálculo do 1º dígito
		SET @SOMA = 0
		SET @INDICE = 1
		WHILE (@INDICE <= 9)
		BEGIN
			SET @Soma = @Soma + CONVERT(INT,SUBSTRING(@CPF,@INDICE,1)) * (11 – @INDICE);
			SET @INDICE = @INDICE + 1
		END

		SET @DIG1 = 11 – (@SOMA % 11)

		IF @DIG1 > 9
		SET @DIG1 = 0;

		-- Cálculo do 2º dígito }
		SET @SOMA = 0
		SET @INDICE = 1
		WHILE (@INDICE <= 10)
		BEGIN
			SET @Soma = @Soma + CONVERT(INT,SUBSTRING(@CPF,@INDICE,1)) * (12 – @INDICE);
			SET @INDICE = @INDICE + 1
		END

		SET @DIG2 = 11 – (@SOMA % 11)

		IF @DIG2 > 9
		SET @DIG2 = 0;

		-- Validando
		IF (@DIG1 = SUBSTRING(@CPF,LEN(@CPF)-1,1)) AND (@DIG2 = SUBSTRING(@CPF,LEN(@CPF),1))
			SET @RESULTADO = ‘S’
		ELSE
			SET @RESULTADO = ‘N’
	END
	RETURN @RESULTADO
END

Dica: Permitir apenas uma instância da aplicação.

As vezes necessitamos limitar a abertura de apenas uma instância da nossa aplicação. O objetivo aqui é demonstrar como fazer isso:

Abra o fonte do seu arquivo DPR e adicione na uses as seguintes units:

uses
System, Windows,

E codifique como o exemplo abaixo

var
Instancia: THandle;
begin
Instancia:= CreateMutex(nil, false, ‘InstanciaIniciada’);
if WaitForSingleObject(
Instancia, 0) = wait_Timeout then
begin
Application.MessageBox(‘Atenção o programa já está aberto!.’,’Atenção’,MB_ICONINFORMATION);;
Exit;
end;

Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

Nesse exemplo criamos um objeto do tipo THandle chamado instancia, em seguida instanciamos o objeto com o nome da nossa janela (InstanciaIniciada), a apartir dai verificamos se já existe uma instância rodando com WaitForSingleObject, caso exista exibimos a mensagem para o usuários e fechamos a aplicação.


Dica: Utilizar formatos diferentes no FormatFloat

Muitas vezes temos a necessidade de formatos diferentes para números POSITIVOS e NEGATIVOS. O que pouca gente sabe é que o FormatFloat faz isso pra nós! Podemos passar no parâmetro format, uma string com os dois formatos separados por ; (ponto e vírgula)
veja:

ShowMessage(FormatFloat(‘R$ 0.00,;”(“R$ 0.00,”)”‘,-1500)); //Número negativo entre parênteses
ShowMessage(FormatFloat(‘R$ 0.00,;R$ 0.00,-‘,-1500)); //Número negativo com sinal a direita
ShowMessage(FormatFloat(‘R$ 0.00,;R$ 0.00,-‘,1500)); //Número positivo


Dica: Form sem barra de títulos. Utilizando API

Muitas vezes precisamos de um form sem barra de títulos quando a idéia é apenas exibir uma informação ao usuário. Sabemos que se alterarmos a propriedade BorderStyle para none conseguimos esse efeito, no entanto o visual não é muito bom, o form fica com uma aparência FLAT e nem sempre é o que queremos (a menos que seja um Splash).

Crie um novo projeto no delphi, coloque o Label e defina as seguintes propriedades:
Align: alClient
Alingment: taCenter
Layout: tlCenter

Seu form deve se parecer com este

Deixe o form com o tamanho que desejar. E no evento onCreate coloque.

procedure TForm1.FormCreate(Sender: TObject);
begin
{Removendo Barra de tírulos}
SetWindowLong(Handle,GWL_STYLE, GetWindowLong(Handle, GWL_STYLE ) and not WS_CAPTION);
end;

Veja a diferença entre as duas técnicas

Utilizando a API

Utilizando BorderStyle = bsNone

Para mais informações sobre a API acesse: http://msdn2.microsoft.com/en-us/library/ms633591.aspx