
Micheus
Veteranos-
Total de itens
3.189 -
Registro em
-
Última visita
Tudo que Micheus postou
-
beleza. É que lendo o post #1, tive a (errada) idéia de que estaríamos falando de aplicações onde uma pertencia ao colega e outra de origem diferente. Realmente, se as duas aplicações são desenvolvidas pela mesma pessoa, não há maior impecílio em implementar o recurso. hencker, para o segundo exemplo, convém citar a possibilidade de as duas aplicações não utilizarem banco de dados. Daí não daria deste jeito. E também, como na questão do uso do arquivo texto, poderia ser utilizado o registro do Windows. Churc, o uso de FindWindow ajuda muito. Mas, vale lembrar que se houverem várias instâncias do mesmo programa aberto, você acessará apenas um deles com este método. O mutex é uma boa opção. Neste contexto, necessitando troca de informações teriamos ainda uso de DDE e FileMapping. Abraços
-
Acho que isso pode ser muito relativo. Minhas observações sobre estas questões: - Tenho pouco contato com o MySQL, mas quando tive que criar um campo de texto, foi justamente o tipo TEXT que utilizei, porque, aparentemente CHAR e VARCHAR exigem a declaração de um tamanho limite. Dando uma olhada na documentação: Os Tipos CHAR e VARCHAR (MySQL) Os Tipos BLOB e TEXT (MySQL) - No Firebird, pelo menos utilizando o IBExpert, se for utilzado CHAR ou VARCHAR, é necessário declarar o tamanho do campo, ou seja limitá-lo, e qualquer coisa a mais é truncado. Para criar um campo do tipo "TEXT", você tem que declará-lo como BLOB e informar o SUBTYPE 1. "Sub-type is 1. This blob field sub-type is designed for the storage and manipulation of text. Typically, this is free-form memo or notes data. Typically you would use this blob field sub-type is for storing large amounts of text data. This is more convenient that a large VARCHAR because, unlike a VARCHAR, there is no 32K limit." (referência) Sobre vantagens e desvantagens de um tipo e outro (vale a leitura): To BLOB or to not BLOB (Interbase/Firebird) Qualquer adendo ou correção é bem vindo Abraços
-
Dá para exemplificar? :huh:
-
Geovani, neste caso acredito que não seja possível. Não sei como lhe explicar isso adequadamente, mas que eu saiba, como o programa tem que ser carregado para a memória para ser executado, ele estará rodando na máquida do usuário que o chamou. Na pior das hipóteses, ele poderá manter algum arquivo aberto no local de origem (que seria sua máquina), mas isso seria uma partigularidade da aplicação (este seria o caso em que você consegue, no gerenciador do windows, saber que arquivos estão em uso em seu computador - não programas rodando e por quem). Espero que outro colega possa explicar-lhe melhor isso ou corrigir-me se estiver enganado. Abraços
-
Não deixa como? você adicionou o nome da unit de seu datamodule na cláusula USES da unit onde o form com o TDBGrid? Só assim, você consegue selecionar visualizar os TDataSources existentes no datamodule.
-
ranilson, para facilitar qualquer ajuda neste sentido, informe: - o banco de dados que está utilizando; - componentes de acesso (dataset da paleta BDE, ADO, Zeos, IB, ... quais você está utilizando); - que tipo de dataset você está utilizando em seu grid: um Table ou Query? - qual a estrutura da tabela a ser consultada. O mais comum é utilizar query, com LIKE no SQL. Para você dar um "start" dê uma olhada nestes post's, tem comentários relacionados ao que você poderá utilizar: http://scriptbrasil.com.br/forum/index.php...st&p=389413 http://scriptbrasil.com.br/forum/index.php...st&p=395764 http://scriptbrasil.com.br/forum/index.php...st&p=353462 Abraços
-
Execultando Arquivo Txt Que Esta Dentro Do Exe...
pergunta respondeu ao Progr'amador de Micheus em Delphi, Kylix
Progr'amador, o procedimento é o mesmo. Se você obtém um ponteiro para a área de memória, seria a mesma coisa que estivesse "falando" de um PChar - é só pegar o conteúdo dele. :huh: Abraços -
Xanxere, é um recurso pouco provável de ser encontrado para um componente como o DBGrid. A menos que você mesmo crie um componente derivado do mesmo, e ainda assim, pode não ser simples implementar esta funcionalidade. você pretende mostrar muitos registros neste DBGrid? Será feita edição no mesmo? Do contrário, talvez você pudesse utilizar um TSgringGrid. Dependendo de alguns fatores, talvez dê para "simular" este efeito com um DBGrid: - Manipulando alguns eventos (OnDrawColumnCell e OnCellClick); - O DBGrid não mantém uma propriedade que indique a linha referênte ao número do registro lido; Então, para mostrar um número referente a linha-resultado da consulta/dataset, uma opção seria utilizar a propriedade RecNo do dataset ligado ao DBGrid - desde que o dataset suporte esta fucionalidade; - Também não temos acessível a propriedade que define o número de colunas fixas, então não daria para manter a sua coluna numerada parada (estática à esquerda) - se todas as colunas couberem na largura do grid não será notada qualquer diferença; Abraços
-
Churc, permita-me um parênteses: é possível sim.O componente TListBox tem a propriedade Style que através das opções lbOwnerDrawFixed e lbOwnerDrawVariable, esta última associada ao evento OnMeasureItem, viabilizam a customização da lista via evento OnDrawItem. fajo, tendo em vista a aplicação que você faz, vou exemplificar para o caso mais simples que é: altura fixa dos itens da lista.Como você não mensionou, vou supor que você utilizará uma lista de imagens (TImageList), seria a opção mais abrangente. Aparentemente sua lista de usuários, conterá apenas o nome dos mesmos. Vou supor uma condição em que o ícone apresentado será adequado a uma determinada opção (tipo on-line, off-line, ...). Há várias formas de associar esta informação ao item da lista, eu vou optar por guardá-la na lista Objects da propriedade Items do TListBox. O importante não é onde estará guardada, mas sim como utilizá-la. É importante que suas imagens tenham o mesmo tamanho, preferencialmente com a altura desejada para o item da lista, para que sejam mantidas as proprorções/aspectos. Esta informação será utilizada na definição das propriedades Height e Width do TImageList e posteriormente no desenho do TListBox. 1) No seu form, selecione a TListBox e defina a propriedade Style para lbOwnerDrawFixed; 2) Adicionei ao TImageList 3 imagens, com a cor de fundo clOlive; No processo de adição de cada imagem a lista, alterei Transparent Color para clNone (detectado como clOlive) e em Options defini Center. Tive que fazer isso para conseguir desenhar as imagens com transparência. 3) No evento OnCreate do form, atribuimos a altura da imagem +2 para a altura da linha (o dois é para as bordas): ListBox1.ItemHeight := ImageList1.Height +2; 4) No evento OnDrawItem colocamos o seguinte código: procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); const IconMargin = 4; TextMargin = 6; var OffSetY :Integer; StatusIcon :TBitmap; begin // Pinta o fundo do retângulo (Control as TListBox).Canvas.FillRect(Rect); // Para centralizar o texto na altura, iremos calcular aqui em que posição (Y) // deverá ser desenhado o texto OffSetY := ((Rect.Bottom -Rect.Top) -(Control as TListBox).Canvas.TextHeight('A')) div 2; // Para as próximas etapas, desenharemos apenas dentro do retângulo, // não interferindo nas suas bordas Inc(Rect.Left, 1 +IconMargin); // também ajustamos o início do icone Inc(Rect.Top, 1); Dec(Rect.Bottom, 1); Dec(Rect.Right, 1); // Alocamos um bitmap para obter uma figura referente ao status da lista de imagens StatusIcon := TBitmap.Create; try // obtemos o bitmap da lista, referente ao status armazenado no item de Objects // a conversão ser faz necessária porque Objects armazena ponteiros if ImageList1.GetBitmap((LongInt((Control as TListBox).Items.Objects[Index])), StatusIcon) then // Utilizando a função BrushCopy, pintamos o bitmap na definida por Rect. // A função fará um stretch da imagem se utilizar outro tamanho que não o da imagem (Control as TListBox).Canvas.BrushCopy(Classes.Rect(Rect.Left, Rect.Top, Rect.Left +ImageList1.Width, Rect.Top +ImageList1.Height), StatusIcon, // imagem Classes.Rect(0, 0, ImageList1.Width -1, ImageList1.Height -1), // área da imagem a copiar StatusIcon.Canvas.Pixels[0, 0]); // cor de fundo (usamos o pixel superior-esquerdo finally // liberamos o bitmap alocado StatusIcon.Free; end; // Para desenhar o texto após o icone, devemos avançar o início do retângulo para // além da largura da imagem + a margem desejada Inc(Rect.Left, ImageList1.Width +TextMargin); (Control as TListBox).Canvas.TextRect(Rect, // área onde será desenhado o texto Rect.Left, // início na posição X Rect.Top +OffSetY, // início na posição Y (Control as TListBox).Items[Index]); end;Obs.: Devido ao conflito entre o nome da função e do parâmetro, temos que indicar a que rect nos referimos, logo apontamos a unit Classes aonde a função se encontra. O demo para download está aqui(aguardar uns segundos até opção de download aparecer). Há n variações possíveis, dependendo do que você utilizar, então, qualquer dúvida é só perguntar. Abraços
-
hencker, por "padrão" você desabilita o filtro antes de atribuir novo filtro e volta a habilitá-lo após a alteração do mesmo (acho que nem seria preciso o Close e Open). Veja se será por isso. Outra coisa, no seu código, observe que em função do valor de RGOpcoes.ItemIndex você fará apenas uma única coisa diferente: a atribuição à propriedade Filter; Logo, todo o resto é repetido e então você poderia simplificar o procedimento para isto: procedure TPesqFuncionarios.BBLocalizarClick(Sender: TObject); begin with MasterCadFuncionarios.TabelaMaster do begin Close; Filtered := False; if RGOpcoes.ItemIndex = 0 then Filter := 'nome LIKE '+QuotedStr('%'+EditPesquisa.Text+'%')+'' else Filter := 'cpf LIKE '+QuotedStr('%'+EditPesquisa.Text+'%')+''; Filtered := True; Open; end end; Abraços
-
Concordo com você e sinto muito não poder auxiliar nisto. Resolver este tipo de problema, as vezes, não é fácil porque ficamos apenas em supodições - nada como ter o "código nas mãos". Eu estava a fazer os lookups com um DbLookUpComboBox que é um componete visual, logo tem de estar no form. Tinha outras hipóteses, como por exemplo, criar um TQuery no DataModule que me desse os valores para uma DbComboBox , etc ... mas não foi assim que fiz. Neste momento já só queria saber qual foi o problema. Parece-me mais uma cena especifica do MySQL do que outra coisa qualquer.Aqui eu me expressei mal. Quando falei lookups estava falando das consultas/tabelas lookups, não dos componentes. :) Isto é característico do dataset ligado a propriedade ListSource estar fechado. Abraços
-
Geovani, por este questionamento, entendo que você quer interromper a execução de qualquer programa (executável) que seja iniciado, via rede, na sua máquina.É isto mesmo ou seria, como no caso da sugestão do colega Eder Moraes, um programa seu que acessa uma base de dados em seu computador? Abraços
-
Quebra De Linha Com Fortes Report
pergunta respondeu ao rodrigo biagioli de Micheus em Delphi, Kylix
procedure TFORM.FormKeyPress(Sender: TObject; var Key: Char); begin IF(KEY = #13)THEN BEGIN IF NOT (ActiveControl is TMemo) THEN BEGIN KEY := #0; PERFORM(WM_NEXTDLGCTL,0,0); END; END; end;rodrigo biagioli, tenta assim, acho que dispensa variáveis globais e fica mais simples. Abraços -
Esse erro ocorre na execução do programa certo?! Ele não estaria ocorrendo na atribuição dos parâmetros, não?! por que você modificou a passagem de parâmetros :huh:: query2.ParamByName('pedidoID').Value := query1.fieldbyname('pedidoID').Value; query2.ParamByName('produtoID').Value := query1.fieldbyname('produtoID').Value; query2.ParamByName('quantidade').Value := query1.fieldbyname('produtoID').Value; quando eu lhe sugeri desta forma <_<: query2.ParamByName('pedidoID').Value := query1.fieldbyname('pedidoID').Value; query2.ParamByName('produtoID').Value := query1.fieldbyname('produtoID').Value; query2.ParamByName('quantidade').Value := query1.fieldbyname('quantidade').Value; Bom, se não for por causa do que coloquei acima, tente colocar a parametrização desta forma: query2.ParamByName('pedidoID').AsInteger := query1.fieldbyname('pedidoID').AsInteger; query2.ParamByName('produtoID').AsInteger := query1.fieldbyname('produtoID').AsInteger; query2.ParamByName('quantidade').AsFloat := query1.fieldbyname('quantidade').AsFloat; Se ainda não for por isso, haveria alguma possibilidade de haverem tipos de campos diferentes (com o mesmo nome) nas duas tabelas envolvidas? Abraços
-
E por que é que você faz isso?Não seria mais simples utilizar um TQRDBRichText e associar o campo DES_TAREFA da query3 a ele?
-
Coloque os lookups no datamodule, não há necessidade colocá-los no form. Se utilizar os lockup's em outros forms, talvez seja conveniente criar um datamodule só para eles - você os declará em um só lugar, e abrirá o dataset apenas que for utilizar quando entrar no form.É conveniente também, utilizar um TQuery, para isso porque daí você traz apenas o campo que precisa (menos tráfico de informação entre seu banco e programa) você tem que ter em mente que quando você utiliza o lookup, você estará "filtrando" os dados no lookupdataset, e que parece fazer sentido a não viabilidade de utilizá-lo para acesso num outro form, tipo num dbgrid - isso levando em conta a forma como sua aplicação está operando. Se o dataset fosse utilizado hora por uma tela, hora por outra, (ao menos em teoria) não deveria haver problema desde que você fecha o dataset e torna a abrí-lo a cada utilização. Abraços
-
Seria uma afirmação sobre duas opções? Eu sei que, em termos de componentes, a View seria tratada como uma tabela. Ou você acessa ela diretamente com um TTable ou via SQL com um TQuery "da vida". Neste caso, utilizando um equivalente a TQuery, vai poder fazer um SELECT e parametrizar a cláusula WHERE, como tem sido feito em uns post's recentes. No caso do uso de Stored Procedures, seria possível utilizá-la para filtrar registros num select e retorná-los como resultado, mas não saberia, mesmo, dizer como fazê-lo (utilzando os componetnes). Talvez alguém tenha uma idéia. Abraços.
-
Quebra De Linha Com Fortes Report
pergunta respondeu ao rodrigo biagioli de Micheus em Delphi, Kylix
Foi só uma cutucadinha... ;) Eu diria o seguinte: chefinho..., esse negócio de teclar enter para avançar funciona legal, mas tem só um probleminha. Quando o usuário está digitando um texto (num campo memo), como vou saber que ao teclar ENTER ele quer ir para outro campo ou apenas avançar uma linha? mas tem algum jeito de eu continuar com esse tratamento e não perder o #13???Até teria. Mas como é que você me responderia a pergunta acima? O usuário tem um campo memo para digitar um texto multi-linhas e você não vai deixar ele fazer isso? De qualquer modo, coloque aí o código que você está utilizando, porque até tentei fazer algo parecido utilizando um TMemo e não cheguei no bichinho (☺). Abraços -
E ele está compatível com o código que você utilizou.Dei uma "acertada" nele. Observe e compare os comentários que coloquei no meio do código, para que você entenda onde estavam os problemas. Acredito que agora fique Ok. Por gentileza, quando postar código, utilize a marcação apropriada (botãozinho com o # na barra de botões do editor). Dá muito trabalho ler o código sem a identação. Abraços procedure TForm1.BBProcessarClick(Sender: TObject); begin if edit1.Text = '' then begin showmessage('Não há valor para Consulta'); exit; end; with query1 do begin close; sql.Clear; sql.Add('Select pedidoID,produtoID, quantidade'); sql.Add('From Pedidos'); sql.Add('Where pedidoID =:ID'); parambyname('ID').Value := StrToInt(edit1.Text); open; end; // Até aqui, você obteve apenas os registros da tabela Pedidos filtrados pelo ID informado // Aqui estamos preparando a query2 para inserção na tabela ItensProcessamentoPedido (vixe que nome grande...) // Eu corrigi a parte do VALUES, porque você esqueceu de colocar o parâmetro PedidoID. Note // que você informa no INSERT INTO que incluirá 3 campos, logo tem que passar os 3 valores with query2 do begin sql.Clear; sql.Add('INSERT INTO itensprocessamentopedido(pedidoID, produtoID, quantidade)'); sql.Add('values(:pedidoID, :produtoID, :quantidade)'); end; // Agora nesta parte, iremos percorrer o resultado obtido na query1 e utilizar seus // valores para inclusão na tabela ItensProcessamentoPedido via query2 // Aqui, há nova correção, note que você tem que atribuir os campos da query1 para os // parâmetros da query2, mas você deu uma "viajadinha" (rsrsrs) e atribuiu novamente a query1 // Lembre também que teremos que fornecer os 3 parâmetros esperados na query2, então... while not query1.Eof do begin query2.ParamByName('pedidoID').Value := query1.fieldbyname('pedidoID').Value; query2.ParamByName('produtoID').Value := query1.fieldbyname('produtoID').Value; query2.ParamByName('quantidade').Value := query1.fieldbyname('quantidade').Value; query2.ExecSQL; query1.Next; end; edit1.SetFocus; end;
-
Seria para a edição ou apresentação?Para edição, particularmente acho o MaskEdit chato para este tipo de informação, porque você tem que pré-definir o número de cadas que o usuário poderá digitar (porque ele vai colocar aqueles tracinho para cada uma que eu definir) e tem outros inconvenientes. Quando sei que se trata de campo fixo, tipo percentual, até dá para usar (!99.9;1;_). Se for só para apresentação, ou seja, você digita 1520.00 e ao sair do campo, fica R$ 1.520,00 (é o que ocorre quando você utiliza DBEdit em que o field tem DisplayFormat = R$ #,##0.00) então você vai ter que tratar isso no OnExit do Edit/MaskEdit e na hora de atribuir ao seu campo na tabela, terá que reverter. O "erro" deve-se ao fato de você ter formatado o maskedit para exigir um valor - colocou 0 (zero) na máscara, por ex. !\(99\) 0000-0000;1;_Se você colocá-la deste modo: !\(99\) 9999-9999;1;_, não terá mais o erro ao sair do campo conforme você mensionou, só que você poderá perder a confiabilidade do conteúdo digitado. Dê uma olhada no help sobre as definições desta máscara (na janela Object Inspector, selecione a p ropriedade EditMask e tecle F1. Na tela que explica estra propriedade, click no link TEditMask e você terá uma descrição completa de todos os caracteres utilizados para formatação e suas funções) Seria isto? Abraços
-
Pessoal, este simples tutorial tem como objetivo apresentar uma das inúmeras formas de manipular dados de uma tabela. Utilizei Paradox com TTable, para simplificar a implementação. O projeto é composto por um Form (CadTesteDBEdit) e um Datamodule (DMCadastro). Entretanto, os conceitos mostrados nele podem ser aproveitados para o uso de quaquer banco e/ou componentes de acesso. (download) Dos recursos explorados - Monitoração da mensagem WM_MOUSEWHEEL (rodinha do mouse) para movimentação no DBGrid; - Utilização do evento OnStateChange do TDataSource para implementação de botões sensiveis ao estado do dataset; - Concentração da manipulação da tabela em um único evento a ser utilizado pelos botões que executarão a ação; - Implementação do evento OnCalcFields, demonstrando sua aplicação; O lay-out proposto para o form, na ordem - 01 TEdit para aplicação da função localizar (edLocalizar); - 01 TPanel para conter os TDBEdits e viabilizar o bloqueio da edição dos campos (Panel1); - 01 TDBGrid para listar os dados da tabela (DBGrid1); - 01 TDataSource para viabilizar a nonitoração do status da tabela - no form; - 03 TButton para inplementação dos botões de estado, onde serão disponibilizadas as funções Novo, Alterar, Excluir, Gravar e Cancelar (btnNovo, btnAlterar, btnExcluir); - 01 TButton para fechar o form (btnFechar); A relevância na ordem dos componentes (Tab Order) 1º - edLocalizar 2º - DBGrid1 3º - Panel1 4º - btnNovo 5º - btnAlterar 6º - btnExcluir 7º - btnFechar nesta ordem, no modo consulta, ao teclar TAB no edLocalizar você estará posicionado no DBGrid1, podendo facilmento movimentar-se no grid ou simplesmente acionando um dos botões; Já no modo edição, ao sair do Panel1, o foco passará automaticamente para o botão btnGravar, facilitando neste processo. Propriedades diversas alteradas em design-time 1) DBGrid1 - Options: dgRowSelect = True; dgAlwaysShowSelection = True; Selecionando toda a linha e automaticamente bloqueando a edição no DBGrid1 - ReadOnly = False; Evitando a exclusão no DBGrid1: CTRL+D 2) Panel1 - Enabled = False; Evitando o acesso inicial aos componentes TDBEdit 3) DBEdit1 (código auto-increment), edComissao (valor fixo) DBEdit4 (campo calculado), - apenas visualização - TabStop = False - ReadOnly = True No datamodule teremos - 01 TTable para acessar os dados da tabela Teste.DB (TabTeste); - 01 TDataSource que será utilizado pelo DBGrid1 para mostrar os dados; Breve descrição do programa - O programa manipula uma tabela simples, onde existem 3 campos: Codigo, Descrição e Valor. Não é muito realista, mas este não é o foco. - Para exemplificação do uso de campos calculados, eu defini (internamente - fixo) uma variável que conterá um percentual de comissão (PcComissao) que será utilizado para calcular o valor da comissão para cada item na tabela. Os campos calculados são ótimos para situações em que precisamos mostrar uma informação que não vem diretamente da tabela. Podem ser dados fixos, cálculos ou vindos de outra consulta/tabela (neste caso, similar a um lookup). - A função localizar implementada, tenta seguir o modelo que costumamos ver no Excel, onde vamos digitando o texto, o grid é posicionado e o texto digitado é complementado com o resto do texto encontrado, ficando este selecionado. Para realizar esta função, serão manipulados os eventos OnChange e OnKeyPress do campo edLocalizar. - A concentração da manipulação da tabela, pelos botões, é feita através de definição única do evento OnClick do botão btnNovo, o qual é associado ao respectivo evento dos botões btnAlterar e btnExcluir. Para viabilizar este procedimento, também são atribuídos os valores 1, 2 e 3 a propriedade TAG dos referidos botões. Vamos ao código Form Principal: - O procedimento AppEventsMessage foi declarado na sessão private do form CadTesteDBEdit e tem como objetivo simular o uso das teclas "para cima" e "para baixo" quando a rodinha do mouse for movimentada nestes sentidos. - Este evento (como implementada sua chamada) deve ser implementado/atribuído à Application.OnMessage apenas no form principal da aplicação (não repetir em cada form). procedure TCadTesteDBEdit.AppEventsMessage(var Msg: TMsg; var Handled: Boolean); var Sentido: SmallInt; begin if Msg.message = WM_MOUSEWHEEL then begin Msg.message := WM_KEYDOWN; Msg.lParam := 0; Sentido := HiWord(Msg.wParam); if Sentido > 0 then Msg.wParam := VK_UP else Msg.wParam := VK_DOWN; end; end; - Como mensionei antes, e sendo este nosso único form (o principal), é neste ponto que iremos inicializar o nosso manipulador de eventos. - O percentual de comissão é fixo, então, para mostrá-lo em nosso form, devemos atribuí-lo ao EdComissao utilizando a função de formatação FormatFloat. Poderíamos, também, ter criado um campo calculado para manter este valor e utilizá-lo para apresentação e os cálculos. - O datamodule é criado apenas no momento em que é utilizado, então este é o momento.procedure TCadTesteDBEdit.FormCreate(Sender: TObject); begin // declara um tratador de eventos para a aplicação // com o objetivo de tratar o evento MouseWheel Application.OnMessage := AppEventsMessage; DMCadastro := TDMCadastro.Create(Self); EdComissao.Text := FormatFloat('##0.0', DMCadastro.PcComissao); end; - Da mesma forma, liberamos o datamodule quando não mais o utilizamosprocedure TCadTesteDBEdit.FormDestroy(Sender: TObject); begin DMCadastro.Free; DMCadastro := Nil; // ou simplesmente: FreeAndNil(DMCadastro); // não existe no D3 end; - O evento OnStateChange do TDataSource (DSTesteLocal) ocorre sempre que o dataset ligado a ele muda de estado. É observando esta mudança que iremos manipular a habilitação e caption dos botões utilizados pelo usuário para manipular a tabela. Visando tormar este procedimento o mais genérico possível (uso de copiar/colar), resolvir fazer o type-cast de Sender (sempre que o evento é chamado pelo componente, Sender será um ponteiro para ele próprio). Como é possível notar, btnNovo estará habilitado sempre que o dataset estiver em modo browse. A partir do momento ele passar para o estado de iserção (se clicado em btnNovo) ou edição (se clicado em btnAlterar), este botão estará desabilitado. Já os botões btnAlterar e btnExcluir, só estarão desabilitados quando a tabela estiver vazia. Na habilitação é verificado se a tabela não está no modo inserção, também, porque ser for utilizado Append ou um Insert no último registro, EOF retornará True e os botões ficariam incorretamente desabilitados. Aproveitamos este evento para também permitir a manipulação dos TDBEdit's através da habilitação do Panel1 onde eles se encontram. Observe que quando estamos no modo inserção/edição, os botões btnAlterar e btnExcluir, passam a ter a função Gravar e Cancelar.procedure TCadTesteDBEdit.DSTesteLocalStateChange(Sender: TObject); begin with Sender as TDataSource do begin BtnNovo.Enabled := DataSet.State = dsBrowse; BtnAlterar.Enabled := not DataSet.EOF or // true sempre que houver dados na tabela e falso se for dada um append (DataSet.State = dsInsert); BtnExcluir.Enabled := not DataSet.EOF or (DataSet.State = dsInsert); Panel1.Enabled := DataSet.State in [dsInsert, dsEdit]; if DataSet.State in [dsInsert, dsEdit] then begin BtnAlterar.Caption := 'Gravar'; BtnExcluir.Caption := 'Cancelar'; end else begin BtnAlterar.Caption := 'Alterar'; BtnExcluir.Caption := 'Excluir'; end; end; end; - Como mensionado anteriormente, utilizamos um único evento OnClick para os botões btnNovo, btnAlterar e btnExcluir. Também foi considerada a utilização da propriedade TAG para identificar-mos a correta função dos botões, mas poderíamos, também, apenas comparar Sender com os botões (btnNovo, ...) através de if..then..else. Assim, utilizando também o princípio da generalização, trabalharemos como o DataSet ligado ao DBGrid1, não importando componente utilizado e nome do mesmo.procedure TCadTesteDBEdit.BtnNovoClick(Sender: TObject); begin with DBGrid1.DataSource do case (Sender as TButton).Tag of 1 : // Incluir begin DataSet.Append; DBEdit2.SetFocus; end; 2 : // Alterar/Gravar begin if DataSet.State in [dsInsert, dsEdit] then // Opção Gravar begin DataSet.Post; DBGrid1.SetFocus; end else // Opção Alterar begin DataSet.Edit; DBEdit2.SetFocus; end; end; 3 : // Excluir/Cancelar begin if DataSet.State in [dsInsert, dsEdit] then // Opção Cancelar begin if MessageDlg('Deseja cancelar a inclusão/edição do registro ?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin DataSet.Cancel; DBGrid1.SetFocus; end else DBEdit2.SetFocus; end else // Opção Excluir if MessageDlg('Confirma a exclusão do registro ?', mtWarning, [mbYes, mbNo], 0) = mrYes then DataSet.Delete; end; end; end; - Para simular, no edLocaliza, o efeito da busca em que o texto digitado é completado com o conteúdo da linha selecionada no DBGrid1 (quando compatível), utilizamos as propriedades SelStart e SelLength. Assim, se localizando um texto compatível com o digitado (text +%), inicialmente salvamos a posição do cursor (ele mudará ao atribuirmos novo valor a Text), evitamos uma indesejável recursividade desabilitando o evento OnChange ao atribuir-lhe nil. Em seguida atribuimos o valor localizado, definimos o início da seleção para a posição salva e seu tamanho para o comprimento do texto menos a posição salva. Podemos então habilitar novamente o evento OnChangeprocedure TCadTesteDBEdit.EdLocalizaChange(Sender: TObject); var CaretPos :Integer; begin with DMCadastro do if TabTeste.Locate('Descricao', EdLocaliza.Text, [loPartialKey, loCaseInsensitive]) then begin CaretPos := EdLocaliza.SelStart; EdLocaliza.OnChange := nil; EdLocaliza.Text := TabTesteDescricao.AsString; EdLocaliza.SelStart := CaretPos; EdLocaliza.SelLength := Length(EdLocaliza.Text) -CaretPos; EdLocaliza.OnChange := EdLocalizaChange; end; end; Entretanto, quando temos um texto selecionado nestas condições, ao teclar BACKSPACE, apenas a seleção é apagada - não o caracter antes dela, como desejaríamos. Então, para resolver este problema, escrevemos no evento OnKeyPress do edLocaliza, o código abaixo. Também desabilitamos o evento OnChange porque, novamente, iremos alterar o conteúdo de Text - vamos corrigir o "bug" citado anteriormente. Após corrigido - copiamos o conteúdo desde o início de Text até o início da seleção menos uma posição atual, habilitamos novamente o evento OnChange e forçamos a tentativa de posicionamento na consulta, baseado no novo conteúdo de Textprocedure TCadTesteDBEdit.EdLocalizaKeyPress(Sender: TObject; var Key: Char); var CaretPos :Integer; begin if Key = #8 then begin EdLocaliza.OnChange := nil; CaretPos := EdLocaliza.SelStart -1; EdLocaliza.Text :=Copy(EdLocaliza.Text, 1, CaretPos); EdLocaliza.SelStart := CaretPos; EdLocaliza.OnChange := EdLocalizaChange; EdLocalizaChange(Sender); Key := #0; end end; DataModule: - Temos apenas um TTable e um DataSource "apontando" para o mesmo. - O campo calculado (VlComissao) é criado através do editor de campos (Fields Editor...), acessado através de um duplo-click no componente. Teclando CTRL+N ou acessando menu popup, New Field..., definimos o nome (VlComissao), o tipo de dados (Float) e o tipo do campo (Calculated). Após clicar em OK temos nosso campo na tabela, definimos então a máscara DisplayFormat e o Label. Utilizaremos o evento OnCalcFields justamente para atribuirmos a VlComissao (criado como Calculated) o valor do cálculo da comissao sobre o campo Valorprocedure TDMCadastro.TabTesteCalcFields(DataSet: TDataSet); begin TabTesteVlComissao.Value := TabTesteValor.AsFloat *PcComissao /100; end;
-
Isto é coisa recente? Porque havia lido em outro forum sobre a não concretização da venda (DevMedia - Nov/2006) Abraços
-
Se você fala do que significa os parâmetro que você passa no WriteString, o 1º é a sessão no arquivo, o 2 seria o identificador da chave e o 3º o valor que ele recebe.No arquivo você identifica fácil quem são eles. No seu caso deve ter ficado assim: [DATABASE] URL=C:\Sysbib\Dados\SYSBIB_DB.GDB USR=SYSDBA PWS=masterkey Lafey, sobre esta questão de gravar usuário e senha, acho interessante você dar novamente uma lida na parte final daquele post que lhe indiquei no início. Outra coisa, com relação ao caminho para gravar seu arquivo ini, se ficar dentro da pasta de instação do seu programa, seria melhor que você não utilizasse esta informação constante (fixa no código). você pode utilizar ExtractFilePath(ParamStr(0)) para obter o path do seu programa, daí você concatena o nome do arquivo ini. Tem exemplo disto no forum - dá um pesquisada. Abraços
-
Seriam sim.O motivo é por aquele que citei. Se você quizer filtrar um período (você não utiliza o ano certo, porque você busca por aniversariantes) onde o mês inicial esteja no final do ano (tipo 15/Nov) até o início do ano seguinte (20/Jan), utilizando a query inicial, você teria - já colocando os valores na query: WHERE MONTH(DATANASC) between 11 and 1 AND DAY(DATANASC) between 15 and 20 Ao menso no Access, esta consulta seria a mesma coisa que:WHERE MONTH(DATANASC) between 1 and 11 AND DAY(DATANASC) between 15 and 20 Observe que ao invés de obtermos os aniversariantes nos meses NOV, DEZ e JAN, teríamos os com aniversário em JAN, FEV, MAR, ABR, MAI, JUN, JUL, AGO, OUT E NOV. Ainda deixaríamos de fora todos osque fizessem aniversário entre os dias 1 a 14 e 21 a 31. Isto só ocorre porque não comparamos datas, mas sim uma fração delas (dia e mês). if MonthOf(DtFim) < MonthOf(DtInicio) then begin SQL.Add('WHERE (Month(DATANASC)*100+Day(DATANASC)) BETWEEN :Inicio AND 1231'); SQL.Add(' OR (Month(DATANASC)*100+Day(DATANASC)) BETWEEN 101 AND :Fim'); end else SQL.Add('WHERE (Month(DATANASC)*100+Day(DATANASC)) between :Inicio and :Fim');utilizando desta forma, pelo menos a princípio, acho que resolvemos o problema. Isso porque se, como exemplifiquei acima, no período final o mês for menor (JAN) do que o inicial (NOV), teremos que considerar dois fragmenos: até DEZ e de JAN em diante. Por isso Inicio a 1231 (31/DEZ) e 101 (01/JAN) a Fim. De outro modo, basta utilizar do Inicio ao Fim. Clariou?! Abraços
-
Quebra De Linha Com Fortes Report
pergunta respondeu ao rodrigo biagioli de Micheus em Delphi, Kylix
Faz toda a diferença para um campo memo que deve contatenar, como disse anterirmente, um #13#10. E você está impedindo isso, removendo o #13.E você ainda me "zuou" sobre o post #3 heim?! ;) Esse negócio de trocar TAB por ENTER, só mesmo para agradar usuários DOS. Em qualquer outro program Windows (que não seja o seu) o usuário terá que utilizar TAB. :angry: Abraços