• Nenhum resultado encontrado

SUBRELATÓRIOS (MESTRE E DETALHE)

Um subrelatório é um elemento que você pode adicionar dentro de um outro relatório. Um subrelatório nada mais é que um relatório inserido dentro de outro. Assim você pode modularizar seus relatórios, criar relatórios complexos ou construir relatórios do tipo mestre-detalhe, objetivo desta parte.

Conceito de Mestre-detalhe

Uma interface de mestre-detalhe exibe um registro principal e os detalhes para o item atualmente selecionado. O mestre pode ser um formulário, lista ou árvore de itens, e o detalhe pode ser um formulário, lista ou árvore de itens tipicamente colocados abaixo ou ao lado da área do mestre.

A relação de mestre-detalhe pode ser do tipo um-para-muitos (1-N). Exemplos de uma relação mestre-detalhe são:

Um conjunto de ordens de compra e um conjunto de itens de linha pertencentes a

cada ordem de compra

Um relatório de despesas com um conjunto de itens referente a cada despesa

Um relatório de departamentos exibindo a lista de funcionários que pertencem a ele

Um relatório de disciplinas cursadas por aluno, onde ao selecionar um determinado

aluno, mostra-se as suas disciplinas.

Um outro exemplo do conceito de mestre-detalhe pode ser aplicado para permitir que os usuários naveguem através dos dados de pedidos de compra e assim ver os dados dos itens detalhadamente.

Como montar um relatório mestre-detalhe

Imagine a seguinte situação: você precisa criar um relatório, onde serão exibidos os dados de todos os clientes e de todos os filmes que cada um alugou. O layout do relatório teria que ficar mais ou menos assim:

Como criar um relatório com esse layout? Usando subrelatórios! A parte mais externa do layout representa o arquivo de relatório mais geral, onde serão listados os clientes e onde será inserido o subrelatório. O subrelatório, destacado em azul, será um outro arquivo de relatório que será utilizado dentro do relatório mais geral. Confuso? Calma, calma, logo vocês vão enteder. Antes disso, um pouquinho mais de teoria.

O funcionamento de um subrelatório é igual ao de um relatório normal, sendo que existe apenas uma diferença e é justamente aqui que as pessoas se confundem. Os parâmetros de um subrelatório não são enviados diretamente do código Java como é feito em um relatório normal. No caso dos subrelatórios, os parâmetros são enviados pelo relatório que os contém, para então serem passados ao subrelatório. Então, caso você passe um parâmetro para o relatório que deve ser usado apenas no subrelatório, o seu relatório vai

ter que ter o “mesmo” parâmetro e você vai ter que criar essa ponte entre o relatório principal e o subrelatório. Veja a Figura abaixo.

Parâmetros sendo passados entre as camadas de relatórios

Em vermelho é destacada a transmissão dos parâmetros a partir da aplicação em Java para o relatório. Esses parâmetros são enviados usando o mapa da parâmetros. Em laranja é destacada a transmissão dos parâmetros para o subrelatório a partir do relatório. Veja então que o relatório vai servir de ponte entre os parâmetros desejados, além de poder criar novos parâmetros e os enviar para o subrelatório. Outro detalhe é que podem haver diversos níveis de relatórios, ou seja, um subrelatório pode enviar parâmetros para

um subsubrelatório, um subsubrelatório pode enviar parâmetros para um

subsubsubrelatório, e assim por diante.

Exemplo de relatório mestre-detalhe a ser construído.

No exemplo proposto em nosso banco de dados, iremos construir um relatório entre

Vendas e Itens, ou seja, mostrará de cada Venda os Itens que foram comprados.

Observe que a tabela de Itens possui o Id_Venda de cada Venda vinculada. Logo, o relatório mostrará a relação de itens de cada venda.

Criando o subrelatório

Para criar um subrelatório primeiro é necessário criar o relatório que esse subrelatório irá referenciar. Para isso, em seu projeto:

 Clique “Arquivo > Novo Arquivo” (ou com o botão direito do mouse em cima de sua

pasta ‘Relatórios’) e selecione “Empty Report”.

 Coloque o nome do relatório de “Subrelatorio_Itens” e clique OK.

Adicione um parâmetro que vai ser usado na consulta SQL. Este será o parâmetro para

