Ir para conteúdo
Fórum Script Brasil

Micheus

Veteranos
  • Total de itens

    3.189
  • Registro em

  • Última visita

Tudo que Micheus postou

  1. paulobergo, é uma solução bastante simples e eficiente - muito boa. Quando lí o questionamento da colega Aghata, dias atrás, imaginei inicialmente(por falta de detalhes) que poderia ser uma situação em que existam campos do tipo memo, os quais, muitas vezes expandem a banda de modo que geram uma outra página. Ainda estes dias, num outro forum, havia um questionamento similar. Pensando nisto estava tentando achar um modo de contornar esta deficiência do QuickRep. O problema é que só temos as informações sobre páginas apenas gerando o relatório. Isto é possível, através do Prepare, mas tem um preço: significa que da visualização até a impressão o relatório será gerado 3 vezes!!! Se houverem filtros que minimizem o número de registros listados até que poderia ser viável. Mas, se estivermos falando de muitos registros, o desemplenho pode ficar comprometido. Neste link tem o projeto que implementei (QuickRep - Paginacao.zip) que basicamente faz uso do Prepare para popular uma TStringList com a informação sobre o número de páginas que o "campo" utilizará e, deste modo, no processo de visualização e impressão faz uso desta informação. Se a Aghata quizer testar esta opção lembro que deve manter uma cópia de seu relatório original. Isto porque, com a base que montei e o artifício que utilizei para "stretchar" uma banda com texto, tive um efeito meio ilógico. Especificamente em um, dos quatro, grupos não há a contagem correta do número de páginas. Se alguém se interessar, fica aí um desafio: descobrir se fiz algo errado ou se a função Prepare está esquecendo de uma página. Eu já não consigo enxergar mais nada. :( (se encontrarem algo me avisem) []s p.s. Tomei a liberdade de utilizar seus scripts para gerar a base de teste.
  2. Se for partindo do princípio de que você tem um Frame adicionado ao seu projeto em desing-time, então sua pergunta seria: como adicionar um frame a um form em tempo de execução? Ex. Adicionando um frame (Frame1 no projeto) a um form ao ser pressionado um botão: procedure TForm1.Button1Click(Sender: TObject); begin with TFrame1.Create(Self) do begin Parent := Self; Top := 120; Left := 104; ... end; end; Ex. Removendo o frame ao pressionar outro botão:procedure TForm1.Button3Click(Sender: TObject); var Frame :TFrame; begin Frame := FindComponent('Frame1') as TFrame; if Assigned(Frame) then Frame.Free; end; Já se for partindo do princípio de que você tem vai criar todo um frame dinamicamente, então sua pergunta seria realmente: como criar um frame dinamicamente? Ex. Ao clicar num botão, um frame e seus respectivos componentes internos são criados:procedure TForm1.Button3Click(Sender: TObject); var Frame :TFrame; Button :TButton; begin Frame := TFrame.Create(Self); with Frame do begin Name := 'FrameDinamico'; Top := 184; Left := 104; end; InsertControl(Frame); Button := TButton.Create(Frame); with Button do begin Caption := 'Teste'; Top := 8; Left := 8; end; Frame.InsertControl(Button); // automaticamente torna Frame o Parent do Button ... end; []s
  3. Não é isto que ele faz. Não com esta palavras.Ele compara o valor a ser testado com zero (que significa FALSO), e o único jeito de isto ser verdade é se este valor for 0 (zero) - não há qualquer conversão para 1. []s
  4. Thales, não foi eu quem escreveu não. Foi o que a janela da CPU me mostrou (View->Debug Windows->CPU) - você deverá ver algo parecido - mudando apenas os endereços.você deve ter notado que as linhas em ASM correspondem a do Delphi logo acima, e há alguns comentários ao lado para tentar explicar o que ocorre. Se não ficou claro posso tentar melhorar a explicação (já tentei fazer isto no post anterior). Minha inteção era apenas buscar uma explicação mais razoável para o meu primeiro post. Algumas vezes tenho a impressão que há uma certa disputa por aqui - o que é uma pena. É justamente com a inclusão de idéias diferentes ou de afirmações que nossos horizontes se expandem. Lembrando, sempre que as discursões são acompanhadas/lidas por outros colegas que apenas aproveitam o "conhecimento" que está sendo passado. []s
  5. kmkg, não precisa muita não, basta acessar o menu View->Debug Windows->CPU. Mas, a idéia proposta por você acho que era justamente de entender o porque de tão "estranho" comportamento - não?! Apenas completando... Thales, isto só é verdade devido a forma simplificada pela qual o compilador faz esta validação, já que sabemos por definição da linguagem que o tipo boolean só pode ter dois valores TRUE(1) e FALSE(0) . Este o motivo de a atribuição forçada do kmkg não estar funcionando corretamente e o teste simples apenas da variável b2 funcionar. Foi exatamente este tipo de proposição que o compilador utilizou na situação proposta pelo kmkg, já que o esperado era que os valores fossem 0 ou 1 e um AND deste tipo resulta em zero, como você bem exemplificou. kmkg, observe que foi VOCE quem atribuiu um terceiro valor - forçosamente. Como disse, para o compilador um Boolean é apenas TRUE(1) e FALSE(0) - ele não se preocupa com outra possibilidade; Se apenas com o BIT, e não o BYTE inteiro, não ocorreria tal problema. Observar que se for feiro um type-cast para Boolean, também teremos a mesma contrução por parte do compilador. E como fica possível o bservar, na primeira situação (if b1 and b2 then) a validação (teste) desvia ser o resultado não for VERDADEIRO, enquanto na segunda (if Bool(b1) and Bool(b2) then) desvia se o resultado for FALSO. São duas formas de "dizer" a mesma coisa mas que o resultado pode mudar. Deste modo, fica a dica para o caso de alguém utilizar algo como o proposto pelo colega kmkg, de utilizar o type-cast de modo que tudo que não for FALSO será VERDADEIRO, de modo que o "compilador não ficará meio maluco". []s
  6. Artigo com dicas de "Como Fazer Perguntas Inteligentes" - link []s p.s. E respostas também ;)
  7. Entendendo a diferença entre as duas formas(meu post anterior) de testar no if. Parece-me uma questão de como o compilar otimiza o código. Vamos escovar bits? Vejamos o código gerado pelo compilador para este fragmento de código pascal: b1 := true; MOV BL,$01 // *** BL é utilizado para "apontar" para b1 Move(Baiti, b2, 1); LEA EDX,[EBP-$01] // *** [EBP-$01] aponta para b2 LEA EAX,[EBP-$02] // *** [EBP-$02] aponta para Baiti MOV ECX,$00000001 // *** Número de bytes a ser movido - 1 CALL Move if b1 and b2 then TEST [EBP-$01],BL // *** aqui $08 está sendo testado com $01, similar a um AND, não haverá bit setado // * de modo que o registrador de flag ZF será SETADO. JZ +$0C // *** fará cair no ELSE caso ZF esteja setado (1) em função da execução da instrução anterior. ShowMessage('b2 é true') else if b1 then if Bool(b1) and Bool(b2) then TEST BL,BL // *** artifício para verificar se o valor de b1 é verdadeiro - se houver um bit LIGADO (qualquer) // * o registrador de flag ZF ficará zerado. Isto é parte da otimização do compilador - basta // * que um dos testes seja falso para pular a sentença JZ +$12 // *** fará cair no ELSE caso ZF esteja setado (1) em função da execução da instrução anterior. // * Em nosso caso, b1 = $01, logo ZF ficará ZERADO e não haverá desvio CMP BYTE PTR [EBP-$01], $00 // *** aqui se o BYTE apontado (PTR) pelo endereço [EBP-$01] (b2) for // * igual a $00 (zero), o registrador de flag ZF será setado (1) JZ +$0C // *** fará cair no ELSE caso ZF esteja setado (1) em função da execução da instrução anterior. // * Em nosso caso, b2 = $08, logo ZF ficará ZERADO e não haverá desvio ShowMessage('b2 é true') else if b1 then Referencias: Link1, Link2 e Link3
  8. kmkg, sabendo que no Delphi, TRUE = $01 e FALSE = $00, como poderia o processador testar $01 and $08 e dar certo (serem iguais), ou qualquer das outras operações? Já se você utilizar no teste: if Bool(b1) and Bool(b2) then, neste caso terá a resposta correta, já que utilizando o type-cast BOOL qualquer coisa diferente de $00 será interpretado como TRUE. []s
  9. Nextel, apesar que concordar que há perguntas mal feitas, não vejo grande problema nisto, já que provavelmente não receberá resposta. Basta desconsiderá-la. seria realmente mais apropriado que você tivesse se logodo para abrir este tópico. Usar pseudômimo afirmando ter um login não parece uma atitude louvável. Mas tentando contribuir para o seu tópico, segue este link que dá algumas dicas de Como Fazer Perguntas Inteligentes (está incluso também, como responder de forma útil) []s p.s. espero que este post seja mais lido que respondido
  10. Colegas, acredito (e acho que faz sentido) que a alteração remota de registro, pelo menos itens críticos, só poderão ser realizadas por um usuário do grupo Administradores. Este link explana um pouco do que é possível fazer utilizando a ferramente REG citada pelo colega Denis. Observar que o próprio artigo cita que alguns comandos só poderão ser realizados na máquina local. []s
  11. Micheus

    Evento Ontimer

    Confirmado - funciona. A título de ilustração, vou colocar o código do teste aqui: unit Unit1; interface uses Mmsystem, // *** Inclusão necessária Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); private Counter :LongInt; timerHnd :THandle; end; var Form1: TForm1; implementation {$R *.DFM} // *** aqui a callback que será chamada a cada 2 segundos (2000 milisegundos) procedure TimerProc(uTimerID, uMsg :UINT; dwUser, dw1, dw2 :PDWORD); stdcall; begin Form1.Memo1.Lines.Add('Timer '+IntToStr(Integer(dwUser^))); Inc(dwUser^); end; procedure TForm1.Button1Click(Sender: TObject); begin Button1.Enabled := False; Counter := 1; timerHnd := timeSetEvent(2000, 0, @TimerProc, LongInt(@Counter), TIME_PERIODIC); end; procedure TForm1.FormDestroy(Sender: TObject); begin if timerHnd > 0 then timeKillEvent(timerHnd); end; end.Observar que o Help define que o parâmetro do usuário (dwUser) deve ser do tipo DWORD(e o compilador exige), entretanto, a procedure (callback) dever declarar este parâmetro do usuário como sendo um PDWORD (ver link). :blink: Assim, para o exemplo que fiz, alterar o conteúdo do parâmetro recebido pela callback, fez-se necessário a inclusão do type-cast do endereço de Counter (convertendo para um LongInt/DWORD). Apenas deste modo a alteração de Counter na callback será mantido fora dela. (do post) Thales, agora lendo os posts que não havia lido, apenas a título de ampliarmos nossos horizontes, acho que na citação acima o termo recursão não é bem adequado, já que o que poderá ocorrer é o processo(se muito demorado) ser interrompido no meio de sua execução para que um novo evento do timer seja processado e chame novamente o procedimento - que não havia sido concluído ainda. Isto porque a definição de recursão implica que um procedimento chame a si mesmo(wikipédia) - que não é o caso. Preempção é mais ou menos o que ocorre (wikipédia), quando o sistema operacional interrompe um processo para executar outro de maior prioridade (p.e evento do timer). Se alguém tiver algum comentário, manda brasa... ;) []s
  12. rochajl, meio estranho, mas como é que você está fazendo a atribuição do texto digitado para o campo na tabela? Uma opção é diretamente como texto: TabXCampoN.AsString := MaskEdit1.Text; Outra é convertendo para float: TabXCampoN.AsFloat := StrToFloatDef(MaskEdit1.Text, 0); (seria o mais apropriado) []s
  13. Micheus

    Evento Ontimer

    No Windows 2000 eu posso testar - caso algum de vocês não possam - e segunda-feira eu posto o resultado.
  14. Micheus

    Hibernação

    Thales, acertou na mosca! Só para deixá-los com água na boca, estive de férias (10 dias) e dei uma passadinha por Natal e Noronha... :D [] p.s. mais um post para aumentar o hit do tópico ;)
  15. Cleverson, talvez falte algo, como ApplyUpdates. Se você está utilizando transações, pode estar faltando "comitá-la". E apenas confirmando, nas telas de consulta e alteração o Dataset é o mesmo (Table1), certo?! []s
  16. Micheus

    Evento Ontimer

    Thales e kmkg, apenas para ampliar o assunto, não poderia ser utilizada a função timeSetEvent já que parece-me ser projetada para executar o que está sendo proposto? Defíne-se o tempo que uma chamada da uma callback deve ocorrer, informando inclusive se é um evento periódico e a "precisão" com que deve ocorrer. definição: MMRESULT timeSetEvent(UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD dwUser, UINT fuEvent); []s
  17. Cleverson, desculpe se entendi mal. Também não dei retorno porque estava ausente em férias. if not Table1.EOF then Table1.Delete else ShowMessage('A tabela está vazia'); Acho que você pode utilizar Table1.Refresh. Mas, se ainda não funcionar, então terá que fechar e abrí-la (mas acredito quen não seja o caso) A questão do reset do auto-incremente ficou ok? []s
  18. tiagojacomini, acho que este outro post pode lhe ajudar: link
  19. Arckyz, ocorre que você definiu Frase como sendo um array de String, enquanto o função Ord deve receber um Char como parâmetro. Não é bem assim, desde que você tenha certeza de que Copy retornará uma string válida(no seu caso um caracter), você pode indexar o resultado e acessar apenas um caracter:var Caracter :Char; begin Caracter := Copy(txt_frase.text,x,1)[1]; Com isto, redefinindo Frase para array de char, acho que você consegue resolver seu problema. Mas, como estou meio desocupado :D, vou tomar a liberdade de sugerir uma alternativa, beleza?! Considerando que sua frase criptografada terá sempre 50 caracteres, independente o tamanho da frase inicial, vamos estabelecer uma constante para controlar este parâmetro. Caso você venha a mudar este tanhanho, fará em um único lugar. Para facilitar as operações que você implementa, vamos definir Frase como sendo um array de Char (buffer a ser tratado como um PChar). Então, esta parte do código:var frase: array [1..50] of string; ordem: array [1..50] of integer; x:integer; begin x:=0; repeat x:=x+1; frase[x]:=copy(txt_frase.text,x,1); until x = 50; obs: da forma como está definida este fragmento, você corre o risco de obter um erro de execução, pois está copiando 50 posições de txt_frase, sendo que provavelmente não há garantias de que esta seja a quantidade de caracteres encontrada nele. Ficaria assim:const StrSize = 50; var X :Integer; Frase :array[1..StrSize +1] of char; begin FillChar(Frase, SizeOf(Frase), 0); StrPCopy(@Frase, txt_frase.Text); FillChar inicializará todo o array com o caracter #0 (último parâmetro). Já StrPCopy, copia um String para um buffer PChar (o @ informa o endereço do início do buffer). Frase é definida com o tamanho StrSize +1 porque um PChar é terminado pelo caracter #0 - então devemos reservar este espaço. Esta parte do código poderá ser executada em apenas uma passada então e utilizando o array inicial x:=0; repeat x:=x+1; ordem[x]:= ord(frase[x]); ordem[x]:=ordem[x] + 45; frase[x]:= chr(ordem[x]); until x = 50; Ficando simplesmente: for x := 1 to StrSize do Frase[x] := Char((Ord(Frase[x]) +45)); Ou ainda, não utilizando funções, mas sim type-cast, poderíamos "dizer" para que o compilador tratasse Frase[x] (Char) como se fosse do tipo Byte (são compatíveis em tamanho), ficaria assim: for x := 1 to StrSize do Byte(Frase[x]) := Byte(Frase[x]) +45; Para retornar o resultado, basta converter devolta Frase(PChar) para String, não sendo necessário a concatenação caracter-a-caracter: x:=0; repeat x:=x+1; txt_crip.text := txt_crip.text + frase[x]; until x = 50; end; Fazendo-se uso da função StrPas que executa o processo de conversão: txt_crip.text := StrPas(@Frase); end; []s
  20. Kindelis, passei uma hora queimando pestana, fuçando aqui e ali. Tem um jeito sim! Estudando o código da criação do form quando o formato é MDI, observei que a área interna do MainMDI tem uma janela, cujo handle é armazenado em ClientHandle. Então usando a função SetParent da unit Windows, dá para definir esta janela como parent dos componentes que você "supostamente" teria colocado sobre ela. No create do main MDI basta chamar SetParent para os componentes que você colocou neste form. No meu exemplo adicionei StringGrid, GroupBox e Panel, ficando assim: procedure TForm1.FormCreate(Sender: TObject); begin Windows.SetParent(StringGrid1.Handle, ClientHandle); Windows.SetParent(GroupBox1.Handle, ClientHandle); Windows.SetParent(Panel1.Handle, ClientHandle); end; []s
  21. Cleverson, abra a tabela, posicione no início e teste se o fim foi encontrado - isto significa que a tabela está vazia:Table1.Open; Table1.First; if not Table1.EOF then begin while not Table1.EOF do Table1.Delete; end else ShowMessage('A tabela está vazia') Table1.Close; Isto dentro do contexto que você colocou, utilizando Table1.Delete. Mas para limpar a tabela toda, você poderia simplesmente utilizar um componente query e executar uma instrução SQL para fazer isto. Algo como:DELETE FROM NOME_TABELA (acho que é esta a sintax para o interbase). você deverá utilizar um componente query para executar a instrução SQL:SET GENERATOR genenator_ID TO 0 []s
  22. Micheus

    Report+access

    Que componetes está utilizando? Como está estruturado o relatório? Dê mais informações e talvez alguém possa ajudar. Está muito vago. []s
  23. Micheus

    Erro Tabela Paradox

    Eder, é verdade sim. Talvez você tenha obtido o procedimento pronto e então não percebeu que o que você faz quando escreve na posição $49, no header da tabela, é justamente subescrever a "variável" que armazena o último número gerado (gravado). Supondo que você exclua o último item, como exemplificou, bastaria que vê chamasse este seu procedimento com o número 6: ResetAutoInc(editbanco.text+'\'+editcaminho.text, 6); Se eu não estiver enganado, a próxima inclusão gerará o campo com o valor 7. Este procedimento deverá sempre ser executado com a tabela vazia justamente para não ter problemas com violação da chave em que normalmente este tipo de campo faz parte. []s
  24. Micheus

    Erro Tabela Paradox

    function ResetAutoInc(FileName: TFileName; Base: Longint): Boolean; begin with TFileStream.Create(FILENAME, fmOpenReadWrite) do begin Result := (Seek($49, soFromBeginning) = $49) and (Write(Base, 4) = 4); Free; end; end;Acho que faltou liberar o stream e então o arquivo será fechado. Da forma como está ele fica aberto e a área em memória alocada. Por isso que só quando você sai do programa e volta é que funciona novamente. Este método eu também já utilizei numa rotina que, juntamente com API's da BDE, corrigiar tabelas com índices corrompidos. Por que em alguns cassos, este contador é corrompido e você não consegue mais incluir nada, pois gera key-violation (se bem me lembro). você só deve ter o cuidado de levar em conta a versão das tabelas Paradox(pro caso de mais alguém utilizar o código), pois a posição no header do arquivo muda de posição de uma versão para a outra(da 5 para a 7 com certeza). []s
  25. Micheus

    Erro Tabela Paradox

    Eder, se não for secredo, o que você está fazendo na função: Não pode ser ela que está deixando a tabela locada?Quando eu zerava via Database Desktop, eu apenas passava o campo para Integer e depois para Auto-incremento digite [ CODE ] no início do código e [ /CODE ] quando terminar - sem os espaços que deixei. []s
×
×
  • Criar Novo...