sexta-feira, 11 de maio de 2012

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

sábado, 31 de março de 2012

Como pegar a posição do mouse na tela

Para obter os valores das coordenadas do mouse de qualquer parte da tela, basta que se utiliza a função da API do Windows GetCursorPos. Esta função é interessante pois oferece ao programador os valores (x,y) de qualquer ponto da tela e não somente da aplicação.

Para implementação, esta função pode ser utilizada da seguinte maneira:

procedure TForm1.Timer1Timer(Sender: TObject);
var
pt: TPoint;
begin
GetCursorPos(pt); // Pega a posição atual do mouse;
//Mostra os valores das coordenadas do mouse
label1.caption := IntToStr(pt.x) + ',' + IntToStr(pt.y);
end;

Esta é mais uma das milhares de funções da API do Windows.

Enviar um email pelo delphi

smtp.postmessage.toAddress := 'StringList (por ex uma listbox';
smtp.postmessage.FromAdreess := 'ex: meu_email@123.pt';
smtp.userid := 'ex: user@123.pt'
smtp.host := 'ex: smtp@123.pt'
smtp.postmessage.subject := 'Assunto'
smtp.postmessage.body := 'Texto da mensagem (stringlist)'

smtp.connect;
smtp.sendmail;
smtp.disconnect;

Contribuição:
O Anonymous.nick enviou um complemento explicando melhor o procedimento para enviar um e-mail usando o Delphi.

Fazer um aplicativo completo para manipulação de e-mails é um tanto trabalhoso e não é o assunto desta dica. Muitas vezes, porém, queremos apenas dar ao nosso software a capacidade de enviar simples e-mails. Isto é fácil, especialmente porque o Delphi5 nos oferece o componente TNMSMTP (paleta FastNet) que faz praticamente todo o trabalho para nós. Precisamos apenas alterar algumas propriedades e chamar alguns métodos para que a mensagem seja enviada. Vamos para a prática:

1. Coloque um componente TNMSMTP no form.

2. Coloque um botão e no evento OnClick deste botão escreva:

procedure TForm1.Button1Click(Sender: TObject);
begin

{ Seu servidor SMTP }
NMSMTP1.Host := 'smtp.servidor.com.br';

{ Porta SMTP, **NÃO MUDE ISTO** }
NMSMTP1.Port := 25;

{ Nome de login do usuário }
NMSMTP1.UserID := 'MeuLogin';

{ Conecta ao servidor }
NMSMTP1.Connect;

{ Se ocorrer algum erro durante a conexão com o servidor, avise! }
if not NMSMTP1.Connected then
raise Exception.Create('Erro de conexão');

with NMSMTP1.PostMessage do begin
{ Seu e-mail }
FromAddress := 'meuemail@meuserver.com.br';

{ Seu nome }
FromName := 'Meu Nome';

{ E-mail do destinatário }
ToAddress.Clear;
ToAddress.Add('destinatario@servidor.com.br');

{ Assunto da mensagem }
Subject := 'Assunto da mensagem';

{ Corpo da mensagem }
Body.Clear;
Body.Add('Primeira linha da mensagem');
Body.Add('Segunda linha da mensagem');
Body.Add(''); { Linha em branco }
Body.Add('Última linha da mensagem');

{ Anexar arquivos(Se não quiser anexar arquivos, apague as 3 linhas seguintes) }

Attachments.Clear;

{ Endereço do anexo }
Attachments.Add('c:\diretorio\arquivo.ext');

end;

{ Manda o e-mail }
NMSMTP1.SendMail;
{ Disconecta do servidor }
NMSMTP1.Disconnect;
end;

Pronto! É só fazer as adaptações necessárias e você terá envio de e-mails em sua aplicação.

Observações:
Para enviar o mesmo e-mail para vários destinatário de uma só vez basta adicionar os endereços de e-mails de todos os destinatários em NMSMTP1.PostMessage.ToAddress.

segunda-feira, 12 de março de 2012

Manipulação de arquivos texto no delphi


Bem, vamos falar inicialmente da escrita de arquivos texto. Existem algumas palavras reservadas, das quais irei falar de apenas algumas delas, que serão abordadas neste artigo. Para conhecer todas as palavras reservadas, relacionadas a manipulação de arquivos, entrem no help do Delphi com o seguinte tema: "Input and output procedures and functions"