realizar a “ponte” entre a Venda e seus Itens. Esse parâmetro é o ID da venda:

No Report Inpsector, selecione a opção “Parameters” e com o botão direito do mouse, selecione “Adicionar Parameter”.

Ele criará um parâmetro com o nome “parameter1”. Selecione e na janela de propriedades:

Name: vendaid

Parameter Class: troque para java.lang.Integer que é o tipo do id.

Default Value Expression: coloque new Integer(1), ou seja, inicializando o

parâmetro com o valor 1 (venda de nº 1) para teste.

O próximo possa, antes de montar o subrelatório é construir a query deste relatório, destinada a mostrar os dados que desejamos nesse subrelatório, a qual será um pouco mais complexa.

Lembramos que este terá os itens e a sua tabela possui algumas chaves estrangeiras, as quais serão substituídas por algum dado na sua tabela base. Por exemplo, Itens possui ‘codigoProduto’ que iremos substituir pelo nome do Produto que está em sua tabela

‘Produtos’. Clique no Report Query para inserir sua query:

select p.nome Nome, i.quantidade, i.valorTotal from itens i, produtos p where id_venda = $P{vendaid} and p.codigo = i.codigoProduto

Observe que iremos listas os itens da venda indicada pelo parâmetro $P{vendaid}, o qual criamos para fazer a “ponte” entre a venda selecionada na tabela de “Vendas”.

Ao inserir a query, o iReport vai carregar os campos retornados por ela. Ao clicar em OK, os campos carregados serão criados na definição do relatório. Os fields lembram? Expanda então o nó Fields do Report Inspector e vamos arrastar os campos no relatório, como indicado a seguir.

Vamos montar o relatório agora!

Agora esconda todos as faixas menos a faixa de detalhe. Nela arraste os campos Fields

criados pela query. Ao lado do valor do item, coloque um Static Text para indicar a

Vamos diminuir a margem de rodapé deste subrelatório, a fim de que não fique muito espaço entre os subrelatórios que serão dispostos um abaixo de outro. Além disso, iremos colocar o total da venda logo abaixo do subrelatório e, a margem muito grande deixará distante o total dos itens acima. Para isso, procure da janela de Propriedades de seu relatório (figura abaixo).

Coloque o valor 5 para a Bottom margin:

Você pode testar seu subrelatório sem necessidade do relatório máster. Repare que

existe uma query, porém ela está parametrizada. Ao dar Preview no relatório abrirá uma

janela que pedirá exatamente um valor para o parâmetro ‘vendaid’.

Você pode entrar um ID de venda válido ou usar o Default, que é o valor 1 que definimos na criação do parâmetro. Você verá o subrelatório gerado e como será exibido.

Criação do relatório principal (master):

Crie um novo relatório. Vamos chama-lo de RelacaoVendas. Clique no Report Query e

insira a query de busca das vendas:

select * from vendas

Observe os campos Fields no Report Inpsector. O relatório terá somente as seguintes

faixas: Title, Page Header, Detail, Page Footer. As demais serão deletadas.

Em Title: coloque um Retângulo com fundo azul claro e faça ele ocupar toda a faixa.

Dentro dele, coloque um Static Text com tamanho 20, negrito e com o texto “Relação de

Vendas e seus Itens”.

Page Footer: só teremos para dar um espaço entre o titulo e as informações que estarão

presentes no Detail. Logo, diminua o tamanho somente desta faixa.

Page Footer: vamos colocar um campo para o número de páginas. Adicione uma variável (Variables do Report Inspector) PAGE_NUMBER e diminua seu tamanho para ajustar à variável.

Detail: aumente um pouco seu tamanho e do seu início, coloque dois Fields, o id da venda e a data. Precisamos formatar a data, logo, com ela selecionada, vá a janela de

formato desejado para mostrar a data (repare que esta janela define outros padrões, além da data)

Coloque Static_Text em cada Field para indicar o que significam. O resultado deverá estar

parecido como na figura abaixo. Não esqueça de realizar os alinhamentos (horizontais e verticais) de cada campo:

Vamos incluir o subrelatório no principal.

Primeiro, remova o campo de texto estático que tem o valor “O Subrelatório vai vir aqui…” (onde foi colocado somente para mostrar onde ele entrará no relatório master) e aumente a banda detail na altura cerca de 120 pixels (depois iremos deixar do tamanho correto).

