sábado, 1 de agosto de 2015

Capturar a data da BIOS ( Basic Input Output System ) do computador

Insira um objeto do tipo Button com a propriedade name definica como Button1 e um objeto do tipo Label com a propriedade definida como Label1.

procedure TForm1.Button1Click(Sender: TObject); 
begin
  Label1.Caption := 'Data da Bios: '+String(PChar(Ptr($FFFF5))); 
end; 

Como retornar a uma lista os campos indexados de um tabela

procedure TForm1.Button1Click(Sender: TObject);
var
      i : integer;
begin
     Table1.IndexDefs.Update;
     ListBox1.Items.add
    ('******** Índice Primário ********');
    for i:=0 to Table1.IndexDefs.Count-1 do
    begin
          if Table1.IndexDefs.Items[i].Options = [ixPrimary..ixUnique] then
          ListBox1.Items.add(Table1.IndexDefs.Items[I].Fields)
    else
         begin
              ListBox1.Items.add('');
              ListBox1.Items.add
              ('**** Índice Secundário ****');
              Listbox1.Items.Add(Table1.IndexDefs.Items[I].Name); 
          end;
     end; 
end;
  

Como filtrar registros de uma tabela pelo mês de um campo data

Você pode usar a função DecodeDate( ) no evento onFilterRecord de um componente TTable.

Ex.:

// não se esqueça de mudar a propriedade Filtered para True;
// isto fará com que o evento onFilterRecord seja disparado.

procedure TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
var
  Dia, Mes, Ano: word;
begin
  Accept := false;
  DecodeDate(Table1['Competencia'],Ano,Mes,Dia);
  if Mes=MesFiltrado then
  Accept := True;
end;
Obs.: Você pode usar este mesmo código para filtrar por Ano ou por Dia, basta utilizar a comparação adequada no bloco if ... then

Como diminuir o tempo de abertura do TTable e TQuery

Operação feita quando é executado o método Open do componente TTable ou TQuery, que produz a compilação e execução do comando select. Quando esse método é executado através do componente TTable, o Delphi realiza uma série de outros comandos SQLs para buscar informações do catálogo da tabela necessárias para as operações de seleção e atualização. Essa busca pode ser otimizada através da opção ENABLE SCHEMA CACHE do BDE, fazendo com que essas informações sejam lidas apenas uma vez durante a execução da aplicação. Quando o primeiro acesso é feito, o BDE armazena as informações em um arquivo e qualquer nova necessidade de abertura da mesma tabela não necessita buscar novamente os elementos do catálogo.

Por outro lado, utilizando-se o componente TQuery, pode-se desviar dessa busca desde que não se utilize a propriedade Request Live que torna o "result set" da "query" atualizável automaticamente pelo Delphi. Se o valor da propriedade Request Live for TRUE e o SELECT utilizado obedecer as restrições para que o Delphi consiga atualizar o "result set", as mesmas buscas utilizadas para o componente TTable terão que ser feitas. 

Concluindo, para que a busca de elementos do catálogo não seja feita é necessário utilizar o componente TQuery e controlar as atualizações manualmente ou através de componentes do tipo TUpdateSQL.

sexta-feira, 31 de julho de 2015

Como formatar data para exibição por extenso

O Delphi permite formatar datas para apresentação por extenso de forma bastante simples. Vejamos os seguintes exemplos: 

Para formatar a data 18/03/1999, podemos utilizar: 

No create do form colocar

Shortdateformat :=

dddd, dd/mm/yyyy = Quinta, 18/03/1999 
dd/mmm/yyyy = 18/Mar/1999 
dddd, dd" de "mmmm" de "yyyy = Quinta, 18 de Março de 1999 
dd" de "mmmm" de "yyyy, dddd = 18 de Março de 1999, Quinta 

Função para acrescentar dias uteis a uma data

Retorna uma data acrescida de mais um certo número de dias  uteis descontando os fins de semana.

function Datafinal(dataini:tdatetime; dias_uteis:integer):tdatetime;
var dw:integer;
begin
  dw := DayOfWeek(dataini)-1;
  result := dataini+dias_uteis+((dias_uteis-1+dw) div 5)*2;
end;
  

Função para extrair o mês por extenso

unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
function MesExtenso( Mes:Word ) : string;
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

function TForm1.MesExtenso( Mês:Word ) : string; const meses : array[0..11] of PChar = ('Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro','Outubro', 'Novembro', 'Dezembro');
begin
result := meses[mes-1];
End;

procedure TForm1.Button1Click(Sender: TObject);
begin
label1.Caption := MesExtenso(3);
end;