Palavra Reservada
Função
AssignFile
Associa o arquivo manipulado a uma variável do tipo File
Append
Abre um arquivo existente para inserção de novos dados
Eof
Verifica se a posição atual do cursor indica o fim do arquivo
Write / Rewrite
Escreve valores diversos no arquivo. O rewrite após a escrita posiciona o cursor na próxima linha do arquivo
Read / Readln
Lê diversos valores no arquivo. O readln após a leitura posiciona o cursor na próxima linha do arquivo

Bem, irei agora explicitar dois exemplos contendo a manipulação de arquivos textos. O primeiro deles, ilustrará a inserção de dados em um arquivo. O segundo irá ilustrar a leitura de dados.

function GravaArquivoLogTransacao(TipoTransacao: TTipoTransacao): Integer;
const
NomArquivo: String = "LogTransacao.txt";
var
Path: String;
Arquivo: TextFile;
begin
        Path := ExtractFilePath(Application.ExeName);
        if not DirectoryExists(Path) then begin
                CreateDir(Path);
        end;
        if not FileExists(Path + NomArquivo) then begin
                FileCreate(Path + NomArquivo);
        end;
        Try
        AssignFile(Arquivo, Path + NomArquivo);
        Append(Arquivo);
        Write(Arquivo, FormatFloat("000000", Transacao.TransactionID) + " / " + FormatFloat("000000", Transacao.GlobalID));
        case TipoTransacao of
        ttBeginTran: WriteLn(Arquivo, " - BeginTran: " + DateToStr(Date) + " " + TimeToStr(Time) + " por usuário: " + IntToStr(UserID));
        ttCommit: WriteLn(Arquivo, " - Commit: " + DateToStr(Date) + " " + TimeToStr(Time) + " por usuário: " + IntToStr(UserID));
        ttRollBack: WriteLn(Arquivo, " - RollBack: " + DateToStr(Date) + " " + TimeToStr(Time) + " por usuário: " + IntToStr(UserID));
end;
CloseFile(Arquivo);
Result := 1;
Except
Result := -1;
End;
end;
Na função acima, ilustro a geração de um log de transações de uma aplicação. Observe que as palavras que realizam a "escrita" no arquivo estão destacadas.
procedure LeArquivoLogTransacao(NomeArquivo: String);
var
strFile: TextFile;
strLine: String;
begin
        AssignFile(strFile, NomeArquivo);
        Reset(strFile);
        Readln(strFile, strLine);
        while not Eof(strFile) do begin
                ShowMessage(strLine);
                Readln(strFile, strLine);
        end;
end;
Já na função acima, realizamos a leitura do arquivo e lançamos uma mensagem contato o conteúdo lido a cada linha.

Como calcular preço de venda [passo-a-passo]


O Brasil tem um mercado informal  muito aberto e, muitas vezes, os trabalhadores autônomos se perdem ao calcular o preço de seus produtos de forma a pagar todas as suas despesas e ainda tirar um lucro legal. Existem alguns cursos voltados para este fim, com dicas de criação, formação de preço e gerenciamento do seu negócio (o SEBRAE é um excelente exemplo disso). Mas para uma pergunta simples, existe também respostas simples. Para facilitar a vida desses pequenos negócios, o Formigueiros também é cultura e explica passo-a-passo como se calcula o preço de venda de um produto. Para calcular é preciso ter as informações conforme exemplo abaixo:

1) Custo unitário do produto: R$ 12,50;
2) Percentual de despesas variáveis*: 9% (sendo 4% do simples nacional + 5% da comissão de vendas);
3) Percentual de despesas fixas**: 25% (esse percentual é medido pelo total das despesas fixas sobre o faturamento. Neste exemplo, utiliza-se o faturamento total de R$ 144.000,00 e despesas fixas de R$ 36.000,00, ou seja, 36.000/144.000,00 = 0,25 *100 = 25%);
4) Defina sua margem de lucro líquido: 12% (aqui você irá definir quanto você quer ter de lucro com o produto vendido já deduzidas todas as despesas);
5) Deduza de 100% as despesas acima citadas (fixas, variáveis e licro líquido): 100% – 46% = 54% (este é o percentual que deve ser aplicado sobre o preço unitário de compra do produto para definir qual o seu preço de venda);
6) Divida o custo unitário (de compra) por 54 (e multiplique por 100): R$ 12,50/54 * 100 = R$ 23,15

