Coleção de Dicas sobre programação Delphi.
Retiradas do E-Zine Grandes Dicas em Delphi
Por Ramos de Souza Janones
www.ramosdainformatica.com.br
1
Índice 1 Índice ............................................................................................................................ 2 Descobrindo o código ASCII de uma tecla .................................................................. 6 Função - Retornando o próximo dia útil....................................................................... 6 DBGrid - Colocando em Letras maiúsculas uma coluna selecionada.......................... 7 DBGrid - Mostrando todo conteúdo de um campo Memo........................................... 7 Crítica de datas no objeto Edit sem mensagem de erro do Delphi ............................. 10 Preenchimento de zeros para completar a data........................................................... 14 Multimídia - Fazendo suas aplicações Delphi falar ................................................... 14 Multimídia - Toque um som quando o mouse passar por cima de um botão............. 15 Hints com multiplas linhas ......................................................................................... 15 Multimídia - Usando cursores animados .................................................................... 16 Detectando a versão do Internet Explorer .................................................................. 16 QuickReport - Filtrando registros............................................................................... 17 Evitando efeito de maximização................................................................................. 17 Calcula a quantidade de dias no mês .......................................................................... 18 Calculando abono salárial de modo progressivo ........................................................ 18 Checa se um processo está rodando ........................................................................... 19 Checa se um diretório está vazio ................................................................................ 20 dbExpress - Passando parâmetros com CommandText via programação.................. 20 Corrigindo problemas de instalação do Borland Data Provider For Firebird............. 21 Lendo texto de um arquivo PDF ................................................................................ 21 Deixando seu EXE mais enxuto e rápido e, mais seguro contra decompilação......... 24 Copiando (Upload) um diretório para um servidor FTP ............................................ 26 Trabalhando com arquivos texto no Delphi ............................................................... 29 Criando uma conexão ao DBExpress em tempo de execução.................................... 31 ActiveX - Pegar um texto selecionado no Internet Explorer...................................... 32 Cria um efeito na apresentação de um formulário...................................................... 33 Criando um Menu transparente .................................................................................. 34 Checa se um diretório está vazio ................................................................................ 36 Mostra multiplas linhas de texto em um ComboBox ................................................. 37 Criando atalhos no Windows pelo Delphi.................................................................. 38 Faça suas aplicações Falar.......................................................................................... 39 Imprimindo arquivos PDF sem abrir-los .................................................................... 39 Ler arquivos PDF ....................................................................................................... 39 Inno Setup - Script para criação de conexão OBDC DSN ......................................... 40 Colocar cursor no final do Edit ao receber o foco...................................................... 42 Mudar a cor de fundo de um Hint............................................................................... 42 Fazer um executável ser executado somente se chamado por um determinado executável ................................................................................................................... 42 DBGrid - Focando a célula selecionada mudando sua cor......................................... 43 Verificando a versão do Windows ............................................................................. 43 Rave Report - Alterar a impressora padrão ................................................................ 44 Atribuíndo efeitos para abertura de formulários......................................................... 44 API do Windows - Função para excluir uma pasta e todos arquivos desta pasta....... 45 Inno Setup - Verificando se existe determinada Chave no Registro do Windows..... 46 Controlando o PowerPoint no Delphi......................................................................... 46 Rave Report - Indicar página inicial........................................................................... 48 2
InnoSetup - Adicionar um programa no iniciar do Windows .................................... 48 Validando endereço de e-mail no Delphi em aplicações Win32, .Net e Asp.Net ...... 49 Memo redondo............................................................................................................ 50 Colocar Banners em Menus........................................................................................ 50 Usando a WebCam no Delphi .................................................................................... 51 Colocando imagens em um ComboBox ..................................................................... 52 Importando e Exportando Registro ............................................................................ 53 DBGrid - Colocar um ComboBox num DBGrid........................................................ 54 Enviando mensagens HTML com imagens anexadas ................................................ 54 Mostrando dicas balão para caixas de edição wm WindowsXP ................................ 56 CheckLisBox - Trocar a cor das linhas ...................................................................... 57 Windows - Verificar a impressora padrão.................................................................. 58 RichEdit - Pesquisar um texto, posicionar sobre ele e mostrar ao usuário................. 58 ActiveControl - Envia um valor para Edit que estiver em foco ................................. 59 Registro do Windows - Retorna portas seriais ........................................................... 59 Verifica se um programa está aberto, caso contrário, abre......................................... 60 Função que verifica a velocidade do processador ...................................................... 60 DBGrid - Ao clicar no campo no DBGrid ordenar os registros ................................. 61 Criando um lista Push and Pop em Delphi ................................................................. 61 Rave Report - Imprimindo código de barras em modo de programação.................... 64 Gerar planilhas no Excel através de uma Query......................................................... 64 Rave Report - Somar valores...................................................................................... 65 Colorir componente focado - Preservando sua cor original ....................................... 66 ActiveControl - Envia valor para Edit que tiver em foco........................................... 67 TFields - Adiciona Fields no Fields Editors em tempo de execução ......................... 67 ListBox - Colorir ........................................................................................................ 69 Associando um extensão de arquivo a um executável ............................................... 69 Retornar as contas de E-Mail...................................................................................... 70 HKEY, Registry ......................................................................................................... 71 Criar e ler chave.......................................................................................................... 72 Retornar lista de hardware via registry....................................................................... 73 Verificar se um valor existe dentro de uma Chave..................................................... 73 Quick Report - Selecionando itens do ComboBox para PapeSize ............................. 74 ListBox - Pesquisa incremental .................................................................................. 74 Acertar data e hora com o servidor............................................................................. 75 QuickReport - Access Violation no Windows 2000 e XP ......................................... 75 DBGrid - Alterar as cores do título em tempo de execução....................................... 75 Testa se a impressora está funcionando...................................................................... 76 Como implementar um AutoComplete num Edit comum.......................................... 76 Como adicionar um CheckBox em um StringGrig .................................................... 78 Abreviação automática de nomes ............................................................................... 80 Compilando a aplicação pelo MS-DOS ..................................................................... 81 Coloração gradiente no Form ..................................................................................... 82 Usar perfeitamente o LookupComboBox................................................................... 83 Como colocar um codigo para que a aplicacao feche apos XX segundos sem atividades no teclado ou sem cliques do mouse. ........................................................ 83 Escondendo a barra de tarefas do Windows............................................................... 85 Pega todos os erros do Sistema, captura tela do erro, grava em arquivo e envia por email ............................................................................................................................. 85 Detectando o tipo de Conexão com a internet............................................................ 86
3
Função de potenciação - Juros.................................................................................... 87 Para trocar as cores dos botoes do radiogroup ........................................................... 87 Como criar uma figura do tipo marca d' água ............................................................ 88 Criptografando Imagens ............................................................................................. 88 Alterar a fonte de determinado registro num DBGrid................................................ 89 Alinhar título da barra de titulos do Form a esquerda ou direita................................ 89 Alterar fonte do Hint................................................................................................... 90 Criando arquivo Texto................................................................................................ 91 Como selecionar tudo (Ctrl+A) em um TMemo/TDBMemo..................................... 92 Mudando o IP da máquina via API do Windows ....................................................... 93 Texto na diagonal e girando ....................................................................................... 93 Criar um alias dinamicamente na memória ................................................................ 94 Rodar videos em um panel ......................................................................................... 94 Como colocar uma coluna do DBGrid em maiuscula ................................................ 95 DBGrid - Alinhando texto conforme condição .......................................................... 95 DBGrid - Colocando CheckBox no grid .................................................................... 96 RichEdit - Como fazer uma pesquisa e substituição em um RichEdit ....................... 97 TForm - Criando formulários transparentes ............................................................... 98 TList - Ordenando os itens ......................................................................................... 99 3 formas de dar um shutdown................................................................................... 100 QuickReport e FastReport - Gerando um PDF......................................................... 103 SetVolumeLabel - Mudando o Label do HD............................................................ 104 Memo - Rolagem vertical ......................................................................................... 105 Como adicionar o evento OnClick no DBGrid ........................................................ 106 Alterando a cor dos TabSheet de um PageControl................................................... 107 Como chamar uma home page utilizando o seu browse padrão............................... 107 Como alterar o caption da janela de preview do quickreport ................................... 107 Como passar parâmetros entre 2 forms .................................................................... 108 Como reduzir o tempo e carga de um programa ...................................................... 109 Escondendo o Programa de Ctrl+Alt+Del................................................................ 110 Verifica se o BDE está instalado .............................................................................. 112 Verificando se um alias está instalado...................................................................... 114 Como prevenir a movimentação do mouse para fora do form? ............................... 114 Como criar hints customizados?............................................................................... 114 Como capturar a tela? ............................................................................................... 116 Como mostrar um TMenuItem alinhado à direita? .................................................. 121 Como mover o form clicando em qualquer lugar? ................................................... 121 Como mostrar um texto de várias linhas em um TCombobox? ............................... 122 Como criar tooltips com balões? .............................................................................. 124 Mostra o total de páginas.......................................................................................... 144 InnoSetup – Verificando a versão do software, se inferior, então, não instalar ....... 144 InnoSetup – Manipulação de arquivos texto ............................................................ 145 Finalizando processos do Windows via programação.............................................. 146 Gravando CDs .......................................................................................................... 147 Quick Report - Obtendo a lista de papeis disponíveis.............................................. 147 DBGrid - Como fazer quebra de linhas .................................................................... 148 Arquivo: Verificar se está ReadOnly........................................................................ 150 Treeview – Foco ....................................................................................................... 151 Rave Report – Indicar página inicial ........................................................................ 151 Desktop do Windows – auto-arranjar icones............................................................ 152
4
Cálculo de Parcelas................................................................................................... 153 Porta Serial – Como verificar se uma porta está em uso .......................................... 154 GIF – Como converter uma imagem GIF para BMP ............................................... 155 Veja como criar atalhos no menu iniciar do Windows............................................. 155 Como mover um componente em Run-time............................................................. 158 Como apresentar o número da linha e coluna em um DBGrid?............................... 159 Como implementar um log de todos os erros gerados na aplicação?....................... 160 Printers - Como retornar informações das impressoras instaladas na máquina ....... 161 IP – Como retornar o hostname a partir de um endereço IP..................................... 163 Windows – Como criar grupos e subgrupos de programas no menu iniciar............ 164 Windows – Como desabilitar uma combinação de teclas genericamente ................ 165
5
Descobrindo o código ASCII de uma tecla Para descobrir o código ASCII de uma determinada tecla você pode criar a seguinte aplicação. 1. Insira um componente Label no form (Label1); 2. Mude a propriedade KeyPreview do form para true; 3. Altere o evento OnKeyDown do form como abaixo: procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin Label1.Caption := Format(‘O código da tecla pressionada é: %d’, [Key]); end; Para testar execute e observe o Label enquanto pressiona as teclas desejadas.
Função - Retornando o próximo dia útil Obtendo o próximo dia útil caso a data informada caia em um fim de semana function ProximoDiaUtil(dData : TDateTime) : TDateTime; begin if DayOfWeek(dData) = 7 then dData := dData + 2 else if DayOfWeek(dData) = 1 then dData := dData + 1; Result := dData; end;
6
DBGrid - Colocando em Letras maiúsculas uma coluna selecionada procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char); begin if DBGrid1.SelectedField.FieldName='NOME' THEN Key := AnsiUpperCase(Key)[Length(Key)]; end;
DBGrid - Mostrando todo conteúdo de um campo Memo Desenvolvedores em geral utilizam o componente DBGrid para apresentar os dados de uma tabela ou banco de dados. Os problemas surgem a partir do momento em que é necessário apresentar o conteúdo de um campo Memo. Porém, existe um jeito fácil de resolver este problema. O que iremos fazer é que, ao usuário clicar sobre o conteúdo de algum campo Memo no DBGrid, seja apresentada uma janela com todas informações contidas neste memo. Primeiro é desenvolvida uma função que realiza este processo: function TForm1.MostraMemo(Dts: TDataSource; Dbg: TDBGrid; Fld: TField): Boolean; var Frm: TForm; Ret: Boolean; Mem: TDBMemo; begin Ret := False; if Dts.DataSet.RecordCount > 0 then if Dbg.SelectedField = Fld then begin Ret := True; Frm := TForm.Create(nil); try Frm.Width := 240; Frm.Height := 120; Frm.Top := Mouse.CursorPos.Y; Frm.Left := Mouse.CursorPos.X; Frm.BorderStyle := bsToolWindow; Frm.Caption := Fld.DisplayLabel; Mem := TDBMemo.Create(nil); try Mem.Parent := Frm; Mem.Align := alClient;
7
Mem.DataSource := Dts; Mem.DataField := Fld.FieldName; Mem.ReadOnly := True; Mem.ScrollBars := ssVertical; Frm.ShowModal; finally Mem.Free; end; finally Frm.Free; end; end; Result := Ret; end;
Uma vez desenvolvida nossa função, é preciso colocar em prática, no evento OnCellClick do DBGrid, insira o código a seguir:
procedure TForm1.DBGrid1CellClick(Column: TColumn); begin MostraMemo(DBGrid1.DataSource, DBGrid1, DBGrid1.SelectedField); end; Confira como ficou todo exemplo: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Grids, DBGrids, DB, DBTables, StdCtrls, DBCtrls; type TForm1 = class(TForm) Table1: TTable; DataSource1: TDataSource; DBGrid1: TDBGrid; procedure DBGrid1CellClick(Column: TColumn); private function MostraMemo(Dts: TDataSource; Dbg: TDBGrid; Fld: TField): Boolean; { Private declarations } public { Public declarations } end;
8
var Form1: TForm1; implementation {$R *.dfm} function TForm1.MostraMemo(Dts: TDataSource; Dbg: TDBGrid; Fld: TField): Boolean; var Frm: TForm; Ret: Boolean; Mem: TDBMemo; begin Ret := False; if Dts.DataSet.RecordCount > 0 then if Dbg.SelectedField = Fld then begin Ret := True; Frm := TForm.Create(nil); try Frm.Width := 240; Frm.Height := 120; Frm.Top := Mouse.CursorPos.Y; Frm.Left := Mouse.CursorPos.X; Frm.BorderStyle := bsToolWindow; Frm.Caption := Fld.DisplayLabel; Mem := TDBMemo.Create(nil); try Mem.Parent := Frm; Mem.Align := alClient; Mem.DataSource := Dts; Mem.DataField := Fld.FieldName; Mem.ReadOnly := True; Mem.ScrollBars := ssVertical; Frm.ShowModal; finally Mem.Free; end; finally Frm.Free; end; end; Result := Ret; end;
9
procedure TForm1.DBGrid1CellClick(Column: TColumn); begin MostraMemo(DBGrid1.DataSource, DBGrid1, DBGrid1.SelectedField); end; end.
Crítica de datas no objeto Edit sem mensagem de erro do Delphi Fazer o tratamento de mensagens de erro em campos de data é fundamental. Neste exemplo, para ilustrar, são inseridos dois componentes Edit. O componente Edit1 é o componente onde serão inseridos as datas e o componente Edit2 é apenas para que possamos fazer a transição entre os componentes. No evento OnExit do Edit1 foi inserido o código a seguir: No evento OnExit do objeto procedure TForm1.Edit1Exit(Sender: TObject); var Data : string; begin Data := Edit1.text; CriticaData(Data); // Se não for um campo válido, a procedure devolve a variável data vazia; if Data = '' then Edit1.SetFocus else Edit1.text := DateToStr(StrToDate(Edit1.text)); end; Foi criado uma procedure para fazer o tratamento das mensagens de erro. Esta procedure terá o nome de Criticadata: procedure TForm1.CriticaData(var Data: string); //Sem controle dos caracteres digitados no objeto Edit1 var I, J, Dia, Mes, Ano : Integer; Barras, Barra1, Barra2 : Integer; // Verifica a posição das barras; K, M : Array Of Integer; Num : Array Of String; Caracter, Erro : String; begin Erro:='n'; //Em princípio o campo é considerado como correto(válido). // Cria-se os Arrays K e M com 13 campos dos quais usaremos do 1 ao 12 SetLength (K, 13); SetLength (M, 13);
10
// A matriz M é preenchida com o último dia de cada mês // A matriz K é preenchida com 1. A posição relativa de cada caracter do campo // data, dentro da matriz K, será prenchida com zero se o caracter for válido. // Caso contrário será setado Erro igual a s for I := 1 to 12 do begin K[I] := 1; M[I] := 31; end; M[4] := 30; M[2] := 28; M[6] := 30; M[9] := 30; M[11] := 30; //Num contém os números e / para controle do campo data. SetLength (Num, 11); for I := 0 to 9 do Num[I] := IntToStr(I); Num[10] := '/'; // Barra controla a posição das duas // do campo data Barras := 0; // Verifica a quantidade de barras digitadas Barra1 := 0; // Posição da 1ª barra (pode ser 2 ou 3) Barra2 := 0; // Posição da 2ª barra (pode ser 4, 5 ou 6) for I := 1 to length(Data) do begin Caracter := copy(Data,I,1); if Caracter = '/' then begin Barras := Barras + 1; if Barra1 = 0 then Barra1 := I else Barra2 := I; end; for J := 0 to 10 do if Num[J] = Caracter then K[I] := 0; end; //Se Algum elemento da variável Data não for válido // seta o erro com s for J := 1 to length(Data) do if K[J] = 1 then Erro := 's'; if (length(data) < 6) or (length(data) > 10) then Erro := 's';//or // (length(data) = 9) then Erro := 's'; if Barras > 2 then Erro := 's'; if (Barra1 > 3) or (Barra1 < 2) then Erro := 's'; if (Barra2 > 6) or (Barra2 < 4) then Erro := 's'; // Até aqui já sabemos que a data está em formato válido com barras if Erro = 'n' then begin Caracter := Copy(Data,(Barra2 + 1),4); if length(Caracter) < 4 then begin Caracter := '20' + Caracter; // Se a data entrar no formato dd/mm/aa // fazemos a data ficar dd/mm/20aa Data := Copy(Data,1,Barra2)+Caracter; end;
11
// Podemos converter as posições da string em inteiros sem receio de recebermos // aquela mensagem de erro do delphi. Dia := StrToInt(Copy(Data,1,(Barra1 - 1))); Mes := StrToInt(Copy(Data,(Barra1+1),(Barra2 - Barra1 - 1))); Ano := StrToInt(Copy(Data,(Barra2 + 1),4)); // Verifica se o ano é bissexto para a crítica do dia se o mês for fevereiro. J := Ano mod 4; if J = 0 then M[2] := 29 else M[2] := 28; // Critica o mes if (mes < 1) or (mes >12) then Erro := 's'; // Critica o dia if Erro = 'n' then if (dia < 1) or (dia > M[Mes]) then Erro := 's'; // critica o ano (Se quiser) if ano < 2003 then Erro := 's'; end; if Erro = 's' then begin Data := ''; messageDlg('Data inconsistente!!!',mtError, // Esta será a única mensagem mostrada. [mbOk],0); end; end;
A mesma procedure CriticaData, mais enxuta, porém, com o controle dos caracteres feito no evento OnKeyPress: procedure TForm1.CriticaData(var Data: string); //Com controle dos caracteres //digitados no objeto Edit1 através do evento OnKeyPress var I, J, Dia, Mes, Ano : Integer; Barras, Barra1, Barra2 : Integer; // Verifica a posição das barras; M : Array Of Integer; Caracter, Erro : String; begin Erro:='n'; //Em princípio o campo é considerado como correto(válido). // Cria-se o Array M com 13 campos dos quais usaremos do 1 ao 12 SetLength (M, 13); // A matriz M é preenchida com o último dia de cada mês for I := 1 to 12 do begin M[I] := 31; end; M[4] := 30; M[2] := 28; M[6] := 30; M[9] := 30; M[11] := 30; // Barra controla a posição das duas // do campo data Barras := 0; // Verifica a quantidade de barras digitadas
12
Barra1 := 0; // Posição da 1ª barra (pode ser 2 ou 3) Barra2 := 0; // Posição da 2ª barra (pode ser 4, 5 ou 6) for I := 1 to length(Data) do begin Caracter := copy(Data,I,1); if Caracter = '/' then begin Barras := Barras + 1; if Barra1 = 0 then Barra1 := I else Barra2 := I; end; end; if (length(data) < 6) or (length(data) > 10) then Erro := 's'; if Barras > 2 then Erro := 's'; if (Barra1 > 3) or (Barra1 < 2) then Erro := 's'; if (Barra2 > 6) or (Barra2 < 4) then Erro := 's'; // Aqui já sabemos se a data é numérica e se está em formato válido com barras if Erro = 'n' then begin Caracter := Copy(Data,(Barra2 + 1),4); if length(Caracter) < 4 then begin Caracter := '20' + Caracter; // Se a data entrar no formato dd/mm/aa // fazemos a data ficar dd/mm/20aa Data := Copy(Data,1,Barra2)+Caracter; end; // Podemos converter as posições da string em inteiros sem receio de recebermos // aquela mensagem de erro do delphi. Dia := StrToInt(Copy(Data,1,(Barra1 - 1))); Mes := StrToInt(Copy(Data,(Barra1+1),(Barra2 - Barra1 - 1))); Ano := StrToInt(Copy(Data,(Barra2 + 1),4)); // Verifica se o ano é bissexto J := Ano mod 4; if J = 0 then M[2] := 29 else M[2] := 28; // Critica o mes if (mes < 1) or (mes >12) then Erro := 's'; // Critica o dia if Erro = 'n' then if (dia < 1) or (dia > M[Mes]) then Erro := 's'; // critica o ano (Se quiser) if ano < 2003 then Erro := 's'; end; if Erro = 's' then begin Data := ''; messageDlg('Data inconsistente!!!',mtError, [mbOk],0); end;
No evento onKeyPress do Edit1 é inserido códigos para que possa controlar os caracteres digitados:
13
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char); begin if not (Key = Chr(vk_Back)) then // Este if habilita a tecla Backspace para correção do objeto if not (Key in ['0'..'9','/']) then // Este if permite a digitação somente de números e da barra / abort; end;
Preenchimento de zeros para completar a data Usuários podem não colocar os zeros de dias e meses menores que dez forçando um erro de digitação de data. Para resolver este problema, no evento OnCreate do formulário insira o código a seguir: procedure TForm1.FormCreate(Sender: TObject); begin ShortDateFormat := 'dd/mm/yyyy'; // pode-se usar ‘dd/mm/yy’ para exibição no formato curto end;
Multimídia - Fazendo suas aplicações Delphi falar Há um tempo atrás inserimos uma dica ensinando o Delphi a falar, no entanto era com sutaque "americado português". Saiu o SAPI 4.0 com a opção de Português Brasil. A seguir, links com downloads e exemplos: Para SAPI 4.0 http://www.microsoft.com/msagent/downloads/user.asp Em Text-to-speech engines, escolha o idioma Português Brasil E mais embaixo faça o download do SAPI 4.0 runtime support No site http://bdn.borland.com/article/0,1410,29582,00.html você tem exemplos para delphi usando o SAPI 4.0. Download dos exemplos: http://codecentral.borland.com/codecentral/ccWeb.exe/listing?id=19509 Para SAPI 5.1 tem o site http://bdn.borland.com/article/0,1410,29583,00.html também com exemplos, mas não sei onde encontrar engine em portugues para esta versao. Um exemplo simples para fazer o seu Delphi falar é este: Primeiro é declarada na cláusula uses “ComObj”. Em seguida, no evento onClick do botão é inserido o código a seguir: procedure TForm1.Button1Click(Sender: TObject);
14
var voice: OLEVariant; begin voice := CreateOLEObject('SAPI.SpVoice'); voice.Rate := 0; voice.Volume := 100; voice.Speak('Ramos da Informática',0); voice := unassigned; end;
Multimídia - Toque um som quando o mouse passar por cima de um botão Neste exemplo iremos utilizar CM_MOUSEENTER quando o mouse entrar no objeto e CM_MOUSELEAVE quando sair do objeto, a rotina deve ficar assim:
uses MMSystem; TYourObject = class(TAnyControl) ... private procedure CMMouseEnter(var AMsg: TMessage); message CM_MOUSEENTER; procedure CMMouseLeave(var AMsg: TMessage); message CM_MOUSELEAVE; ... end; implementation procedure TYourObject.CMMouseEnter(var AMsg: TMessage); begin sndPlaySound('c:\win\media\ding.wav',snd_Async or snd_NoDefault); end; procedure TYourObject.CMMouseLeave(var AMsg: TMessage); begin sndPlaySound(nil,snd_Async or snd_NoDefault); end;
Hints com multiplas linhas É muito simples, no evento OnCreate do formulário insira o código a seguir: procedure TForm1.FormCreate(Sender: TObject); begin Button1.Hint:='Ramos da'+#13+'Informática'; end; 15
Multimídia - Usando cursores animados Cursores animados existem aos montes pela internet, você pode utilizar estes cursores em suas aplicações, neste pequeno exemplo inserimos o código no evento OnCreate do formulário, acompanhe: procedure TForm1.FormCreate(Sender: TObject); const MyCursor=1; begin Screen.Cursors[MyCursor]:=LoadCursorFromFile('C:\Shuttle.ani'); Screen.Cursor:=MyCursor; end;
Detectando a versão do Internet Explorer Para detectar a versão do Internet Explorer, basta consultar uma chave do registro cujo endereço é: HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer Existem 3 chaves neste local que determinam a versão do IE: - IVer disponível no IE 1, 2 e 3 - Build disponível a partir do IE 2 - Version disponível a partir do IE 4.0 É possível consultar a versão do IE através da versão da Shdocvw.dll, porém essa DLL só está disponível a partir da versão 3.0. A chave IVer contém os seguintes valores: 100 - IE 1.0 101 - IE para NT 4.0 102 - IE 2.0 103 - IE 3.0 A chave Version contém o número da versão por extenso que não corresponde ao número da versão que o usuário vê. Na página abaixo tem uma lista detalhada que relaciona um valor com o outro: http://www.codeproject.com/shell/detectie.asp E finalmente, o código da função que obtém a versão: function GetIEVersion: string; var Reg: TRegistry; 16
begin Reg := TRegistry.Create; try Reg.RootKey := HKEY_LOCAL_MACHINE; Reg.OpenKey('Software\\Microsoft\\Internet Explorer', False); try Result := Reg.ReadString('Version'); if (Result='') then Result := Reg.ReadString('IVer'); except Result := ''; end; Reg.CloseKey; finally Reg.Free; end; end; Através da versão do IE determina-se qual ActiveX poderá ser carregado para fazer OLE com o IE. Até a versão 3.0 o componente é o TWebBrowser_V1 e a partir do IE 4.0, o componente é o TWebBrowser.
QuickReport - Filtrando registros procedure TForm1.QuickReport1Filter(var PrintRecord:Boolean); begin PrintRecord:= ( Table1.fieldbyname ('idade').value > 21 ); end;
Evitando efeito de maximização Se você já desenvolveu uma aplicação MDI com um formulário MDIChild que tem que ser exibido em estado Maximizado (WindowState=wsMaximized), provavelmente você já se deparou com aquele deselegante problema em que o usuário acompanha a maximização do seu formulário. Para evitar isto, faça o seguinte: Antes de criar o seu formulário para a exibição, utilize LockWindowUpdate(Handle); Após a criação do formulário, utilize LockWindowUpdate(0); Com isto, você dará um efeito mais profissional às suas aplicações. Exemplo: procedure MainForm.ItemArqCadFor(Sender: TObject); begin LockWindowUpdate(Handle); with TFrmCadFor.Create(self) do Show; LockWindowUpdate(0); end;
17
Calcula a quantidade de dias no mês function DaysInMonth: Integer; var Year, Month, Day: Word; begin DecodeDate(Now, Year, Month, Day); Result := MonthDays[IsLeapYear(Year), Month]; end; Exemplo de uso: procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(IntToStr(DaysInMonth)); end;
Calculando abono salárial de modo progressivo function Abono (S, F, A1, A2: Double) : Double; Begin If S>=F then begin Result:=S+A2 end else begin If S>F-A1 then Result:=(100-(((F-S)/A1)*100))*A2/100+F else Result:=S+A1 end; end; • • • • •
Onde S = Salário (No nosso exemplo R$ 290,00 ou R$ 300,00). F= Faixa do Abono (No nosso exemplo R$ 300,00). A1= 1º Abono (Valor mais alto, no nosso exemplo R$ 50,00). A2= 2º Abono (Valor mais baixo, no nosso exemplo R$ 30,00). Result= Retorno da função com o calculo do novo salário.
Para executar basta declarar as variáveis ou campos do banco de dados exatamente na ordem acima em modo ‘Double’.
18
Esta é uma função para calcular de modo progressivo um abono (por exemplo, folha de pagamento) sem cometer injustiça. Expl: Digamos que queremos que todos os funcionários que ganham até R$ 299,99 recebam um abono de R$ 50,00 e acima deste valor um abono de R$ 30,00. Se não aplicarmos a formula o que vai acontecer quem ganha, por exemplo, R$ 290,00 recebera R$ 340,00 (o correto seria ganhar R$ 324,00) passando a ganhar mais de quem ganhava R$ 300,00, pois este terá apenas um abono de R$ 30,00 percebendo R$ 330,00. A função acima corrige estas distorções, e pode ser aplicada num banco de dados para diversas faixas salariais.
Checa se um processo está rodando { .... } uses TlHelp32; { .... }
function processExists(exeFileName: string): Boolean; var ContinueLoop: BOOL; FSnapshotHandle: THandle; FProcessEntry32: TProcessEntry32; begin FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); FProcessEntry32.dwSize := SizeOf(FProcessEntry32); ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32); Result := False; while Integer(ContinueLoop) <> 0 do begin if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) = UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) = UpperCase(ExeFileName))) then begin Result := True; end; ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32); end; CloseHandle(FSnapshotHandle); end;
// Exemplo: procedure TForm1.Button1Click(Sender: TObject); begin if processExists('calc.exe') then ShowMessage('Processo em execução') else 19
ShowMessage('O processo NÃO está em execução'); end;
Checa se um diretório está vazio function DirectoryIsEmpty(Directory: string): Boolean; var SR: TSearchRec; i: Integer; begin Result := False; FindFirst(IncludeTrailingPathDelimiter(Directory) + '*', faAnyFile, SR); for i := 1 to 2 do if (SR.Name = '.') or (SR.Name = '..') then Result := FindNext(SR) <> 0; FindClose(SR); end;
// Exemplo: procedure TForm1.Button1Click(Sender: TObject); begin if DirectoryIsEmpty('C:\test') then Label1.Caption := 'empty' else Label1.Caption := 'not empty'; end;
dbExpress - Passando parâmetros com CommandText via programação O parametro não é adicionado quando criamos o CommandText via programação, portanto devemos criá-lo da seguinte forma: procedure TForm1.Button1Click(Sender: TObject); begin SQLClientdataSet1.Close; SQLClientdataSet1.Params.Clear; SQLClientdataSet1.CommandText := 'select * from CLIENTE where CODIGO = :COD'; SQLClientdataSet1.Params.CreateParam(ftInteger, 'COD', ptInput).AsInteger := 1; SQLClientdataSet1.Open; end;
20
Corrigindo problemas de instalação do Borland Data Provider For Firebird Em alguns casos, o Borland Data Provider For Firebird têm apresentado problemas de instalação, abaixo segue algumas dicas para tentar auxiliar na resolução dos mesmos: 1. Verificar se o D8 está atualizado com Update Pack#2; 2. Se o BDP For Firebird foi instalado 'antes' do D8 ter sido atualizado,desinstalar, atualizar o D8 e após isso instalar o BDP For Firebird novamente; 3. Efetuar testes diretamente via 'Data Explorer' a fim de verificar se a conexão ocorre sem problemas; 4. Copiar o arquivo 'FirebirdSql.Data.Bdp' para a pasta: C:\Arquivos de programas\Arquivos comuns\Borland Shared\BDS\Shared\Assemblies\2.0 5. No projeto, acesse 'Project Manager' | 'References' e adicione a referência ao 'Firebirdsql.Data.Bdp'
Lendo texto de um arquivo PDF É o seguinte, esta dica peguei em um site Alemão, fiz aqui sua tradução e alguns testes e funciou. Para quem precisa criar algum sistema que leia o conteúdo de texto de um arquivo PDF. Não lembro quem havia pedido, mas aqui está a solução: {++++++++++++++++++++++++++++++++++++++++++++++++++ Esta é uma rotina para ler informações de arquivos PDF. No formulário adicione um TMemo, 5 TLabel, 1 TButton e um OpenDialog. Só um detalhe, vá oa menu do Delphi e na opção "Import TypeLibrary" escolha a opção do Adobe Acrobat, senão, não irá funcionar. Bem, o código completo da aplicação é este que segue: +++++++++++++++++++++++++++++++++++++++++++++++++++} unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, OleCtrls, acrobat_tlb; type TForm1 = class(TForm) Button1: TButton; 21
Memo1: TMemo; OpenDialog1: TOpenDialog; GroupBox1: TGroupBox; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end;
var Form1: TForm1; implementation uses ComObj; {$R *.dfm} {$TYPEDADDRESS OFF} //Ă&#x2030; preciso dazer esta chamada var PDDoc: Acrobat_TLB.CAcroPDDoc; PDPage: Variant; PDHili: Variant; PDTextS: Variant; acrobat: Variant; Result: Boolean; NTL, i, j, Pagecount: Integer; zeilen: string; stichwortcounter: Integer; Size: Integer; gesamtstring: AnsiString; zwreal: Real; procedure TForm1.Button1Click(Sender: TObject); function removecrlf(workstring: string): string; var i: Integer; begin removecrlf := ''; for i := 0 to Length(workstring) do begin if workstring[i] = #13 then workstring[i] := ' '; if workstring[i] = #10 then
22
workstring[i] := ' '; end; removecrlf := workstring; end; begin if not opendialog1.Execute then Exit; memo1.Clear; gesamtstring := ''; stichwortcounter := 0; Size := 0; try acrobat := CreateOleObject('AcroExch.pdDoc'); //Identifica arquivos PDF através do OLE Result := acrobat.Open(opendialog1.FileName);
if Result = False then begin messagedlg('O arquivo não pode ser aberto', mtWarning, [mbOK], 0); Exit; end; for j := 0 to acrobat.GetNumPages - 1 do begin memo1.Lines.Add('----------------------------------------------'); //Primeira página do documento ativa PDPage := acrobat.acquirePage(j); PDHili := CreateOleObject('AcroExch.HiliteList'); Result := PDHili.Add(0, 4096); //Marca sobre o texto PDTextS := PDPage.CreatePageHilite(PDHili); ntl := PDTextS.GetNumText; for i := 0 to ntl - 1 do begin zeilen := PDTextS.GetText(i); if (Length(zeilen) > 0) and (zeilen <> '') then memo1.Lines.Add(removecrlf(zeilen)); gesamtstring := gesamtstring + removecrlf(zeilen); //Apenas para estatística Size := Size + SizeOf(zeilen); Inc(stichwortcounter);
23
Application.ProcessMessages; end; //Depois libera pdhili := Unassigned; pdtextS := Unassigned; pdpage := Unassigned; label2.Caption := IntToStr(stichwortcounter); label4.Caption := IntToStr(Size); label2.Refresh; label4.Refresh; end;
except on e: Exception do begin messagedlg('Erro: ' + e.Message, mtError, [mbOK], 0); Exit; end; end; if Size > 1024 then begin zwreal := Size / 1024; str(zwreal: 2: 1,zeilen); label4.Caption := zeilen; label5.Caption := 'KB'; end; memo1.Lines.SaveToFile(Extractfilepath(Application.exename) + '\debug.txt'); end; end.
Deixando seu EXE mais enxuto e rápido e, mais seguro contra decompilação Geralmente, arquivos EXE criados com Delphi são maiores que os criados com outras linguagens de programação. O motivo disso são as VCL (Claro que VCL tem muitas vantagens e devem ser usadas). Porém, é possível deixar os executáveis menores e, consequentemente, mais rápidos de serem abertos, fácil de distribuição pela Web (mesmo na era da banda larga), fica mais difícil de piratas de códigos abrir seus softwares, etc. Então apresento aqui, 10 passos (ou dicas) para deixar seu executável mais enxuto: 01) Use um EXE-Packer (UPX, ASPack,...) 02) Use o KOL.
24
03) O que puder ser desenvolvido sem o uso de VCL deve ser feito, pois quanto maior a quantidade de VCLs, maior será o executável, mas as VCL devem ser usadas, ok. 04) Use a ACL (API Controls Library) 05) Use StripReloc. 06) Desative a opção remote debugging information e TD32 do Delphi. 07) You might want to put code in a dll. 08) Não coloque imagens em Formulários. De preferência, leia em tempo de execução. 09) Use imagens compactas, como por exemplo JPG ao invés de BMP. ****************************************************** 01) UPX é um software freeware, Compactação de alto desempenho em linha de comando (sem interface gráfica). Em testes, alguns arquivos chegaram a ficar com apenas 22% de seu tamanho original. A descompressão também é muito veloz: mais de 10 MB por segundo em um pentium 133. http://upx.sourceforge.net/ ASPack é um Compressor de arquivos executáveis Win32, capaz de reduzir o tamanho de programas Windows 32-bit em mais de 70% (bem melhor que o padrão industrial ZIP, que fica em torno de 10 a 20%). Torna menores os programas e suas bibliotecas, diminuindo o tempo de transferência através de rede e o tempo de download a partir da Internet. Também protege os programas contra engenharia reversa por hackers não profissionais. Os programas comprimidos pelo ASPack rodam da mesma maneira que rodavam antes, sem perda de performance do tempo de execução.
http://www.aspack.com/aspack.htm {****************************************************************} 02) KOL - Key Objects Library é um conjunto de objetos para desenvolvimento de poderosas aplicações Windows 32 bit GUI usando Delphi sem o uso de VCL. É distribuído livremente e com o código fonte http://bonanzas.rinet.ru/ {****************************************************************} 03) nonVCL Delphi possibilita muitos caminhos. Se você quer um executável pequeno, então não uso a VCL. Isso é possível usando 100% chamadas APIs, standards resources, etc. Alguns sites que podem ajudar: http://nonvcl.luckie-online.de http://www.erm.tu-cottbus.de/delphi/stuff/Tutorials/nonVCL/index.html http://www.angelfire.com/hi5/delphizeus/ http://www.tutorials.delphi-source.de/nonvcl/
25
{****************************************************************} 04) ACL (API Controls Library) Você também pode usar a ACL, o que facilita o uso de APIs, para mais informações visite este site: http://www.apress.ru/pages/bokovikov/delphi/index.html/ {****************************************************************} 05) StripReloc Este programa remove a seção de recolocação (".reloc") dos executávies Win32 PE, reduzindo o tamanho deles. A maioria do compiladores/linkeditores (inclusive o do Delphi) insere esta seção no executável e é uma seção que nunca será usada e não tem outra finalidade senão desperdiçar espaço na memória e em disco. http://www.jrsoftware.org/striprlc.php {****************************************************************} 06) Desativando o Debug Information Exclusa qualquer informação de debug no final indo ao menu do Delphi Project / Pptions Compiler - Debugging e Project / Options: Linker EXE e DLL options. {****************************************************************} 08 e 09) Sobre imagens Formulários com muitas imagens anexadas são criadas junto ao executável, deixando ele muito grande e sempre que é executado o tamanho original é multiplicado, o que torna inviável. O melhor é anexar as imagens e enviar junto ao executável pois assim não há esta multiplicação. Use arquivos JPEG ao invés de BMP. Isso ajuda a reduzir o tamanho do EXE. {****************************************************************} Essas são apenas algums dicas, não é preciso fazer todas elas, mas caso precise...
Copiando (Upload) um diretório para um servidor FTP Oferecer uma opção de backup para clientes, ou até mesmo alguma outra aplicação, é sempre um diferencial. Para esta rotina é necessário ter o componente Indy instalado em seu Delphi. procedure UploadPerFTP; procedure GetDir(dir: string); 26
var SearchRec: TSearchRec; details, nodetails: TStringList; k: Integer; begin //Pega direito o diretório if FindFirst(dir + '*.*', faAnyFile, SearchRec) = 0 then begin repeat if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin //Se acharmos a pasta if (SearchRec.Attr and faDirectory) = faDirectory then begin //Pega a pasta que contém do FTP. um com detalhes e outro sem details := TStringList.Create; nodetails := TStringList.Create; FTPClient.List(details, '', True); FTPClient.List(nodetails, '', False); for k := details.Count - 1 downto 0 do begin if details.Strings[k] <> '' then begin if (details.Strings[k][1] <> 'd') or (nodetails.Strings[k] = '.') or (nodetails.Strings[k] = '..') then begin details.Delete(k); nodetails.Delete(k); end; end; end; //Se o diretório não existe no servidor, então cria if nodetails.IndexOf(SearchRec.Name) = -1 then begin FTPClient.MakeDir(SearchRec.Name); end; //Muda o diretório no servidor FTPClient.ChangeDir(SearchRec.Name); details.Free; nodetails.Free; //Se achou, vai para o próximo sub-siretório GetDir(dir + SearchRec.Name + '\'); //Temos que ir a um diretório a cima
27
FTPClient.ChangeDirUp; end else begin //Se é apenas um arquivo, upload o diretório atual FTPClient.Put(dir + SearchRec.Name, SearchRec.Name); end; end; until FindNext(SearchRec) <> 0; FindClose(SearchRec); end; end; var dir: string; details, nodetails: TStringList; k: Integer; begin //Seta as configurações para acesso ao servidor de FTP(TIdFTPClient) with FTPClient do begin Host := 'your_server.com'; // Coloque host Username := 'your_username'; // Colque senha Password := 'your_password'; // Adjust your data here Passive := True; end; FTPClient.Connect; //Se for de um computador remoto, ou na rede, faça isso dir := StringReplace('your/remote_directory', '\', '/', [rfReplaceAll]); if dir <> '' then begin if dir[1] = '/' then Delete(dir, 1, 1); if dir[Length(dir)] <> '/' then dir := dir + '/'; while Pos('/', dir) > 0 do begin details := TStringList.Create; nodetails := TStringList.Create; FTPClient.List(details, '', True); FTPClient.List(nodetails, '', False); for k := details.Count - 1 downto 0 do begin if details.Strings[k] <> '' then begin if (details.Strings[k][1] <> 'd') or
28
(nodetails.Strings[k] = '.') or (nodetails.Strings[k] = '..') then begin details.Delete(k); nodetails.Delete(k); end; end; end; if nodetails.IndexOf(Copy(dir, 1, Pos('/', dir) - 1)) = -1 then begin FTPClient.MakeDir(Copy(dir, 1, Pos('/', dir) - 1)); end; FTPClient.ChangeDir(Copy(dir, 1, Pos('/', dir) - 1)); Delete(dir, 1, Pos('/', dir)); details.Free; nodetails.Free; end; end; dir := 'C:\your\local\directory\'; if dir[Length(dir)] <> '\' then dir := dir + '\'; GetDir(dir); FTPClient.Disconnect; end;
Trabalhando com arquivos texto no Delphi Para trabalhar com arquivo texto: Existem vários métodos em Delphi para gravar arquivos texto a partir de informações gravadas em bases de dados ou para ler arquivos texto e armazená-los em bases de dados. Esta dica apresenta um destes métodos: o uso de TextFiles. TextFile é um tipo de dado pré-definido no Delphi e corresponde ao tipo Text do Turbo Pascal e do Object Pascal. Inicialmente para acessar um arquivo de texto, você precisa definir uma variável tipo TextFile, no local que você achar mais apropriado, da seguinte forma: var arq: TextFile; Vamos precisar também de uma variável tipo string para armazenar cada linha lida do arquivo: var linha: String;
29
Antes de se iniciar a leitura do arquivo, precisamos associar a variavel TextFile com um arquivo fisicamente armazenado no disco: AssignFile ( arq, 'C:\AUTOEXEC.BAT' ); Reset ( arq ); A rotina AssignFile faz a associação enquanto Reset abre efetivamente o arquivo para leitura. AssignFile corresponde à Assign do Turbo Pascal. Em seguida é necessário fazer uma leitura ao arquivo, para isto utilizaremos a procedure ReadLn: ReadLn ( arq, linha ); O comando acima lê apenas uma linha de cada vez, assim precisamos de um loop para efetuar várias leituras até que o arquivo acabe. Para verificar o fim do arquivo, utilizaremos a função Eof: while not Eof ( arq ) do Agora uma rotina quase completa para fazer a leitura de um arquivo texto. Esta rotina recebe como parâmetro o nome do arquivo que será lido: procedure percorreArquivoTexto ( nomeDoArquivo: String ); var arq: TextFile; linha: String; begin AssignFile ( arq, nomeDoArquivo ); Reset ( arq ); ReadLn ( arq, linha ); while not Eof ( arq ) do begin { Processe a linha lida aqui. } { Para particionar a linha lida em pedaços, use a função Copy. } ReadLn ( arq, linha ); end; CloseFile ( arq ); end; E também uma rotina quase completa para gravação de um arquivo texto. Esta rotina recebe como parâmetro o nome do arquivo que será gravado e uma tabela (TTable) de onde os dados serão lidos: procedure gravaArquivoTexto ( nomeDoArquivo: String; tabela: TTable ); var arq: TextFile; linha: String; begin AssignFile ( arq, nomeDoArquivo ); Rewrite ( arq ); tabela.First; while not tabela.Eof do begin Write ( arq, AjustaStr ( tabela.FieldByName ( 'Nome' ).AsString, 30 ) ); Write ( arq, FormatFloat ( '00000000.00', tabela.FieldByName ( 'Salario' ).AsFloat ) );
30
WriteLn ( arq ); tabela.Next; end; CloseFile ( arq ); end; Note nesta segunda rotina, a substituição de Reset por Rewrite logo após o AssignFile. Rewrite abre o arquivo para escrita, destruindo tudo que houver lá anteriormente . Note também o uso de Write e WriteLn para gravar dados no arquivo texto. Finalmente note o uso de AjustaStr e FormatFloat para garantir que campos string e numericos sejam gravados com um número fixo de caracteres. FormatFloat é uma rotina do próprio Delphi enquanto AjustaStr está definida abaixo: function AjustaStr ( str: String; tam: Integer ): String; begin while Length ( str ) < tam do str := str + ' '; if Length ( str ) > tam then str := Copy ( str, 1, tam ); Result := str; end; O uso da função AjustaStr é fundamental quando você estiver gravando arquivos texto com registros de tamanho fixo a partir de bases de dados Paradox que usualmente não preenchem campos string com espaços no final.
Criando uma conexão ao DBExpress em tempo de execução { O caminho normal para se criar uma conexão com o DBExpress no Delphi e no Kylix é o desenvolvedor colocar um componente TSQLConnection no formulário de com um duplo clique no componente abrir o editor de conexão e setar os parâmetros (drive, caminho do banco de dados, nome da conexão, etc) para indicar a conexão. Veja agora como fazer isso em tempo de execução. } procedure TVCLScanner.PostUser(const Email, FirstName, LastName: WideString); var Connection: TSQLConnection; DataSet: TSQLDataSet; begin Connection := TSQLConnection.Create(nil); with Connection do begin
31
ConnectionName := 'VCLScanner'; DriverName := 'INTERBASE'; LibraryName := 'dbexpint.dll'; VendorLib := 'GDS32.DLL'; GetDriverFunc := 'getSQLDriverINTERBASE'; Params.Add('User_Name=SYSDBA'); Params.Add('Password=masterkey'); Params.Add('Database=milo2:D:\ramosinfo\webservices\umlbank.gdb'); LoginPrompt := False; Open; end; DataSet := TSQLDataSet.Create(nil); with DataSet do begin SQLConnection := Connection; CommandText := Format('INSERT INTO kings VALUES("%s","%s","%s")', [Email, FirstN, LastN]); try ExecSQL; except end; end; Connection.Close; DataSet.Free; Connection.Free; end;
ActiveX - Pegar um texto selecionado no Internet Explorer Em defesa do Ctrl+C, Ctrl+V: Eu bem que queria saber quem é que teve a péssima idéia de condenar a cópia intelectual deslavada, deixando a gente com essa sensação desconfortável de ter que fazer as coisas por si mesmo. O sujeito que inventou a patente era obviamente um chato e provavelmente se chamava Lazinho. Nestes tempos de subjetivismo, de dinâmicas de grupo e de cursos de gestão, as pessoas são pagas para serem originalíssimas. Estamos na era da tirania da criatividade. A quantidade de bobagem, de feiúra e de chatice que isso gerou é incalculável. É por isso que, sempre que posso, tento privar o mundo de minhas desinteressantíssimas particularidades. Penso que é melhor ter um pouco mais de pudor e não sair mostrando as originalidades pra todo mundo não. Mais ou menos como barriga de mulher: se é feia, melhor nem mostrar. Pensando nisso, que tal uma rotina que pega textos selecionados do IE? Pode ser bastante útil: uses SHDocVw_TLB; // http://www.euromind.com/iedelphi Se você não tiver esta unit, visite este site.
32
function GetSelectedIEtext: string; var x: Integer; Sw: IShellWindows; IE: HWND; begin IE := FindWindow('IEFrame', nil); sw := CoShellWindows.Create; for x := SW.Count - 1 downto 0 do if (Sw.Item(x) as IWebbrowser2).hwnd = IE then begin Result := variant(Sw.Item(x)).Document.Selection.createRange.Text; break; end; end;
Cria um efeito na apresentação de um formulário procedure TForm1.animin(Sender: TObject); procedure delay(msec: Longint); var start, stop: Longint; begin start := GetTickCount; repeat stop := GetTickCount; Application.ProcessMessages; until (stop - start) >= msec; end; var maxx, maxy: Integer; MyHand: HWND; MyDc: HDC; MyCanvas: TCanvas; hal, hat, hak, haa: Integer; begin maxx := (Sender as TForm).Width; maxy := (Sender as TForm).Height; hal := 2; hat := 2; MyHand := GetDesktopWindow; MyDc := GetWindowDC(MyHand); MyCanvas := TCanvas.Create; MyCanvas.Handle := MyDC; MyCanvas.Brush.Color := (Sender as TForm).Color;
33
repeat if hat + (maxy div 24) >= maxy then begin hat := maxy end else begin hat := hat + (maxy div 24); end; if hal + (maxx div 24) >= maxx then begin hal := maxx end else begin hal := hal + (maxx div 24); end; hak := (Sender as TForm).Left + ((Sender as TForm).Width div 2) - (hal div 2); haa := (Sender as TForm).Top + ((Sender as TForm).Height div 2) - (hat div 2); MyCanvas.Rectangle(hak, haa, hak + hal, haa + hat); delay(10); until (hal = maxx) and (hat = maxy); (Sender as TForm).Show; end;
procedure TForm1.Button1Click(Sender: TObject); begin animin(form2); end; procedure TForm1.Button2Click(Sender: TObject); begin animin(form3); end;
Criando um Menu transparente Que tal brincar um pouco com suas aplicações: var hHookID: HHOOK; // Função para criar um menu transarente function MakeWndTrans(Wnd: HWND; nAlpha: Integer = 10): Boolean; type
34
TSetLayeredWindowAttributes = function(hwnd: HWND; crKey: COLORREF; bAlp ha: Byte; dwFlags: Longint): Longint; stdcall; const // Use crKey para definir a cor como transparente LWA_COLORKEY = 1; // Use bAlpha para determinar a opacidade do layer do windows LWA_ALPHA = 2; WS_EX_LAYERED = $80000; var hUser32: HMODULE; SetLayeredWindowAttributes: TSetLayeredWindowAttributes; i : Integer; begin Result := False; // É imnportante usarmos a DLL USER32.DLL e distribuir na aplicação. hUser32 := GetModuleHandle('USER32.DLL'); if hUser32 <> 0 then begin @SetLayeredWindowAttributes := GetProcAddress(hUser32,'SetLayeredWindowAtt ributes'); if @SetLayeredWindowAttributes <> nil then begin SetWindowLong(Wnd, GWL_EXSTYLE, GetWindowLong(Wnd, GWL_EXST YLE) or WS_EX_LAYERED); SetLayeredWindowAttributes(Wnd, 0, Trunc((255 / 100) * (100 nAlpha)), LWA_ALPHA); Result := True; end; end; end; // hook procedure function HookCallWndProc(nCode: Integer; wParam, lParam: Longint): Longint; stdca ll; const MENU_CLASS = '#32768'; N_ALPHA = 60; var cwps: TCWPStruct; lRet: THandle; szClass: array[0..8] of char; begin if (nCode = HC_ACTION) then begin CopyMemory(@cwps, Pointer(lParam), SizeOf(CWPSTRUCT)); case cwps.message of WM_CREATE: begin GetClassName(cwps.hwnd, szClass, Length(szClass)-1);
35
// Window name for menu is #32768 if (lstrcmpi(szClass, MENU_CLASS) = 0) then begin MakeWndTrans(cwps.hwnd, N_ALPHA {Alphablending}); end; end; end; end; Result := CallNextHookEx(WH_CALLWNDPROC, nCode, wParam, lParam); end; // Coloque no evento OnCreate do form procedure TForm1.FormCreate(Sender: TObject); var tpid: DWORD; begin tpid := GetWindowThreadProcessId(Handle, nil); hHookID := SetWindowsHookEx(WH_CALLWNDPROC, HookCallWndProc, 0, tpi d); end; // Pare o processo no evento OnDestroy procedure TForm1.FormDestroy(Sender: TObject); begin if (hHookID <> 0) then // Remove o menu transparente UnhookWindowsHookEx(hHookID); end;
Checa se um diret贸rio est谩 vazio function DirectoryIsEmpty(Directory: string): Boolean; var SR: TSearchRec; i: Integer; begin Result := False; FindFirst(IncludeTrailingPathDelimiter(Directory) + '*', faAnyFile, SR); for i := 1 to 2 do if (SR.Name = '.') or (SR.Name = '..') then Result := FindNext(SR) <> 0; FindClose(SR); end;
// Exemplo de uso: procedure TForm1.Button1Click(Sender: TObject);
36
begin if DirectoryIsEmpty('C:\test') then Label1.Caption := 'empty' else Label1.Caption := 'not empty'; end;
Mostra multiplas linhas de texto em um ComboBox procedure TForm1.ComboBox1MeasureItem(Control: TWinControl; Index: Integer; var Height: Integer); var ItemString: string; MyRect: TRect; MyImage: TImage; MyCombo: TComboBox; begin if (Index > -1) then begin MyCombo := TComboBox(Control); // Create a temporary canvas to calculate the height MyImage := TImage.Create(MyCombo); try MyRect := MyCombo.ClientRect; ItemString := MyCombo.Items.Strings[Index]; MyImage.Canvas.Font := MyCombo.Font; // Calc. using this ComboBox's font size Height := DrawText(MyImage.Canvas.Handle, PChar(ItemString), - 1, MyRect, DT_CALCRECT or DT_WORDBREAK); finally MyImage.Free; end; end; end; Modo de usar: procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var ItemString: string; begin TComboBox(Control).Canvas.FillRect(Rect); ItemString := TComboBox(Control).Items.Strings[Index]; DrawText(TComboBox(Control).Canvas.Handle, PChar(ItemString), - 1, Rect, DT_WORDBREAK); end;
37
Criando atalhos no Windows pelo Delphi implementation uses ShlObj, ActiveX, ComObj; {$R *.dfm} procedure CriaShortCut(aNome, aFileName: string; aLocation: integer); var IObject : IUnknown; ISLink : IShellLink; IPFile : IPersistFile; PIDL : PItemIDList; InFolder : array[0..MAX_PATH] of Char; TargetName : String; LinkName,s : WideString; begin TargetName := aFileName; IObject := CreateComObject(CLSID_ShellLink); ISLink := IObject as IShellLink; IPFile := IObject as IPersistFile; with ISLink do begin SetPath(pChar(TargetName)); SetWorkingDirectory(pChar(ExtractFilePath (TargetName))); end; SHGetSpecialFolderLocation (0, aLocation, PIDL); SHGetPathFromIDList(PIDL, InFolder); s := InFolder; LinkName := s + '\' + aNome + '.LNK'; if FileExists(LinkName) then ShowMessage('Atalho jรก existe!') else IPFile.Save(PWChar(LinkName), false); end; // Para utilizar: CriaShortCut('Calculadora', 'c:\windows\system32\calc.exe', CSIDL_DESKTOP);
38
Faça suas aplicações Falar Um exemplo que demonstra o uso dos objetos de fala da Microsoft para fazer suas aplicações tornarem-se falantes. Para fazer suas aplicações em Delphi FALAR basta baixar o pacote Speech SDK no site da microsoft. http://www.microsoft.com/speech Feito isso, use o seguinte código para falar "Hello World". uses Comobj; procedure TForm1.Button1Click(Sender: TObject); var objVoice: OLEVariant; begin objVoice := CreateOLEObject('SAPI.SpVoice'); objVoice.Speak('Hello World',0); objVoice := unassigned; end; Veja outros exemplos: http://www.blong.com/Conferences/DCon2002/Speech/SAPI51/SAPI51.htm
Imprimindo arquivos PDF sem abrir-los Implementation Uses shellApi; {$R *.DFM} procedure Tform1.Button1Click(Sender: Tobject); begin ShellExecute(Handle, 'print', Pchar('C;\Pasta\Leiame.pdf'), nil,nil,SW_SHOW); End;
Ler arquivos PDF Tem que ter o Acrobat instalado no computador. 1.) Coloque um opendialog e um button. 39
2.) Vá em Project + Import Type Library. 3.) Selecione Acrobat Control para ActveX..... + install ........... 4.) Aparcerá uma tela, clique em compilar...... 5.) Vá depois na palheta ActiveX e escolha o componente PDF 6.) Faça as devidos ajuste e digite no button: if opendialog1.execute then pdf1.src:=opendialog1.filename;
Inno Setup - Script para criação de conexão OBDC DSN [Setup] AppName=ODBC2 AppVerName=ODBC2 Uninstallable=false UpdateUninstallLogAppName=false DisableDirPage=false DisableProgramGroupPage=true DefaultDirName={pf}\ODBC2 DisableStartupPrompt=true CreateAppDir=false [_ISTool] EnableISX=true [Tasks] Name: cfgdsndlg; Description: Config DSN with dialog; GroupDescription: Configuration:; Flags: unchecked [Code] function SQLConfigDataSource(hwndParent: LongInt; fRequest: LongInt; lpszDriver: String; lpszAttributes: String): LongInt; external 'SQLConfigDataSource@ODBCCP32.DLL stdcall'; const ODBC_ADD_DSN = 1; // Add data source ODBC_CONFIG_DSN = 2; // Configure (edit) data source ODBC_REMOVE_DSN = 3; // Remove data source ODBC_ADD_SYS_DSN = 4; // add a system DSN ODBC_CONFIG_SYS_DSN = 5; // Configure a system DSN ODBC_REMOVE_SYS_DSN = 6; // remove a system DSN
function CreateDSN( showdlg: Boolean) : LongInt; var hwnd : LongInt; var
40
strDriver, strAttributes, NewLine : String; begin // if it is not auto configuration, setting HWND of wizard let show // DSN setup dialog with attributes specified if not showdlg then hwnd := 0 else hwnd := StrToInt(ExpandConstant('{wizardhwnd}')); // MYSQL Sample { strDriver := 'MySQL'; NewLine := Chr(0); strAttributes := 'SERVER=localhost' + NewLine + 'DESCRIPTION=MySQL Driver DSN' + NewLine + 'DSN=SAMPLE_DSN' + NewLine + 'DATABASE=test' + NewLine + 'UID=username' + NewLine + 'PASSWORD=password' + NewLine + 'PORT=3306' + NewLine + 'OPTION=3' + NewLine; } Result := SQLConfigDataSource( hwnd, ODBC_ADD_SYS_DSN, strDriver, strAttributes); end;
function NextButtonClick(CurPage: Integer): Boolean; var showdlg : Boolean; begin // by default go to next page Result := true; // if curpage is wpSelectTasks check config DSN if CurPage = wpSelectTasks then begin showdlg := ShouldProcessEntry( '','cfgdsndlg') = srYes ; if CreateDSN( showdlg ) = 0 then MsgBox( 'DSN not done.', mbError, MB_OK ) else MsgBox( 'DSN Created !', mbInformation, MB_OK ); end; end;
41
Colocar cursor no final do Edit ao receber o foco No evento OnEnter do TEdit coloque: procedure TForm1.Edit1Enter(Sender: TObject); begin Edit1.Selstart:= Length(Edit1.text); end;
Mudar a cor de fundo de um Hint Application.HintColor := clBlack;
Fazer um executável ser executado somente se chamado por um determinado executável Inclua na seção uses: Windows Problema: Gostaria que um determinado programa (Prog1.EXE) fosse executado apenas através de outro programa (Prog2.EXE). Solução: Antes da linha "Application.Initialize;" de Prog1.dpr (programa a ser chamado), coloque o código abaixo: if ParamStr(1) <> 'MinhaSenha' then begin { Para usar ShowMessage, coloque Dialogs no uses } ShowMessage('Execute este programa através de Prog2.EXE'); Halt; { Finaliza } end; No Form1 de Prog2 (programa chamador) coloque um botão e escreva o OnClick deste botão como abaixo: procedure TForm1.Button1Click(Sender: TObject); var Erro: Word; begin Erro := WinExec('Pro2.exe MinhaSenha', SW_SHOW); if Erro <= 31 then { Se ocorreu erro... } ShowMessage('Erro ao executar o programa.'); end; Observações: Aqui o parâmetro passado foi 'MinhaSenha'. Você deverá trocar 'MinhaSenha' por algo que apenas você saiba (uma senha). Caso uma pessoa conheça 42
esta senha, será possível chamar este programa passando-a como parâmetro. Neste caso sua "trava" estará violada.
DBGrid - Focando a célula selecionada mudando sua cor É possível fazer um tratamento no evento onDrawDataCell do DBGrid e verificar a célula em foco alterando a cor da mesma, veja abaixo simples exemplo: procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState); begin if (gdSelected in State) then begin with DBGrid1.Canvas do begin Brush.Color := clAqua; Font.Color := clNavy; FillRect( Rect ); TextOut(Rect.Left, Rect.Top, Field.AsString); end; end; end; Obs. Para que toda a linha fica selecionada você deverá alterar a propriedade Options -> dgRowSelect para True;
Verificando a versão do Windows Neste exemplo apresentamos uma rotina para verificar qual a versão do Windows. O que diferencia esta rotina de outras já apresentadas é que ela consegue distinguir entre todas as versões do Windows, ou seja, se é Windows 95, 98, ME, NT 4, 2000 ou XP. function GetWinVersion: String; begin case Win32MajorVersion of 3: Result := ‘Windows NT 3.51’; // NT 3.51 4: // WIn9x/ME, NT 4 case Win32MinorVersion of 0: Result := ‘Windows 95’; 10: Result := ‘Windows 98’; 90: Result := ‘Windows ME’; else if (Win32Platform and VER_PLATFORM_WIN32_NT) <> 0 then Result := ‘Windows NT 4.0’ else Result := ‘SO desconhecido’; end;
43
5: // Win2K, XP case Win32MinorVersion of 0: Result := ‘Windows 2000’; 1: Result := ‘Windows XP or .NET server’; else Result := ‘SO desconhecido’; end; else Result := ‘SO desconhecido’; end; end; // Chamada: { mostrar em um label } OSVersion.Caption := GetWinVersion;
Rave Report - Alterar a impressora padrão Basta informar o índice da impressora da seguinte forma: uses RpDevice, Printers; procedure TForm1.Button1Click (Sender: TObject); begin Printer.PrinterIndex := 0; RPDev.DeviceIndex := Printer.PrinterIndex; rvTestes.ExecuteReport(‘Rep_Employee’); end;
Atribuíndo efeitos para abertura de formulários Existe uma função chamada AnimateWindow. Veja a seguir como chamar: procedure TForm1.Button1Click(Sender: TObject); begin Form2.BringToFront; AnimateWindow(Form2.Handle, 3000, AW_BLEND); Form2.Show; { No terceiro parâmetro da função você pode utilizar uma das opções abaixo AW_BLEND : Uses a fade effect AW_SLIDE : Uses slide animation. AW_ACTIVATE : Activates the window AW_HIDE : Hides the window. 44
AW_CENTER : Makes the window appear to collapse inward AW_HOR_POSITIVE : Animates the window from left to right. AW_HOR_NEGATIVE : Animates the window from right to left AW_VER_POSITIVE : Animates the window from top to bottom AW_VER_NEGATIVE : Animates the window from bottom to top } end;
API do Windows - Função para excluir uma pasta e todos arquivos desta pasta implementation uses ShellApi; {$R *.dfm} procedure DeleteDir(hHandle: THandle; Const sPath : String; Confirm: boolean); var OpStruc: TSHFileOpStruct; FromBuffer, ToBuffer: Array[0..128] of Char; begin FillChar( OpStruc, Sizeof(OpStruc), 0 ); FillChar( FromBuffer, Sizeof (FromBuffer), 0 ); FillChar( ToBuffer, Sizeof(ToBuffer), 0 ); StrPCopy( FromBuffer, sPath); With OpStruc Do Begin Wnd:= hHandle; wFunc:=FO_DELETE; pFrom:= @FromBuffer; pTo:= @ToBuffer; if not confirm then begin fFlags:= FOF_NOCONFIRMATION; end; fAnyOperationsAborted:=False; hNameMappings:=nil; End; ShFileOperation(OpStruc); end; Usando a Função: procedure TForm1.Button1Click(Sender: TObject); begin DeleteDir(Self.Handle,’C:\TESTE’,True) 45
end; end.
Inno Setup - Verificando se existe determinada Chave no Registro do Windows O Inno Setup é o instalador oficial do nosso site. Aqui trazemos mais uma dica deste fantástico gerador de instalações, onde demonstramos como verificar se uma determinada chave existe no registro do Windows: [Setup] AppName=VerificaChave AppVerName=VerificaChave DefaultDirName={pf}\VerificaChave DisableStartupPrompt=true Uninstallable=false DisableDirPage=true OutputBaseFilename=VerificaChave [Code] function InitializeSetup(): Boolean; begin if RegKeyExists(HKEY_LOCAL_MACHINE, ‘SOFTWARE\Firebird Project\Firebird Server’) then begin MsgBox(‘ Não posso instalar! ‘, mbInformation, MB_OK ); Result := false; end else Result := true; end; Isso é muito interessante, por exemplo, para verificar se uma determinada aplicação já existe no computador do cliente.
Controlando o PowerPoint no Delphi Seguindo a linha da automação OLE Office, veja agora como controlar o powerpoint em uma aplicação delphi uses comobj; procedure TForm1.Button1Click(Sender: TObject); 46
var PowerPointApp: OLEVariant; begin try PowerPointApp := CreateOleObject('PowerPoint.Application'); except ShowMessage('Error...'); Exit; end; // Torna o Powerpoint visivel PowerPointApp.Visible := True; // Mostra versão do PowerPoint ShowMessage(Format('Powerpoint version: %s',[PowerPointApp.Version])); // Abre uma apresentação PowerPointApp.Presentations.Open('c:\\windows\\desktop\\teste.ppt', False, False, True); // SMostra o número de slides ShowMessage(Format('%s slides.',[PowerPointApp.ActivePresentation.Slides.Count])); // Roda a apresentação PowerPointApp.ActivePresentation.SlideShowSettings.Run; // Vai para o próximo slide PowerPointApp.ActivePresentation.SlideShowWindow.View.Next; // Vai para slide 2 PowerPointApp.ActivePresentation.SlideShowWindow.View.GoToSlide(2); // Vai para o slide anterior PowerPointApp.ActivePresentation.SlideShowWindow.View.Previous; // Vai para o último slide PowerPointApp.ActivePresentation.SlideShowWindow.View.Last; // Mostra o nome do Slide corrente ShowMessage(Format('Current slidename: %s',[PowerPointApp.ActivePresentation.SlideShowWindow.View.Slide.Name])); // Fecha o Powerpoint PowerPointApp.Quit; PowerPointApp := UnAssigned; end;
47
Rave Report - Indicar página inicial O Rave Reports permite ter várias páginas de relatório (cada página com um layout) para um mesmo relatório. Neste exemplo, iremos demonstrar como definir via programação qual página será apresentada como inicial. uses RVClass, RVProj, RVCsStd; procedure TForm1.btnChamaRelClick (Sender: TObject); var Pagina: TRavePage; Report: TRaveReport; QualPagina: String; begin // Nome da página dentro do projeto Rave. QualPagina := ‘Page2’; // Abre RvProject. RvProject1.Open; // Pega referência do “Report” // dentro do projeto Rave. Report := RvProject1.ProjMan.ActiveReport; // Pega referência da “Page” dentro do “Report”. Pagina := RvProject1.ProjMan.FindRaveComponent (‘Report1.’+QualPagina,nil) as TRavePage; // Indica a página inicial. Report.FirstPage := Pagina; // Executa o relatório. RvProject1.Execute; end;
InnoSetup - Adicionar um programa no iniciar do Windows O InnoSetup é uma gerador gratuito de instalações que vêm dia-a-dia se popularizando meio a comunidade Delphi. A seguir, apresentamos uma dica para adicionar sua aplicação para iniciar junto com o Windows. [Code] [Setup] AppName=Adicionar no iniciar. AppVerName= Adicionar no iniciar. DefaultDirName={pf}\ Adicionar no iniciar. DisableStartupPrompt=true Uninstallable=false DisableDirPage=true OutputBaseFilename=Adicionar no iniciar. 48
[Files] Source: C:\teste.exe; DestDir: {userstartup}; DestName: teste.exe Veja que o ‘segredo’ está no diretório de destino da aplicação ou atalho da mesma, o qual deverá ser destinado para {userstartup} que representa um path especial que o Windows irá buscar no momento que estiver iniciando.
Validando endereço de e-mail no Delphi em aplicações Win32, .Net e Asp.Net { Exemplo: If IsValidEMail(Edit1.Text) then ShowMessage('Valid E-Mail!') Else ShowMessage('Invalid E-Mail!'); } Function OcorrenciasEm(De, NoTexto:String):LongInt; Var h,CONT:LongInt; TEMP:String; Begin TEMP:=AnsiReplaceText(NoTexto, '|', '¨'); TEMP:=AnsiReplaceText(TEMP, De, '|'); CONT:=0; For h:=1 to Length(TEMP) do If TEMP[h] = '|' then CONT:=CONT+1; Result:=CONT; End; Function IsValidEMail(EMail:String):Boolean; Var h,A_POS:LongInt; OK:Boolean; TEMP:String; Begin OK:=True; TEMP:=UpperCase(EMail); For h:=1 to Length(TEMP) do Begin If Not ((ORD(TEMP[h]) >= 64) and (ORD(TEMP[h]) <= 90)) and Not (ORD(TEMP[h]) = 95) and Not (ORD(TEMP[h]) = 46) then OK:=False; End;
49
A_POS:=Pos('@', EMail); If (A_POS = 0) or (A_POS < 3) then OK:=False; If Pos('.', Copy(EMail, A_POS, Length(EMail)-A_POS)) = 0 then OK:=False; If OcorrenciasEm('@', EMail) > 1 then OK:=False; If Pos('..', EMail) > 0 then OK:=False; If Pos('@.', EMail) > 0 then OK:=False; If Email[1] = '.' then OK:=False; If Email[Length(EMail)] = '.' then OK:=False; If Length(Email) > 250 then OK:=False; Result:=OK; End;
Memo redondo Pensando no carnaval, que tal montar o Rei Memo? Veja a rotina: procedure TForm1.Button1Click(Sender: TObject); procedure MemoRedondo(QueMemo: TMemo); var rect : TRect; rgn : HRGN; begin rect := QueMemo.ClientRect; rgn := CreateRoundRectRgn( rect.Left, rect.top, rect.right, rect.bottom, 20, 20); QueMemo.BorderStyle := bsNone; QueMemo.Perform(EM_GETRECT, 0, lparam(@rect)); InflateRect(rect, -5, -5); QueMemo.Perform(EM_SETRECTNP, 0, lparam(@rect)); SetWindowRgn(QueMemo.Handle, rgn, true); end; Como usar: begin MemoRedondo(Memo1); end;
Colocar Banners em Menus Vamos adicionar em um menu, uma imagem no estilo “banner”. Para isso, adicione no formulário um Image e carregue uma imagem de sua preferência. Selecione todos os itens do menu e no evento OnDrawItem digite o seguinte código:
50
procedure TForm1.Exit1DrawItem(Sender: TObject; ACanvas: TCanvas; ARect: TRect; Selected: Boolean); begin ACanvas.FillRect(ARect); ACanvas.TextOut(ARect.Left+48, ARect.Top, StripHotkey((Sender as TMenuItem).Caption)); ACanvas.Draw(0, 0, Image1.Picture.Graphic); ImageList1.Draw(ACanvas, ARect.Left+30, ARect.Top, (Sender as TMenuItem).ImageIndex); end;
Usando a WebCam no Delphi Recebo constantemente e-mails pedindo informações de como usar a WebCam no Delphi. O primeiro passo é baixar o SDK do fabricante da WebCam. Neste exemplo, que segue, estou utilizando o Quick Cam SDK, que pode ser encontrado no site do fabricante, que neste caso é: http://developer.logitech.com/ O exemplo a seguir mostra como usar o método PictureToMemory da biblioteca Quick Cam SDK. No site do fabricante também há documentações de como usar a SDK. type TMemoryStream = class(Classes.TMemoryStream); var MS : TMemoryStream; lSize : LongInt; pBuffer : ^Byte; begin MS := TMemoryStream.Create; bitmap1 := TBitmap.Create; try if VideoPortal1.PictureToMemory(0,24,0,lSize,'') = 1 then begin pBuffer := AllocMem(lSize); if VideoPortal1.PictureToMemory(0,24,integer(pBuffer),lSize,'') = 1 then begin MS.SetPointer(pBuffer,lSize); bitmap1.loadfromstream(MS); end; end; finally MS.Free; FreeMem(pBuffer);
51
end; end;
Colocando imagens em um ComboBox Inicialmente, é necessário setar a propriedade "Style" do ComboBox para "csOwnerDrawVariable". Desta forma teremos a liberdade para desenharmos o que quisermos dentro do ComboBox. Imaginemos que o nosso ComboBox possui três ítens. E para cada ítem colocaremos uma imagem diferente. Para isso, criaremos um vetor que terá um número de elementos correspondente a quantidade de ítens de nosso ComboBox. No nosso exemplo, serão três elementos. Este vetor deve ser criado como uma variável "private" (em "private declarations" do form). private Img: Array[0..2] of TBitmap; A seguir, no evento "OnCreate" do nosso formulário colocaremos o seguinte: procedure TForm1.FormCreate(Sender: TObject); begin Img[0] := TBitmap.Create; Img[0].LoadFromFile('edit.bmp'); ComboBox1.Items.AddObject('Edit', Img[0]); Img[1] := TBitmap.Create; Img[1].LoadFromFile('delete.bmp'); ComboBox1.Items.AddObject('Delete', Img[1]); Img[2] := TBitmap.Create; Img[2].LoadFromFile('export.bmp'); ComboBox1.Items.AddObject('Export', Img[2]); end; Agora o trabalho é no evento "OnDrawItem" do ComboBox que deverá ter o seguinte: procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var Bmp: TBitmap; Off: Integer; Cmb: TComboBox;
52
begin Cmb := (Control as TComboBox); with Cmb.Canvas do begin FillRect(Rect); Off := 0; Bmp := TBitmap(ComboBox1.Items.Objects[Index]); if Bmp <> nil then begin BrushCopy(Bounds(Rect.Left+2, Rect.Top+2, Bmp.Width, Bmp.Height), Bmp, Bounds(0, 0, Bmp.Width, Bmp.Height), clOlive); Off := Bmp.Width+8; end; TextOut(Rect.Left + Off, Rect.Top, ComboBox1.Items[Index]); end; end; E, finalmente, no evento "OnMeasureItem" do ComboBox: procedure TForm1.ComboBox1MeasureItem(Control: TWinControl; Index: Integer; var Height: Integer); begin Height := 20; end; Alguma explicação: O evento "OnDrawItem" é o responsável por "desenhar" cada ítem do ComboBox quando clicamos no ícone para abrí-lo. Simplesmente aproveitamos isto para desenhar a nossa imagem antes do texto. Neste mesmo evento fizemos uma chamada a função "BrushCopy", onde o último parâmetro é a cor que deseja que fique transparente. Como eu utilizei imagens que vem com o Delphi, a cor de fundo destas imagens é o amarelo escuro (clOlive). Daí pra frente é testar com imagens diferentes, porém, uma sugestão é que todas tenham o mesmo tamanho para que se mantenha um padrão dentro do seu ComboBox.
Importando e Exportando Registro Um técnica bem simples para exportar/importar o registry em arquivos no formato .REG. Function ExportRegistry(FileName:String; ExportKey:String):Boolean; Begin ShellExecute(0,nil,'REGEDIT.EXE',PChar('/SC /E '+FileName+' "'+ExportKey+'"'),nil,sw_hide);
53
Result := FileExists(FileName); End; Function ImportRegistry(FileName:String; ExportKey:String):Boolean; Begin Result := FileExists(FileName); If Result Then Begin ShellExecute(0,nil,'REGEDIT.EXE',PChar('/SC /C '+FileName),nil,sw_hide); End; End; Exemplo: procedure TForm1.Button1Click(Sender: TObject); begin ExportRegistry('c:\\windows\\desktop\\teste.reg','HKEY_CURRENT_USER\\Software\\ Borland'); end;
DBGrid - Colocar um ComboBox num DBGrid As colunas da DBGrid tem uma propriedade chamada PickList, que permite colocar as opções numa lista, que serão mostradas quando a coluna é editada. Para preenchê-la, basta abrir o editor de colunas da DBGrid, selecionar a coluna desejada, abrir o editor da PickList e colocar as opções para aquela coluna. Assim, ao editar a coluna, abre-se a combobox.
Enviando mensagens HTML com imagens anexadas Para se enviar uma mensagem html com os componentes Indy basta usar a propriedade ContentType de TIdMessage, configurando-a para text/html. Quando se quer mandar uma imagem nesta mensagem, uma maneira que pode ser usada é colocar um link externo para ela: <img src="http://www.meusite.com/imagem.jpg">. Isto, além de gerar um tráfego desnecessário no site, tende a ser desabilitado nos mailers, por ser um risco de segurança. Outra maneira é embutir a imagem na mensagem como anexo e ligar o link a ela. Porém, como fazer isso ? Qual é o link para a mensagem anexa ? Este link é dado pelo Content-Id da imagem. Ao chamar o link para a imagem, faz-se algo como <img src="cid:minhaimagem">. minhaimagem é o content-id da imagem, que é definido quando colocamos a mensagem como anexo:
54
Imagem := TIdAttachment.Create(MessageParts, 'c:\windows\cafezinho.bmp'); // Aqui estou preenchendo o Content-ID Imagem.ExtraHeaders.Values['Content-ID'] := '<minhaimagem>'; Imagem.ContentType := 'image/jpeg'; Desta maneira, a imagem vai na mensagem e é aberta sem problemas. Ao executar o programa da postagem, notamos um problema: a mensagem é enviada corretamente, com a imagem em anexo, porém o html não é gerado corretamente, aparecendo como texto normal. Analisando o cabeçalho da mensagem, vemos que o content-type da mensagem está como text/plain, mesmo tendo especificado text/html. O que ocorre é que a mensagem, quando tem um anexo, é transformada em multipart e isso faz que o conteúdo seja enviado como texto. Uma solução para isto é enviar o texto da mensagem como uma parte de texto, com conteúdo html. Isto é feito criando-se uma variável do tipo TIdText, que será preenchida com o texto que queremos. Na realidade, iremos criar duas partes de texto na mensagem: uma normal, não html, que será mostrada em leitores de e-mail não html, e outra html. Isto é feito da seguinte maneira:
// configura para multipart ContentType := 'Multipart/Alternative'; // parte de texto normal idText := TIdText.Create(MessageParts,nil); idText.ContentType := 'text/plain'; idText.Body.Add('Esta parte é texto puro e não mostra a imagem'); // parte de texto html idText := TIdText.Create(MessageParts,nil); idText.ContentType := 'text/html'; idText.Body.Text := '<html><body>Esta mensagem html tem '+ 'imagens<br />'+ 'A imagem está como anexo, e não está fora da mensagem:<br />'+ '<img src="cid:MinhaImagem"></body></html>'; // Configura anexos Imagem := TIdAttachment.Create(MessageParts, 'c:\windows\cafezinho.bmp'); Imagem.ExtraHeaders.Values['Content-ID'] := '<minhaimagem>'; Imagem.ContentType := 'image/jpeg'; Desta maneira, temos a mensagem com anexos formatada corretamente, podendo ser vista tanto em leitores texto como html.
55
Mostrando dicas balão para caixas de edição wm WindowsXP Para mostrar uma dica balão para uma caixa de edição, devemos mandar uma mensagem EM_SHOWBALLOONTIP para ela. O texto, título e ícone da dica são mandados prenchendo um record do tipo TEditBalloonTip, definida como: TEditBalloonTip = packed record cbStruct: DWORD ; pszTitle: LPCWSTR ; pszText: LPCWSTR; ttiIcon: Integer; end; Uma vez preenchido record, passamos como o terceiro parâmetro para a função SendMessageW: procedure ShowBalloonTip(Window : HWnd; Texto, Titulo : PWideChar;Tipo : Integer); var EditBalloonTip : TEditBalloonTip; begin EditBalloonTip.cbStruct := SizeOf(TEditBalloonTip); EditBalloonTip.pszText := Texto; EditBalloonTip.pszTitle := Titulo; EditBalloonTip.ttiIcon := Tipo; SendMessageW(Window, EM_SHOWBALLOONTIP, 0, Integer(@EditBalloonTip)); end; O código completo das funções que mostram e escondem a dica é o seguinte: TEditBalloonTip = packed record cbStruct: DWORD ; pszTitle: LPCWSTR ; pszText: LPCWSTR; ttiIcon: Integer; end; const ECM_FIRST = $1500; EM_SHOWBALLOONTIP = (ECM_FIRST + 3); EM_HIDEBALLOONTIP = (ECM_FIRST + 4); TTI_NONE = 0; TTI_INFO = 1; TTI_WARNING = 2; TTI_ERROR = 3; var Form1: TForm1; implementation 56
{$R *.dfm}
procedure ShowBalloonTip(Window : HWnd; Texto, Titulo : PWideChar;Tipo : Integer); var EditBalloonTip : TEditBalloonTip; begin EditBalloonTip.cbStruct := SizeOf(TEditBalloonTip); EditBalloonTip.pszText := Texto; EditBalloonTip.pszTitle := Titulo; EditBalloonTip.ttiIcon := Tipo; SendMessageW(Window, EM_SHOWBALLOONTIP, 0, Integer(@EditBalloonTip)); end; procedure HideBalloonTip(Window : HWnd); begin SendMessageW(Window, EM_HIDEBALLOONTIP, 0, 0) end; procedure TForm1.Button1Click(Sender: TObject); begin ShowBalloonTip(Edit1.Handle,'Texto a ser mostrado', 'Título da janela',TTI_INFO); end; procedure TForm1.Button2Click(Sender: TObject); begin HideBalloonTip(Edit1.Handle); end; Nota: Esta dica só funciona com os estilos do XP ativados. Assim, você precisa colocar um componente TXpManifest na sua Form.
CheckLisBox - Trocar a cor das linhas Existe uma forma simples de fazer este tipo de trabalho. Inclua alguns itens no seu CheckListBox, vá até a propriedade Style e altere para lbOwnerDrawVariable, agora vá até ao evento OnDrawItem e inclua o código abaixo: CheckListBox1.Canvas.FillRect(Rect); if not (odFocused in State) then begin if CheckListBox1.Checked[index] then begin CheckListBox1.Canvas.Font.Color := clRed; CheckListBox1.Canvas.Brush.Color := clWhite; end
57
else begin CheckListBox1.Canvas.Font.Color := clBlack; CheckListBox1.Canvas.Brush.Color := clWhite; end; end; CheckListBox1.Canvas.TextOut(Rect.Left+2,Rect.Top,CheckListBox1.Items.Strings[In dex]);
Windows - Verificar a impressora padrão implementation uses Printers; {$R *.dfm} function GetDefaultPrinter: string; var ResStr: array[0..255] of Char; begin GetProfileString('Windows', 'device', '', ResStr, 255); Result := StrPas(ResStr); end; procedure TForm1.Button1Click(Sender: TObject); begin Caption := GetDefaultPrinter; end;
RichEdit - Pesquisar um texto, posicionar sobre ele e mostrar ao usuário No Windows XP somente utilizar o SelStart não mostrou a linha encontrada ao usuário, foi necessário utilizar o perform para mostrar a linha onde está o texto encontrado. procedure TForm1.SpeedButton1Click(Sender: TObject); var nPos, Linha: Integer; begin With RichEdit1 do begin SetFocus; { Pega a linha atual } Linha := Perform(EM_LINEFROMCHAR, SelStart, 0); nPos := FindText(Edit1.Text, 0, Length(RichEdit1.Text), []); { Posiciona o cursor sobre o texto encontrado na pesquisa } 58
SelStart := nPos; SelLength := Length(Edit1.Text); { Pega a quantidade de linhas que separa a última linha para essa nova linha posicionada } Linha := Perform(EM_LINEFROMCHAR, SelStart, 0)-Linha; { Visualiza a nova linha } Perform(EM_LINESCROLL, Linha, Linha); end; end;
ActiveControl - Envia um valor para Edit que estiver em foco Verifica se o componente que está com o foco é da classe do TEdit, se for envia um Texto para esse componente. procedure TForm1.SpeedButton1Click(Sender: TObject); begin if (ActiveControl is TEdit) then (ActiveControl as TEdit).Text := 'Teste'; end; Funciona para outros componentes, trocando a propriedade Text utilizado neste exemplo pela propriedade do outro componente.
Registro do Windows - Retorna portas seriais procedure TForm1.Button1Click(Sender: TObject); var Reg: TRegistry; ts : TStrings; i : Integer; begin Reg := TRegistry.Create; Reg.RootKey := HKEY_LOCAL_MACHINE; Reg.OpenKey('HARDWARE\DEVICEMAP\SERIALCOMM', False); ts := TStringList.Create; Reg.GetValueNames(ts); for i := 0 to ts.Count -1 do ListBox1.Items.Add(Reg.ReadString(ts.Strings[i])); ts.Free; Reg.CloseKey; Reg.Free; end;
59
Verifica se um programa está aberto, caso contrário, abre Existe uma forma que é pegando o nome da janela. Veja o exemplo abaixo que trabalha com a calculadora do Windows. procedure TForm1.Button1Click(Sender: TObject); var TheWindow: HWND; begin {find a handle to the Windows Explorer window} TheWindow:=FindWindow(nil,'Calculadora'); if TheWindow <> 0 then // Chama calculadora se já estiver carregada SetForegroundWindow(TheWindow) else // Carrega calculadora se estiver fechada ShellExecute(Handle, 'Open', 'Calc.exe', nil, 'c:\windows', end;
sw_shownormal);
Função que verifica a velocidade do processador function GetCPUSpeed: Double; const DelayTime = 500; var TimerHi, TimerLo: DWORD; PriorityClass, Priority: Integer; begin 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); 60
Result := TimerLo / (1000.0 * DelayTime); end; procedure TForm1.Timer1Timer(Sender: TObject); var CPUSpeed: Double; begin CPUSpeed := GetCPUSpeed; Label1.Caption := FormatFloat('0.00 MHz', CPUSpeed); end;
DBGrid - Ao clicar no campo no DBGrid ordenar os registros Temos na tabela 04 campos: Empresa, Inscricao, Contador e Telefone No Evento OnTitleClick do dbgrid: var campo:string; begin campo:=column.fieldname; application.processmessages; query1.sql.clear; query1.sql.add('select * from Contribuinte order by '+campo); if not query1.Prepared then query1.Prepare; query1.Open; if campo='Nome' then label12.caption:='Consulta por ordem de Empresa'; // campo Empresa if campo='Inscricao' then label12.caption:='Consulta por ordem de Inscrição'; // campo Inscrição if campo='Contador' then label12.caption:='Consulta por ordem de Contador'; // campo Contador if campo='Telefone' then label12.caption:='Consulta por ordem de Telefone' // campo Telefone // Ao clicar em cada campo os registros são ordenados
Criando um lista Push and Pop em Delphi Veja como implementar uma lista Push and Pop (Last In First Out) usando Array e TList. Demonstra ainda a técnica do uso de Arrays em um TList.
61
Type TInfo = Record Nome : String; End; PInfo = ^TInfo; //============================================================= ================= // Coloca itens na lista //============================================================= ================= Procedure PushItem(List:TList; Nome:String); Var Info : PInfo; Begin New(Info); Info.Nome := Nome; List.Add(Info); End; //============================================================= ================= // Retira o ultimo item da lista //============================================================= ================= Procedure PopItem(List:TList; Var Nome:String); Begin If List.Count>0 then Begin Nome := PInfo(List[List.Count-1]).Nome; Dispose(PInfo(List[List.Count-1])); List.Delete(List.Count-1); End Else Begin Nome := ''; End; End; //============================================================= ================= // Retorna um item a partir de sua posicao //============================================================= ================= Procedure GetItem(List:TList; Var Info:PInfo; RecordNumber:Integer); Begin Info := PInfo(List[RecordNumber]); End; //============================================================= ================= // Cria o objeto de lista //============================================================= =================
62
Procedure CreateList(Var List:TList); Begin If not Assigned(List) then List := TList.Create Else List.Clear; End; //============================================================= ================= // Destroi a lista e remove os ponteiros //============================================================= ================= Procedure DestroyList(List:TList); Var I : Integer; Begin for i := 0 to List.Count-1 do Dispose(PInfo(List[i])); List.Free; End; //============================================================= ================= // Exemplo de Uso da lista //============================================================= ================= procedure TForm1.Button1Click(Sender: TObject); Var List : TList; i : Integer; Info : PInfo; Nome : String; begin CreateList(List); // Empilha itens PushItem(List,'Adenilton'); PushItem(List,'Ana'); PushItem(List,'Roberto'); PushItem(List,'Marta'); PushItem(List,'Silvia'); PushItem(List,'Pedro'); // Remove itens comecando pelo ultimo inserido PopItem(List,Nome); ShowMessage('Retirando '+Nome+' da lista '); PopItem(List,Nome); ShowMessage('Retirando '+Nome+' da lista '); PopItem(List,Nome); ShowMessage('Retirando '+Nome+' da lista ');
63
PushItem(List,'Carlos'); // Mostra os demais Itens de baixo para cima for i := List.Count-1 downto 0 do Begin GetItem(List,Info,i); ShowMessage(Info.Nome); End; // Destroi a lista DestroyList(List); end;
Rave Report - Imprimindo código de barras em modo de programação // Uses rpBars procedure TForm1.RvSystem1Print(Sender: TObject); begin With TRPBars2of5.Create(Sender as TBaseReport) do Begin BarHeight := 1.5; BarWidth := 0.065; WideFactor := BarWidth; Text := '27596000000000000000902900000124000341010150'; PrintXY(1,1); Free; end; end;
Gerar planilhas no Excel através de uma Query Procedimento que recebe um Query e gera um planilha do Excel. procedure GerarExcel(Consulta:TQuery); var coluna, linha: integer; excel: variant; valor: string; begin try excel:=CreateOleObject('Excel.Application'); excel.Workbooks.add(1); except Application.MessageBox ('Versão do Ms-Excel'+
64
'Incompatível','Erro',MB_OK+MB_ICONEXCLAMATION); end; Consulta.First; try for linha:=0 to Consulta.RecordCount-1 do begin for coluna:=1 to Consulta.FieldCount do // eliminei a coluna 0 da relação do Excel begin valor:= Consulta.Fields[coluna-1].AsString; excel.cells [linha+2,coluna]:=valor; end; Consulta.Next; end; for coluna:=1 to Consulta.FieldCount do // eliminei a coluna 0 da relação do Excel begin valor:= Consulta.Fields[coluna-1].DisplayLabel; excel.cells[1,coluna]:=valor; end; excel.columns.AutoFit; // esta linha é para fazer com que o Excel dimencione as células adequadamente. excel.visible:=true; except Application.MessageBox ('Aconteceu um erro desconhecido durante a conversão'+ 'da tabela para o Ms-Excel','Erro',MB_OK+MB_ICONEXCLAMATION); end; end;
Rave Report - Somar valores Existe um componente chamado "CalcTotal" o qual faz praticamente as mesmas operações que o QRExpr. Para utilizar, faça o seguinte: 1. Adicione um CalcOp em sua banda de totalização; 2. Configure suas propriedades: - DataView, apontando para seu DataView - DataField, campo a ser totalizado - Controller, banda "detalhe" - DestPIVar, uma variável criada na propriedade PIVars da "page" - CalcType, ctSum 3. Adicione um componente DataText e configure sua propriedade DataField apontando para a variável que recebeu o valor no item acima. Com isso, o será efetuada a soma do campo e apresentado no referido DataText.
65
Colorir componente focado - Preservando sua cor original public procedure ColorControl(Sender: TObject); end;
type TControlaCor = Record Objeto: TComponent; Cor: TColor; end;
var Form1: TForm1; ControlaCor: TControlaCor;
implementation {$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject); begin Screen.OnActiveControlChange := ColorControl; end;
{Procedure que altera a cor} procedure TForm1.ColorControl(Sender: TObject); begin if Screen.ActiveControl is TForm then Exit; if (ControlaCor.Objeto = Nil) or (not TComboBox(ControlaCor.Objeto).Showing) then begin ControlaCor.Objeto := Screen.ActiveControl; ControlaCor.Cor := TComboBox(Screen.ActiveControl).Color; end; With Screen.ActiveForm do begin TComboBox(ControlaCor.Objeto).Color := ControlaCor.Cor; ControlaCor.Objeto := Screen.ActiveControl; ControlaCor.Cor := TComboBox(Screen.ActiveControl).Color; TComboBox(Screen.ActiveControl).Color := clInfoBk end; end; 66
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Screen.OnActiveControlChange := Nil; end;
ActiveControl - Envia valor para Edit que tiver em foco Verifica se o componente que está com o foco é da classe do TEdit, se for envia um Texto para esse componente. procedure TForm1.SpeedButton1Click(Sender: TObject); begin if (ActiveControl is TEdit) then (ActiveControl as TEdit).Text := 'Teste'; end; Funciona para outros componentes, trocando a propriedade Text utilizado neste exemplo pela propriedade do outro componente.
TFields - Adiciona Fields no Fields Editors em tempo de execução { Primeiramente temos que ter declarado as variáveis onde serão criado os Objetos Fields. } public Table1Name: TStringField; Table1Capital: TStringField; Table1Continent: TStringField; Table1Area: TFloatField; Table1Population: TFloatField; { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} { Agora criamos os Objetos e configuramos suas propriedades } procedure TForm1.Button1Click(Sender: TObject); begin Table1.Close; Button1.Enabled := False; Button2.Enabled := True; 67
Table1Name := TStringField.Create(Table1); Table1Name.FieldName := 'Name'; Table1Name.DataSet := Table1; Table1Name.FieldKind := fkData; Table1Name.Size := 24; Table1Capital := TStringField.Create(Table1); Table1Capital.FieldName := 'Capital'; Table1Capital.DataSet := Table1; Table1Capital.FieldKind := fkData; Table1Capital.Size := 24; Table1Continent := TStringField.Create(Table1); Table1Continent.FieldName := 'Continent'; Table1Continent.DataSet := Table1; Table1Continent.FieldKind := fkData; Table1Continent.Size := 24; Table1Area := TFloatField.Create(Table1); Table1Area.FieldName := 'Area'; Table1Area.DataSet := Table1; Table1Population := TFloatField.Create(Table1); Table1Population.FieldName:= 'Population'; Table1Population.DataSet := Table1; Table1.Open; end; { Aqui destruimos todos os objetos Fields criados } procedure TForm1.Button2Click(Sender: TObject); begin Table1.Close; Button1.Enabled := True; Button2.Enabled := False; Table1Name.Free; Table1Capital.Free; Table1Continent.Free; Table1Area.Free; Table1Population.Free; Table1.Open; end; { Um simples exemplo de como configurar a máscara via programação } procedure TForm1.Button3Click(Sender: TObject); begin try Table1.Close; Table1Area.DisplayFormat := '###,###,##0'; Table1Population.DisplayFormat := '###,###,##0';
68
Table1.Open; except ShowMessage('Adicione os campos...') end; end;
ListBox - Colorir procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); begin if StrToInt(ListBox1.Items[Index]) > 5 then begin ListBox1.Canvas.Font.Color := clBlue; ListBox1.Canvas.Font.Style := [fsBold]; ListBox1.Canvas.Brush.Color := clYellow; end; ListBox1.Canvas.FillRect(Rect); ListBox1.Canvas.TextOut(Rect.Left, Rect.Top, Listbox1.Items[Index]); end; *** Alterar a propriedade Style para onDrawVariable
Associando um extensão de arquivo a um executável { é necessário declarar a unit abaixo } Registry procedure CriaChave(const Chave, Nome, Valor: string); var K: TRegistry; begin K := TRegistry.Create; try K.RootKey := HKEY_CLASSES_ROOT; K.OpenKey(Chave, true); K.WriteString(Nome, Valor); finally K.Free; end; end;
procedure CriaAssociacao(const NomeDoc, NomeApp, NomeEXE, NomeIcone, Ext: string); begin CriaChave(NomeDoc, ‘’, NomeApp); 69
CriaChave(Ext, ‘’, NomeDoc); CriaChave(NomeDoc+‘\shell\open\command’,‘’,NomeEXE); CriaChave(NomeDoc + ‘\DefaultIcon’,‘’, NomeIcone); end;
procedure TForm1.Button1Click(Sender: TObject); begin Button1.Enabled := false; Try // EdDoc.Text = Nome do arquivo Exemplo: Doc01 // EdNome.Text = Nome do programa Exemplo:NotePad // EdExe.Text = Executável Exemplo: // c:\windows\notepad.exe %1 // EdIcone.Text = Ícone Exemplo: // c:\windows\notepad.exe // EdExt.Text = Extensão Exemplo: .xxx // CriaAssociacao(EdDoc.Text, EdNome.Text, // EdEXE.Text, EdIcone.Text, EdExt.Text); finally Button1.Enabled := true; end; end;
Retornar as contas de E-Mail Nesta dica iremos demonstrar como obter as contas de email registradas na Máquina, verificando as informações armazenadas do registrador do Windows. Neste exemplo iremos utilizar um componente TListBox e um TButton... implementation uses Registry; {$R *.DFM} { Evento OnShow do Formulário } procedure TForm1.FormShow(Sender: TObject); var Reg: TRegistry; begin Reg := TRegistry.Create; try Reg.RootKey := HKEY_CURRENT_USER; Reg.OpenKey(‘\Software\Microsoft\Internet Account Manager\Accounts’, False); Reg.GetKeyNames(ListBox1.Items); finally
70
Reg.CloseKey; Reg.Free; end; end; { evento OnClick do TButton } procedure TForm1.Button1Click(Sender: TObject); var Reg: TRegistry; sKey : String; begin if ListBox1.ItemIndex = -1 then Exit; Reg := TRegistry.Create; try Reg.RootKey := HKEY_CURRENT_USER; sKey := ‘\Software\Microsoft\Internet Account Manager\Accounts\’; sKey := sKey + ListBox1.Items[ListBox1.ItemIndex]; Reg.OpenKey(sKey, False); if Reg.ValueExists(‘SMTP Server’) then ShowMessage( ‘O SMTP da conta selecionada é :’+#13+ Reg.ReadString(‘SMTP Server’) ) else ShowMessage(‘SMTP não existe para esta conta’); finally Reg.CloseKey; Reg.Free; end; end;
HKEY, Registry implementation uses registry;
{ Atribui um informacao para o Registry } procedure TForm1.BitBtn2Click(Sender: TObject); Var Reg : TRegistry; begin Reg := Tregistry.Create; With TRegistry.Create do begin RootKey:= HKEY_USERS; OpenKey(RamosInformatica\curso\teste', True); WriteString('Teste_Reg1','Teste Teste'); Free; end;
71
end; { Recupera um valor do Registry } procedure TForm1.BitBtn7Click(Sender: TObject); Var Reg : TRegistry; Value : string; begin Reg := Tregistry.Create; With TRegistry.Create do begin RootKey:= HKEY_USERS; OpenKey('Ramosinformatica\curso\teste', True); Caption := ReadString('Teste_Reg1'); Free; end; end;
Criar e ler chave procedure TForm1.Button1Click(Sender: TObject); var Reg: TRegistry; S: String; begin Reg := TRegistry.Create; Reg.RootKey := HKey_Classes_Root; if Reg.Openkey('RamosDaInformatica',True) then { Cria ou Abre a chave principal } begin Reg.CreateKey('Empresa'); { Cria Sub-Chave dentro de RamosDaInformatica} Reg.CreateKey('Chave'); { Cria Sub-Chave dentro de RamosDaInformatica} ShowMessage('Chave Criada...') end else ShowMessage('Erro na criação da Chave...'); // S := Reg.ReadString('(Padrão)'); Reg.free; end;
//Lê informações da Empresa cadastrado na máquina procedure TForm1.Button1Click(Sender: TObject); var Info: TRegDataInfo; Reg: TRegistry; begin Reg := TRegistry.Create; Reg.RootKey := HKEY_LOCAL_MACHINE;
72
if not Reg.OpenKey('\SOFTWARE\Microsoft\Windows\CurrentVersion', FALSE) then Reg.GetDataInfo('RegisteredOrganization', Info); Label1.Caption := 'Empresa...: ' + Reg.ReadString('RegisteredOrganization'); Label2.Caption := 'Usuario...: ' + Reg.ReadString('RegisteredOwner'); end;
Retornar lista de hardware via registry var Reg: TRegistry; Chs, tmp: TStringList; i, t: integer; begin Chs := TStringList.Create; tmp := TStringList.Create; Reg := TRegistry.Create; Reg.RootKey := HKEY_LOCAL_MACHINE; Reg.OpenKey('hardware\devicemap\', false); Reg.GetKeyNames(Chs); for i := 0 to Chs.Count -1 do begin Reg.Free; Reg := TRegistry.Create; Reg.RootKey := HKEY_LOCAL_MACHINE; Reg.OpenKey('hardware\devicemap\' + Chs[i], false); Reg.GetKeyNames(tmp); if tmp.Count = 0 then Reg.GetValueNames(tmp); Memo1.Lines.Add('---> ' + Chs[i]); Memo1.Lines.Add(tmp.Text); Memo1.Lines.Add('------------------------'); end; Chs.Free; tmp.Free; Reg.CloseKey; Reg.Free; end;
Verificar se um valor existe dentro de uma Chave implementation uses Registry; {$R *.DFM} 73
procedure TForm1.Button1Click(Sender: TObject); var Reg: TRegistry; begin Reg := TRegistry.Create; Reg.RootKey := HKEY_LOCAL_MACHINE; Reg.OpenKey('\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo\', False); if Reg.ValueExists('DSQUERY') then Showmessage('Existe!'); end;
Quick Report - Selecionando itens do ComboBox para PapeSize procedure TForm1.ComboBox1Click(Sender: TObject); var i : integer; begin //Atribui o item selecionado no ComboBox a prop. PaperSize For i := 1 to ComboBox1.Items.Count-1 do begin if ComboBox1.Items[ComboBox1.ItemIndex] = 'Letter' then QuickRep1.Page.PaperSize := Letter else if ComboBox1.Items[ComboBox1.ItemIndex] = 'Custom' then QuickRep1.Page.PaperSize := Custom else if ComboBox1.Items[ComboBox1.ItemIndex] = 'A4' then QuickRep1.Page.PaperSize := A4; end; end;
procedure TForm1.FormCreate(Sender: TObject); begin // Atribui os nomes ao ComboBox ComboBox1.Items.ADD('Letter'); ComboBox1.Items.ADD('Custom'); ComboBox1.Items.ADD('A4'); end;
ListBox - Pesquisa incremental Para fazer uma pesquisa incremental no ListBox você irá precisar também de um componente Edit. Inclua o código abaixo no evento OnChange do componente Edit. 74
procedure TForm1.Edit1Change(Sender: TObject); var S: Array[0 ..255] of char; begin StrPCopy(S, Edit1.Text); with ListBox1 do ItemIndex := Perform(LB_SELECTSTRING, 0, LongInt(@S)); if (ListBox1.ItemIndex < 0) or (ListBox1.Items[ListBox1.ItemIndex] <> Edit1.Text) then ListBox1.ItemIndex := -1; end;
Acertar data e hora com o servidor No Windows NT/2000/XP existem APIs específicas para obter a data e hora de um Servidor, porém com Windows 9x não encontramos APIs com o mesmo efeito, porém é possível implementar via um utilitário DOS e com isso acertar a data e hora de uma máquina com outra da rede. procedure AcertaHora(ServerName: String); begin WinExec(PChar(‘net time ‘ + ServerName +’ /set /yes’), 0); end;
QuickReport - Access Violation no Windows 2000 e XP Ocorre devido ao tamanho do caminho do diretório temporário do Windows. Vá em Control Panel -> System -> Clique na aba Advanced -> Clique no botão Environment Variables. Altere o caminho da variável TMP para um caminho menor, como por exemplo c:\temp. Confirme se este diretório já está criado.
DBGrid - Alterar as cores do título em tempo de execução. procedure TForm1.DBGrid1TitleClick(Column: TColumn); var I: integer; begin for i:=0 to DBGrid1.Columns.count-1 do begin DBGrid1.Columns[i].Title.Color := clBtnFace;
75
DBGrid1.Columns[i].Title.Font.Color := clBlack; DBGrid1.Columns[i].Title.Font.Style := []; end; Column.Title.color := ClYellow; Column.Title.Font.Style := [ fsBold, fsItalic]; Column.Title.Font.Color := clRed; end;
Testa se a impressora está funcionando function PrinterOK(Lpt: Word): Boolean; const PrnStInt : Byte = $17; StRq : Byte = $02; var nResult : Byte; begin asm mov ah,StRq; mov dx,Lpt; Int $17; mov nResult,ah; end; Result := (nResult and $80) = $80; end; Modo de utilização: if PrinterOK(0) then ShowMessage('Impressora OK') else ShowMessage('Impressora sem papel ou desligada'); O parâmetro da função equivale ao número da porta da impressora. 0- LPT1 1- LPT2
Como implementar um AutoComplete num Edit comum Esta dica vou publicar sem tradução, primeiro porque no original é bem melhor e segundo para não haver erros.
76
// To add auto-complete capability to a TEdit component // 1) Declare a global TStringlist object // 2) Create it on the form create event // 3) Free it on the form destroy event // 4) Add new entry to it on the TEdit exit event // 5) Do the auto-complete on the TEdit keyUp event // 6) Add a TCheckbox control for enable/disable // If desired, initialize the list from a database, ini file etc. procedure TForm1.FormCreate(Sender: TObject); begin listValues := TStringList.create; listValues.sorted := true; listValues.Duplicates := dupIgnore; end; procedure TForm1.FormDestroy(Sender: TObject); begin listValues.free; end; procedure TForm1.edtListExit(Sender: TObject); begin listValues.add(edtList.text); end; procedure TForm1.edtListKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); var theText: string; i, p: integer; begin if not ckbxList.checked then exit; // User can enable/disable with edtList do case key of 8, 13, 46, 37..40: ; // No backspace, enter, delete, or arrows else begin // Search for unselected portion at start of text p := selStart; // cursor position theText := copy(text, 0, p); // Excludes searched portion // Match entered text portion for i := 0 to listValues.count-1 do begin // Keep case of listed item if pos(upperCase(theText), upperCase(listValues[i]))=1 then if compareText(theText, listValues[i]) < 0 then begin text := listValues[i]; selStart := p;
77
SelLength := length(text) - selStart; break; // Match found, so quit search end; end; // for end; // case end; // with end;
Como adicionar um CheckBox em um StringGrig Esta é uma maneira bem simples de adicionar um checkbox, ou qualquer outro objeto, num StringGrid Para fazer este exemplo, adicione TPanel, e um StringGrid,com 5 colunas e 4 linhas, no Painel .
procedure TForm1.CheckBox1Click(Sender: TObject); begin ShowMessage('Aqui'); end; procedure TForm1.FormCreate(Sender: TObject); begin StringGrid1.Cells[0,0] := 'Uma Maneira'; StringGrid1.Cells[1,0] := 'Simples'; StringGrid1.Cells[2,0] := 'Para'; StringGrid1.Cells[3,0] := 'Fazer'; StringGrid1.Cells[4,0] := 'Marcar'; AdicionarCheckBoxes; //rotina que adiciona os Check end; procedure TForm1.AdicionarCheckBoxes; var i: Integer; NovoCheckBox: TCheckBox; begin limpaBuffer; //é bom não esquecer de limpar controles não utilizados for i := 1 to 4 do begin StringGrid1.Cells[0,i] := 'a'; StringGrid1.Cells[1,i] := 'b'; StringGrid1.Cells[2,i] := 'c'; StringGrid1.Cells[3,i] := 'd'; NovoCheckBox := TCheckBox.Create(Application); NovoCheckBox.Width := 0; NovoCheckBox.Visible := false; NovoCheckBox.Caption := 'OK'; NovoCheckBox.Color := clWindow;
78
NovoCheckBox.Tag := i; NovoCheckBox.OnClick := CheckBox1.OnClick; //Associar um evento OnClick já existente para o Novo CheckBox NovoCheckBox.Parent := Panel1; StringGrid1.Objects[4,i] := NovoCheckBox; StringGrid1.RowCount := i; end; AlinhaCheck; // agora vamos alinhar o check na celular end; Procedure TForm1.Limpabuffer; var NovoCheckBox: TCheckBox; i: Integer; begin for i := 1 to StringGrid1.RowCount do begin NovoCheckBox := (StringGrid1.Objects[4,i] as TCheckBox); if NovoCheckBox <> nil then // o objeto deve existir para poder ser destruído begin NovoCheckBox.Visible := false; StringGrid1.Objects[4,i] := nil; end; end; end; Procedure TForm1.AlinhaCheck; var NovoCheckBox: TCheckBox; Rect: TRect; i: Integer; begin for i := 1 to StringGrid1.RowCount do begin NovoCheckBox := (StringGrid1.Objects[4,i] as TCheckBox); if NovoCheckBox <> nil then begin Rect := StringGrid1.CellRect(4,i); // aqui descobrimos a posição da celula para utilizarmos no check NovoCheckBox.Left := StringGrid1.Left + Rect.Left+2; NovoCheckBox.Top := StringGrid1.Top + Rect.Top+2; NovoCheckBox.Width := Rect.Right - Rect.Left; NovoCheckBox.Height := Rect.Bottom - Rect.Top; NovoCheckBox.Visible := True; end; end; end; procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
79
begin if not (gdFixed in State) then AlinhaCheck; end;
Abreviação automática de nomes Abrevia nomes extensos pegando a primeira letra do nome e acrescentando ponto no final. Ótimo para impressão de etiquetas. function AbreviaNome(Nome: String): String; var Nomes: array[1..20] of string; i, TotalNomes: Integer; begin Nome := Trim(Nome); Result := Nome; {Insere um espaço para garantir que todas as letras sejam testadas} Nome := Nome + #32; {Pega a posição do primeiro espaço} i := Pos(#32, Nome); if i > 0 then begin TotalNomes := 0; {Separa todos os nomes} while i > 0 do begin Inc(TotalNomes); Nomes[TotalNomes] := Copy(Nome, 1, i - 1); Delete(Nome, 1, i); i := Pos(#32, Nome); end; if TotalNomes > 2 then begin {Abreviar a partir do segundo nome, exceto o último.} for i := 2 to TotalNomes - 1 do begin {Contém mais de 3 letras? (ignorar de, da, das, do, dos, etc.)} if Length(Nomes[i]) > 3 then {Pega apenas a primeira letra do nome e coloca um ponto após.} Nomes[i] := Nomes[i][1] + '.'; end; Result := ''; for i := 1 to TotalNomes do Result := Result + Trim(Nomes[i]) + #32; Result := Trim(Result); end;
80
end; end;
Compilando a aplicação pelo MS-DOS Apenas a título de curiosidade, este texto explica como criar um programa em Delphi a partir do zero, usando somente o compilador do Delphi utilizado na linha de comando (dcc32) e o prompt do dos. Para fazer o programa, você precisará criar dois arquivos : teste.pas (o programa propriamente dito) e teste.dfm (definicoes do formulario). Primeiro, crie o programa teste.pas e teste.dfm. ARQUIVO: teste.pas ------------------------------------------------------program teste; uses windows,sysutils,classes,forms,stdctrls; type tfrm = class(tform) button1 : tbutton; constructor create(aowner:tcomponent);override; procedure button1click(sender:tobject); end; constructor tfrm.create(aowner:tcomponent); begin inherited create(aowner); left:=(screen.width div 2)-width div 2; top:=(screen.height div 2)-height div 2; end; procedure tfrm.button1click(sender:tobject); begin if button1.caption = 'Clique' then button1.caption:='Aperte' else button1.caption:='Clique'; end; {$R *.dfm} var frm : tfrm; begin application.initialize; application.createform(tfrm,frm); application.run; end. -------------------------------------------------------
81
ARQUIVO: teste.dfm ------------------------------------------------------object frm: tfrm width = 350 height = 290 caption = 'programa teste' object button1: tbutton caption = 'Clique' left = 20 top = 20 width = 100 height = 30 onclick = button1click end end ------------------------------------------------------Pense no arquivo .dfm como se fosse a janela de propriedades do objeto. Caso você queira alterar cor, alinhamento, etc, etc e etc, é só colocar no .dfm. Para compilar, simplesmente digite na linha do prompt : dcc32 teste Pronto. Você terá, no mesmo diretório, um arquivo chamado teste.exe, que é nada mais que o seu projeto compilado.
Coloração gradiente no Form procedure TForm1.FormPaint(Sender: TObject); var altura, coluna: Word; begin altura := (ClientHeight + 255) div 256; for coluna := 0 to 255 do with Canvas do begin Brush.Color := RGB(coluna, 0, 0); { Modifique para obter cores diferentes } FillRect(Rect(0, coluna * altura, ClientWidth, (coluna + 1) * altura)) ; end; end; procedure TForm1.FormResize(Sender: TObject); begin Invalidate; end;
82
Usar perfeitamente o LookupComboBox O componente DBLookupComboBox é utilizado para seleciona registros de uma tabela e gravar em outra tabela. As propriedades necessárias para a utilização são: DataSource - Ligar a DataSource da Tabela ao qual vai receber o valor do registro selecionado; DataField - Ligar o campo de ligação entre as duas tabelas, ao qual vai receber o valor do registro selecionado; ListSource - Ligar a DataSource da Tabela ao qual vai Ter o registro selecionado; ListField - Ligar o campo que será listado quando o usuário abrir a janela para seleção do registro; KeyField - Ligar o campo de ligação entre as duas tabelas, ao qual terá o seu valor enviado para gravação. O campo de ligação entre as duas tabelas pode ser um campo código, pois é este campo que manterá os valores iguais entre as duas tabelas.
Como colocar um codigo para que a aplicacao feche apos XX segundos sem atividades no teclado ou sem cliques do mouse. Olá Ramos, enviei uma duvida no forum do Ramos e nao esperava ter tido tanta discussao, mas depois que consegui a resposta ninguem mais comentou sobre o assunto. De qualquer forma apesar de ter postado no forum a resposta que recebi de outro camarada, abaixo segue de novo um exemplo de como colocar um codigo para que a aplicacao feche apos XX segundos sem atividades no teclado ou sem cliques do mouse. Este codigo deve ser colocado no Form principal e fazer os devidos ajustes. Nao esquecer de colocar o timer. Esta dica foi enviada por Cristiano Menusi- Oeste - SC e ele tambem havia encontrado na Net
unit Unit1; interface
83
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls; type TForm1 = class(TForm) Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); private procedure AppIdle(Sender: TObject; var Done: Boolean); procedure AppMessage(var Msg: TMsg; var Handled: Boolean); public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} { TForm1 } procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean); begin Timer1.Enabled := True; end; procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean); begin Case Msg.message of WM_LBUTTONDOWN,WM_RBUTTONDOWN,WM_KEYDOWN :Timer1.Enabled := False; end; end; procedure TForm1.FormCreate(Sender: TObject); begin Application.OnMessage := AppMessage; Application.OnIdle := AppIdle; end; procedure TForm1.Timer1Timer(Sender: TObject); begin Application.Terminate; end;
84
Escondendo a barra de tarefas do Windows var Jan: HWnd; begin Jan:= FindWindow(Nil,'Nome_do_projeto'); if Jan <> 0 then ShowWindow(Jan,SW_Hide); end;
Pega todos os erros do Sistema, captura tela do erro, grava em arquivo e envia por e-mail Como montar uma rotina para pegar todos os erros do sistema e capturar tela do erro e gravar em arquivo para futura inspecao ou envio por e-mail. Coloque esta rotina no menu principal de seu sistema. unit Form_Menu; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, DB, ComCtrls, ExtCtrls, StdCtrls,Buttons, Mask, DBTables, DBIPROCS, DBITypes, DBIErrs, Gauges, ImgList, ToolWin, jpeg, ExtDlgs; type TFrm_Menu = class(TForm) MainMenu1: TMainMenu; PRIVATE { Private declarations } Procedure ManipulaExcecoes(Sender: TObject; E: Exception); public { Public declarations } end; var Frm_Menu: TFrm_Menu; implementation //------------------------------------// //...Rotina de manipulaco de erros // //------------------------------------//
85
Procedure TFrm_Menu.ManipulaExcecoes(Sender: TObject; E: Exception); Var BitMap : TBitmap; Begin //...Captura e salva a tela atual do erro. BitMap := TBitmap.Create; BitMap := CaptureScreenRect(Bounds(0,0,Screen.Width,Screen.Height)); BitMap.SaveToFile(ExtractFilePath(Application.ExeName)+'erro.bmp') ; BitMap.Free; //...Messagem de erro do sistema MessageDlg(E.Message + #13#13 +'Suporte técnico:'#13 +'aceinfo@starknet.com.br',mtError, [mbOK], 0); end; {$R *.DFM} procedure TFrm_Menu.FormCreate(Sender: TObject); Begin Application.OnException := ManipulaExcecoes; end; End.
Detectando o tipo de Conexão com a internet uses Wininet function ConnectionKind: Boolean; var flags: DWORD; begin Result := InternetGetConnectedState(@flags, 0); if Result then begin if (flags and INTERNET_CONNECTION_MODEM) = INTERNET_CONNECTION_MODEM then ShowMessage('Modem'); if (flags and INTERNET_CONNECTION_LAN) = INTERNET_CONNECTION_LAN then ShowMessage('LAN'); if (flags and INTERNET_CONNECTION_PROXY) = INTERNET_CONNECTION_PROXY then ShowMessage('Proxy'); if (flags and INTERNET_CONNECTION_MODEM_BUSY) = INTERNET_CONNECTION_MODEM_BUSY then
86
ShowMessage('Modem Busy'); end; end; procedure TForm1.Button1Click(Sender: TObject); begin ConnectionKind; end;
Função de potenciação - Juros Segue abaixo uma função para efetuar a potenciação. É útil para compor formulas financeiras, como a de VP ("PV" valor presente) VF ("FV" valor futuro) Exemplo: Calcular o valor de um produto para o prazo de 30 dias com a taxa de juros de 5% mês. var i: Real; // taxa de juros valor: Real; // valor base para calculo do valor futuro. pz: Integer // prazo em dias begin i := 5//100; valor:= 1000.00 pz := 30 Result:= valor*( Pot( (1+i), (pz/30) ) //Resultado 1.050,00 end; no excel a Pot é substituída pelo sinal ^ Ex. =E18*((1+C19)^(C20/30)) Function Pot( base, expoente: real ):real; // Potenciação begin { utiliza a função de exponencial e de logaritmo } Result:= Exp((expoente * Ln( base ))); end; Dica: Não amplie o nome da função, pois as funções financeiras costumam ser bem extensas.
Para trocar as cores dos botoes do radiogroup No Object Inspector na propriedade Font coloque a cor verde. procedure TForm1.RADIOGROUP1Click(Sender: TObject); Var i : Integer;
87
begin // Para trocar as cores dos botoes do RadioGroup for i := 0 to RADIOGROUP1.Items.Count-1 do begin TRadioButton(RADIOGROUP1.Controls[i]).Font.Color := clGreen; TRadioButton(RADIOGROUP1.Controls[i]).Font.Style := [fsBold]; end; TRadioButton(RADIOGROUP1.Controls[RADIOGROUP1.ItemIndex]).Font.Color := clRed; TRadioButton(RADIOGROUP1.Controls[RADIOGROUP1.ItemIndex]).Font.Style := [fsBold]; end;
Como criar uma figura do tipo marca d' รกgua procedure TForm1.Button1Click(Sender: TObject); var X, Y : Integer; begin brush.style := bsClear; for y:=0 to image1.height-1 do for x:=0 to image1.width-1 do begin if (x mod 2)=(y mod 2) then image1.canvas.pixels[x,y]:=clWhite; end; end;
Criptografando Imagens procedure cripto(const BMP: TBitmap; Key: Integer); var BytesPorScan: Integer; w, h: integer; p: pByteArray; begin try BytesPorScan := Abs(Integer(BMP.ScanLine[1]) Integer(BMP.ScanLine[0])); except raise Exception.Create('Erro !'); end; RandSeed := Key; for h := 0 to BMP.Height - 1 do begin P := BMP.ScanLine[h]; for w := 0 to BytesPorScan - 1 do 88
P^[w] := P^[w] xor Random(256); end; end; Agora vamos ao evento onclick do Button chamar a nossa procedure cripto, basta digitar o seguinte código: procedure TForm1.Button1Click(Sender: TObject); begin cripto(Image1.Picture.Bitmap, 1); Image1.Refresh; end; Ao chamar a rotina passamos como parâmetro o caminho da imagem que no exemplo foi utilizado o componente image e 1 como um valor inteiro para retornamos a imagem normal, logo após a execução da nossa procedure atualizamos o image para que ele possa exibir nossa imagem criptografada.
Alterar a fonte de determinado registro num DBGrid Para trocar a fonte de um DBGrid, utilize a rotina abaixo no evento OnDrawDataCell: if Tabela.FieldByName ('Salario').Value >= 10000 then begin DbGrid1.Canvas.Font.Color := clRed; DbGrid1.Canvas.Font.Style := [fsBold]; end; DbGrid1.DefaultDrawDataCell(Rect, Field, State); No caso, somente os registros com salário maior que R$ 10.000,00 ficarão com cor vermelha e em negrito. Nota: Não é necessário mover o ponteiro da tabela para colorir os registros.
Alinhar título da barra de titulos do Form a esquerda ou direita //Deve ser usada assim: //Procedure TForm1.Titulo(Titulo: Pchar;pos,wParam: Integer); //e declarada na clausua private. procedure Titulo(Titulo: Pchar;pos,wParam: Integer); var DC: THandle; R1, R2: TRect; begin DC := GetWindowDC(Handle); 89
try SetWindowText(Handle, nil); GetWindowRect(Handle, R2); R1.Left := GetSystemMetrics(SM_CXSIZE) + GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME); R1.Top := GetSystemMetrics(SM_CYFRAME); R1.Right := R2.Right - R2.Left - R1.Left - 2 * GetSystemMetrics(SM_CXSIZE); R1.Bottom := R1.Top + GetSystemMetrics(SM_CYSIZE); if wParam = 1 then begin SetBkColor(DC, GetSysColor(COLOR_ACTIVECAPTION)); end else begin SetBkColor(DC, GetSysColor(COLOR_INACTIVECAPTION)); end; SetTextColor(DC, GetSysColor(COLOR_CAPTIONTEXT)); if pos = 1 then begin DrawText(DC, Titulo, -1, R1, DT_LEFT or DT_VCENTER); end else begin DrawText(DC, Titulo, -1, R1, DT_RIGHT or DT_VCENTER); end; finally ReleaseDC(Handle, DC); end; end;
Alterar fonte do Hint Para testar este exemplo inclua no seu form alguns componentes. Nestes componentes coloque informações na propriedade Hint de cada componente e altere a propriedade ShowHint para True. unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Edit1: TEdit;
90
Edit2: TEdit; Edit3: TEdit; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } procedure MyShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo); end; var Form1: TForm1; implementation {$R *.DFM} // Função que irá alterar a fonte do Hint procedure TForm1.MyShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: HintInfo); var i : integer; begin for i := 0 to Application.ComponentCount - 1 do if Application.Components[i] is THintWindow then with THintWindow(Application.Components[i]).Canvas do begin Font.Name := 'Arial'; Font.Size := 18; Font.Style := [fsBold]; HintInfo.HintColor := clWhite; end; end; // Evento OnCreate do Form procedure TForm1.FormCreate(Sender: TObject); begin // Ativa a função que irá alterar o formato do Hint Application.OnShowHint := MyShowHint; end;
Criando arquivo Texto Veja abaixo os passos básicos para criação de arquivos texto: Var
91
F:TextFile; Begin AssignFile(f,'c:\qq_arquivo.txt'); Rewrite(f); //abre o arquivo para escrita Writeln(f,'Testando'); escreve no arquivo e desce uma linha Write(f,'Linha de Código - www.linhadecodigo.com.br'); //escreve no arquivo sem descer a linha Closefile(f); //fecha o handle de arquivo End; ///Rotina para ler de um arquivo texto: var f:TextFile; linha:String; begin AssignFile(f,'c:\qq_arquivo.txt'); Reset(f); //abre o arquivo para leitura; While not eof(f) do begin Readln(f,linha); //le do arquivo e desce uma linha. O conteúdo lido é transferido para a variável linha Memo1.lines.add(linha); End; Closefile(f); end;
Como selecionar tudo (Ctrl+A) em um TMemo/TDBMemo Você pode selecionar todo o conteúdo de um TMemo ou TDBMemo utilizando as teclas de atalho Crtl+A adicionando no evento OnKeyDownEvent destes componentes o código a seguir: procedure OnKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState) ; begin if (Key = Ord('A')) and (ssCtrl in Shift) then begin TMemo(Sender).SelectAll; Key := 0; end; end;
92
Mudando o IP da máquina via API do Windows {Como posso mudar meu IP? via API? A resposta para essa pergunta é não neste artigo estou unsando o Delphi 7, mas pode ser feito com qualquer outra versão do delphi. nos Windows 2000 e XP existe um aplicativo chamado NETSH que faz essa mudança para nós sem que precisemos reiniciar o computador. bem vamos por a mão na massa e brincarmos um pouco com as configurações de IP. Mudando a Configuração para DHCP: Crie uma aplicação no Delphi, NEW -> Application no FormDesigner ponha um TButton e no evento OnClick escreva o seguinte código:}
if Win32Plataform = VER_PLATAFORM_WIN32_NT then WinExec('cmd /c netsh interface ip set address "Conexão local" DHCP', SW_SHOWNORMAL) else MessageBox(Handle, 'esse Comando não pode ser rodado fora da plataforma NT', 'NETSH', MB_ICONWARNING); {onde verifico se a plataforma do Programa é uma plataforma NT, caso contrário informo ao usuário que esse comando não pode ser rodado fora de uma plataforma NT. Mudando as Configurações dos IPs da máquina, menos os DNS: Na mesma aplicação do exemplo acima Ponha outro TButton e no Evento OnClick dele escreva:} if Win32Plataform = VER_PLATAFORM_WIN32_NT then WinExec('cmd /c netsh interface ip set address "Conexão local" static 192.168.10.104 255.255.255.0 192.168.10.1 1', SW_SHOWNORMAL) else MessageBox(Handle, 'esse {Comando não pode ser rodado fora da plataforma NT', 'NETSH', MB_ICONWARNING);
Pronto seu IP, SubnetMask e Gateway foram mudados. Para maiores informações sobre o NETSH visite o site da Microsoft: Suporte Microsoft.
Texto na diagonal e girando Procedure TForm1.Button1Click(Sender: TObject); 93
var lf : TLogFont; tf : TFont; i : integer; begin with Form1.Canvas do begin Font.Name := 'Verdana'; Font.Size := 16; tf := TFont.Create; tf.Assign(Font); GetObject(tf.Handle, sizeof(lf), @lf); lf.lfOrientation := 1000; end; For i:= 50000 Downto 1 do Begin lf.lfEscapement := i; tf.Handle := CreateFontIndirect(lf); Form1.Canvas.Font.Assign(tf); Form1.Canvas.TextOut(200, Height div 2, 'Ramos da Informática'); //Sleep(10); Este pode cria um Delay na execução end; tf.Free; end;
Criar um alias dinamicamente na memória procedure TForm1.FormCreate(Sender: TObject); begin if not Session.IsAlias(‘Teste’) then session.AddStandardAlias(‘Teste’, ExtractFilePath(Application.ExeName),’PARADOX’); end;
Rodar videos em um panel begin if opendialog1.execute then begin mediaplayer1.filename:= opendialog1.filename; mediaplayer1.open; mediaplayer1.Perform (wm_lbuttondown,0,$00090009); mediaplayer1.Perform (wm_lbuttonup,0,$00090009); end; end;
94
Como colocar uma coluna do DBGrid em maiuscula procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char); begin if DBGrid1.SelectedField.FieldName='NOME' THEN Key := AnsiUpperCase(Key)[Length(Key)]; end;
DBGrid - Alinhando texto conforme condição Aqui iremos demonstrar como colorir e alinhar o texto de uma coluna do DBGrid com base em uma condição. Estamos utilizando a tabela COUNTRY do alias DBDemos e verificamos o conteúdo do campo Continent. Caso seja ‘North America’ iremos mudar a cor da fonte para verde e o alinhamento do texto para direita, o qual será ‘redesenhado’ através da API DrawText. Este tratamento será feito no evento OnDrawColumnCell do próprio DBGrid, acompanha o código abaixo: { constantes para o alinhamento } const FmtCentered = DT_SingleLine or DT_VCenter or DT_NoClip or DT_Center; FmtLeft = DT_SingleLine or DT_VCenter or DT_NoClip or DT_Left; FmtRight = DT_SingleLine or DT_VCenter or DT_NoClip or DT_Right; implementation implementation {$R *.DFM} procedure TForm1.gridCountryDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); var Format: integer; R: TRect; begin if (tabCountryContinent.AsString = 'North America') and (DataCol = 1) then begin gridCountry.Canvas.Font.Color := clGreen; R := Rect; Format := FmtRight; { poderá utilizar: FmtCentered, FmtLeft, FmtRight } gridCountry.Canvas.FillRect(Rect); DrawText(gridCountry.Canvas.Handle, PChar(Column.Field.AsString), Length Column.Field.AsString), R, Format); end; if (tabCountryContinent.AsString = 'South America') and (DataCol = 1) then begin 95
gridCountry.Canvas.Font.Color := clRed; R := Rect; Format := FmtCentered; { poderá utilizar: FmtCentered, FmtLeft, FmtRight } gridCountry.Canvas.FillRect(Rect); DrawText(gridCountry.Canvas.Handle, PChar(Column.Field.AsString), Length Column.Field.AsString), R, Format); end; end;
DBGrid - Colocando CheckBox no grid Frequentemente e-mail de nossos visitantes sobre como colocar um CheckBox em uma coluna referente um campo lógico apresentada no DBGrid. Aqui irei demonstrar uma abordagem bem simples que ‘desenha’ uma imagem que irá imitar um CheckBox e caso o conteúdo do campo seja verdadeiro, mostraremos uma imagem ‘checada’ e do contrário uma imagem ‘desmarcada’. Neste exemplo, o campo lógico possui o nome de ‘situacao’. No evento OnDrawColumnCell verificamos se a coluna atual é ‘situacao’ e conforme o valor do referido campo desenhamos a imagem correspondente. No evento OnCellClick permitimos a alteração do valor do campo que, quando estiver = true irá receber false e vice-versa. E finalizando, no evento OnEnter do DBGrid efetuamos um tratamento para não permitir a edição ‘direta’ na coluna referente o campo lógico. Neste exemplo iremos codificar os eventos: OnDrawColumnCell, OnCellClick e OnEnter do DBGrid, além ainda de um componente ImageList que será responsável em armazenar e fornecer as imagens que serão desenhada referida coluna. procedure TForm1.grdExemploDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin { Desenha CheckBox } if Column.FieldName = 'Situacao' then begin grdExemplo.Canvas.FillRect(Rect); Imagens.Draw(grdExemplo.Canvas, Rect.Left+10, Rect.Top+1, 0); if not cdsExemploSituacao.IsNull then if cdsExemploSituacao.AsBoolean then Imagens.Draw(grdExemplo.Canvas, Rect.Left+10, Rect.Top+1, 2) else Imagens.Draw(grdExemplo.Canvas, Rect.Left+10, Rect.Top+1, 1); end; end; procedure TForm1.grdExemploCellClick(Column: TColumn); begin { Quando clicar, alterna o valor True/False } if Column.FieldName = 'Situacao' then begin
96
if cdsExemplo.State = dsBrowse then cdsExemplo.Edit; cdsExemploSituacao.AsBoolean := not cdsExemploSituacao.AsBoolean; end; end; procedure TForm1.grdExemploEnter(Sender: TObject); begin { Não permite edição na célula do CheckBox } with grdExemplo do begin if SelectedField = cdsExemploSituacao then Options := Options - [dgEditing] else Options := Options + [dgEditing]; end; end; procedure TForm1.cdsExemploNewRecord(DataSet: TDataSet); begin cdsExemploSituacao.AsBoolean := True; end;
RichEdit - Como fazer uma pesquisa e substituição em um RichEdit O código abaixo procurará por uma string e a substituirá. Tenha certeza que você tem o RichEdit1 em seu Form1. procedure TForm1.RearchAndReplace (InSearch, InReplace: string) ; var X, ToEnd : integer; oldCursor : TCursor; begin oldCursor := Screen.Cursor; Screen.Cursor := crHourglass; with RichEdit1 do begin X := 0; ToEnd := length(Text) ; X := FindText(inSearch, X, ToEnd, []) ; while X <> -1 do begin SetFocus; SelStart := X; SelLength := length(inSearch) ; SelText := InReplace; X := FindText(inSearch, 97
X + length(InReplace), ToEnd, []) ; end; end; Screen.Cursor := oldCursor; end; procedure TForm1.Button1Click (Sender: TObject) ; var SearchText, ReplaceText: string; begin SearchText := ‘Pascal’; ReplaceText := ‘Delphi’; RearchAndReplace(SearchText, ReplaceText) ; end;
TForm - Criando formulários transparentes private { Private declarations } FullRgn, ClientRgn, CtlRgn: THandle; procedure MakeTransparent; procedure UndoTransparent; end; {...} implementation {...} procedure TForm1.MakeTransparent; var AControl: TControl; A, Margin, X, Y, CtlX, CtlY: Integer; begin Margin := (Width - ClientWidth) div 2; FullRgn := CreateRectRgn(0, 0, Width, Height); X := Margin; Y := Height - ClientHeight - Margin; ClientRgn := CreateRectRgn(X, Y, X + ClientWidth, Y + ClientHeight); CombineRgn(FullRgn, FullRgn, ClientRgn, RGN_DIFF); for A := 0 to ControlCount - 1 do begin AControl := Controls[A]; if (AControl is TWinControl) or (AControl is TGraphicControl) then with AControl do begin if Visible then begin
98
CtlX := X + Left; CtlY := Y + Top; CtlRgn := CreateRectRgn(CtlX, CtlY, CtlX + Width, CtlY + Height); CombineRgn(FullRgn, FullRgn, CtlRgn, RGN_OR); end; end; end; SetWindowRgn(Handle, FullRgn, True); end; procedure TForm1.UndoTransparent; begin FullRgn := CreateRectRgn(0, 0, Width, Height); CombineRgn(FullRgn, FullRgn, FullRgn, RGN_COPY); SetWindowRgn(Handle, FullRgn, True); end; Para usar: // Teste: procedure TForm1.Button1Click(Sender: TObject); begin MakeTransparent end; procedure TForm1.Button1Click(Sender: TObject); begin UndoTransparent end;
TList - Ordenando os itens Quando você está trabalhando com um objeto TList e quer ordenar os itens baseados um critério seu, pode usar o código abaixo. O exemplo a seguir mostra como ordenar os itens em ordem alfabética baseado nos nomes. Ele assume que a lista contém apenas referências para as variáveis do tipo TMyListItem, onde TMyListItem é definida como: type TMyListItem = record Points : Integer; Name: string[255] ; end; A função CompareNames faz as comparações entre os objetos da lista. A lista é ordenada quando o usuário clicar no botão.
99
function CompareNames (Item1, Item2: Pointer): Integer; begin Result := CompareText((Item1 as TMyListItem).Name, (Item2 as TMyListItem).Name) ; end; procedure TForm1.Button1Click (Sender: TObject) ; begin List1.Sort(@CompareNames) ; end;
{ Note: the Sort method needs a pointer to a custom function (with the signature below) that indicates how the items are to be ordered. type TListSortCompare = function (Item1, Item2: Pointer): Integer; Your sorting / comparison function should return a positive value if Item1 is less than Item2, 0 if they are equal, and a negative value if Item1 is greater than Item2. }
3 formas de dar um shutdown Existem 3 formas distintas de fazer a mesma coisa, s達o elas: //------------- Forma 1-----------------
procedure TForm1.Button1Click(Sender: TObject); begin ExitWindowsEx(EWX_FORCE and EWX_SHUTDOWN,0); //EWX_SHUTDOWN para shutdown //EWX_REBOOT para reboot //EWX_LOGOFF para logoff end;
//------------- Forma 2-----------------
100
Executando o programa shutdown.exe do Windows: run %Windir%\system32\shutdown.exe Example : procedure TForm1.Button1Click(Sender: TObject); begin WinExec('shutdown.exe -s -f -t 0' , SW_HIDE); end;
//------------- Forma 3-----------------
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} function SetPrivilege1 (sPrivilegeName: string; bEnabled: Boolean) : Boolean; var TPPrev, TP : TTokenPrivileges; Token : THandle; dwRetLen : DWORD; begin
101
result := False; OpenProcessToken (GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token); TP.PrivilegeCount := 1; if LookupPrivilegeValue (nil, PChar (sPrivilegeName), TP.Privileges[0].LUID) then begin if bEnabled then TP.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED else TP.Privileges[0].Attributes := 0; dwRetLen := 0; result := AdjustTokenPrivileges (Token, False, TP, SizeOf (TPPrev), TPPrev, dwRetLen) end; CloseHandle (Token) end;
function WinExit1 (iFlags: integer) : Boolean; begin result := true; if SetPrivilege1 ('SeShutdownPrivilege', true) then begin if (not ExitWindowsEx (iFlags, 0)) then begin result := False end; SetPrivilege1 ('SeShutdownPrivilege', False) end else begin result := False end; end;
procedure TForm1.Button1Click(Sender: TObject); begin // 0= Logoff // 1= Shutdown WinExit1(1); end; end.
102
QuickReport e FastReport - Gerando um PDF Esse componente ExportQR foi criado para trabalhar com o QuickReport e com o FastReport, mas aqui vou dar exemplo apenas do QuickReport. Caso alguém queira pegar a versão que também trabalha com o FastReport recomendo que acesse o site do fabricante no seguinte link: http://usuarios.lycos.es/isma A instalação desse componente é bastante simples, abra o arquivo ExPackD6.dpk (Delphi 6) ou ExPackD7.dpk (Delphi 7) através do delphi e em seguida compile e instale. Esse componente já está trazendo os dois componentes utilizados no primeiro exemplo, isso é, o componente TNPDV e o componente de compactação. Após efetuar a instalação acesse o menu Tools, do Delphi, e depois a opção Environment Options. Selecione a aba Library e depois acesse o botão da Library path. Na janela que será aberta indique o caminho onde estão os arquivos .pas do componente e depois clique em Add e em seguida em Ok. Agora estando com o componente instalado podemos colocá-lo no form do nosso projeto que contem o relatório criado no QuickReport e depois através de um botão colocar a instrução que irá fazer a exportação. A instrução do botão para exportação ficará da seguinte forma: procedure TMainForm.BtnExportQRClick(Sender: TObject); begin { Liga o componente do QuickReport ao componente de exportação } EXQR.Report := Rep; { Faz a exportação } EXQR.ExportQR; end; Este componente também nos permite exportar relatórios a partir do componente QRPreview que é o componente ao qual criamos preview personalizado no QuickReport. Para isso podemos colocar um botão no form de preview e neste botão colocar a seguinte instrução: procedure TFPreviewQR.TBSaveClick(Sender: TObject); begin { Faz a ligação do QRPreview com o componente } EXQR.Preview := Preview; { Faz a exportação do relatório } EXQR.ExportQRFromPreview; end; Esses códigos acima podem ser encontrados no projeto de Exemplo1 que acompanha o componente ExportQR.
103
Outros formatos: A exportação dos relatórios para os demais formatos é bastante simples também, veja abaixo as sintaxes utilizadas para cada tipo: PDF com Alta Compressão: EXQR.ExportQRPDF(edFileName.Text, True); PDF com Baixa Compressão EXQR.ExportQRPDF(edFileName.Text, False); JPG EXQR.ExportQRJPG(edFileName.Text); BMP EXQR.ExportQRBMP(edFileName.Text); WMF EXQR.ExportQRWMF(edFileName.Text); EMF EXQR.ExportQREMF(edFileName.Text); Esses códigos acima podem ser encontrados no projeto de Exemplo3 que acompanha o componente ExportQR.
SetVolumeLabel - Mudando o Label do HD A seguir a rotina completa: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; Button1: TButton; ComboBox1: TComboBox; Edit1: TEdit; procedure FormCreate(Sender: TObject);
104
procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin SetVolumeLabel(pansichar(ComboBox1.Text), pchar(Edit1.Text)); end; procedure TForm1.FormCreate(Sender: TObject); var i:Integer; begin for i:=Ord('A') to Ord('Z') do begin if GetDriveType(pchar(char(i)+':\'))=3 then ComboBox1.Items.Add(char(i)+':\'); end; ComboBox1.Text:=ComboBox1.Items.Strings[0]; Button1Click(Self); end; end.
Memo - Rolagem vertical Inclua na seção uses: Windows Problema: Gostaria que o meu programa rolasse automaticamente o conteúdo de um TMemo, simulando o deslizamento da barra de rolagem vertical. Isto é possível no Delphi? Solução: Sim. Utilizando mensagens do Windows isto é fácil. Vejamos algums exemplos: SendMessage(Memo1.Handle, WM_VSCROLL, SBPAGEDOWN, 0); Onde: 105
Memo1.Handle = manipulador da janela do Memo1. WM_VSCROLL = Mensagem do Windows - rolagem vertical. SB_PAGEDOWN = Comanndo de rolagem - página para baixo. Outros exemplos: { Página para cima } SendMessage(Memo1.Handle, WM_VSCROLL, SBPAGEUP, 0); { Linha para baixo } SendMessage(Memo1.Handle, WM_VSCROLL, SBLINEDOWN, 0); { Linha para cima } SendMessage(Memo1.Handle, WM_VSCROLL, SBLINEUP, 0); Observações: Além desta técnica existem API's do Windows que fazem um trabalho equivalente.
Como adicionar o evento OnClick no DBGrid O componente DBGrid não tem o evento OnClick no Object Inspector. Mas podemos utilizá-lo através de uma instancia da classe THack. Inclua as duas linhas abaixo da seção Implementation: type THack = class(TControl); Depois na seção Private declare a nova procedure que utilizaremos no evento OnClick: private { Private declarations } procedure DBGridClick(Sender: TObject); Agora crie a procedure que declaramos na seção private. procedure TForm1.DBGridClick (Sender: TObject); begin ShowMessage(‘O conteúdo desta célula é ‘ +TDBGrid(Sender).SelectedField.AsString); end; Para utilizarmos esta procedure temos que fazer a sua ligação no evento OnCreate do form. Veja o código abaixo: procedure TForm1.FormCreate(Sender: TObject); begin THack(dbgrid1).controlstyle := THack(dbgrid1).controlstyle + [csClickEvents]; THack(dbgrid1).OnClick := DBGridClick; end;
106
Alterando a cor dos TabSheet de um PageControl Coloque um PageControl no Form. - Adicione 6 TabSheet (New Page). - Agora basta implementar o codigo abaixo no evento OnDrawTab.
procedure TForm1.PageControl1DrawTab(Control: TCustomTabControl; TabIndex: Integer; const Rect: TRect; Active: Boolean); begin case TabIndex of 0: Control.Canvas.Font.Color := clGreen; 1: Control.Canvas.Font.Color := clRed; 2: Control.Canvas.Font.Color := clBlue; 3: Control.Canvas.Font.Color := clYellow; 4: Control.Canvas.Font.Color := clMaroon; 5: Control.Canvas.Font.Color := clWhite; end; Control.Canvas.TextOut(Rect.left+5, Rect.top+3,PageControl1.Pages [TabIndex].Caption); PageControl1.Pages[TabIndex].Font.Color := Control.Canvas.Font.Color; end; Obs.: Não esqueça de alterar a propriedade OwnerDraw para True.
Como chamar uma home page utilizando o seu browse padrão uses UrlMon; procedure TForm1.Button1Click(Sender: TObject); begin HlinkNavigateString(nil, ’http://www.theclub.com.br’); end;
Como alterar o caption da janela de preview do quickreport Para mudar o título da barra de título da janela de Preview de seus relatórios, use o seguinte comando: QRPrinter.PreviewCaption := ‘Visualização do Relatório’; Como colocar Captions no DBNavigator 107
type TDBNewNavigator = class(TDBNavigator); procedure TForm1.FormCreate(Sender: TObject); var B: TNavigateBtn; begin for B := Low(TNavigateBtn) to High(TNavigateBtn) do with TDBNewNavigator(DBNavigator1).Buttons[B] do begin Case Index of nbFirst : Caption := ‘Inicio’; nbPrior : Caption := ‘Anterior’; nbNext : Caption := ‘Próximo’; nbLast : Caption := ‘Último’; nbInsert : Caption := ‘Novo’; nbDelete : Caption := ‘Apagar’; nbEdit : Caption := ‘Alterar’; nbPost : Caption := ‘Gravar’; nbCancel : Caption := ‘Cancelar’; nbRefresh: Caption := ‘Atualizar’; End; Hint := Caption; ShowHint := True; end; end; end;
Como passar parâmetros entre 2 forms Suponha que você esteja no Form1 e precise chamar o Form2 passando dois parametros ("Verde" e "Amarelo"). 1. Crie as variáveis de instância do Form2 que receberão os dois parâmetros. 2. Reescreva o Construtor desse form, de forma a receber os parâmetros e atribuí-los às suas variáveis de instância: type TForm2 = class(TForm) private Parametro1 : String; Parametro2 : String; public constructor Create(AOwner : TComponent; pPar1, pPar2 : String); end; var
108
Form2: TForm2; implementation constructor TForm2.Create(AOwner : TComponent; pPar1, pPar2 : String); begin inherited Create(AOwner); Parametro1 := pPar1; Parametro2 := pPar2; end; Agora no seu form1, abra o form2 com a seguinte sintaxe: With TForm2.Create(self, ‘Verde’, ‘Amarelo’) do Begin ShowModal; Free; End; No evento OnShow inclua a seguinte linha: procedure TForm2.FormShow(Sender: TObject); begin Caption := Parametro1 + ‘ - ‘+ Parametro2; end; Obs: Não deixe o Delphi criar automaticamente o formulário. Crie-o (e o destrua) manualmente.
Como reduzir o tempo e carga de um programa É comum acontecer um sensível aumento de tempo de carga de um aplicativo desenvolvido em Delphi à medida que este aplicativo cresce e adquire mais e mais formulários. Às vezes o tempo de carga se torna totalmente insuportável. Os programas se tornam lentos principalmente devido a grande quantidade de formulários que são criados e inicializados logo no início da execução do programa. Antes de ser efetivamente utilizado, todo formulário precisa ser criado. A criação do formulário acontece sempre que você adiciona um novo formulário ao sistema, o IDE do Delphi providencia código para que ele seja criado automaticamente. Isto simplifica a vida do programador que não precisará se preocupar com este detalhe. O aumento do tempo de carga do aplicativo pode ser resolvido pela simples remoção do código que o Delphi gerou para a criação do formulário. Para remover o código que o Delphi criou automaticamente, selecione Project|Options no menu. Selecione a aba ‘Forms’. Aponte para um dos formulários e clique no botão ‘>’. Isto faz com que o formulário passe do painel ‘Auto-create forms’ para o painel ‘Available forms’.
109
Se você quer saber onde está este código, clique em View|Units (ou use Ctrl-F12) e selecione o seu projeto na lista de units que aparecerá. O código que cria formulários é algo mais ou menos como se segue: Application.CreateForm(TForm1, Form1); Cada formulário auto-criado terá uma linha como esta. Quando o formulário passa para o painel de ‘Available forms’, a linha correspondente é removida. Você também pode simplesmente remover a linha manualmente, usando o editor de textos. Normalmente usar um formulário significa mostrá-lo na tela. Isto é feito invocando-se os métodos Show ou ShowModal do formulário conforme o estilo do aplicativo. Agora que o formulário não é mais criado automaticamente, isto se torna um pouco mais complicado, por exemplo: if Form1 = nil then Form1 := TForm1.Create ( Application ); Form1.Show; { ou Form1.ShowModal; } Alternativamente você poderia escrever assim: if Form1 = nil then Application.CreateForm ( TForm1, Form1 ); Form1.Show; { ou Form1.ShowModal; } O efeito é o mesmo, mas eu, pessoalmente, prefiro a primeira forma. Você deve ter extremo cuidado ao usar esta técnica. Se você tirar o código de criação automática do formulário e tentar executar o Show ou ShowModal você vai receber um erro do tipo ‘Access Violation’. Tome cuidado e faça isto um formulário por vez. Atenção! Não faça isto para o seu formulário principal. O formulário principal precisa ser o primeiro formulário a ser criado. Assim é melhor mantê-lo como auto-criado. Esta técnica efetivamente ‘distribui’ o tempo de carga e inicialização do aplicativo pela execução do programa. Os formulários agora são carregados ‘sob-demanda’. Os formulários nunca utilizados nunca serão criados. Isto também melhora o uso de memória.
Escondendo o Programa de Ctrl+Alt+Del unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private
110
{ Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} { Para ocultar um programa, deve-se registrar este programa como um serviço do Windows. Normalmente um serviço do Windows é ativado quando com a inicialização do sistema (Windows) e permanece ativo até a finalização deste. Este processo esconde o programa da lista "Ctrl+Alt+Del" } Const Servico_Simples = 1; Servico_Unregister = 1; Function RegisterServiceProcess(DwProcessID, dwType: DWord): DWord; StdCall; External ‘KERNEL32.dll’; procedure TForm1.FormCreate(Sender: TObject); begin RegisterServiceProcess(GetCurrentProcessID, Servico_Simples); end; procedure TForm1.FormDestroy(Sender: TObject); begin RegisterServiceProcess(GetCurrentProcessID, Servico_Unregister); end; end.
Alterando a página inicial do Internet Explorer via programação
function PaginaInicialIE(endereco : string) : boolean; Var Reg : TRegistry; begin Reg:= TRegistry.Create; try Reg.RootKey:= HKEY_CURRENT_USER; Reg.OpenKey(‘Software\Microsoft\ Internet Explorer\Main’,false); try
111
try Reg.WriteString (‘Start Page’,endereco); result := true; finally Reg.CloseKey; result := True; end; except result := false; end; finally Reg.Free; end; end; procedure TForm1.Button1Click(Sender: TObject); begin if PaginaInicialIE(‘http://www.theclub.com.br’) then ShowMessage(‘Foi alterado com sucesso’) else ShowMessage(‘Não foi alterado’); end;
Verifica se o BDE está instalado // Usando o registrador do Windows procedure TForm1.Button1Click (Sender: TObject); var Reg: TRegistry; begin reg := TRegistry.create; try reg.RootKey := HKEY_CURRENT_USER; reg.OpenKey(‘\Software\Borland’, False); if Reg.KeyExists(‘BdeAdmin’) then ShowMessage(‘BDE já instalado’) else ShowMessage(‘Sem BDE’); finally Reg.CloseKey; Reg.Free; inherited; end; end;
112
Arredondar casas decimais de forma personalizada Na seção de procedures digite: Function Arredondar (value: double;casas : integer): double; Na seção implementation digite a função conforme descrita abaixo. Function Tform1.Arredondar(value: double;casas : integer): double; Var fracao, Total:real; decimal:string; begin try fracao:=Frac(value); //Retorna a parte fracionária de um número decimal:=(RightStr(floattostr(fracao), length(floattostr(fracao))-2)); //decimal recebe a parte decimal //enquanto o tamanho da variavel decimal for maior que o número de casas faça while length(decimal) > casas do begin //Verifica se o último digito da variável decimal é maior que 5 if strtoint(RightStr(decimal,1))>5 then begin //Descarta o último digito da variável Decimal decimal:=leftstr(decimal,length(decimal)-1); //Soma o valor número da variavel decimal + 1 decimal:=floattostr(strtofloat(decimal) + 1); end else decimal:=leftstr(decimal,length(decimal)-1); //Descarta o último digito da variável Decimal end; result:=(int(value) + (strtofloat(decimal)/100)); //devolve o resultado para a função except Raise Exception.Create(‘Erro no arredondamento’); end; end; Como usar... arredondar(Campo ou vaiável do tipo Real (Float) , número de casas decimais desejado); Ex:Var valor,Resultado:real; Valor:=10.005.526 Resultado :=Arredondar(valor,2); Resultado=10.005,53
113
Obs: O codigo foi escrito em Delphi 6 porém isso não a impede de funcionar no Delphi 4 ou 5, é pouco provavel que ocorra erro.
Verificando se um alias está instalado var vList: TStringList; x: Integer; begin vList := TStringList.Create; Session.Open; Session.GetAliasNames(vList); if vList.Find(‘NomeDoAlias’, x) then // x receberá a posição do alias na lista // Alias encontrado else // Alias não encontrado end;
Como prevenir a movimentação do mouse para fora do form? procedure TForm1.FormMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Form1.Left <= 0 then Form1.Left := 0; if Form1.Top <= 0 then Form1.Top := 0; if Form1.Left >= Screen.Width - Form1.Width then Form1.Left := Screen.Width - Form1.Width; if Form1.Top >= Screen.Height - Form1.Height then Form1.Top := Screen.Height - Form1.Height; end;
Como criar hints customizados? type TGraphicHintWindow = class(THintWindow) constructor Create(AOwner: TComponent); override; private FActivating: Boolean; public procedure ActivateHint(Rect: TRect; const AHint: string); override; protected procedure Paint; override;
114
published property Caption; end; {...} constructor TGraphicHintWindow.Create (AOwner: TComponent); begin inherited Create(AOwner); { Aqui você pode customizar as propriedades da fonte } with Canvas.Font do begin Name := ’Arial’; Style := Style + [fsBold]; Color := clBlack; end; end; procedure TGraphicHintWindow.Paint; var R: TRect; bmp: TBitmap; begin R := ClientRect; Inc(R.Left, 2); Inc(R.Top, 2); {*************************************** O código abaixo é um exemplo de como crier um objeto Hint customizado: } bmp := TBitmap.Create; bmp.LoadfromFile(‘D:\hint.bmp’); with Canvas do begin Brush.Style := bsSolid; Brush.Color := clsilver; Pen.Color := clgray; Rectangle(0, 0, 18, R.Bottom + 1); Draw(2,(R.Bottom div 2) - (bmp.Height div 2), bmp); end; bmp.Free; /Cor do Hint customizada Color := clWhite; Canvas.Brush.Style := bsClear; Canvas.TextOut(20, (R.Bottom div 2) - (Canvas.Textheight(Caption) div 2), Caption); {**************************************} end; procedure TGraphicHintWindow.ActivateHint (Rect: TRect; const AHint: string); begin FActivating := True;
115
try Caption := AHint; //Ajuste a propriedade ”Height” do Hint Inc(Rect.Bottom, 14); //Ajuste a propriedade “Width” do Hint Rect.Right := Rect.Right + 20; UpdateBoundsRect(Rect); if Rect.Top + Height > Screen.DesktopHeight then Rect.Top := Screen.DesktopHeight Height; if Rect.Left + Width > Screen.DesktopWidth then Rect.Left := Screen.DesktopWidth - Width; if Rect.Left < Screen.DesktopLeft then Rect.Left := Screen.DesktopLeft; if Rect.Bottom < Screen.DesktopTop then Rect.Bottom := Screen.DesktopTop; SetWindowPos(Handle, HWND_TOPMOST, Rect.Left, Rect.Top, Width, Height, SWP_SHOWWINDOW or SWP_NOACTIVATE); Invalidate; finally FActivating := False; end; end; procedure TForm1.FormCreate(Sender: TObject); begin HintWindowClass := TGraphicHintWindow; Application.ShowHint := False; Application.ShowHint := True; end;
Como capturar a tela? uses Graphics; // Captura a tela inteira procedure ScreenShot(Bild: TBitMap); var c: TCanvas; r: TRect; begin c := TCanvas.Create; c.Handle := GetWindowDC(GetDesktopWindow); try r := Rect(0, 0, Screen.Width, Screen.Height); Bild.Width := Screen.Width; Bild.Height := Screen.Height; Bild.Canvas.CopyRect(r, c, r); finally
116
ReleaseDC(0, c.Handle); c.Free; end; end; procedure TForm1.Button1Click(Sender: TObject); begin Form1.Visible := False; Sleep(750); // um atraso ScreenShot(Image1.Picture.BitMap); Form1.Visible := True; end; // Somente a janela ativa procedure ScreenShotActiveWindow(Bild: TBitMap); var c: TCanvas; r, t: TRect; h: THandle; begin c := TCanvas.Create; c.Handle := GetWindowDC(GetDesktopWindow); h := GetForeGroundWindow; if h <> 0 then GetWindowRect(h, t); try r := Rect(0, 0, t.Right - t.Left, t.Bottom - t.Top); Bild.Width := t.Right - t.Left; Bild.Height := t.Bottom - t.Top; Bild.Canvas.CopyRect(r, c, t); finally ReleaseDC(0, c.Handle); c.Free; end; end; procedure TForm1.Button2Click(Sender: TObject); begin Form1.Visible := False; Sleep(750); //um atraso ScreenShotActiveWindow(Image1.Picture.BitMap); Form1.Visible := True; end; {*****************************************} // Outra função de print screen function: // Captura a tela inteira procedure ScreenShot(x: Integer; y: Integer; Width: Integer; Height: Integer; bm: TBitMap);
117
var dc: HDC; lpPal: PLOGPALETTE; begin if ((Width = 0) or (Height = 0)) then Exit; bm.Width := Width; bm.Height := Height; dc := GetDc(0); if (dc = 0) then Exit; if (GetDeviceCaps(dc, RASTERCAPS) and RC_PALETTE = RC_PALETTE) then begin GetMem(lpPal, SizeOf(TLOGPALETTE) + (255 * SizeOf(TPALETTEENTRY))); FillChar(lpPal^, SizeOf(TLOGPALETTE) + (255 * SizeOf(TPALETTEENTRY)), #0); lpPal^.palVersion := $300; lpPal^.palNumEntries := GetSystemPaletteEntries(dc, 0, 256, lpPal^.palPalEntry); if (lpPal^.PalNumEntries <> 0) then bm.Palette := CreatePalette(lpPal^); FreeMem(lpPal, SizeOf(TLOGPALETTE) + (255 * SizeOf(TPALETTEENTRY))); end; BitBlt(bm.Canvas.Handle, 0, 0, Width, Height, Dc, x, y, SRCCOPY); ReleaseDc(0, dc); end; // Examplo: procedure TForm1.Button1Click(Sender: TObject); begin ScreenShot(0,0,Screen.Width, Screen.Height, Image1.Picture.Bitmap); end;
118
{****************************************} // Captura a janela procedure ScreenShot(hWindow: HWND; bm: TBitmap); var Left, Top, Width, Height: Word; R: TRect; dc: HDC; lpPal: PLOGPALETTE; begin if not IsWindow(hWindow) then Exit; GetWindowRect(hWindow, R); Left := R.Left; Top := R.Top; Width := R.Right - R.Left; Height := R.Bottom - R.Top; bm.Width := Width; bm.Height := Height; dc := GetDc(0); if (dc = 0) then begin Exit; end; if (GetDeviceCaps(dc, RASTERCAPS) and RC_PALETTE = RC_PALETTE) then begin GetMem(lpPal, SizeOf(TLOGPALETTE) + (255 * SizeOf(TPALETTEENTRY))); FillChar(lpPal^, SizeOf(TLOGPALETTE) + (255 * SizeOf(TPALETTEENTRY)), #0); lpPal^.palVersion := $300; lpPal^.palNumEntries := GetSystemPaletteEntries(dc, 0, 256, lpPal^.palPalEntry); if (lpPal^.PalNumEntries <> 0) then begin bm.Palette := CreatePalette(lpPal^); end; FreeMem(lpPal, SizeOf(TLOGPALETTE) + (255 * SizeOf(TPALETTEENTRY))); end; BitBlt(bm.Canvas.Handle, 0,
119
0, Width, Height, Dc, Left, Top, SRCCOPY); ReleaseDc(0, dc); end; // Exemplo procedure TForm1.Button1Click(Sender: TObject); begin ScreenShot(GetForeGroundWindow, Image1.Picture.Bitmap); end; {**********************************************} {As vezes você quer capturar a tela, no entanto o Windows tem problemas com grande quantidade de dados e fica muito lento. Uma solução bem simples é fazer pequenas capturas e colar o resultado unindo tudo. Não é a velocidade da luz, mas é mais rápido que capturar a tela inteira.} const cTileSize = 50; function TForm1.GetSCREENSHOT: TBitmap; var Locked: Boolean; X, Y, XS, YS: Integer; Canvas: TCanvas; R: TRect; begin Result := TBitmap.Create; Result.Width := Screen.Width; Result.Height := Screen.Height; Canvas := TCanvas.Create; Canvas.Handle := GetDC(0); Locked := Canvas.TryLock; try XS := Pred(Screen.Width div cTileSize); if Screen.Width mod cTileSize > 0 then Inc(XS); YS := Pred(Screen.Height div cTileSize); if Screen.Height mod cTileSize > 0 then Inc(YS); for X := 0 to XS do for Y := 0 to YS do begin R := Rect( X * cTileSize, Y * cTileSize, Succ(X) * cTileSize,
120
Succ(Y) * cTileSize); Result.Canvas.CopyRect(R, Canvas, R); end; finally if Locked then Canvas.Unlock; ReleaseDC(0, Canvas.Handle); Canvas.Free; end; end;
Como mostrar um TMenuItem alinhado Ă direita? procedure TForm1.FormCreate(Sender: TObject); const MenuIndex = 3; var MII: TMenuItemInfo; MainMenu: hMenu; Buffer: array[0..50] of Char; begin MainMenu := GetMenu(Handle); with MII do begin cbSize := SizeOf(MII); fMask := MIIM_TYPE; dwTypeData := Buffer; cch := SizeOf(Buffer); GetMenuItemInfo(MainMenu, MenuIndex, True, MII); fType := fType or MFT_RIGHTJUSTIFY; SetMenuItemInfo(MainMenu, MenuIndex, True, MII); DrawMenuBar(Handle); end; end;
Como mover o form clicando em qualquer lugar? private procedure WMNCHitTest(var msg: TWMNCHitTest); message WM_NCHITTEST; end; var Form1: TForm1; implementation {$R *.DFM}
121
procedure TForm1.WMNCHitTest(var msg: TWMNCHitTest); begin inherited; if msg.Result = htClient then msg.Result := htCaption; end; {...} { ************************* } procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); const SC_DRAGMOVE = $F012; begin if Button = mbleft then begin ReleaseCapture; Form1.Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0); end; end;
Como mostrar um texto de vรกrias linhas em um TCombobox? unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) ComboBox1: TComboBox; procedure FormCreate(Sender: TObject); procedure ComboBox1MeasureItem (Control: TWinControl; Index: Integer; var Height: Integer); procedure ComboBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin Combobox1.Style := csOwnerDrawVariable; // preencha o combobox com alguns exemplos
122
with Combobox1.Items do begin Add(‘Short, kurzer String’); Add(‘A long String. / Ein langer String.....’); Add(‘Another String’); Add(‘abcd defg hijk lmno’); Add(‘..-.-.-.-.-.-.-.-.-’); end; end; procedure TForm1.ComboBox1MeasureItem(Control: TWinControl; Index: Integer; var Height: Integer); // Calculata o tamanho necessário para o texto com várias linhas var i, PosSp: Integer; strVal: string; strTmp: string; begin if Index >= 0 then begin strVal := Combobox1.Items[Index]; // coloque a string em várias linhas, // cada linha separada por #$D#$A strTmp := WrapText(strVal, 20); // Número de separadores de linha // + 1 = número de linhas i := 1; while Pos(#$D#$A, strTmp) > 0 do begin i := i + 1; strTmp := Copy(strTmp, Pos(#13#10, strTmp) + 2, Length(strTmp)); end; // calcule o tamanho do texto Height := i * Combobox1.ItemHeight; end; end; procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); // Escreva o texto em um combobox. Se o texto é muito comprido, então sera feito var strVal: string; strTmp: string; intPos: Integer; i: Integer; rc: TRect; begin strVal := WrapText(Combobox1.Items[Index], 20); i := 0;
123
Combobox1.Canvas.FillRect(Rect); // saída de cada linha while Pos(#$D#$A, strVal) > 0 do begin intPos := Pos(#$D#$A, strVal); // copie a linha corrente da string if intPos > 0 then strTmp := Copy(strVal, 1, intPos - 1) else strTmp := strVal; rc := Rect; rc.Top := Rect.Top + i * Combobox1.ItemHeight; ComboBox1.Canvas.TextRect(rc, Rect.Left, Rect.Top + i * Combobox1.ItemHeight, strTmp); // delete a linha da string strVal := Copy(strVal, intPos + 2, Length(strVal)); Inc(i); end; rc := Rect; rc.Top := Rect.Top + i * Combobox1.ItemHeight; //escreva a última linha ComboBox1.Canvas.TextRect(rc, Rect.Left, Rect.Top + i * Combobox1.ItemHeight, strVal); Combobox1.Canvas.Brush.Style := bsClear; // faça um retangulo em volta do texto Combobox1.Canvas.Rectangle(Rect); end; end.
Como criar tooltips com balões? {....} uses Commctrl; {....} const TTS_BALLOON = $40; TTM_SETTITLE = (WM_USER + 32); var hTooltip: Cardinal; ti: TToolInfo; buffer : array[0..255] of char; {....} procedure CreateToolTips(hWnd: Cardinal); begin hToolTip := CreateWindowEx(0, ’Tooltips_Class32', nil, TTS_ALWAYSTIP or TTS_BALLOON, Integer(CW_USEDEFAULT),
124
Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT), hWnd, 0, hInstance, nil); if hToolTip <> 0 then begin SetWindowPos(hToolTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE); ti.cbSize := SizeOf(TToolInfo); ti.uFlags := TTF_SUBCLASS; ti.hInst := hInstance; end; end; procedure AddToolTip(hwnd: DWORD; lpti: PToolInfo; IconType: Integer; Text, Title: PChar); var Item: THandle; Rect: TRect; begin Item := hWnd; if (Item <> 0) and (GetClientRect(Item, Rect)) then begin lpti.hwnd := Item; lpti.Rect := Rect; lpti.lpszText := Text; SendMessage(hToolTip, TTM_ADDTOOL, 0, Integer(lpti)); FillChar(buffer, SizeOf(buffer), #0); lstrcpy(buffer, Title); if (IconType > 3) or (IconType < 0) then IconType := 0; SendMessage(hToolTip, TTM_SETTITLE, IconType, Integer(@buffer)); end; end; procedure TForm1.Button1Click(Sender: TObject); begin CreateToolTips(Form1.Handle); AddToolTip(Memo1.Handle, @ti, 1, ’Tooltip text’, ’Title’); end; {IconType pode ser: 0 – Sem ícone 1 - Informação 2 - Aviso 3 - Erro }
125
Como mostrar Menu Item Hints Quando o mouse está sobre um componente (um TButton, por exemplo) se a propriedade ShowHint é True e se houver algum texto na propriedade Hint, o hint/tooltip será mostrado para o componente. Hints para itens de menu? Por projeto, mesmo se você colocar algo na propriedade Hint de um Menu Item o popup hint não será exibido. No entanto, os Itens do menu Iniciar do Windows mostram hints, e o menu dos Favoritos do Internet Explorer também. É comum usar o evento OnHint nas variáveis globais da aplicação, nas aplicações Delphi, para mostrar os hints do menu como uma barra de status. O Windows não expõe as mensagens necessárias que suportem o evento tradicional OnMouseEnter. No entanto, a implementação do WM_MENUSELECT no TCustomForm (ancestral do TForm) tem o item hint de menu no Application.Hint que pode ser usado no evento Application.OnHint. Se você quer adicionar itens de menu com popup hints nos menus de sua aplicação Delphi você precisa “somente” apontar a mensagem WM_MenuSelect corretamente. A classe TMenuItemHint – hints popup para itens de menu! Como não podemos depender do método Application.ActivateHint para mostrar a janela para os itens de menu (o apontamento de menus é feito totalmente pelo Windows), para obter a janela de hint exibida você precisa criar sua própria versão da janela hint – derivando uma nova classe a partir de THintWindow. Segue como criar a classe TMenuItemHint – uma janela hint que realmente é exibida nos itens de menu. Primeiro você precisa apontar a mensagem WM_MENUSELECT do Windows: type TForm1 = class(TForm) ... private procedure WMMenuSelect(var Msg: TWMMenuSelect) ; message WM_MENUSELECT; end ... implementation ... procedure TForm1.WMMenuSelect (var Msg: TWMMenuSelect) ; var
126
menuItem : TMenuItem; hSubMenu : HMENU; begin inherited; // from TCustomForm //(so that Application.Hint is assigned) menuItem := nil; if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then begin if Msg.MenuFlag and MF_POPUP = MF_POPUP then begin hSubMenu := GetSubMenu (Msg.Menu, Msg.IDItem) ; menuItem := Self.Menu.FindItem (hSubMenu, fkHandle) ; end else begin menuItem := Self.Menu.FindItem (Msg.IDItem, fkCommand) ; end; end; miHint.DoActivateHint(menuItem) ; end; (*WMMenuSelect*) A mensagem WM_MENUSELECT é enviada à janela proprietária do menu (Form 1) quando o usuário seleciona (não quando clica) um item de menu. Usando o método FindItem da classe TMenu, você consegue pegar o item de menu que está selecionado no momento. Os parâmetros da função FindItem relatam as propriedades que a mensagem recebeu. Uma vez que você saiba qual o item de menu sobre qual está o mouse, chamaremos o método DoActivateHint da classe TMenuItemHint. Observe que a variável miHint é definida como “var miHint : TMenuItemHint” e é criada no evento OnCreate do Form. Agora vamos fazer a implementação da classe TMenuItemHint. Aqui está a parte da interface: TMenuItemHint = class(THintWindow) private activeMenuItem : TMenuItem; showTimer : TTimer; hideTimer : TTimer; procedure HideTime(Sender : TObject) ; procedure ShowTime(Sender : TObject) ; public constructor Create (AOwner : TComponent) ; override; procedure DoActivateHint
127
(menuItem : TMenuItem) ; destructor Destroy; override; end; Você pode ver toda a implementação no projeto exemplo. Basicamente, a função DoActivateHint chama o método ActivateHint do THintWindow usando a propriedade Hint do TMenuItem (se estiver atribuída). O showTimer é usado para se ter certeza que o HintPause (do Application) transcorre antes do hint ser mostrado. O hideTimer usa o Application.HintHidePause para esconder a janela do hint após um intervalo específico. Quando usar os hints nos itens do menu? Enquanto alguns podem dizer que não é uma boa coisa mostrar hints nos itens de menu, há situações que mostrar hints no menu é muito melhor do que mostrar uma barra de status. Segue o código fonte do Form, com a implementação da classe TMenuItemHint. unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Menus, AppEvnts, StdCtrls, ExtCtrls, ComCtrls; type TMenuItemHint = class(THintWindow) private activeMenuItem : TMenuItem; showTimer : TTimer; hideTimer : TTimer; procedure HideTime(Sender : TObject) ; procedure ShowTime(Sender : TObject) ; public constructor Create (AOwner : TComponent) ; override; procedure DoActivateHint (menuItem : TMenuItem) ; destructor Destroy; override; end; TForm1 = class(TForm) ... procedure FormCreate(Sender: TObject) ;
128
procedure ApplicationEvents1Hint (Sender: TObject) ; private miHint : TMenuItemHint; procedure WMMenuSelect (var Msg: TWMMenuSelect) ; message WM_MENUSELECT; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate (Sender: TObject) ; begin miHint := TMenuItemHint.Create(self) ; end; (*FormCreate*) procedure TForm1.ApplicationEvents1Hint (Sender: TObject) ; begin StatusBar1.SimpleText := ‘App.OnHint : ‘ + Application.Hint; end; (*Application.OnHint*) procedure TForm1.WMMenuSelect (var Msg: TWMMenuSelect) ; var menuItem : TMenuItem; hSubMenu : HMENU; begin inherited; // TCustomForm // (se certifica que o Application.Hint // é atribuído) menuItem := nil; if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then begin if Msg.MenuFlag and MF_POPUP = MF_POPUP then begin hSubMenu := GetSubMenu (Msg.Menu, Msg.IDItem) ; menuItem := Self.Menu.FindItem (hSubMenu, fkHandle) ; end else begin
129
menuItem := Self.Menu.FindItem (Msg.IDItem, fkCommand) ; end; end; miHint.DoActivateHint(menuItem) ; end; (*WMMenuSelect*)
{ TMenuItemHint } constructor TMenuItemHint.Create (AOwner: TComponent) ; begin inherited; showTimer := TTimer.Create(self) ; showTimer.Interval := Application. HintPause; hideTimer := TTimer.Create(self) ; hideTimer.Interval := Application. HintHidePause; end; (*Create*) destructor TMenuItemHint.Destroy; begin hideTimer.OnTimer := nil; showTimer.OnTimer := nil; self.ReleaseHandle; inherited; end; (*Destroy*) procedure TMenuItemHint.DoActivateHint (menuItem: TMenuItem) ; begin //força a remoção da velha janela //do hint hideTime(self) ; if (menuItem = nil) or (menuItem.Hint = ‘’) then begin activeMenuItem := nil; Exit; end; activeMenuItem := menuItem; showTimer.OnTimer := ShowTime; hideTimer.OnTimer := HideTime;
130
end; (*DoActivateHint*) procedure TMenuItemHint.ShowTime (Sender: TObject) ; var r : TRect; wdth : integer; hght : integer; begin if activeMenuItem <> nil then begin //position and resize wdth := Canvas.TextWidth (activeMenuItem.Hint) ; hght := Canvas.TextHeight (activeMenuItem.Hint) ; r.Left := Mouse.CursorPos.X + 16; r.Top := Mouse.CursorPos.Y + 16; r.Right := r.Left + wdth + 6; r.Bottom := r.Top + hght + 4; ActivateHint(r,activeMenuItem.Hint) ; end; showTimer.OnTimer := nil; end; (*ShowTime*) procedure TMenuItemHint.HideTime(Sender: TObject) ; begin //esconde (destroy) a janela hint self.ReleaseHandle; hideTimer.OnTimer := nil; end; (*HideTime*) end
Overwrite no TMemo e Tedit Os controles do Windows TMemo e TEdit não têm a capacidade overwrite. No entanto, é possível simular este comportamento, ajustanto a propriedade SelLength do controle edit ou memo durante o processamento do evento KeyPress. Isso faz com que o caractere que está na posição corrente seja sobrescrito. O exemplo a seguir mostra como emular a capacidade de overwrite de um componente TMemo. O estado do modo de sobrescrever pode ser mudado pressionando a tecla Insert.
131
type TForm1 = class(TForm) Memo1: TMemo; procedure Memo1KeyDown (Sender: TObject; var Key: Word; Shift: TShiftState) ; procedure Memo1KeyPress (Sender: TObject; var Key: Char) ; private { Private declarations } InsertOn : bool; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Memo1KeyDown (Sender: TObject; var Key: Word; Shift: TShiftState) ; begin if (Key = VK_INSERT) and (Shift = []) then InsertOn := not InsertOn; end; procedure TForm1.Memo1KeyPress (Sender: TObject; var Key: Char) ; begin if ((Memo1.SelLength = 0) and (not InsertOn)) then Memo1.SelLength := 1; end; Algumas vezes precisamos limpar todos os componentes Edit que estão no Form. Esta tarefa é feita facilmente com o seguinte procedimento: procedure ClearEdits; var j : Integer; begin for j := 0 to ComponentCount-1 do if (Components[j] is TEdit) then (Components[j] as TEdit).Text := ‘’; end;
132
Como chamar o “Ver fonte (view source)” em um WebBrowser Aqui está como chamar o Ver fonte do IE (para examinar o HTML) com o componente TWebBrowser. Simplesmente arraste uma instância do componente TWebBrowser em um formulário e um botão (Button) e faça como segue: uses ActiveX; procedure WBViewSourceDialog (AWebBrowser: TWebbrowser) ; const CGID_WebBrowser: TGUID = ‘{ED016940-BD5B-11cf-BA4E-00C04FD70816}’; HTMLID_VIEWSOURCE = 2; var CmdTarget : IOleCommandTarget; vaIn, vaOut: OleVariant; PtrGUID: PGUID; begin New(PtrGUID) ; PtrGUID^ := CGID_WebBrowser; if AWebBrowser.Document <> nil then try AWebBrowser.Document. QueryInterface(IOleCommandTarget, CmdTarget) ; if CmdTarget <> nil then try CmdTarget.Exec(PtrGUID, HTMLID_VIEWSOURCE, 0, vaIn, vaOut) ; finally CmdTarget._Release; end; except end; Dispose(PtrGUID) ; end; procedure TForm1.FormCreate (Sender: TObject); begin WebBrowser1.Navigate (‘http://www.delphi.about.com’) ; end;
133
procedure TForm1.Button1Click (Sender: TObject) ; begin WBViewSourceDialog(WebBrowser1) ; end;
MessageBox com timeout Aqui está como chamar um Message Box com timeout, ele irá fechar a si mesmo após um período de tempo. O truque é chamar uma API não documentada localizada no user32.dll, a API é a MessageBoxTimeOut. A função retorna um valor inteiro para MB_TIMEDOUT (indicando que o período de tempo para o timeout foi alcançado e o Message Box foi automaticamente fechado), ou um valor representando o botão que o usuário clicou. Observe que o valor retornado é sempre 1, quando o Message Box tem somente um botão de OK (MB_OKFlag). //declaração de interface const MB_TIMEDOUT = 32000; function MessageBoxTimeOut (hWnd: HWND; lpText: PChar; lpCaption: PChar; uType: UINT; wLanguageId: WORD; dwMilliseconds: DWORD): Integer; stdcall; external user32 name ‘MessageBoxTimeoutA’; //implementação (Apontamento do evento //OnClick do Button1 no Form1) procedure TForm1.Button1Click (Sender: TObject) ; var iRet: Integer; iFlags: Integer; begin iFlags := MB_OK or MB_SETFOREGROUND or MB_SYSTEMMODAL or MB_ICONINFORMATION; MessageBoxTimeout (Application.Handle, ‘Test a timeout of 2 seconds.’, ‘MessageBoxTimeout Teste’, iFlags, 0, 2000) ; iFlags := MB_YESNO or MB_SETFOREGROUND or MB_SYSTEMMODAL or MB_ICONINFORMATION; iRet := MessageBoxTimeout (Application.Handle, ‘Teste de timeout 134
de 5 segundos.’, ‘MessageBoxTimeout Teste’, iFlags, 0, 5000) ; case iRet of IDYES: ShowMessage(‘Yes’) ; IDNO: ShowMessage(‘No’) ; MB_TIMEDOUT: ShowMessage(‘TimedOut’) ; end; end;
Como colocar uma barra de progresso dentro de um dialog box padrão Vamos dizer que você tem um dialog box padrão do Windows mostrando uma pergunta ao usuário com os botões de “Yes” e “No”. Não seria ótimo se existisse uma barra de progresso contando o tempo até que o dialog box se feche automaticamente? Vamos lá então: Vamos criar um dialog usando CreateMessageDialog. Esta função retornará um form object com o dialog. Neste objeto podemos adicionar a barra de progresso. Também podemos adicionar um objeto Timer para uma atualização dinâmica da posição da barra de progresso. Mostramos o dialog com ShowModal. Apontamos o evento OnTimer do componente TTimer para ver o número se passou a quantidade de segundos necessária, se sim, fechamos o dialog ajustando a propriedade ModalResult, no código, para mrCancel. Se não, usamos StepIt para atualizar a barra de progresso. Coloque um botão no formulário e tente este código: procedure TForm1.Button1Click (Sender: TObject) ; var AMsgDialog : TForm; AProgressBar : TProgressBar; ATimer : TTimer; begin AMsgDialog := CreateMessageDialog(‘Quickly! Answer Yes or No!’, mtWarning, [mbYes, mbNo]) ; AProgressBar := TProgressBar. Create(AMsgDialog) ; ATimer := TTimer.Create(AMsgDialog) ; with AMsgDialog do try Tag := 10; //seconds! Caption := ‘You have 10 seconds’; Height := 150;
135
with AProgressBar do begin Name := ‘Progress’; Parent := AMsgDialog; Max := AMsgDialog.Tag; //seconds Step := 1; Top := 100; Left := 8; Width := AMsgDialog.ClientWidth - 16; end; with ATimer do begin Interval := 1000; OnTimer:=DialogTimer; end; case ShowModal of ID_YES: ShowMessage(‘Answered “Yes”.’) ; ID_NO: ShowMessage(‘Answered “No”.’) ; ID_CANCEL: ShowMessage(‘Time up!’) end;//case finally ATimer.OnTimer := nil; Free; end; end; //make sure you add this function’s //header in the private part of the TForm1 //type declaration. procedure TForm1.DialogTimer(Sender:TObject); var aPB : TProgressBar; begin if NOT (Sender is TTimer) then Exit; if ((Sender as TTimer).Owner) is TForm then with ((Sender as TTimer).Owner) as TForm do begin aPB := TProgressBar (FindComponent(‘Progress’)) ; if aPB.Position >= aPB.Max then ModalResult := mrCancel else aPB.StepIt; end; end;
136
Como imprimir uma página/documento com o TWebBrowser Você primeiro precisa carregar uma página no TWebBrowser, por exemplo (supondo que você tem um componente chamado WebBroser1): WebBrowser1.Navigate(‘http://theclub.activeinterno.com.br’); // impressão sem aparecer um dialog procedure WBPrintNoDialog(WB: TWebBrowser) ; var vIn, vOut: OleVariant; begin WB.ControlInterface.ExecWB (OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, vIn, vOut) ; end; //com chamada do dialog procedure WBPrintWithDialog(WB: TWebBrowser) ; var vIn, vOut: OleVariant; begin WB.ControlInterface.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, vIn, vOut) ; end; // Preview de impressão procedure WBPrintPreview(WB: TWebBrowser) ; var vIn, vOut: OleVariant; begin WB.ControlInterface.ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_DONTPROMPTUSER, vIn, vOut); end; //Chama o dialog de setup de página procedure WBPrintPageSetup(WB: TWebBrowser) ; var vIn, vOut: OleVariant; begin WB.ControlInterface.ExecWB(OLECMDID_PAGESETUP, OLECMDEXECOPT_PROMPTUSER, vIn, vOut) ; end;
Como esconder o text cursor dentro de um Tmemo Aqui está um código exemplo de como esconder o text cursor no Memo1 dentro do Form1. Substitua todo o código pelo que segue abaixo:
137
unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls; const WM_MYMEMO_ENTER = WM_USER + 500; type TForm1 = class(TForm) Memo1: TMemo; procedure Memo1Enter(Sender: TObject) ; procedure Memo1Exit(Sender: TObject) ; procedure Memo1Change(Sender: TObject); private public procedure WMMYMEMOENTER (var Message: TMessage) ; message WM_MYMEMO_ENTER; end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.WMMYMEMOENTER (var Message: TMessage) ; begin CreateCaret(Memo1.Handle,0,0,0) ; end; procedure TForm1.Memo1Enter(Sender: TObject); begin PostMessage (Handle, WM_MYMEMO_ENTER, 0, 0); end; procedure TForm1.Memo1Exit(Sender: TObject); begin CreateCaret(Memo1.handle,1,1,1) ; end; procedure TForm1.MemoChange(Sender: TObject); begin
138
CreateCaret(Memo1.handle,0,0,0) ; end; end.
Como determinar a posição do cursor dentro de um TrichEdit Veja o exemplo: { Usage: var sRC:string; src := GetPosition(RichEdit1) ; //src reults in a string //formated like: Row:Col } function GetPosition (ARichEdit: TRichEdit): string var iX,iY : Integer; begin iX := 0; iY := 0; iY := SendMessage(ARichEdit.Handle, EM_LINEFROMCHAR,ARichEdit.SelStart,0) ; iX := ARichEdit.SelStart SendMessage(ARichEdit.Handle, EM_LINEINDEX, iY, 0) ; Result := IntToStr(iY + 1) + ‘:’ + IntToStr(iX + 1) ; end;
Como completer strings parciais digitadas dentro de um Combo Box O exemplo abaixo mostra como completar strings parciais digitadas dentro de um combo box. O código representa o apontamento do evento OnKeyPress do combo box, que faz a execução padrão das teclas antes de encontrar o item na lista correspondente e atualizar o texto. Observação: O evento OnKeyPress não faz nada quando o usuário pressiona Delete. Neste caso deve-se capturar a tecla utilizando-se o evento OnKeyDown. procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: Char) ; var Found: boolean; j,SelSt: Integer;
139
TmpStr: string; begin { primeiro, processe a tecla para obter a string corrente } { Este código requer que todos os itens estejam listados em uppercase} if Key in [‘a’..’z’] then Dec(Key,32) ; {Somente Uppercase!} with (Sender as TComboBox) do begin SelSt := SelStart; if (Key = Chr(vk_Back)) and (SelLength <> 0) then TmpStr := Copy(Text,1,SelStart)+Copy (Text,SelLength+SelStart+1,255) else if Key = Chr(vk_Back) then {SelLength = 0} TmpStr := Copy(Text,1,SelStart1)+Copy(Text,SelStart+1,255) else {Key in [‘A’..’Z’, etc]} TmpStr := Copy(Text,1,SelStart)+Key+Copy (Text,SelLength+SelStart+1,255) ; if TmpStr = ‘’ then Exit; { atualize SelSt para a posição corrente de inserção } if (Key = Chr(vk_Back)) and (SelSt > 0) then Dec(SelSt) else if Key <> Chr(vk_Back) then Inc(SelSt) ; Key := #0; { indica qual tecla foi apontada } if SelSt = 0 then begin Text:= ‘’; Exit; end; {Agora que TmpStr é a string sendo digitada no momento, veremos se conseguimos encontrar uma correspondência } Found := False; for j := 1 to Items.Count do if Copy(Items[j-1],1,Length(TmpStr)) = TmpStr then begin
140
Text := Items[j-1]; { atualize para a correspondente que foi encontrada} ItemIndex := j-1; Found := True; Break; end; if Found then { selecione o final nรฃo digitado da string } begin SelStart := SelSt; SelLength := Length(Text)-SelSt; end else Beep; end; end;
Como arredondar os cantos dos controles Aqui estรก como desenhar controles com os cantos arredondados. Para testar, arraste um TEdit, TPanel e TMemo em um formulรกrio. procedure DrawRounded(Control: TWinControl) ; var R: TRect; Rgn: HRGN; begin with Control do begin R := ClientRect; rgn := CreateRoundRectRgn(R.Left, R.Top, R.Right, R.Bottom, 20, 20); Perform(EM_GETRECT, 0, lParam(@r)) ; InflateRect(r, - 4, - 4) ; Perform(EM_SETRECTNP, 0, lParam(@r)) ; SetWindowRgn(Handle, rgn, True) ; Invalidate; end; end; procedure TForm1.FormCreate(Sender: TObject); begin // arredondando o Panel1 DrawRounded(Panel1) ; // arredondando o Memo1 Memo1.BorderStyle := bsNone; DrawRounded(Memo1) ; // arredondando o Edit1 Edit1.BorderStyle := bsNone;
141
DrawRounded(Edit1) ; end;
Usando as setas do teclado para se mover entre os controles As teclas Up e Down são virtualmente inúteis em controles Edit. Então, porque não usálas para navegar entre os controles? Se você ajustar a propriedade KeyPreview de um form para True você pode usar o seguinte código no seu evento OnKeyDown do formulário para controlar a navegação: procedure TForm1.FormKeyDown( Sender : TObject; var Key: Word; Shift : TShiftState ); var Direction : Integer; begin Direction := -1; case Key of VK_DOWN, VK_RETURN : Direction := 0; {Next} VK_UP : Direction := 1; {Previous} end; if Direction <> -1 then begin Perform(WM_NEXTDLGCTL, Direction, 0) ; Key := 0; end; end;
Qual é a palavra sob o cursor do mouse em um TRichEdit? Aqui está o código para você saber qual a palavra que está sob o cursor do mouse. A variável string WordInRE conterá a palavra. Observação: Você precisará de um TRichEdit (RichEdit1), um form (Form1), e o código abaixo no evento OnMouseMove do RichEdit1.
142
uses RichEdit; var WordInRE : string; procedure TForm1.RichEdit1MouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer) ; var ci, lix, co, k, j: Integer; Pt: TPoint; s: string; begin with TRichEdit(Sender) do begin Pt := Point(X, Y) ; ci := Perform(Messages. EM_CHARFROMPOS, 0, Integer(@Pt)) ; if ci < 0 then Exit; lix := Perform (EM_EXLINEFROMCHAR, 0, ci); co := ci - Perform (EM_LINEINDEX, lix, 0) ; if -1 + Lines.Count < lix then Exit; s := Lines[lix]; Inc(co) ; k := co; while (k > 0) and (s[k] <> ‘ ‘) do k:=k-1; Inc(co) ; j := co; while (j <= Length(s)) and (s[j] <> ‘ ‘) do Inc(j) ; WordInRE := Copy(s, k, j - i) ; end; end;
143
Mostra o total de páginas Você pode fazer este tipo de trabalho, mas ele terá que ser manual. O primeiro passo é pegar o total de páginas e jogar para uma variável. Para pegar o total de páginas você pode executar o código abaixo antes de chamar o relatório. QuickRep1.Prepare; TotalPaginas := QuickRep1.PageNumber; TotalPaginas mostrada anteriormente é uma variável do tipo inteiro. Para mostrar isto no QuickReport você pode utilizar um componente QRSysData alterando a propriedade Data para PageNumber e colocar a rotina a seguinte no evento OnPrint. procedure TForm1.QRSysData1Print (sender: TObject; var Value: String); begin Value := Value + ‘/’ + IntToStr(TotalPaginas) end;
InnoSetup – Verificando a versão do software, se inferior, então, não instalar O InnoSetup permite a inclusão de scripts em uma sua seção “CODE” e isso sem dúvidas permite grande flexibilidade no desenvolvimento de instalações personalizadas. Abaixo, segue um script para o InnoSettup onde demonstramos como efetuar este tipo de verificação. [Setup] AppName=VerificaVersao AppVerName=VerificaVersao DefaultDirName={pf}\VerificaVersao DisableStartupPrompt=true Uninstallable=false DisableDirPage=true OutputBaseFilename=VerificaVersao [Code] function GetVersion(): String; var sVersion: String; begin sVersion := ‘’; GetVersionNumbersString( ExpandConstant
144
(‘{win}\notepad.exe’) , sVersion ); Result := sVersion; end; function InitializeSetup(): Boolean; begin if GetVersion() = ‘5.1.2600.0’ then begin MsgBox( ‘Versão instalada: ‘ + GetVersion() + chr(13) + ‘ Você só poderá instalar uma versão superior.’, mbInformation, MB_OK ); Result := false; end else Result := true; end;
InnoSetup – Manipulação de arquivos texto Utilizando a seção de codificação do InnoSetup é possível implementar a manutenção em arquivos texto de forma bem simples, acompanhe o script abaixo: [Setup] AppName=EditaTexto AppVerName=EditaTexto DefaultDirName={pf}\EditaTexto DisableStartupPrompt=true Uninstallable=false DisableDirPage=true OutputBaseFilename=EditaTexto [Code] function AddToText(strFilename, strNewLine: String): Boolean; var strTemp : String; iLineCounter : Integer; a_strTextfile : TArrayOfString; begin Result := False; { Carrega as linhas do texto em um Array } LoadStringsFromFile(strFilename, a_strTextfile); { Adiciona uma linha no Array } SetArrayLength(a_strTextfile, GetArrayLength(a_strTextfile)+1); { Escreve o texto } a_strTextfile[GetArrayLength (a_strTextfile)-1] := strNewLine;
145
{ ‘Regrava’ o arquivo } SaveStringsToFile(strFilename, a_strTextfile, False); Result := True; end; function InitializeSetup(): Boolean; var Arquivo: String; begin Arquivo := ExpandConstant(‘{pf}\ Firebird\Firebird_1_5\aliases.conf’); if AddToText(Arquivo, ‘THECLUB = D:\THECLUB\THECLUB.FDB’) then begin MsgBox(‘Alteração efetuada com sucesso!’, mbInformation, MB_OK ); Result := false; end else Result := true; end;
Finalizando processos do Windows via programação Segue abaixo instrução para finalizar um processo do Windows, via Delphi. implementation Uses Tlhelp32; {$R *.dfm} function KillTask(ExeFileName: string): Integer; const PROCESS_TERMINATE=$0001; var ContinueLoop: BOOL; FSnapshotHandle: THandle; FProcessEntry32: TProcessEntry32; begin Result := 0; FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); FProcessEntry32.dwSize := Sizeof(FProcessEntry32); ContinueLoop := Process32First (FSnapshotHandle, FProcessEntry32); while integer(ContinueLoop) <> 0 do begin
146
if ((UpperCase(ExtractFileName (FProcessEntry32.szExeFile)) = UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) = UpperCase (ExeFileName))) then Result := Integer(TerminateProcess (OpenProcess(PROCESS_TERMINATE, BOOL(0),FProcessEntry32. th32ProcessID), 0)); ContinueLoop := Process32Next (FSnapshotHandle, FProcessEntry32); end; CloseHandle(FSnapshotHandle); end; procedure TForm1.Button1Click(Sender: TObject); begin KillTask( ‘Outlook.exe’ ); end;
Gravando CDs No endereço: http://sourceforge.net/projects/delphineroapi/ encontrará um pacote de APIs para Delphi que possibilitam efetuar a gravação de CDs.
Quick Report - Obtendo a lista de papeis disponíveis No caso do QReport, o mesmo possui uma tipagem própria com nomes dos papeis que não coincidem com os tipos pré-definidos no Windows. Assim sendo, adicione estes valores “fixos” ao seu ComboBox, pois, estes são dos tipos possível aceitos pelo QR: TQRPaperSize = (Default, Letter, LetterSmall, Tabloid, Ledger, Legal, Statement, Executive, A3, A4, A4Small, A5, B4, B5, Folio, Quarto, qr10X14, qr11X17, Note, Env9, Env10, Env11, Env12, Env14, CSheet, DSheet, ESheet, Custom) Para pegar o valor do ComboBox e alterar no QReport, utilize o seguinte: implementation uses QrPrNtr, TypInfo; {$R *.dfm} procedure SetPaper(const PaperName: string; QR: TQuickRep); var Paper : TQRPaperSize; 147
begin Paper := TQRPaperSize(GetEnumValue(TypeInfo (TQRPaperSize),PaperName)); QR.Page.PaperSize := Paper; end; procedure TForm1.Button1Click(Sender: TObject); begin SetPaper(‘LetterSmall’, QuickRep1); // ou SetPaper(ComboBox.Items[ComboBox.ItemIndex], QuickRep1); end;
DBGrid - Como fazer quebra de linhas Iremos demonstrar aqui como fazer quebra de linhas no texto apresentado em um DBGrid. Para isso, será necessário declararmos um tipo para poder acessar propriedades protegidas do mesmo. { tipo para acessar propriedades protegidas } type TGrid = class(TCustomDBGrid); { Flags de alinhamento } const AlignFlags : array [TAlignment] of Integer = ( DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX, DT_RIGHT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX, DT_CENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX ); RTL: array [Boolean] of Integer = (0, DT_RTLREADING); var Form1: TForm1; implementation {$R *.dfm} { Evento OnDrawColumnCell do DBGrid. } procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); var R: TRect; begin with DBGrid1 do begin if DataCol = 1 then { Verifica se é a 2ª coluna} begin
148
CopyRect(R, Rect); Canvas.FillRect(Rect); { Ajusta limite para Quebrar o texto, neste caso, verifica a largura da coluna } R.Right := R.BottomRight.X; { desenha o texto na "área" determinada em "R" } DrawText(Canvas.Handle, PChar(Column.Field.AsString), StrLen(PChar(Column.Field.AsString)), R, DT_EXPANDTABS or DT_WORDBREAK ); end; end; end; { Evento OnCreate do Form } procedure TForm1.FormCreate(Sender: TObject); begin { Ajusta altera padrão para as linhas } TGrid(DBGrid1).DefaultRowHeight := 50; end;
Mensagens: Alterar a cor da fonte de um ShowMessage Neste dica, utilizamos um evento do objeto Application para verificar que houve mudança de formulário e se o formulário que foi chamado for do tipo TmessageForm (o qual indica que é uma caixa de mensagem), irá alterar a cor da fonte do texto da mesma. Vamos ao código: type TForm1 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Button1Click(Sender: TObject); private public procedure FormFoco(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormFoco(Sender: TObject); var Comp: TLabel; begin { Verifica se o form que está com o
149
foco é o form de mensagem } if Screen.ActiveForm.ClassName = ‘TMessageForm’ then begin { Pesquisa o componente label de mensagem } Comp := TLabel(Screen.ActiveForm. FindComponent(‘Message’)); if Comp <> Nil then Comp.Font.Color :=clBlue; { Altera a sua cor } end; end; procedure TForm1.FormCreate(Sender: TObject); begin Screen.OnActiveFormChange := FormFoco; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Screen.OnActiveFormChange := Nil; end; procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(‘THE CLUB - O maior clube de programadores do Brasil’); end; end.
Arquivo: Verificar se está ReadOnly var Attributes: Word; begin Attributes := FileGetAttr(‘d:\arquivo.txt’); if (Attributes and faReadOnly) = faReadOnly then ShowMessage(‘ReadOnly’); end;
DBGrid: Como alterar a altura das linhas Existem propriedades protegidas no DBGrid que para podermos acessá-las somos obrigados a derivar uma nova classe. Veja o código abaixo: type TGrid = class(TCustomDBGrid); var Form1: TForm1;
150
implementation {$R *.dfm} procedure TForm1.SpeedButton1Click(Sender: TObject); begin { ajusta altura padrão para as linhas } TGrid(DBGrid1).RowHeights[1] := 50; end;
Treeview – Foco Veja neste exemplo como mandar o foco à um ítem do treeview quando clicar no botão de expansão (+): // evento OnMouseDown do Treeview. procedure TForm1.TreeView1MouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var T: TTreeNode; begin // Pega o ítem através das coordenadas do mouse. T := Treeview1.GetNodeAt(X,Y); if T <> nil then Treeview1.Selected := T; end;
Rave Report – Indicar página inicial O Rave Reports permite ter várias páginas de relatório (cada página com um layout) para um mesmo relatório. Neste exemplo, iremos demonstrar como definir via programação qual página será apresentada como inicial. uses RVClass, RVProj, RVCsStd; procedure TForm1.btnChamaRelClick (Sender: TObject); var Pagina: TRavePage; Report: TRaveReport; QualPagina: String; begin // Nome da página dentro do projeto Rave. QualPagina := ‘Page2’;
151
// Abre RvProject. RvProject1.Open; // Pega referência do “Report” // dentro do projeto Rave. Report := RvProject1.ProjMan.ActiveReport; // Pega referência da “Page” dentro do “Report”. Pagina := RvProject1.ProjMan.FindRaveComponent (‘Report1.’+QualPagina,nil) as TRavePage; // Indica a página inicial. Report.FirstPage := Pagina; // Executa o relatório. RvProject1.Execute; end;
Desktop do Windows – auto-arranjar icones Esta dica pode ser útil após a instalação de sua aplicação, onde geralmente é disponibilizado um ícone na área de trabalho do Windows e em muitos casos sendo necessário arranjá-los após a instalação. mplementation uses CommCtrl; {$R *.dfm} function GetDesktopListViewHandle: THandle; var S: String; begin Result := FindWindow(‘ProgMan’, nil); Result := GetWindow(Result,GW_CHILD); Result := GetWindow(Result, GW_CHILD); SetLength(S, 40); GetClassName(Result, PChar(S), 39); if PChar(S) <> ‘SysListView32’ then Result := 0; end; procedure TForm1.Button1Click(Sender: TObject); begin SendMessage(GetDesktopListViewHandle, LVM_ARRANGE, 0, 0); end;
152
Cálculo de Parcelas Neste simples exemplo iremos demonstrar como fazer a divisão de um valor em parcelas, fazendo o tratamento da diferença, jogando para a primeira ou última parcela, na figura 1 poderá verificar o layout sugerido para o formulário deste exemplo.
Figura 1 – Layout sugerido Acompanha agora o código do botão “Gerar”: procedure TForm1.btnGerarClick(Sender: TObject); var Total, ValorParc, TotParc: Extended; NParc: Integer; Parcelas: Array of Extended; i: Integer; begin { Variáveis auxiliares } Total := 0; ValorParc := 0; TotParc := 0; NParc := 0; ListParcelas.Clear; { tenta converter o valor do Edit } try Total := StrToFloat(edValor.Text); except ShowMessage(‘Valor Inválido!’); Abort; end; { Verifca número de parcelas } if speParcelas.Value < 2 then
153
Exit else NParc := speParcelas.Value; { Pega somente a parte inteira da divisão } ValorParc := Trunc(Total / NParc); { Ajusta array que guardará o } {valor de cada parcela } SetLength(Parcelas, NParc); { Atribui valor de cada parcela e acumula total } for i := Low(Parcelas) to High(Parcelas) do begin Parcelas[i] := 0; Parcelas[i] := ValorParc; TotParc := TotParc + Parcelas[i]; end; { Verifica em qual parcela será “jogada” a } { diferença } if rg_diferenca.ItemIndex = 0 then Parcelas[Low(Parcelas)] := Parcelas[Low(Parcelas)] + (Total - TotParc) else Parcelas[High(Parcelas)] := Parcelas[High(Parcelas)] + (Total - TotParc); { mostra parcelas no ListBox } for i := Low(Parcelas) to High(Parcelas) do ListParcelas.Items.Add(FormatFloat(‘###,##0.00’, Parcelas[i])); end; O exemplo referente esta dica está disponível para download em: http://theclub.activeinterno.com.br/revista/downloads/CalcParcelas.zip
Porta Serial – Como verificar se uma porta está em uso Existem APIs do Windows que possibilitam fazer acesso e manutenção à portas seriais, veja abaixo: var portHandle: Integer; begin portHandle := 0; portHandle := CreateFile(Pchar(ComboCOM.Text), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if portHandle > 0 then
154
ShowMessage(‘Porta em uso!’) else raise Exception.Create (‘Não consegui abrir a porta!’); end;
GIF – Como converter uma imagem GIF para BMP Neste exemplo, estamos utilizando o objeto TGifImage que é instalado junto com a suite de componentes RxLib. Esta suite é gratuíta e possui vários componentes bem legais e, caso haja interesse, poderá baixar em nosso site, theclub.activeinterno.com.br. Abaixo, segue a rotina de conversão: implementation uses RxGif; {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var GIF: TGIFImage; BMP: TBitmap; begin GIF := TGIFImage.Create; BMP := TBitmap.Create; try GIF.LoadFromFile(‘c:\banner_theclub.gif’); BMP.Assign(GIF); BMP.SaveToFile(‘c:\theclub.bmp’); finally GIF.Free; BMP.Free; end; end;
Veja como criar atalhos no menu iniciar do Windows Neste exemplo, iremos demonstrar uma forma bastante simples para criar: - Grupos de programas - Items de programas - Atalhos para programas Em nossa abordagem, não iremos utilizar a criação via interface DDE por alguns questões de parametrização e sim, demonstraremos a partir da criação direta de “folders” na pasta “Programs” do Windows.
155
Primeiramente, vamos criar uma procedure para criação de atalhos: implementation uses ShlObj, ActiveX, ComObj; {$R *.dfm} procedure CriaShortCut(aNome, aFileName, aPathGroup: string; aLocation: integer); var IObject : IUnknown; ISLink : IShellLink; IPFile : IPersistFile; PIDL : PItemIDList; InFolder : array[0..MAX_PATH] of Char; TargetName : String; LinkName,s : WideString; begin TargetName := aFileName; IObject := CreateComObject(CLSID_ShellLink); ISLink := IObject as IShellLink; IPFile := IObject as IPersistFile; with ISLink do begin SetPath(pChar(TargetName)); SetWorkingDirectory(pChar(ExtractFilePath(TargetName))); end; SHGetSpecialFolderLocation(0, aLocation, PIDL); SHGetPathFromIDList(PIDL, InFolder); s := InFolder; LinkName := s + ‘\’ + aPathGroup + ‘\’ + aNome + ‘.LNK’; IPFile.Save(PWChar(LinkName), false); end; Esta procedure recebe como parâmetro o Nome do atalho a ser apresentado, o caminho e nome do aplicativo a ser executado, e por último o grupo ao qual ele irá pertencer no menu Iniciar do Windows. Agora vamos para a procedure responsável em criar o Grupo e o Ítem de Programa: function CreateFolder(Foldername: string; aLocation: integer): boolean; var pIdl: PItemIDList; hPath: PChar; begin Result := False;
156
if SUCCEEDED(SHGetSpecialFolderLocation(0, aLocation, pidl)) then begin hPath := StrAlloc(max_path); SHGetPathFromIDList(pIdl, hPath); SetLastError(0); if ForceDirectories(PChar(hPath + ‘\\’ + Foldername)) then Result := true; StrDispose(hPath); end; end; Observe que esta procedure recebe como parâmetro o nome do grupo (que na realidade será o nome de um “Folder” e a localização, ou seja, onde ele deverá ser criado. Exemplo de utilização: procedure TForm1.Button1Click(Sender: TObject); begin // cria Grupo principal. CreateFolder(‘The Club’, CSIDL_PROGRAMS); // cria sub-grupo dentro do “The Club” CreateFolder(‘The Club\Grupo 1’, CSIDL_PROGRAMS); // cria sub-grupo dentro do “The Club” CreateFolder(‘The Club\Grupo 2’, CSIDL_PROGRAMS); // cria sub-grupo dentro do “The Club” CreateFolder(‘The Club\Grupo 3’, CSIDL_PROGRAMS); // cria sub-grupo dentro do “The Club\Grupo 1” CreateFolder(‘The Club\Grupo 1\Sub Grupo 1’, CSIDL_PROGRAMS); // cria sub-grupo dentro do “The Club\Grupo 2” CreateFolder(‘The Club\Grupo 2\Sub Grupo 1’, CSIDL_PROGRAMS); // cria sub-grupo dentro do “The Club\Grupo 3” CreateFolder(‘The Club\Grupo 3\Sub Grupo 4’, CSIDL_PROGRAMS); // cria atalho para os programas CriaShortCut(‘Calculadora’, ‘c:\windows\system32\calc.exe’ , ‘The Club\Grupo 1’, CSIDL_PROGRAMS); CriaShortCut(‘Bloco de Notas’, ‘c:\windows\system32\notepad.exe’, ‘The Club\Grupo 2’, CSIDL_PROGRAMS); CriaShortCut(‘WordPad’, ‘C:\Program Files\Windows NT\Accessories\wordpad.exe’, ‘The Club\Grupo 3’, CSIDL_PROGRAMS); end; Dica: A constante CSIDL_PROGRAMS indica a pasta padrão onde os ítens do menu iniciar do Windows ficam armazenados. Trabalhando com esta constante, independente da versão e linguagem do Windows, a pasta irá ser criada no local correto. Observe que primeiramente criamos um grupo principal, chamado “The Club”. Seguindo, dentro de “The Club” criamos sub-grupos e dentro dos sub-grupos os atalhos que irão chamar os aplicativos em questão.
157
Este exemplo está disponível para download em nosso site no endereço: http://theclub.activeinterno.com.br/revista/download/CriaGrupoAtalho.zip
Como mover um componente em Run-time Para montar este exemplo vamos incluir um componente Button. Para testar este exemplo mantenha a tecla CTRL pressionada clique com o mouse sobre o componente Button e arraste-o para qualquer lugar do form.
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Button1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure Button1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); private { Private declarations } public { Public declarations } MouseDownSpot : TPoint; Capturing : bool; end; var Form1: TForm1; implementation {$R *.dfm} // Evento OnMouseDown do botão procedure TForm1.Button1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 158
begin if ssCtrl in Shift then begin SetCapture(Button1.Handle); Capturing := true; MouseDownSpot.X := x; MouseDownSpot.Y := Y; end; end; // Evento OnMouseMove do botão procedure TForm1.Button1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if Capturing then begin Button1.Left:= Button1.Left(MouseDownSpot.x-x); Button1.Top:= Button1.Top (MouseDownSpot.y-y); end; end; // Evento OnMouseUp do botão procedure TForm1.Button1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Capturing then begin ReleaseCapture; Capturing := false; Button1.Left := Button1.Left (MouseDownSpot.x -x); Button1.Top := Button1.Top (MouseDownSpot.y - y); end; end;
Como apresentar o número da linha e coluna em um DBGrid? O DBGrid possui estas informações, porém elas não estão visíveis para acesso direto. Contudo, podemos derivar uma classe a partir de TDBGrid e utilizá-las sem problemas...
implementation {$R *.DFM} type TMostraProp = class (TDBGrid);
159
{evento OnColEnter do DBGrid} procedure TForm1.DBGrid1ColEnter(Sender: TObject); begin Caption := Format(‘Coluna: %2d; Row: %2d’, [TMostraProp(DbGrid1).Col, TMostraProp(DbGrid1).Row]); end; { evento OnDataChange do DataSource } procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField); begin DBGrid1ColEnter(Sender); end;
Como implementar um log de todos os erros gerados na aplicação? Isso poderá ser implementado utilizando um componente TApplicationEvents (aba Additional), interceptando seu evento OnException e gerando um arquivo texto com as mensagens de erros geradas durante a execução do aplicativo. Para isso, adicione um componente TapplicationEvents no Form principal de sua aplicação e abra o evento OnExxception onde iremos programar o seguinte:
procedure TFormLog.LogException(Sender: TObject; E: Exception); var NomeDoLog: string; Arquivo: TextFile; begin { preparar o arquivo de log utiliza o nome da aplicação, trocando a extensão para “.log”. } NomeDoLog := ChangeFileExt(Application.Exename, ‘.log’); { pega ponteiro para o arquivo } AssignFile(Arquivo, NomeDoLog); { verifica se existe } if FileExists(NomeDoArquivo) then Append(Arquivo) { se existir, apenas adiciona linhas } else ReWrite(Arquivo); { cria um novo se não existir } try { grava Data e Hora + Mensagem de erro } WriteLn(Arquivo, DateTimeToStr(Now) + ‘:’ + E.Message); { mostra mensagem original de erro } Application.ShowException(E); finally { fecha o arquivo } CloseFile (LogFile); end; end; Para testar, bastará por exemplo em um botão, gerar uma exceção de divisão por zero:
160
procedure TForm1.Button1Click(Sender: TObject); var a, b, c: Integer; begin a := 10; b := 0; c := a div b; ShowMessage(IntToStr(c)); end;
Printers - Como retornar informações das impressoras instaladas na máquina Nesta dica, demonstraremos como retornar informações úteis das impressoras instaladas na máquina, como por exemplo, o caminho da rede, seu nome de compartilhamento, porta, etc. Insira um componente ListView e um botão, como mostra a figura 1.
Na lista de uses, declare:
uses Printers, WinSpool; { Procedure que irá adicionar as informações ao ListView } procedure AdicionaImpressoras(LV: TListView; Servidor, NomeImpressora, Compartilhamento, Porta, NomeDriver, Comentario: String); var i: integer; begin with LV do begin Items.Add; i := Items.Count-1; Items[i].Caption := Servidor; Items[i].SubItems.Add(NomeImpressora); Items[i].SubItems.Add(Compartilhamento); Items[i].SubItems.Add(Porta); Items[i].SubItems.Add(NomeDriver); Items[i].SubItems.Add(Comentario);
161
end; end; O retorno das informações será feito através da API EnumPrinters:
procedure GetPrinterList(List: TListView); var Buffer, PrinterInfo: PChar; Flags, Count, NumInfo: DWORD; i: Integer; Level: Byte; begin Flags := PRINTER_ENUM_CONNECTIONS or PRINTER_ENUM_LOCAL; Level := 2; Count := 0; EnumPrinters(Flags, nil, Level, nil, 0, Count, NumInfo); if Count > 0 then begin GetMem(Buffer, Count); try if not EnumPrinters(Flags, nil, Level, PByte(Buffer), Count, Count, NumInfo) then Exit; PrinterInfo := Buffer; for i := 0 to NumInfo - 1 do begin case Level of 2: begin AdicionaImpressoras(List, PPrinterInfo2(PrinterInfo)^.pServerName, PrinterInfo2(PrinterInfo)^.pPrinterName, PPrinterInfo2(PrinterInfo)^.pShareName, PPrinterInfo2(PrinterInfo)^.pPortName, PPrinterInfo2(PrinterInfo)^.pDriverName, PPrinterInfo2(PrinterInfo)^.pComment); Inc(PrinterInfo, SizeOf(TPrinterInfo2)); end; 4: begin AdicionaImpressoras(List, PPrinterInfo4(PrinterInfo)^.pServerName, PPrinterInfo4(PrinterInfo)^.pPrinterName, ‘null’, ‘null’, ‘null’, ‘null’); Inc(PrinterInfo, SizeOf(TPrinterInfo4)); end; 5: begin AdicionaImpressoras(List, ‘null’, PPrinterInfo5(PrinterInfo)^.pPrinterName, ‘null’, PPrinterInfo2(PrinterInfo)^.pPortName,
162
‘null’, null’); Inc(PrinterInfo,SizeOf(TPrinterInfo5)); end; end; end; finally FreeMem(Buffer, Count); end; end; end; { abaixo, fazemos a chamada da procedure no evento OnClick do botão } GetPrinterList(LView); O projeto completo referente esta dica está disponível para download em http://theclub.activeinterno.com.br/revista/download/ListaImpressoras.zip
IP – Como retornar o hostname a partir de um endereço IP Em muitas situações, necessitamos saber o nome de uma máquina e temos apenas seu endereço IP. Na unit WinSock, poderemos encontrar diversas APIs para este tipo de abordagem, veja abaixo um simples exemplo: implementation uses WinSock; {$R *.dfm} function ResolveHostByIp(IP: string): String; type TAPInAddr = Array[0..100] of PInAddr; PAPInAddr = ^TAPInAddr; var WSAData: TWSAData; Address: String; InetAddr: u_long; HostEntPtr: PHostEnt; HostEnt: THostEnt; HostName: String; len, struct: Integer; i: Integer; begin Result := ‘’; WSAStartUp( $101, WSAData );
163
try Address := Trim(IP); if Address = ‘’ then raise Exception.Create ( ‘IP address not entered’ ); // Convert textual IP address to binary format InetAddr := inet_addr( PChar(Address) ); if InetAddr = SOCKET_ERROR then raise Exception.Create ( ‘Invalid address entered’ ); // Get hist entry by IP HostEntPtr := GetHostByAddr( @InetAddr, len, struct ); if HostEntPtr = NIL then raise Exception.Create( ‘WinSock error: ‘ + IntToStr( WSAGetLastError() ) ); // Insert hostname into list HostName := String( HostEntPtr^.h_name ); Result := HostName; except on E: Exception do begin Beep(); ShowMessage( E.Message ); end; end; WSACleanUp(); end; Para utilizar:
Edit.Text := ResolveHostByIp(‘200.210.71.16’); // retorna o nome da máquina
Windows – Como criar grupos e subgrupos de programas no menu iniciar Uma das formas para fazer a criação de grupos e subgrupos de aplicativos no menu iniciar do Windows, é obtendo o path de sistema onde o Windows guarda estas informações e nele criar os grupos. Veja abaixo como proceder: implementation uses ShlObj, FileCtrl; {$R *.dfm}
164
function GetProgramFolder: string; var pidl: PItemIDList; Path: array[0..MAX_PATH] of char; begin SHGetSpecialFolderLocation(Application.Handle, CSIDL_PROGRAMS, pidl); SHGetPathFromIDList(pidl,path); Result := path; Result := Result + ‘\’; end; function CriaGrupo(Path: string): Boolean; begin Result := ForceDirectories(GetProgramFolder+Path); end; procedure TForm1.Button1Click(Sender: TObject); begin if CriaGrupo(‘TheClub\Grupo 1’) then ShowMessage(‘Grupo TheClub\Grupo 1 criado com sucesso!’); if CriaGrupo(‘TheClub\Grupo 2’) then ShowMessage(‘Grupo TheClub\Grupo 2 criado com sucesso!’); if CriaGrupo(‘TheClub\Grupo 3’) then ShowMessage(‘Grupo TheClub\Grupo 3 criado com sucesso!’); end;
Windows – Como desabilitar uma combinação de teclas genericamente Para desabilitar uma combinação de teclas válida para todos os formulários da aplicação, será necessário fazer um tratamento de mensagens do Windows. O exemplo abaixo demonstra como desabilitar a combinação CTRL+P:
type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private procedure ProcessaMsg(var Msg: TMsg; var Handled: Boolean); { Private declarations } public { Public declarations } end; var Form1: TForm1;
165
implementation {$R *.DFM} { procedure de tratamento } procedure TForm1.ProcessaMsg(var Msg: TMsg; var Handled: Boolean); begin if Msg.message = WM_KEYDOWN then begin if (GetASyncKeyState(VK_CONTROL) <> 0) and (GetASyncKeyState(Ord(‘P’)) <> 0) then // Ctrl+P begin ShowMessage(‘Ctrl+P está sendo desabilitado!’); Msg.wParam := VK_CLEAR; end; end; end; procedure TForm1.FormCreate(Sender: TObject); begin { liga a procedure } Application.OnMessage := ProcessaMsg; end; end.
Veja como definir o papel de impressão personalizado no Windows XP/2000/NT No Windows 9x, para definirmos um papel como personalizado basta acessar as propriedades da impressora que iremos encontrar este tipo de papel. Porém, no Windows XP isso é um pouco diferente, pois não há um papel pré-definido como personalizado, porém temos a opção de criar um novo tipo de papel nas medidas que desejarmos. Para isso, abra o item “Impressoras & Faxes” de seu Windows e sem selecionar NENHUMA impressora acesse o menu “Arquivo ( ou File)” e neste selecione a opção “Propriedades do Servidor (ou Server Properties)” como mostra a imagem ao lado. Agora, bastará clicar em “Create a new form” e criar o seu papel personalizado e salvar logo em seguida e clicar em OK para finalizar!
166
Bom, agora bastará acessar as propriedades da impressora e definir este novo papel nas configurações de sua impressora, como exemplo:
função que me retorne a quantidade de arquivos existentes em um dado diretório? Poderá utilizar o objeto TSearchRec para obter o número de arquivos em um dado diretório:
implementation {$R *.dfm} function GetTotFiles(Diretorio: String): Integer; var SRec: TSearchRec; 167
Res: Integer; begin Result := 0; Res := FindFirst(Diretorio+’\*.*’, faAnyFile, SRec); while Res = 0 do begin Res := FindNext(SRec); Inc(Result); end; end; procedure TForm1.Button1Click(Sender: TObject); begin Caption := IntToStr( GetTotFiles(‘d:\testes’) ); end;
168