end.

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.

segunda-feira, 27 de julho de 2015

Enviando informações direto para a impressora

Muitas vezes torna-se necessário, ou até mesmo, imprescindível que você envie informações diretamente para a impressora, uma vez que a utilização da impressão típica do Windows é um pouco demorada e o uso do driver Genérico/Somente Texto não é muito confiável.

Uma boa solução para enviar informações diretamente para a impressora é usar o seguinte código:

Procedure TForm1.Button1Click(Sender: Object);
var
    Imp: TextFile;
begin
    AssignFile(Imp, 'LPT1');
    Rewrite(Imp);
    Write(Imp, 'Isto vai sair na impressora');
    CloseFile(Imp);
end;

COMO ARRASTAR UM FORM SEM CLICAR NO CAPTION?

Quando você pressiona o botão do mouse, o Windows identifica a posição da tela onde o cursor estava no momento do clique. Se a posição é igual a área do Caption do Form, o Windows ativa o modo de movimentação do Form permitindo que este seja arrastado. Portanto, a maneira mais fácil de solucionar esta questão é "enganar" o Windows.
Neste exemplo vamos considerar que o usuário poderá arrastar o Form ao cli-car na área cliente deste Form:

a) Crie uma nova aplicação;
b) Adicione a seguinte declaração na seção private do Form:
procedure WMNCHitTest(var M: TWMNCHitTest); message wm_NCHitTest;
c) Adicione o código deste procedimento na seção implementation do Form:

procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
begin
inherited;                   { ativa a herança da mensagem }
if M.Result = htClient then { o clique foi na área cliente? }
            M.Result := htCaption;     { se sim, faz o Windows pensar que foi no Cap-tion. }
          end;

      Este exemplo tratou o clique na área cliente. Você pode alterar este código para suas necessidades. Eis os possíveis valores para o Result:

     VALOR - Local do clique
     HTBORDER - Borda da janela que não tem a borda de tamanho
     HTBOTTOM - Borda horizontal inferior da janela
     HTBOTTOMLEFT - Canto inferior esquerdo da janela
     HTBOTTOMRIGHT - Canto inferior direito da janela
     HTCAPTION - Barra de Título(Caption)
     HTCLIENT - Área cliente
     HTERROR - igual ao HTNOWHERE, a diferença é que produz um beep indicando erro
     HTGROWBOX - Caixa de tamanho (igual ao HTSIZE)
     HTHSCROLL - Barra de rolagem horizontal
     HTLEFT - Borda esquerda da janela
     HTMENU - Em um menu
     HTNOWHERE - Plano de fundo da janela ou linha de divisão entre janelas
     HTREDUCE - Botão minimizar
     HTRIGHT - Borda direita da janela
     HTSIZE - Caixa de tamanho (igual ao HTGROWBOX)
     HTSYSMENU - Botão de Sistema/Fechar da janela MDIChild
     HTTOP - Borda horizontal superior da janela
     HTTOPLEFT - Canto superior esquerdo da janela
     HTTOPRIGHT - Canto direito superior da janela
     HTTRANSPARENT - Janela em segundo plano
     HTVSCROLL - Barra de rolagem vertical
     HTZOOM - Botão maximizar

terça-feira, 14 de julho de 2015

Como tornar um servidor datasnap rest compatível com o cache off-line do HTML5


Por padrão, servidores DataSnap stand-alone WebBroker não permitem usar o "novo" HTML5 Aplicação manifesto de arquivo de cache.
Enquanto eu estava me preparando os conteúdos e as demonstrações do meu "HTML5 e aplicação web DataSnap desenvolvimento" eu configurei os componentes DataSnap para suportar esse recurso HTML5. Há apenas uma alteração a fazer ao "WebApplication REST" padrão gerado pelo assistente. No WebModuleUnit há o componente utilizado TWebFileDispatcher. Este componente tem as WebFileExtensions propriedade que é uma coleção de valores-chave contendo todas as extensões de arquivos permitidas relacionada com o mime-type.
A imagem abaixo mostra o que precisa ser configurado.

quarta-feira, 29 de abril de 2015

Função para gerar senhas aleatórias


Essa é uma dica simples e que para os que trabalham com redes sem fio pode ser muito útil. O que a função faz é gerar um string com caracteres hexadecimais, mas que podem ser adaptados para qualquer outro tipo. Esta função recebe como parâmetros o comprimento da senha como um integer, e outros três parametros do tipo boolean que indicam se estarão presentes letras minúsculas, maiúsculas e números.