NOTA: Despesas fixas são as despesas permanentes da empresa como água, luz, telefone, aluguel, etc. Já as despesas variáveis são, como o próprio nome diz, despesas eventuais ou sem valor permanente como encargos, aquisição de bens ou produtos, etc.
Pronto, este é o valor de venda do seu produto. A dica é do blog do Élcio. Boas vendas e sucesso nos seus negócios.

Cálculo ICMS CST 00

Como prometido, vamos iniciar a explicação para o calculo da CST de ICMS 00, e suas possíveis variações.

ICMS CST 00 quer dizer, Tributada Integralmente. Para calcular este ICMS é simples, basta multiplicar a base de calculo(veja como aqui obter a base de calculo) pelo aliquota estabelecida.

Mais ou menos assim:

Base = 100,00

Alíquota = 17%

Valor ICMS = 100,00 x 17% = 17,00

Simples né? Então vamos começar a complicar

Embora a operação seja tributada integralmente, ela pode possuir Alíquota de ICMS reduzida.
A alíquota de ICMS também muda de acordo com o estado de origem x destino da mercadoria.

Algumas regras básicas:

1 – Venda para consumidor final, não contribuinte do ICMS, residente em UF diversa do emitente da nota fiscal, aplica-se a alíquota interna da UF do emissor da nota fiscal.

2 – Venda para consumidor final, contribuinte do ICMS, residente em UF diversa do emitente da nota fiscal, aplica-se a alíquota interestadual entre as UF’s.

3 – Venda para contribuinte do ICMS que não seja consumidor final, aplica-se a alíquota interestadual.

Obs: Como já citei anteriormente, a alíquota do ICMS é uma característica do ITEM da nota, então dentro de uma nota, pode ter vários itens tributados integralmente, mas cada um com alíquota de ICMS diferente. E isso em operações internas(dentro do estado)

Precisa prestar atenção a tabela de alíquota entre UF’s (Confira a tabela aqui)

Lembrando, essas regras são aplicadas para a operações tributadas integralmente, ou seja, CST 00.

quinta-feira, 8 de março de 2012

Evitar que a aplicação trave ao executar um processo grande

Já devemos ter precisado executar um comando muito grande e, para ficar mais amigável ao usuário, colocar uma barrinha de progresso, para avisá-lo em que estágio de processamento está.

Porém, nos deparamos com um pequeno problema: Nossa aplicação fica travada enquanto executa o comando!! Como resolver isto?

Existe um método chamado Application.ProcessMessages;   que força a aplicação processas as mensagens do sistema operacional, como por exemplo a exibição correta do form. Com isto, não só o form é visualizado corretamente, mas também nossa barrinha de progresso funciona perfeitamente. :D

Vejamos um exemplo simples:

Digamos que tenhamos um ADOTable com vários registros abertos e vamos percorrer um a um:

ADOTable1.First;
  while not (ADOTable1.Eof) do
  begin
      lblStatus.Caption := 'Processando registro...'; // exibimos alguma mensagem
      Application.ProcessMessages; // chamados o método que força o SO a desenha a janela
      ADOTable1.Next; // pula para o próximo registro da tabela
  end;

Pronto. Agora é só você implementar uma barra de progresso e colocar mais algumas perfumarias (objetos que deixam a cara do formulário mais amigável para o usuário) caso seja necessário :)

segunda-feira, 30 de janeiro de 2012

Detectando o Numero Serial do HD

Function SerialNum(FDrive:String) :String;
Var
    Serial:   DWord;
    DirLen,Flags: DWord;
    DLabel : Array[0..11] of Char;