Na paleta de componentes, procure por Subreport. Arraste um subreport para a banda

Assim que arrastar e soltar, o assistente de criação de subrelatórios irá abrir. Como o

Subrelatório já está criado,escolha “Use na existing report” e clique em Next. Veja a

Figura abaixo.

A opção “Create a New Report” iria direciona-lo para construir o subrelatório, da mesma forma que foi feito anteriormente, porém através do Wizard.

Clique em Brrowse e selecione na pasta ‘relatorios’ de seu projeto o relatório

No próximo passo, é perguntado como os dados do subrelatório serão obtidos. Marque a

opção “Use the same connection used to fill the master report”, ou seja, vamos usar

o mesmo objeto Connection passado para executar a query do relatório principal. Clique em Finish. Veja a Figura abaixo.

A próxima tela mostrará os parâmetros de vinculação, que no caso temos somente

Clique em próximo e aparecerá a janela para a configuração do Location. Não mexa em Location, poque já deve estar apontando para o diretório do relatório principal. Abaixo,

escolha “Store the directory name in a parameter”. Isso é útil para informarmos onde

está o subrelatório. A outra opção mapeia o arquivo pelo “caminho absoluto”, oque é

particularmente drástico em caso de modificação do diretório do projeto. A primeira opção mapeia de forma relativa, pelo subdiretório do projeto. Feito isso, clique em Finalizar. Veja a Figura abaixo.

Ao clicar em Finalizar, você vai perceber que foi inserida uma caixa cinza no relatório. Essa caixa indica onde o subrelatório vai ser inserido. Note então que, para cada venda, teremos um subrelatório renderizado, afinal, estamos na banda Detail não é mesmo? Expanda a caixa na largura, para ocupar quase a totalidade do relatório e altere a largura da banda detail acomodar a caixa do subrealtório. Veja a Figura abaixo.

Mencionamos que os parâmetros do subrelatório teriam de ser enviados pelo relatório principal. Logo, no nosso caso, o nosso subrelatório espera pelo parâmetro “vendaid”

($P{vendaid}) para executar sua query. Então precisamos fazer com que o relatório

principal passe este valor, que está sendo guardado do campo id_venda ($F{id_venda})

que é obtido na query do relatório principal.

Para isso, vá no relatório principal e selecione a caixa que vai conter o subrelatório. Ao selecioná-la, procure pela propriedade Parameters no painel de propriedades. Seguindo os passos anteriores, provavelmente já teremos mapeado ambos os campos como

mostra a imagem abaixo. Se já estiver, pule para a etapa “Testando seu relatório” mais

Porém, caso o valor esteja definido como “No parameter defined”, significa que esse mapeamento não está feito. Para isso, clique no pequeno botão a direita e a janela mostrada na Figura abaixo vai ser exibida.

Esta janela é utilizada para criar um parâmetro de passagem (eu que inventei esse nome de “parâmetro de passagem”), que deve ter o mesmo nome do parâmetro esperado pelo subrelatório. Os parâmetros de passagem ficam na coluna destacada em roxo da tabela. O valor desse parâmetro é gerado pela expressão que for definida (coluna destacada em

verde). Para criar o novo parâmetro de passagem, clique no botão Add. Ao clicar no botão, a janela mostrada na Figura abaixo é mostrada.

Preencha o campo “Subreport parameter name” com o valor vendaid (nome do

parâmetro do subrelatório) e preencha o campo “Value expression” com o valor

$F{id_venda}, ou seja, o campo id_venda da query do relatório principal e clique em OK.

Veja a Figura abaixo.

Precisamos fazer com que o relatório principal (master) passe este valor, que está sendo

guardado do campo idCliente ($F{idCliente}) que é obtido na query do relatório principal.

Para isso, vá no relatório principal e selecione a caixa que vai conter o subrelatório. Ao selecioná-la, procure pela propriedade Parameters no painel de propriedades. O valor vai

estar definido como “No parameter defined”. Clique no pequeno botão a direita e a janela mostrada na Figura abaixo vai ser exibida.

Note que você pode usar o editor de expressões (Expression editor) clicando no botão

destacado em laranja. Entendeu o que fizemos? Amarramos o parâmetro “vendaid” do