Aqui vai o código e as explicações seguem logo abaixo.

function GeraSenhaHex(Digitos: Integer; Min: Boolean; Mai: Boolean; Num: Boolean): string;
const
   MinC = 'abcdef';
   MaiC = 'ABCDEF';
   NumC = '1234567890';
var
   p, q : Integer;
   Char, Senha: String;
begin
   Char := '';
   If Min then Char := Char + MinC;
   If Mai then Char := Char + MaiC;
   If Num then Char := Char + NumC;
   for p := 1 to Digitos do
   begin
      Randomize;
      q := Random(Length(Char)) + 1;
      Senha := Senha + Char[q];
   end;
   Result := Senha;
end;

Explicações:

Primeiro criamos as constantes que trarão os caracteres referentes a letras minúsculas, maiúsculas, e números, depois, iniciamos como vazia, só por desencargo de consciência já que o delphi faz isso por padrão, a variável "Char", que conterá todos os caracteres a serem usados para a geração da senha randômica.

Após isso, testamos os parâmetros para letras maiúsculas, minúsculas e números, acrescentando à "Char" cada um dos que forem verdadeiros segundo os parâmetros passados na chamada da função.

E depois, para finalizar, um laço com o número de repetições igual aos dígitos passados também como parâmetro na chamada, que usando a função Random do delphi gera números aleatórios dentro do limite estabelecido pelo cumprimento da variável "Char", lembrando que o fato de acrescentar o "+ 1" é por que as posições dos caracteres dentro de um string iniciam em 1, e a função Random gera números de 0 até o valor estipulado como limite. Por exemplo uma String = 'teste' temos os valores a seguir:

String[1] = 't'
String[2] = 'e'
String[3] = 's'
String[4] = 't'
String[5] = 'e'

segunda-feira, 9 de março de 2015

Como Identar código no Delphi

O comando para identar o código é: 

- CTRL + SHIFT + i (para avançar o código, ou seja, mover pra a direita) 
- CTRL + SHIFT + u (para retroceder o código ou mover para a esquerda). 

Lembrando de selecionar o código antes de utilizar as teclas de atalho. 

sexta-feira, 6 de março de 2015

dbExpress Suporte ao MySQL no Delphi 2010 e XE


Parece ser frequente as dúvidas relacionadas a utilização do driver dbExpress para MySQL, na grande maioria usuários das versões 2010 e XE do Delphi
O arquivo readme.html que está localizado no diretório onde o Delphi foi instalado, documenta as versões de MySQL e dos outros bancos suportados pelo dbExpress. No caso do MySQL o arquivo inclui as combinações de versões de server e bilbiotecas clientes suportadas, infelizmente o MySQL a cada nova versão traz inúmeras alterações nas API’s e acabe dificultando uma pouco nosso trabalho.

Abaixo informações que você deve saber.

Versões de servidores MySQL oficialmente suportadas e testadas.

MySQL 5.1, 5.0.27, 4.1 (Todas) (Driver dbxMYS.dll, Client libmysql.dll)

Combinação das versões de servidores e clientes MySQL que foram testadas

LibMySQL.dll (5.1.XX) Client - DBXMys.dll MySQL 4.0.XX Server
LibMySQL.dll (5.1.XX) Client - DBXMys.dll MySQL 5.0.XX Server
LibMySQL.dll (5.1.XX) Client - DBXMys.dll MySQL 5.1.XX Server
Em resumo, você tem que instalar a versão do cliente do MySQL 5.1.xx para que sua aplicação cliente funcione com servidores MySQL 4.0.XX, 5.0.XX e 5.1XX

O que fazer caso você tenha outras versões do Delphi na mesma máquina?

Caso isso aconteça o IDE poderá carregar uma das versões antigas do driver dbExpress para MySQL, isso acontece porque o diretório bin da versão anterior do Delphi está a frente na variável de sistema PATH, para resolver este problema, no menu Tools -> Options -> Environment Variables adicione o PATH da versão atual do Delphi a frente de todas as variáveis. Lembre-se que casa você use a versão anterior instalada na sua máquina, você deverá atualiza a variável de ambiente PATH novamente.

Espero que essas dicas tenham ajudado. 

Post Origial blog do Andreano.
http://www.andreanolanusse.com/pt/dbexpress-suporte-ao-mysql-no-delphi-2010-e-xe/

Usando Coalesce em Comandos SQL


Nessa dica, vou expor uma situação comum para nós desenvolvedores, que pode ser resolvida de várias formas, (como tudo em programação), mas sempre existe a forma correta ou a que vai garantir a integridade do sistema, e ainda, ser resolvida em pouquíssimo tempo.