begin
     Try GetVolumeInformation(PChar(FDrive+':\'),dLabel,12,@Serial,DirLen,Flags,nil,0);
            Result := IntToHex(Serial,8);
       Except Result :='';
end;
end;

Recuperar a Velocidade da CPU

Esta interessante função recupera a velocidade de processamento aproximada da CPU:

const
ID_BIT=$200000; // EFLAGS ID bit
 
function GetCPUSpeed: Double;
const
DelayTime = 500;
var
TimerHi, TimerLo: DWORD;
PriorityClass, Priority: Integer;
begin
try
PriorityClass := GetPriorityClass(GetCurrentProcess);
Priority := GetThreadPriority(GetCurrentThread);
 
SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_TIME_CRITICAL);
 
Sleep(10);
asm
dw 310Fh // rdtsc
mov TimerLo, eax
mov TimerHi, edx
end;
Sleep(DelayTime);
asm
dw 310Fh // rdtsc
sub eax, TimerLo
sbb edx, TimerHi
mov TimerLo, eax
mov TimerHi, edx
end;
 
SetThreadPriority(GetCurrentThread, Priority);
SetPriorityClass(GetCurrentProcess, PriorityClass);
 
Result := TimerLo / (1000.0 * DelayTime);
except end;
end;
No evento OnClick, basta atribuir a saída da função a uma string:

procedure TForm1.Button1Click(Sender: TObject);
var cpuspeed:string;
begin
cpuspeed:=Format('%f MHz', [GetCPUSpeed]);
edit1.text := cpuspeed;
end;

Verificando o tipo de Drive

Verificando o tipo de Drive

O código abaixo implementa uma função para testar qual o tipo de drive da unidade especificada.

Para isto, é necessário utilizar uma função de API do windows chamada GetTypeDrive.

Esta função retorna valores default que indicam o tipo de drive selecionado.(Drive_Removable,Drive_Fixed,Drive_Remote,Drive_CdRom,Drive_RamDisk)

Código Completo:

Function Tipo_Drive(Drive:Char):String;
Const
Drive_Removable = 2;
Drive_Fixed = 3;
Drive_Remote = 4;
Drive_CdRom = 5;
Drive_RamDisk = 6;
var
Tipo: byte;
begin
Tipo := GetDriveType(PChar(Drive + ':\'));
Case Tipo of
0: Result := 'Indeterminado';
1: Result := 'Inexistente ';
2: Result := 'Removível';
3: Result := 'Fixo';
4: Result := 'Rede';
5: Result := 'CD-ROM';
6: Result := 'RAM Disk';
else Result := ' Erro';
End;
end;

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, os meses de Janeiro a Dezembro. Este exemplo foi testado com Delphi4, BDE5 e tabela Paradox7.

Criando tabelas via SQL

Inclua na seção uses: dbTables

- Coloque um TButton no form;

- Escreve no OnClick do Button como abaixo:

procedure TForm1.Button1Click(Sender: TObject);
var
  Q: TQuery;
begin
  Q := TQuery.Create(Application);
  try
  Q.DatabaseName := 'SF';
  with Q.SQL do begin
  Add('Create Table Funcionarios');
  Add('( Codigo AutoInc,');
  Add(' Nome Char(30),');
  Add(' Salario Money,');
  Add(' Depto SmallInt,');
  Add(' Primary Key (Codigo) )');
  end;
  Q.ExecSQL;
  finally
  Q.Free;
  end;
end;

ObservaçõesEste exemplo foi testado com banco de dados Paradox, porém deverá funcionar em vários outros bancos de dados com pouca ou nenhuma alteração.

Mostrando progresso de uma SQL

Algumas pessoas estavam interessadas em saber como apresentar o progresso de um TQuery enquanta ele esta sendo aberto (ou executada, no caso de um

INSERT / UPDATE / DELETE).

A tecnica que vou demostrar nao apenas serve para o proposito procurado, mas tambem serve para mostrar o progresso de diversas outras atividades que o BDE executa, como:

* Criacao de tabelas

* Criacao de indices para tabelas

* Reestruturacao de tabelas

* Execucao de queries (ja comentado)

* alguma outra coisa que no momento nao me ocorre... :))

Importante:


1) No meu exemplo, estou usando o Delphi 3.02. Caso seu Delphi seja de uma versao menor, vc devera ter um trabalho extra para repor a classe TBDECallback. Acredito que seja possivel fazer uma rotina que funcione em Delphi 1, mas que com certeza dara um certo trabalhinho, ah, isso dara...

:-/

2) Ate agora so usei esse codigo com tabelas Paradox, mas realmente acredito que ele venha a funcionar com base de dados Interbase, Oracle, etc...

3) Nao sei se com o uso do Opus, Apollo ou qualquer outro substituto do BDE a tecnica ira funcionar, uma vez que nao se estaria trabalhando com o BDE original. Talvez alguem da lista possa dar essa informacao.

Teoria