subrelatório com o valor que vai ser inserido no campo id_venda ($F{id_venda}), ou

seja, a cada vez que o subrelatório for chamado (para cada venda) o valor do parâmetro

“vendaid” vai ser configurado com o valor do campo id_Venda. Note que o valor do

parâmetro do subrelatório tem que ser do mesmo tipo que o valor gerado pela expressão de valor (value expression). É nesta mesma janela que você vai amarrar todos os parâmetros do subrelatório com valores gerados no relatório ou passados para ele.

Por exemplo, o subrelatório tem um parâmetro chamado “paramSub1” e o valor deste parâmetro é passado ao relatório principal no parâmetro chamado “paramPrin1”. Então você teria que amarrar paramSub1 (coluna name, em verde) com a expressão $P{paramPrin1} (coluna expression, em roxo) entendeu? É como se estivéssemos chamando um método, passando parâmetros para ele.

Testando seu Relatório

Você vai perceber que para cada venda será gerado a lista de seus itens vendidos. Agora que está tudo pronto, organize o layout do subrelatório e personalize da forma que achar melhor. Eu coloquei a largura com 7,694 polegadas e expandi a linha para ocupar toda a largura. Note que se você mudar alguma coisa no subrelatório precisará compilar apenas ele. Agora, para finalizar, vamos chamar este relatório a partir do nosso programa em Java, mas para isso ainda temos que fazer algumas pequenas modificações no arquivo de relatório principal.

Melhorando os caminhos relativos

Para entender o que vamos fazer, abra o arquivo RelacaoVendas.jrxml e selecione a

caixa do subrelatório. Nas propriedades procure pela propriedade Subreport Expression.

Essa expressão que é responsável em fazer o subrelatório ser carregado, ou seja, é ela que define para o relatório principal a localização do subrelatório. Por padrão – na verdade, definimos quando usamos o assistente de subrelatórios – ela vai conter o valor $P{SUBREPORT_DIR} + "Subrelatorio_Itens.jasper", ou seja, o

caminho do subrelatório é formado pelo valor do parâmetro SUBREPORT_DIR concatenado com o nome do arquivo de Subrelatório. O problema é que o parâmetro SUBREPORT_DIR está configurado com um valor fixo, que corresponde ao caminho absoluto do relatório e isso não é bom… Iremos então fazer com que tudo execute corretamente tanto no projeto, quanto no programa compilado e empacotado.

Primeiro, no Report Inspector, procure pelo parâmetro SUBREPORT_DIR. Ao

selecioná-lo, verifique a propriedade “Default Value Expression”. Ela vai estar definida como o caminho absoluto do diretório onde está o subrelatório.

Vamos mudar esse valor para “/” (com as aspas), ou seja, uma String que contém uma

barra, que vai indicar a raiz do projeto. O tipo da classe do parâmetro ainda é String. Ok, aqui está pronto. Agora selecione novamente a caixa do subrelatório. Na propriedade Subreport expression entre com o seguinte código.

Note que o ponto e vírgula da instrução não é colocado. Essa linha de código vai retornar

um objeto URL que aponta para o arquivo do subrelatório (“/Subrelatorio_Itens.jasper”),

sendo então carregado corretamente tanto no projeto, quanto no .jar. Note que poderíamos fixar esse valor sem precisar usar o parâmetro, mas caso haja a necessidade de mudar os diretórios dos subrelatórios, essa abordagem facilita o trabalho, tendo apenas que mudar o valor padrão do parâmetro.

Como a expressão vai retornar um objeto URL, ainda nas propriedades da caixa do

subrelatório, mude a Expression Class (logo abaixo da Subreport Expression) para

java.net.URL.

Feito isso, salve o relatório e dê um preview. Na aba iReport output vai ser acusado um warning, dizendo que não é possível encontrar o relatório, no entanto o relatório vai ser renderizado direitinho. Agora não precisamos mais nos preocupar, pois tanto no iReport, quanto no .jar que for ser gerado do projeto, o relatório vai abrir corretamente com o subrelatório. Algumas observações no resultado final:

1. Foram colocados Static_Text antes do subrelatório no relatório máster para indicar cada dado exibido no subrelatório.

2. Modifiquei a propriedade Pattern do $F{valorTotal} para Currency, a qual já coloca o R$

sem necessidade de um Static_Text adicional.