Imaginem a seguinte situação, uma empresa possui uma entidade chamada TitulosPagar, nessa entidade estão gravados os titulos a pagar com as suas respectivas datas de vencimento. Nessa mesma entidade temos um campo chamado Prorrogado, que é preenchido quando o fornecedor concede uma prorrogação no título para que o mesmo seja pago após a data de vencimento sem juros etc.

Vocês ja devem ter imaginado que o sistema em questão possui um relatório de Titulos a Pagar em um determinado período. Certo?

Nesse caso o mesmo poderia usar o um Sql simples como o abaixo:

Select titulo, valor, vencimento
From titulosPagar
Where dataVcto between :dataIni and :dataFim

Tranquilo né. O Sql retorna todos os títulos a pagar com vencimento no período passado nos parâmetros dataIni e dataFim.

Vamos complicar, um belo dia o cliente liga para você pedindo para que nesse mesmo relatório de titulos a pagar considerasse a data de prorrogação também, ou seja deve ser listado todos os títulos analisando a data de vencimento, e também a data de prorrogação. 

Saída rápida, fazer duas querys, com dois Sql diferentes, um analisando o período pela data de vencimento e o outro analisando pela data de prorrogação, depois gravar tudo em um ClientDataSet e ligar o Client ao relatório. Beleza? Funciona com certeza, mas da um trabalhão, sem falar no tempo de processamento, dependendo o tamanho da entidade de TitulosPagar o processo será demorado.

Solução:
Criar o seguinte comando SQL.

Select titulo, valor, vencimento
From titulosPagar
Where Coalesce(Prorrogado, dataVcto) between :dataIni and :dataFim

Bingo! Temos uma query apenas, um processamento, e a solução com certeza não demorou mais que 1 minuto para alterar a query.

Sistema Fechando Sozinho


Amigos, acompanhando os grupos de discussão sobre programação e outros, percebi que muitas pessoas estão enfrentando um problema em comum.
Programas feitos em Delphi e ou VB, fechando sozinho, do nada o sistema fecha, como se alguém tivesse clicado em finalizar processo.

Também passei por isso, e depois de muitos testes descobri a causa.
O Bradesco, contratou uma empresa para desenvolver uma solução de segurança para eles, a mesma criou um processo que é inicializado quando o site do banco é aberto, e que verifica todos os outros processos que estão rodando. Caso considere o programa suspeito imediatamente encerra o processo.

Se você tem o costume de usar o compactador de exe chamado UPX, esse processo de segurança irá identificar o seu sistema como um programa malicioso ou suspeito, e irá finalizá-lo. 
Fato já comprovado! Para piorar o processo inicializado pelo site do Bradesco não é finalizado quando o browser é fechado, ou seja, para você conseguir usar o seu programa precisa reinicializar a máquina. 

sexta-feira, 15 de agosto de 2014

COMO RETIRAR SOMENTE OS NUMEROS DE UMA STRING

Segue uma função básica de como extrair de uma string somente números no formato currency.

function StrToCurr(Texto: String): Currency;
var
  nI: Integer;
  TextoLimpo: String;
begin
  TextoLimpo := '';
  For nI := 1 to Length(Texto) do begin
    if Texto[nI] in ['0'..'9',','] then
       TextoLimpo := TextoLimpo + Texto[nI];
  end;
  Result := StrToCurr(TextoLimpo);
end;

segunda-feira, 12 de agosto de 2013

ClientDataSet - Clicando no Título das Colunas do DBGrid para Ordenar


Veja nesta dica como é simples realizar a tarefa de ordenação dos dados de um DBGrid que está ligado a um ClientDataSet, criando e selecionando índices em memória.
O código abaixo mostra como realizar a ordenação clicando no titulo da coluna desejada. Clicando uma uma vez será utilizada a ordem crescente e na segunda, a ordem decrescente.

Primeiramente, no evento onCreate do Form, criaremos um índice Crescente e um Decrescente para cada campo do DBGrid, com o seguinte código:

procedure TForm1.FormCreate(Sender: TObject);
var
  i : integer;
begin
  for i := 0 to clientdataset1.FieldCount - 1 do
  begin
    CLIENTDATASET1.IndexDefs.Add('a' + CLIENTDATASET1.Fields[i].FieldName, 
      CLIENTDATASET1.Fields[i].FieldName, []);
    CLIENTDATASET1.IndexDefs.Add('d' + CLIENTDATASET1.Fields[i].FieldName,
      CLIENTDATASET1.Fields[i].FieldName, [ixDescending]);
  end;