Segundo o help do Delphi, "o TBDECallback eh um wrapper para uma funcão de callback do BDE. Com ele eh possivel instruir o BDE para que o mesmo execute algumas tarefas em resposta a eventos que ocorram durante uma chamada de uma funcao do BDE. " - Fim do plagio do arquivo de help.

O tipo de callback depende de um parametro CBType que eh fornecido no momento da criacao do TBDECallback. E, entre os diversos valores que o CBType pode apresentar, existe um que muito nos interessa; o cbGENPROGRESS.

:))

Assim, vc deveria criar uma funcao de callback do tipo cbGENPROGRESS chamada AtualizaGauge e indicar que a mesma eh que devera ser executada "entre cada respiracao" do BDE. Na rotina AtualizaGauge, o BDE iria te informar o percentual de progresso da tarefa .

O que voce faria nessa rotina ? Simples... atualizar o Gauge / ProgressBar.

Tudo muito bonito, tudo muito comovente, mas agora vamos para o lado pratico...

Pratica

Para que o BDE possa informar o progresso da tarefa, ele precisa obter essa informacao da base de dados que esta sendo utilizada. Acontece que, por razoes diferentes, nem sempre ele eh capaz de saber o PERCENTUAL da tarefa. Numa copia de registros de uma tabela para outra, ele pode saber que ja foram copiados 270 registros, mas nao saber que esse esforco representa 36 % de todos os registros que serao copiados.

Assim sendo, na funcao de callback que sera criada, receberemos um parametro do tipo pCBPROGRESSDesc, que por sua vez eh um ponteiro para uma estrutura que contem duas informacoes:

iPercentDone => percentual do servico realizado

szMsg => texto descrevendo o progresso do servico.

Como usar esses parametros ? Simples: sempre que o iPercentDone for negativo, voce devera considerar o texto descrito no campo szMsg. Se for igual ou maior que zero, entao vc devera considerar o valor do proprio iPercentDone.

Uma boa noticia para quem se preocupa com as mensagens que aparecem em ingles, quando se quer na verdade mostra-las em portugues: a mensagem fornecida por szMsg devera sempre aparecer no formato

<:>

.....

Exemplo:

Records copied: 170

Assim, voce pode procurar pelos dois pontos ":" e pegar o valor que vem a seguir para montar sua propria informacao em portugues.

Pessoalmente, ate agora nunca obtive um iPercentDone positivo. Li no newsgroup da Borland que poucas bases de dados eram capazes de informar o real percentual para o BDE. Se nao me engano, o Sybase era um deles... NAO ESTOU CERTO DISSO.

Vamos para um exemplo pratico ? Crie um projeto novo, e coloque um:

TQuery, TButton, TProgressBar e TLabel.

Sua query deve ser montada para abrir uma tabela razoavelmente grande, demodo que a operacao de abertura demore um pouco.

Agora vamos aos codigos:

1) Acrescente a unit BDE no seu USES da unit.

2) Acrescente algumas declaracoes na declaracao do seu Form:

==============================

type
TForm1 = class(TForm)
... (bla bla bla)
private
{ Private declarations }
FCBPROGRESSDesc: pCBPROGRESSDesc;
FProgressCallback: TBDECallback;
function GetDataCallback(CBInfo: Pointer): CBRType;
public
{ Public declarations }
end;
==============================

No evento OnCreate do seu Form:

==============================

procedure TForm1.FormCreate(Sender: TObject);
begin
FCBPROGRESSDesc := AllocMem(SizeOf(CBPROGRESSDesc));
FProgressCallback := TBDECallback.Create(Self, Query1.Handle,
cbGENPROGRESS, FCBPROGRESSDesc, SizeOf(CBPROGRESSDesc),
GetDataCallback, True);
end;
==============================

Percebam que no segundo parametro do Create do callback, eu coloquei Query1.Handle.

Caso voce queira usar isso numa TTable, coloque Table1.Handle.

E se quiser que essa funcao de callback seja chamada para todos os "progressos" de qualquer componente DataSet, voce deixa esse parametro como

NIL.

No evento OnDestroy do Form:

==============================

procedure TForm1.FormDestroy(Sender: TObject);
begin
FProgressCallback.Free;
FreeMem(FCBPROGRESSDesc, SizeOf(CBPROGRESSDesc));
end;
==============================

