
Micheus
Veteranos-
Total de itens
3.189 -
Registro em
-
Última visita
Tudo que Micheus postou
-
(Resolvido) Tratando ReceiveText() -Socket - Delphi
pergunta respondeu ao Jhonatas araujo de Micheus em Delphi, Kylix
Jhonatas, dá uma olhada neste imenso tópico Comunicação entre PCs em uma rede - mas não pule páginas. Em alguns pontos são tratados deste assunto que você precisa. Acho que lhe dará uma idéia. Abraços -
(Resolvido)Programa lento ao iniciar
pergunta respondeu ao João Paulo Taraciuk de Micheus em Delphi, Kylix
João, acho que seria interessante estudar a possibilidade criar estes forms apenas no momento de seu uso. Muito provavelmente ajudaria a diminuir este tempo. Principalmente, se eles utilizarem componentes de acesso ao banco de dados e que estes estejam abertos, ou seja, a cada form que vai sendo criado, também é estabelecido o acesso ao banco e executadas as consultas. Abraços -
R.: não usei não..que eu me lembro nunca usei o Union.......o paradox suporte este comando, poderias dar um exemplo no codigo? Eder, segue um exemplo. Observe que neste caso, as duas (ou n) consultas devem ter o mesmo número de colunas, preferencialmente o mesmo nome (veja que usei um "AS UNIDADE"). A cláusula ORDER BY fica apenas no final (tem que ver se o Paradox, vai fazer esta ordenação direitinho - tem que testar, use o DBD): SELECT SUM(Valor_Frete) as VALOR_FRETE_TOTAL, SUM(CONTADOR) AS CONTADOR_TOTAL, SUM(KG_CALCULO) AS KG_CALCULO_TOTAL, SUM(VALOR_N_FISCAL) AS VALOR_N_FISCAL_TOTAL, SIGLA_CTRC AS UNIDADE FROM ctrc WHERE (SITUACAO_CTRC <> "C") AND DATA_EMISSAO between :datai and :dataf Group By SIGLA_CTRC UNION ALL SELECT SUM(Valor_Frete) as VALOR_FRETE_TOTAL, SUM(CONTADOR) AS CONTADOR_TOTAL, SUM(KG_CALCULO) AS KG_CALCULO_TOTAL, SUM(VALOR_N_FISCAL) AS VALOR_N_FISCAL_TOTAL, FIL_DEST AS UNIDADE FROM ctrc WHERE (SITUACAO_CTRC <> "C") AND DATA_EMISSAO between :datai and :dataf Group By FIL_DEST ORDER BY 1 DESC R.: Bom...eu tenho a RxLib instalada....mas nem imagino como fazer este processo que você menciona....SortOnFields, mas eu nunca usei e estou sem tempo para testar agora. Vamos partir para outra abordagem: criar uma tabela Paradox temporária. Lembra deste post? A idéia é a mesma, mudam os campos e o fato de que você não precisa criar a chave primária, apenas um índice normal (pelo campo a ser ordenado) e coloque nas suas opções: [ixDescending], para que você tenha o resultado ordenado em forma decrescente. Acho que você consegue implementar, qualquer coisa, eu só poderei ajudar novamente na segunda. ;) Abraços
-
Angela, quando você está no ambiente de programação (na IDE), você consegue ativar o banco através da da respectiva propriedade na janela Object Inspector? OU ocorre o mesmo erro? ____________________ Olhando melhor a questão, e sendo mais específico quanto ao erro, ele tem que estar ocorrendo no momento em que seu dataset (IBQUERY) está sendo aberto (Open) ou ativado (Active=True). Verifique se a propriedade Database do seu dataset (IBQUERY) está apontando para o Database localizado no datamodule. - Experimente ativar a sua consulta (IBQUERY) em design-time, via janela Object Inspector, e veja se o erro ocorre; - Certifique-se de que o datamodule está sendo criado antes do form; - Confira se em algum ponto do programa, você não manipula a propriedade Database deste IBQUERY ou qualquer outro que use; Em ambiente de desenvolvimento, quando este erro ocorre o fluxo do programa é desviado para dentro da IDE do dephi. Isso dará pistas sobre em que linha do código (em que momento) está ocorrendo o erro. Se você souber "debugar" - trabalhar com break-points - poderá interromper o programa antes da referida linha e avaliar a propriedade em questão, conferindo o seu real valor. Este é o tipo de erro que normalmente está associado a algum detalhe esquecido. É difícil ajudar mais sem ter o projeto na mão. Abraços
-
Bom, isso pode ser um problema, já que supondo a existência uma coluna que corresponda ao código do produto, ela poderá ter valor igual em ambas as tabelas de produtos. Será que estas informações diferentes são tantas que justifiquem alguma manobra para contornar esta situação? Abraços
-
permitam-me um pitaco aqui... Cadu0220, a mensagem: "You have error in your SQL syntax .... near 'CASE", se refere àquele CASE após o END. aqui, você retirou tudo, motivo da nova mensagem de erro. Você deve manter apenas o END. A sintax seria, grosseiramente: CASE <campo> WHEN <valor> THEN <resultado> ... WHEN <valor> THEN <resultado> ELSE <resultado> END [AS <nome_coluna>] Voce pode usar o alias como sugeriu o colega Denis Courcy, pois dará um nome legível e mais significativo a coluna criada com o uso do case. Abraços
-
Permitam-me dar minha opinião sobre o assunto... Eu pediria: por favor não ressucitem os mortos... É algo que tenho observado recentemente pelo forum. Será que seria apenas para aumentar os hits pessoais?! O que se ganha com isto? Alguns dos posts, seriam dígnos de serem excluídos, porque simplesmente não agregam nada ao assunto. Fora o fato de que quem postou a dúvida, muito provavelmente não lerá este post para fazer algum proveito (se bem que até poderia servir a outro) e não dirá se ele realmente resolve a questão ou serviu para alguma coisa. Pensa bem, se a galera sai a responder tudo o que tá em aberto, quem é que vai validar as respostas, já que existem inúmeros pseudo-sábios por ai? Ressucitar tópicos antigos com respostas que possam estar furadas, só vão "piorar a imagem do forum" (se é que a idéia inicial é melhorar). É como um cara que conta muita mintira, com o passar do tempo, ninguém mais confia nele. KaKarotto, que discurso heim?! Muito bom. chegando ao ponto de usuários enviar MPs para a moderação, pedindo ajuda, mesmo sendo contra as regras do forum. Aliás, regras??? Será que algum dos usuários algum dia as leu? (claro que uma minoria bem pequena, sim) Estão vendo minha assinatura?Acho que eu deveria aumentar o tamanho das letras... Sabe quantas vezes acabo fazendo uma busca por algo que já respondi e indicando a um sujeito? Quanto a indicação de tópico resolvido, isto já foi pior, em minha sessão. Mas mesmo assim, quando percebo que a questão foi sanada, tento confirmar com o autor. Por quê? Porque acho que isto sim é útil. Mas, vai servir quando? Quando alguém fizer uma busca e vendo que o assunto foi resolvido, ter convicção de que pode ler este tópico que resolverá seu problema. Puxa..., mas quase ninguém usa o bendito do botão Pesquisar. :( Fazer o quê?! A gente tenta... Concordo. Tem algumas sessões que se a moderação não postar, pode fechar porque, não demora muito, deixam de procuradas por falta de respostas. O que vai de encontro com o que o Thelon postou antes: "Para o fórum ter as duvidas respondidas precisa de pessoas que não vem apenas para perguntar. Que é o que a maioria faz." Abraços
-
(Resolvido)Programa lento ao iniciar
pergunta respondeu ao João Paulo Taraciuk de Micheus em Delphi, Kylix
João, por acaso você já deu uma olhada no fonte do projeto e verificou se ao ser mostrada a tela de Splash, não há um comando Sleep(<milesegundos>) que possa estar erroneamente configurado? São muitos forms, mas todos eles são criados na inicialização do programa? Quantos são? Se forem, vai mesmo demorar o suficiente para ser notado. Abraços -
Eder, seria mostrar junto no sentido de que o ranking não faria distinção entre uma e outra - é isto? Você tentou fazer um Union All das duas consultas SQL. Use o Database Desktop para fazer a consulta e testar o resultado. Você ainda está utilizando o Paradox, não é. Talvez o resultado não fique bom. Neste caso você poderia criar uma tabela temporária adicionando nela os dois resultados. Poderia até utilizar uma tabela em memória se você tiver instalado a biblioteca RxLib. Abraços
-
hideki, me diga uma coisa: esta descrição que você mostra em um TDBText está na mesma tabela que você utiliza para buscar os dados para seu TDBLookupListBox? Mesmo assim, independente da resposta, observe o seguinte: select * from AMB92GRUPO where cod_familia = campo order by descricao - quantas colunas você realmente precisa desta consulta? Traga apenas o essencial. - esta tabela tem um índice que utilize o campo sendo filtrado, pelo menos em seu início? A existência de índices possibilita ao gerenciador do banco, "ir" direto ao ponto e trazer apenas a informação que interessa - não tem que varrer toda a tabela. Imagine uma tabela com algumas milhares de linhas sendo "varrida" de "cabo-a-rabo", com dezenas de campos e vários usuários a acessando concorrentemente? O procedimento que você implementou em dois eventos (KeyUp e KeyDown), voce poderia colocá-lo no evento OnDataChange do DataSource vinculado a propriedade ListSource do seu TDBLookupListBox. Assim, você só faz algum processamento quanto houver mudança do item visualizado - nada de testar a cada tecla pressionada. Mas isto é só sugestão, não é relevante ao problema. Abraços
-
Angela, este tópico está sendo "ressucitado" pela segunda vez, e como da primeira, eu já havia solicitado ao colega mais informações. Eu sugeria a você que postasse os detalhes do seu problema: banco que usa, momento em que ocorre o erro,... Abraços
-
Felipe, meio estranho esse negócio de um orçamento com duas tabelas de produto relacionadas :blink: Mas dúvida em si... Sabendo que você pode fazer uma consulta (querie) para cada tabela de produto e vinculá-la a de orçamento via relacionamento entre os campos comuns? Qual é exatamente a dúvida? É sobre como construir o SQL ou como fazer isto no programa? Abraços p.s. vamos tentar melhorar este título depois - está em desacordo com as regras ;)
-
Kuroi, acredito que deste modo não dá mesmo.O único caso possível é com relação a TIMESTAMP. Dê uma olhada neste item do manual: Data Type Default Values. Não resolveria você criar uma trigger para isto, tipo: CREATE TRIGGER tgBI<tabela> BEFORE INSERT ON <tabela> FOR EACH ROW set NEW.<coluna> = current_date; Abraços
-
é isto mesmo. Veja: select cesta, SUM(amount) QtdTotal from table where fruit = 'banana' group by cesta Voce estará procurando pela fruta (fruit) "banana", fazendo um agrupamento por cesta, onde estará somando (SUM) a quantidade (amount) existente em cada uma delas.
-
foi um pouco mais que "mais tarde". :rolleyes: Eder, se estes arquivos a serem importados seguem corretamente a padronização de colunas (cada linha tem a mesma quantidade de colunas), utiliza um caracter de delimitação de campos (colunas) e se adicionarmos (em design-time) apenas os campos necessários ao dataset, poderemos criar uma função genérica que pode funcionar para a maioria dos casos de importação deste tipo. No exemplo, eu utilizei um dataset com 8 campos nesta ordem: CdFolha, CdDesenho, CdPasta, CdTitulo, DsFolha, DsRevisao, VlAno, InSituacao. No entanto, o arquivo de importação possui apenas informação para 4 campos: DsFolha, CdFolha, CdDesenho, CdTitulo. Para utilizar o procedimento como mencionei, adicionei ao dataset (em design-time) apenas os referidos campos, e na ordem em que os mesmos estarão organizados no arquivo de importação. Vejamos como está parte do arquivo a ser importado: "DsFolha","CdFolha","CdDesenho","CdTitulo" "1",1,1,1 "1/3",2,2,2 "2/3",3,3,2 "1",4,4,3 ... este arquivo tem 2989 linhas, sendo a primeira a de cabeçalho. A procedure de importação - genérica, que pode ser colocada em uma unit de utilidades: procedure ImportFile(DataSet :TDataSet; // dataset a incluir os dados importados ProgressBar :TProgressBar; // Barra de progresso FirstRowData :Word; // Primeira linha de dados - começa em 0 (zero) FileToImport :String); // Nome do arquivo a ser importado var DSActive :Boolean; Idx, IdxField :Integer; Columns, ArqToImport :TStringList; begin Columns := TStringList.Create; Columns.Delimiter := ','; // define o delimitador de campo Columns.QuoteChar := '"'; // define o limitador de strings ArqToImport := TStringList.Create; try DSActive := DataSet.Active; // salva condição inicial do dataset DataSet.Active := True; // força abertura do dataset ArqToImport.LoadFromFile(FileToImport); // carrega arquivo a ser importado ProgressBar.Max := ArqToImport.Count; // inicializa barra de progresso // processa todas as linhas do arquivo sendo importado for Idx := FirstRowData to ArqToImport.Count -1 do begin Columns.DelimitedText := ArqToImport[Idx]; // desmembra a linha em colunas - campos ProgressBar.Position := Idx; // move o indicador de progresso DataSet.Append; // Inicializa novo registro // atribui cada coluna lida à um campo do dataset // organizados na mesma seqüência for IdxField := 0 to DataSet.FieldCount -1 do DataSet.Fields[IdxField].AsString := Columns[IdxField]; DataSet.Post; // grava informações Application.ProcessMessages; // permite processamento de mensagens end; finally DataSet.Active := DSActive; // retorna a condição incial ProgressBar.Position := 0; // reinicializa a barra ArqToImport.Free; // libera linhas importadas Columns.Free; // libera colunas importadas end; end; Como usá-la: // botão para start da importação procedure TForm1.Button1Click(Sender: TObject); begin // Elimino os registros da minha tabela temporária Table1.EmptyTable; Table1.Open; // no arquivo exemplo, a 1ª linha (seria a 0 - zero) contém // o nome das colunas. Neste caso eu não vou importá-la, logo // começamos a partir de 1 (2ª linha) ImportFile(Table1, ProgressBar1, 1, 'Arquivo.csv'); end; Para o seu caso, você poderia apenas colocar o código no lugar da procedure atual, e testar a coluna do estado (9) desta forma: ... Columns.DelimitedText := ArqToImport[Idx]; // desmembra a linha em colunas - campos ProgressBar.Position := Idx; // move o indicador de progresso if Columns[8] <> 'SC' then // 8 porque começa em 0, ou seja 9-1=8 Continue; DataSet.Append; // Inicializa novo registro // atribui cada coluna lida à um campo do dataset // organizados na mesma seqüência for IdxField := 0 to DataSet.FieldCount -1 do DataSet.Fields[IdxField].AsString := Columns[IdxField]; ...Se funcionar bem, você há de notar o quanto diminui as linhas de código. A quantidade que tem naquele outro post, é gigantesca. :D Abraços Importacao_Arquivos.zip
-
Bom, o ideal é adicionar ao SELECT apenas o nome das colunas a serem utilizadas - supondo que você não fá utilizar todas. Isto evita trafego desnecessário de informações na rede, bem como uso dos buffers de memória. Mas você poderia fazer desta forma então: SELECT C.*, S.status AS DscStatus FROM tb_clientes C LEFT JOIN tb_status S on (S.id = C.status)neste caso, estamos buscando todas as colunas de tb_clientes (C.*) e para evitar erro devido a existência de uma coluna status em ambas as tabelas envolvidas, utilizamos um alias (apelido) para aquele que vem da tabela tb_status, chamando-o de DscStatus (você pode dar outro nome, desde que não seja um que exista na outra tabela). Abraços
-
se você acompanhar os tópicos que há por aqui, verá que o que mais tem são novatos. ;) Informações são necessárias pois facilitam a exemplificação, principalmente para novatos que não tem tanta intimidade com os termos que podem ser utilizados. Obrigado por postá-las, agora é ver ser alguém, poderá lhe ajudar de forma mais efetiva. Acho que agora ficou claro. Não há necessidade de gritar... <_< Abraços
-
Se você vai adicionar as séries em run-time, pode proceder mais ou menos assim: - adiciona um TChart (paleta Additional); - dá um duplo-click nele e configura o que precisar, depois, em Séries, seleciona Serie1 e clica em Delete; - se você precisar que o gráfico mostre os valores em Y desde 0 até o maior valor, você deve acessar a guia Axis e na sub-guia Scales, desmarca Automatic; marca Auto para Maximum e em Minimum, clica em Change e define 0 (zero); - No Object Inspector, você seleciona a propriedade BottomAxis, expande ela e configura a propriedade LabelsAngle para 90º para que apareçam as data/horas. Depois no código: procedure TForm1.BtnIncluiClick(Sender :TObject); procedure InsertSerieValue(Serie :TChartSeries; StrDateTime :String; Value :Double); begin Serie.AddXY(StrToDateTime(StrDateTime), Value, StrDateTime); end; var LineSerie :TLineSeries; begin LineSerie := TLineSeries.Create(Self); InsertSerieValue(LineSerie, '25/02/2008 23:40', 300); InsertSerieValue(LineSerie, '26/02/2008 01:40', 400); InsertSerieValue(LineSerie, '26/02/2008 03:40', 500); InsertSerieValue(LineSerie, '26/02/2008 05:40', 600); InsertSerieValue(LineSerie, '26/02/2008 07:40', 700); Chart1.AddSeries(LineSerie); LineSerie := TLineSeries.Create(Self); InsertSerieValue(LineSerie, '25/02/2008 23:40', 250); InsertSerieValue(LineSerie, '26/02/2008 01:40', 350); InsertSerieValue(LineSerie, '26/02/2008 03:40', 450); InsertSerieValue(LineSerie, '26/02/2008 05:40', 550); InsertSerieValue(LineSerie, '26/02/2008 07:40', 650); Chart1.AddSeries(LineSerie); ... end; Para limpar o gráfico, liberando as series alocadas, faça assim: ... while Chart1.SeriesList.Count > 0 do Chart1.Series[0].Free; ... é por aí.... Abraços
-
tem certeza?Estes dias já havia mencionado: quando você atribui algum valor a Filter ele assume este valor - não é cumulativo. Logo, a primeira atribuição a Filter e IndexName, são "queimadas" quando você faz a segunda atribuição, ou seja, elas estão sobrando - estão valendo as últimas. Outra coisa, você fala de um campo "tipo", onde em um DBComboBox tem os itens Receitas e Despesas (supostamente os valores possíveis para "tipo") e daí você usa o valor de um edit para aplicar no filtro justo no campo "tipo". Afinal, o que é que tem neste edit? acho que você está meio atrapalhado por aqui...você tem uma tabela onde estão cadastradas as receitas e despesas, e nesta tabela tem um campo "tipo" que supostamente define o tipo da informação nela contida, ou seja, se é uma receita ou se é uma despesa. Assim, este DBComboBox, não tem nenhuma relação com o relatório que você quer. Você precisa apenas "olhar" na tabela e ver o que é receita e o que é despesa, levando em consideração a data. O mais apropriado seria você utilizar uma querie para filtrar esta informação, conforme sugeriu o visitante (mas não a consulta que lá ele postou) - evidentemente que foi só uma idéia, já que você não passou qualquer informação sobre sua tabela (como nome dos campos) que permitisse a ele uma exemplificação mais apurada. Voce também poderia mostra qual o lay-out desejado para o relatório final, já que pode influenciar em uma solução a ser apresentada. Abraços
-
(Resolvido) Relatório Diário de Caixa Entrada/Saída
pergunta respondeu ao Tatiane.InterArt de Micheus em Delphi, Kylix
realmente deve dar um pouco de trabalho, já que tem que "imprimir" tudo na mão.você verificou se a impressão está ficando correta ao quebrar página? Bom, como agora você informou o banco que utiliza, fica mais fácil passar um exemplo. Já que é um banco decente (um SGBD) possivelmente você poderá fazer uso de sub-selects nas queries. Isto irá simplificar muito as coisas já que você pode resolver quase que todo o problema via queries. Apesar de não ser o seu caso, que é mais simples - tratando apenas 01 dia, vou dar uma sugestão que pode ser utiliza por você sem problemas. Consiste basicamente em: - fazer uma querie que agrupe os valores das duas tabelas gerando um resultado que tem as colunas Data, Valor da Entrada, Valor da Saída e Saldo na data; Fora outras facilidades, esta consulta evitará o uso de cálculos manuais; - esta consulta será utilizada como fonte de dados para filtrar os lançamentos nas tabelas EntCaixa e SaiCaixa, baseado (filtrado) na data; Em termos de quickreport, definiríamos sua propriedade DataSet com a consulta baseada na data e utilizaríamos: - uma banda Detail para percorrer a primeira consulta, baseada na data (haverá um registro/linha por data); - uma banda Sub-Detail para percorrer os lançamentos em ambas as tabelas, EntCaixa e SaiCaixa, paralelamente. Para isto, não definimos sua propriedade DataSet e fazemos uso do evento OnNeedData; - uma banda Sumary para fazer a totalização por Entrada e Saída, bem como apresentação do Saldo; Vamos a consulta principal (IBQryRegistros): select Data, SUM(VlEntrada) VlEntrada, SUM(VlSaida) VlSaida, SUM(VlEntrada -VlSaida) VlSaldo from (select E.DataRecto as Data, Valor as VlEntrada, 0 as VlSaida from EntCaixa E where E.DataRecto between :dtInicio and :dtTermino union all select S.DataPagto as Data, 0 as VlEntrada, Valor as VlSaida from SaiCaixa S where S.DataPagto between :dtInicio and :dtTermino) group by data order by 1 como é possível observar, fazemos um agrupamento por dia, de todos os registros retornados no sub-select que faz a união de todos os registros das tabelas EntCaixa e SaiCaixa, que satisfazem o filtro na cláusula WHERE. Adicionamos um componente TDataSource (DSRegistros) e vinculamos a este dataset para uso com os demais datasets. A consulta na tabela EntCaixa (IBQryEntradas), onde selecionaremos todos os registros da data sendo processada na linha detalhe (linha de IBQryRegistros), deverá ser parametrizada conforme segue: select Descricao, Valor, DataRecto, Tipo from EntCaixa where DataRecto = :Data order by codigo A consulta na tabela SaiCaixa (IBQrySaidas), é similar: select Descricao, Valor, DataPagto, Tipo from SaiCaixa where DataPagto = :Data order by codigo Em ambos os componentes, faremos o link para o dataset IBQryRegistros via propriedade DataSource, onde selecionamos o componente DSRegistros. Como sempre menciono, o nome do parâmetro deve ser exatamente o mesmo do campo definido no dataset de onde buscaremos a informação via propriedade DataSource. No QuickRep1, adicionamos: - um QRBand, com a propriedade BandType = rbDetail; - uma QRSubDetail, verificando a propriedade Master = QuickRep1; Nesta banda, formataremos as colunas. Colocamos os componentes TQRDBText para a coluna Entrada, vinculados ao dataset IBQryEntradas, bem como, colocamos TQRDBText para a coluna Saídas, vinculados ao dataset IBQrySaidas; No lugar de TQRLabels, devido ao lay-out e visando simplificar o código, utilizaremos TQRMemo para os labels; - uma QRSummary, para adicionarmos os os QRExpr que farão a totalização. As expressões ficaram: a. 'Total:' +FORMATNUMERIC('#,##0.00',SUM(IBQryRegistros.VLENTRADA)), para a totalização da entradas; b. 'Total:' +FORMATNUMERIC('#,##0.00',SUM(IBQryRegistros.VLSAIDA)), para a totalização das saídas; c. 'Saldo:' +FORMATNUMERIC('#,##0.00',SUM(IBQryRegistros.VLSALDO)), para o saldo. com é possível ver, o agrupamento no IBQryRegistros, facilitou muito estes cálculos. No exemplo que preparei, no form principal, o botão que aciona o relatório, passa os parâmetros necessários: dtInicio e dtTermino procedure TForm1.Button1Click(Sender: TObject); begin RelLivroCaixa := TRelLivroCaixa.Create(Self); try RelLivroCaixa.ShowPreview(DateTimePicker1.Date, DateTimePicker2.Date); finally RelLivroCaixa.Release; end; end; ShowPreview é um procedimento definido no form do relatório. Por uma questão de organização, eu prefiro utilizar esta abordagem do que acessar os componentes no outro form diretamente. No form do relatório (RelLivroCaixa) o procedimento ficou assim: procedure TRelLivroCaixa.ShowPreview(DtInicio, DtTermino :TDateTime); begin DetailBand1.Height := 0; // zeramos a banda que não mostrará informações IBQryRegistros.ParamByName('dtInicio').AsDate := DtInicio; IBQryRegistros.ParamByName('dtTermino').AsDate := DtTermino; IBQryRegistros.Open; IBQryEntradas.Open; IBQrySaidas.Open; try QuickRep1.PreviewModal; finally IBQrySaidas.Close; IBQryEntradas.Close; IBQryRegistros.Close; end; end; No evento OnNeedData da banda subdetail, que permite informar até quando a banda deverá ser impressa, atribuimos ao parâmetro MoreData (mais dados) o resultado da avaliação de uma das duas condições necessárias para a impressão dos dados: imprimimos a banda enquanto não for fim do arquivo de entradas ou do de saídas: procedure TRelLivroCaixa.QRSubDetail1NeedData(Sender: TObject; var MoreData: Boolean); begin MoreData := not IBQryEntradas.EOF or not IBQrySaidas.EOF; end; No evento BeforePrint da banda subdetail, iremos manipular a visibilidade das "colunas". Como pode ocorrer de uma coluna ter quantidade de linhas diferente da outra, faz necessário que escondamos os componentes daquela coluna em que já atingimos o fim do arquivo: procedure TRelLivroCaixa.QRSubDetail1BeforePrint(Sender: TQRCustomBand; var PrintBand: Boolean); begin QREnt_DataRecto.Enabled := not IBQryEntradas.Eof; QREnt_Descricao.Enabled := QREnt_DataRecto.Enabled; QREnt_Tipo.Enabled := QREnt_DataRecto.Enabled; QREnt_Valor.Enabled := QREnt_DataRecto.Enabled; QRMEntradas.Enabled := QREnt_DataRecto.Enabled; QRSai_DataPgto.Enabled := not IBQrySaidas.Eof; QRSai_Descricao.Enabled := QRSai_DataPgto.Enabled; QRSai_Tipo.Enabled := QRSai_DataPgto.Enabled; QRSai_Valor.Enabled := QRSai_DataPgto.Enabled; QRMSaidas.Enabled := QRSai_DataPgto.Enabled; end; Para promovermos o avanço das informações, após impressa a banda subdetail, avançamos ambas as tabelas. Observe que não precisamos nos preocupar com nada - basta chamar Next. Caso já tenha chegado ao fim do arquivo, não haverá qualquer erro e ainda estará forçando a atualização da propriedade EOF: procedure TRelLivroCaixa.QRSubDetail1AfterPrint(Sender: TQRCustomBand; BandPrinted: Boolean); begin IBQryEntradas.Next; IBQrySaidas.Next; end; As vezes uma coisa tão simples como esta, precisa de um tempo e explicação consideravelmente grandes... Bom, espero ter descrito o processo de forma compreensível e que seja útil a quem necessite de algo parecido, porque variações são possíveis. Fica em anexo, para quem tiver InterBase ou FireBird, o projeto exemplo. O resultado final do relatório, também, pode ser visto na imagem em anexo. Abraços Relatorio_Tipo_Livro_Caixa.zip -
então é simples: SELECT C.id, C.nome, S.status FROM tb_clientes C LEFT JOIN tb_status S on (S.id = C.status) Abraços
-
(Resolvido)Adicionar um dia na data
pergunta respondeu ao João Paulo Taraciuk de Micheus em Delphi, Kylix
João, deveria ser algo parecido com isto, apenas:TabCaixaDATA.value := Date +1; -
Ramon, talvez sua dúvida não tenha muito a ver com com DBGrid, mas sim com SQL/banco de dados/relacinamentos... Este seu DBGrid apenas mostra a informação ou você o utiliza para inclusão/edição, também?
-
Deivid Luz, não sei se você já havia observado, mas no início do nosso índice há um link tipo Destaque que aponta para uma sessão Cristal Reports. Apesar de ela ser um sub-forum do Visual Basic, há grandes chances de você obter ajuda lá, já que a linguagem que se usa, neste caso, pouco irá influenciar. Voce até poderia pesquisar por lá para ver se já não há algo a respeito. Estou movendo este tópico para lá, talvez tenha mais sorte. Abraços
-
(Resolvido) Relatório Diário de Caixa Entrada/Saída
pergunta respondeu ao Tatiane.InterArt de Micheus em Delphi, Kylix
Tatiane, se você já tem a informação em uma única consulta, poderia colocar o nome das colunas que você tem como resultado? E você criou uma coluna para indicar, quando a linha é D ou C, ou você manteve duas colulas, uma com o valor do Crédito e outra do Débito? Tendo um único dataset, a questão de colunar os valores é apenas uma questão de manipulação visual. Mas é necessário saber os campos envolvidos e as colunas em questão. Vai acabar caindo mais ou menos no que o Denis Courcy já postou. Abraços