end;
Em seguida, programaremos o evento onTitleClick do DBGrid:

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
  if 'a' + Column.FieldName = CLIENTDATASET1.IndexName then
    CLIENTDATASET1.IndexName := 'd' + column.FieldName
  else
    CLIENTDATASET1.IndexName := 'a' + column.FieldName;
end;
Pronto! Seu DBGrid em ordem Crescente e Decrescente de qualquer coluna, com apenas um click!

segunda-feira, 22 de julho de 2013

Enviando e-mails com Delphi 5

Este resumo não está disponível. Clique aqui para ver a postagem.

Repositório do Delphi


O repositório do Delphi é um local para armazenamento de objetos, como formulários e projetos, que facilita o compartilhamento desses objetos por vários projetos. Quando você clica em File|New... para criar um novo objeto, você pode escolher um dos itens do repositório.

Acrescentando um formulário ao repositório 

     Abra um projeto DPR, e dentro dele o formulário "Form" (Form1.pas). Esse formulário está sendo compartilhado dentro do mesmo projeto, mas se você quiser reutilizá-lo em outros projetos, pode acrescentá-lo ao repositório. 
     Para isso, clique com o botão direito e em Add to Repository. Você deve informar o título do item, uma descrição e qual a página onde ele será inserido (se você digitar um nome de página que não existe, uma nova será criada), além do seu nome para indicar qual o autor desse item. Opcionalmente você pode escolher um ícone que será usado para representar o item. Para o exemplo digite o seguinte: 

   Title: Formulário para uma tabela
   Description: Formulário de banco de dados para uma tabela
   Page: Forms (default)
   Author: seu nome 

     O botão "Browse" permite você procurar um ícone , para representar sua classe de formulário, caso não informe ele irá mostrar o seguinte ícone . Clique Ok. O novo item será adicionado ao repositório. Agora crie um novo projeto com File|New Application e veremos como o item pode ser reutilizado. 

     Formas de criar novos objetos 
     Se você clicar em File|New... e na página "Forms", você verá que o novo item ("Formulário para uma tabela") está dentro do repositório. Agora ele está disponível em qualquer projeto, permitindo criar novos formulários a partir dele. 

     Existem três opções para criar novos objetos a partir do repositório: copiar [copy] o item, herdar [inherit] do item (criar uma nova classe derivada) ou usar [use] o item diretamente. 

Se você marcar a opção "Copy" e clicar Ok, o Delphi cria uma cópia separada do objeto original que está no repositório. Qualquer alteração no original posteriormente não vai afetar essa cópia e qualquer alteração na cópia é independente do que está no repositório. Note que a unidade do formulário não foi salva e está em memória como "Unit2". Isso permite você salvar com um nome qualquer. 

     A opção "Inherit" (herdar) faz diferente: faz uma referência ao original (ou seja, acrescenta o formulário original dentro do projeto) e cria uma nova classe derivada da original, TForm1. O novo formulário será chamado de 'FormBase1', com a classe 'TFormBase1'. A unidade do formulário não foi salva ainda. Nesse caso, qualquer alteração no original, que está no repositório, será herdada pela classe derivada. 

     A opção "Use" não copia o objeto original, mas compartilha com o projeto atual. Nesse caso, alterações feitas no item dentro do projeto afetam o item no repositório e vice-versa. Se vários projetos usarem o mesmo item, todos eles compartilham o mesmo item. 

     Adicionando um projeto ao repositório 
     Para reutilizar um projeto inteiro, você pode acrescentá-lo ao repositório com o menu Project|Add to Repository... e informar a descrição do item como antes. 

     Gerenciando o repositório 
     Para gerenciar as páginas do repositório e os itens de cada página, você pode clicar em   Tools|Repository. Na caixa de diálogo você pode criar, renomear ou excluir uma página do repositório (você só pode excluir se ela estiver vazia). É possível também mudar a ordem das páginas. 

     Você pode mover os itens entre páginas arrastando o item da lista da esquerda e soltando sobre a página desejada. Também é possível renomear ou alterar características de um item ou excluir o item. 

     Compartilhando o repositório numa equipe 
     Quando uma equipe de desenvolvedores trabalha em conjunto, é importante que eles possam compartilhar o repositório, de forma que novos itens adicionados a ele estejam disponíveis para toda a equipe. 

     Para compartilhar o repositório, você deve usar um diretório na rede que seja acessível a todos os desenvolvedores. Por exemplo, se G: é uma letra de drive que aponta para a rede, você pode usar G:\REPOS. Você deve também copiar os arquivos do repositório do Delphi para esse diretório. 

     Os arquivos do repositório do Delphi são armazenados num subdiretório OBJREPOS, abaixo do diretório onde o Delphi foi instalado (geralmente C:\Arquivos de Programas\Borland\Delphi6). Além desses arquivos, o Delphi usa um arquivo de texto chamado DELPHI32.DRO, localizado no subdiretório BIN do Delphi. 

     Para compartilhar o repositório na rede, faça o seguinte: 
     • Crie um diretório compartilhado (e.g. G:\REPOS). Verifique que todos os desenvolvedores têm acesso a ele e usam a mesma letra de drive; 
     • Copie o repositório de um computador para o diretório compartilhado (G:\REPOS), ou seja, todos os arquivos do subdiretório OBJREPOS do Delphi, mais DELPHI32.DRO, do subdiretório BIN; 
     • Em cada um dos computadores, no Delphi, clique em Tools|Environment Options. Na página Preferences Em "Shared Repository", digite o caminho do diretório compartilhado. 