E agora, a tao falada funcao de callback:

==============================

function TForm1.GetDataCallback(CBInfo: Pointer): CBRType;
begin
Result := cbrCONTINUE;
with pCBPROGRESSDesc(CBInfo)^ do
begin
if iPercentDone < 0 then
begin
Label1.Caption := szMsg;
Label1.Refresh;
ProgressBar1.StepIt; {Apenas para ficar rodando o gauge}
end
else
ProgressBar1.Position := iPercentDone;
end;
end;
==============================

Agora eh so executar a query no clicar do botao e curtir o visual... :))

IMPORTANTE !!!!!!

Caso voce receba uma mensagem de erro informando que nao foi possivel inicializar o BDE (o que provavelmente acontecera, pois voce esta criando uma funcao de callback do BDE, quando ate entao nenhuma tabela havia sido aberta), va no DPR do seu projeto (Menu View -> Project Source) e faca o seguinte:

1) Acrescente a unit BDE no uses do projeto.

2) Acrescente a instrucao

DbiInit(nil);

apos a instrucao Application.Initialize;

Isso deve resolver o problema.

Bom, nao vou me alongar mais, porque senao essa mensagem vai ficar maior do que ja esta...

Espero que tenha contribuido para a solucao desse problema de mostar progresso de uma query. Qualquer duvida mandem mensagem.

Otimizações SQL

As dicas abaixo foram testadas essencialmente com Oracle:

1) Todas as vezes que for utilizar um SQL que possua condições de OR, é mais aconselhável e mais rápido utilizar IN, como no exemplo:

AO INVÉS DE

  Select * from projint where sit_projint = ‘AI’ or sit_projint = ‘EL’

COLOQUE

  Select * from projint where sit_projint IN (‘AI’,‘EL’);

2) Quando existem duas ou mais condições AND juntas, especifique primeiro sempre a que possui o maior limite de ocorrências

AO INVÉS DE

  select count(*) from pessoa where sit_pessoa = 11 AND cod_munic > 1100155

COLOQUE

  select count(*) from pessoa where cod_munic > 1100155 AND sit_pessoa = 11

3) Quando existem duas ou mais condições OR juntas, especifique primeiro sempre a que possui o maior limite de ocorrências

AO INVÉS DE

  select count(*) from pessoa where cod_munic > 1100155 OR sit_pessoa = 11

COLOQUE

  select count(*) from pessoa where sit_pessoa = 11 OR cod_munic > 1100155

4) Tenha cuidado com o sinal de <>

AO INVÉS DE

  select count(*) from pessoawhere cod_munic < > 1100155

COLOQUE

  select count(*) from pessoawhere cod_munic < 1100155 OR cod_munic > 1100155

Procura com mais de um Banco de Dados

edit1.text:= dbcombobox1.Text;
QueryPrinc.active := false;
QueryPrinc.sql.clear;
QueryPrinc.sql.add('select * from estrucpr where portugues = "' + edit1.Text + '"');
QueryPrinc.active:= true;
 
if DBcodEl.text=DBcodEl.text then
edit2.Text:= DBcodEl.Text;
 
QuerySin.active := false;
QuerySin.sql.clear;
QuerySin.sql.add(' select * from sinonimo where sin_est_id = "' + edit2.text + ' "');
QuerySin.active:= true;
 
 if DBcodEl.text=DBcodEl.text then
edit3.Text:= DBcodEl.Text;
 
QueryPropFis.active := false;
QueryPropFis.sql.clear;
QueryPropFis.sql.add('select * from FIQU_PRO where fiqu_id = "' + edit3.Text + '"');
QueryPropFis.active:= true;

Selecionando registros de uma tabela que não existam em outra tabela

(SELECT * FROM , WHERE . = .    AND . = 'AP' )
  MINUS
(SELECT * FROM @remoto1, @remoto1   WHERE @remoto1. = @remoto1.   AND @remoto1. = 'AP' )

Obs: todos os campos retornados no SELECT secundário deverá conter os mesmos campos do SELECT primário

Sql por campo edit pesquisando pelo nome

Inclua um componente Tedit e Tquery conectado a tabela do banco de dados, e no eveento OnChange do compoente TEdit digite:

query1.active := false;
query1.sql.clear;
query1.sql.add('select * from teste where nome = "' + edit1.Text + '"');
query1.active:= true;