Agora lembre-se que qualquer alteração ou acréscimo feito por um desenvolvedor afeta todos os outros. É importante também notar que quando você quiser compartilhar um objeto, ele deve ser salvo num diretório compartilhado também, acessível a todos (por exemplo, G:\BIBLIOTECAS). 

Autor    : Celso Rodrigues

segunda-feira, 17 de junho de 2013

Mainmenu e popupmenu personalizados utilizando canvas (muito simples)


Olá Pessoal!!!

Bom estou aqui com mais uma dica que interessa a muitas pessoas! Personalizar 
uma aplicação sem utilizar componentes externos.
Estaremos Pesonalizando os Menus de Nossa aplicação.
  Mas antes quero esclarecer algumas coisas para quem esta procurando por isso:
  -A dica é para personalizar os Menus da aplicação, tanto MainMenu quanto popupMenu.
  -Para quem utiliza Delphi 7 (Exemplo) pode utilizar os Componentes ActionMainMenuBar e 
  ActionManager para fazer alguns MainMenus bacanas(em breve mostrarei passo-a-passo como 
  utilizar estes componentes que são muito legais de trabalhar).
  -Neste exemplo estarei trabalhando com Canvas!
  
 Então... Mãos à Obra!!!!

   Neste exemplo que faremos utilizarei o Componentes MainMenu mas o que vai ser aplicado nele
 pode ser sem problemas aplicado para um popupmenu.

 Vamos deixar os nossos menus com uma aparência bem legal!.

 Eventos Utilizados no componente: onDrawItem, onMeasureItem.

 1º- Crie uma nova aplicação.
 2º- Coloqueno formulario o componente MainMenu (Standard Palette).
 3º- Ative a propriedade OwnerDraw do componente MainMenu.
 3º- Abra o "Editor de Menus" dando 2 clique no componente e crie 1 menu.
        (insira Caption, Name...)

 4º- Acesse o Evento onDrawItem de deste item do Menu e vamos implementar o seguinte código:
}
procedure TForm1.Arquivo1DrawItem(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; Selected: Boolean);
begin
  //Pinta a opção
  
  if Selected then  //verifica se o item está selecionado
    BEGIN
      ACanvas.Brush.Color :=  $00EFD3C6;        //cor de fundo do item (Lembrando que podemos printar um Imagem).
          //   Canv.Brush.Color :=  clAppWorkSpace;
      ACanvas.Rectangle(Arect);                         //Desenharemos uma retangulo em todo o Item selecionado.
      ACanvas.pen.Color:=$00C66931;             //seta a cor da borda do retangulo.
      InflateRect (ARect, -1,-1);
    end
    else
    ACanvas.Brush.Color:=clMenu;                        //se não estiver selecionado o item coloca a cor normal do item.
        //-->  dietrich 01/02/2007
        
        //coloca o texto
    ACanvas.pen.Color:=clBlack;  //cor
    ACanvas.TextRect(ARect,ARect.Left+5, ARect.Top+1,'Sair');//local onde sera escrito o texto ARect

end;

quinta-feira, 18 de abril de 2013

[Básico] - Tabela temporária com ClientDataSet – Conceito


Uma das vantagens de um fórum de programação é observar as dúvidas mais frequentes dos usuários e tentar ajudá-los de uma forma mais prática. Dessa vez, notei que muitos desenvolvedores têm dificuldades em compreender, criar e manipular tabelas temporárias no Delphi utilizando ClientDataSet. Além de ser um recurso muito útil, trabalhar com tabelas temporárias não exige conhecimentos avançados de programação.
Preparado pra mais um pequeno tutorial sobre desenvolvimento?

Tabela temporária? O que é isso?
Também conhecida como “tabela virtual”, uma tabela temporária é capaz de armazenar registros em memória sem a necessidade de estar conectada a um banco dados, diferentes das tabelas físicas, que armazenam os dados em disco. Os registros da tabela temporária são apagados automaticamente quando a aplicação é encerrada ou quando se utiliza um comando próprio pra isso, no qual veremos no próximo artigo. Um grande recurso da tabela temporária é permitir manipular estes dados em memória, como inclusões, alterações, exclusões e filtros, tal como podemos fazer com tabelas físicas no banco de dados.

Mas qual a vantagem de utilizar uma tabela temporária no meu projeto?
Bom, depende do tipo de projeto que você está desenvolvendo. Tabelas temporárias, em linhas gerais, são úteis para trabalhar com dados locais na aplicação de forma dinâmica. Por exemplo, em um ambiente master/detail, uma tabela temporária pode armazenar os registros filhos antes mesmo do registro mestre ser gravado no banco de dados.

Ainda não entendi. Poderia dar um exemplo?
Claro que sim.
Imagine que estamos desenvolvendo um sistema para controle de vendas.
No nosso banco de dados, teremos as seguintes tabelas relacionadas à venda:

-- Tabela VENDAS
COD_VENDA
DATA
COD_CLIENTE
TOTAL

-- Tabela ITENS
COD_VENDA (chave estrangeira referenciando a tabela VENDAS)
COD_PRODUTO
QTDE
VALOR
TOTAL

Agora, suponha que iremos gravar uma nova venda no sistema com os seguintes dados:

COD_VENDA = 1
DATA = 15/02/2013
COD_CLIENTE = 20
TOTAL = ?

Ué, cadê o total?
Você deve concordar que, para informar o valor total, é necessário adicionar os itens, ou seja, precisamos somá-los para calcular o valor total da venda, não é? Por outro lado, para adicionar os itens precisamos do código da venda, já que as duas tabelas são relacionadas por uma chave estrangeira:

(ITENS.COD_VENDA = VENDAS.COD_VENDA).

Agora raciocine comigo: se tentarmos adicionar um item sem o código da venda ou com o código de uma venda que (ainda) não existe, receberemos o erro de “violação de chave estrangeira”, visto que, na verdade, tentaríamos adicionar um registro filho sem a existência do registro pai.
Pois bem, e para obtermos o código da venda, precisamos primeiro gravá-la no banco de dados, certo? Mas espere aí… conforme vimos acima, não temos o valor total pra gravar a venda!
E então entramos em um impasse:
- Não podemos gravar primeiro a venda, pois não temos os itens
- Não podemos gravar primeiro os itens, pois não temos a venda

E agora? Já sei! Vamos gravar a venda sem o valor total!
Muitos desenvolvedores utilizam essa “técnica”, se é que podemos chamá-la assim. Aplicando à nossa realidade, gravamos a venda sem o valor total, apenas para obter o código da venda. Dessa forma, podemos gravar os itens da venda normalmente, e após gravá-los, calculamos o valor total e alteramos o registro da venda, atualizando o total. Em um contexto procedimental, ficaria dessa forma:
Gravar a venda sem o valor total
Obter o código da venda gravada
Gravar os itens utilizando o código da venda obtido
Somar os itens para calcular o total
Editar a venda e atualizar o valor total
Observe que para cada venda será necessário fazer duas operações na tabela de vendas: uma de inserção e outra para alteração. Eu, particularmente, não sou de acordo com esse procedimento.
Em um exemplo, imagine que gravamos a venda, mas ao começar a adicionar os itens, a energia é cortada ou o usuário decide fechar a tela por algum motivo. Obviamente o registro ficará incompleto, já que teremos uma venda sem itens gravada no banco de dados. Tecnicamente, será um registro mestre sem registros filhos.
No caso da energia acabar, o problema pode ainda se agravar um pouco mais. Ao reiniciar o sistema, o usuário irá gerar uma nova venda, visto que, aos olhos do usuário, a outra venda não foi gravada. No fim da história haverá 2 vendas idênticas no sistema: uma sem itens (perdida) e outra válida.

Mas neste caso é só excluir essa venda incompleta, não é?
Sim, pode ser. Mas para isso, você terá que implementar um controle eficiente no seu sistema para identificar esses registros problemáticos. E também, lembre-se que cada vez que isso ocorrer, o código da venda será perdido (“pulado”) no banco de dados.
Aí prepare-se para receber algumas ligações do usuário perguntando:
“Por quê o sistema pulou o número da venda?”
“A venda nº X sumiu do sistema…”
“Tem uma venda aqui sem itens!”

Certo, e qual a sugestão para resolver isso?
Opa, chegou aonde eu queria!
Amigos, todos os problemas citados acima podem ser resolvidos utilizando tabelas temporárias! Durante a inclusão da venda, ao invés de gravarmos os itens no banco de dados, iremos gravá-los em uma tabela temporária. Se a energia acabar, nada será afetado, já que nenhuma alteração foi feita no banco de dados.
Este será o nosso procedimento:
Inserir os itens na tabela temporária;
Ao gravar a venda, os itens da tabela temporária serão “copiados” para a tabela física, tudo em um mesmo método.
Desta maneira, iremos reduzir bastante a possibilidade de uma venda ficar incompleta, visto que a gravação da venda e os itens da venda acontecerão praticamente ao mesmo tempo. E o melhor: durante a inclusão da venda não faremos nenhuma operação no banco de dados, somente na gravação.


Firemonkey: substituição da tecla TAB por tecla ENTER


Antes de tudo, gostaria de deixar claro que esta é uma dica básica; porém alguns encontram dificuldades nesse assunto, então estou aqui com o intuito de esclarecimento. Ultimamente tenho visto algumas dicas na internet de substituição da tecla tab pela tecla enter, porém muitas dicas não funcionam perfeitamente, pulando muitas vezes dos “tedit” para o próximo componente, mas ainda há a possibilidade de o caso ser um botão e ter um comando no evento “onclick”, o comando no “onclick” não ser executado. Pois bem, tenho uma dica aqui que vai funcionar perfeitamente, em ambos aspectos: tanto no salto nos controls, como sem perder os eventos onclick dos botões.

No Evento OnKeyDown do Form digite os comandos abaixo:

begin
if Key = vkReturn then
begin
Key := vkTab;
KeyDown(Key, KeyChar, Shift);
end;
end;

Dica básica mas muito útil, espero que tenham gostado!




quarta-feira, 2 de janeiro de 2013

Trabalhando com POO na prática


Depois de abrirmos o tema para que todos pudessem opinar, iremos começar a criar nossa série de artigos, segue abaixo a descrição de nosso sistema.

Peço a todos que pretendem colaborar de alguma forma que enviem um e-mail para mim para que possamos facilitar o contato e agilizarmos o processo de publicação dos artigos. Segue meu e-mail, rboaro@gmail.com.
 
Fica difícil mensurarmos quantos artigos iremos desenvolver sobre o tema, pois desenvolver uma aplicação por menor que seja requer bastante tempo ,muitas coisas precisam ser definidas. Sendo assim iniciamos descrevendo as funcionalidades básicas do sistema, por favor comentem (por e-mail) e sugiram alterações se acharem necessário.
 
Objetivo do Sistema: Processar vendas de um determinado estabelecimento, quando falo processar vendas, estou me referindo a controlar o estoque dos produtos, e ter as funcionalidades básicas de controle, como por exemplo, gerar títulos a receber , efetuar lançamentos no caixa, quando a venda for a vista etc.
 
Cadastros que serão criados:
> Cidades
> Clientes
> Produtos
> Pedidos
> Titulos a Receber
Seria interessante criarmos tambem outros cadastros, como por exemplo cadastro de Titulos a Pagar, mas nesse caso precisaríamos criar um cadastro de lançamento de notas fiscais de entrada o que pode ser feito baseado nos exemplos que iremos desenvolver.
 
Banco de dados utilizado: depois de muitas opiniões e como é de costume divergentes, pois cada um de nós simpatiza com um determinado banco de dados, como costumo dizer, "o melhor banco de dados é aquele que dominamos e sabemos utilizar o máximo das suas funcionalidades". Dessa forma pensei em criarmos classes de acesso ao Firebird e ao Sql Server Express (free).
 
Driver de acesso ao banco: esse não abro mão de usar dbExpress que é o que há de melhor nas ultimas versões do Delphi.
Versão do Delphi utilizada: Delphi XE2, mas me coloco a disposição para auxiliá-los a adaptar o fonte para outras versões.
 
Frequência dos artigos publicados: no mínimo um por semana, se possível mais, mas como todos temos nossos compromissos a cumprir, deixamos aqui acordado que não podemos passar uma semana sem publicar nada.
 
Acredito que os principais itens foram citados. Sendo assim mãos a obra.