Olá. Boa noite.
Estou tentando agora implementar como me foi passado, vejam se estou no caminho correto.
1) Eu tenho uma Classe Produto, normal.
public class Produto {
private int codigo;
private String nomeProduto;
private String tamanho;
private String cor;
private Double quantidade;
private BigDecimal valor;
//Construtor vazio, Setts e Getts omitidos
2) Eu tenho uma Classe Venda.
public class Venda {
private int codigo;
private String nomeCliente;
private BigDecimal valorTotal;
private Date dataVenda;
private List produtos;
//Construtor vazio, Setts e Getts omitidos
Então na Classe Venda, eu teria uma lista de Produtos.
No Relatório Master, eu apontei o ClassPath do iReport para a pasta: build/classes criado no meu projeto. (no caso: C:\Users\Marcos\Desktop\Relatorios\build\classes)
Dessa forma, ao criar o relatório, eu consigo mapear os Fields de forma automática, na Tela Report Query, na Aba JavaBean Datasource. Lá eu digito o package.nomeDaClasse e clico no botão Read Attributes e ele me relaciona os Atributos dessa minha classe. E dessa classe ele mapeou minha lista de produtos, como List, mesmo.
Então, eu adicionei os Field mapeados na Banda Detalhe, normalmente. Criei um Novo Relatório, com Empty DataSource. Nele, eu apontei o mapeamento da mesma forma como no anterior, só que para a Classe Produto.
E, voltando no Relatório Master, selecionei o Subrelatório criado e adicionado, fui na propriedade Connection type e selecionei "Use a datasource expression" e na propriedade Datasource expression coloquei a expressão:
new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{produtos})
Onde "produtos" é o nome da lista que está dentro da Classe Venda.
Compilando no iReport, ambos relatórios não apresentam erro algum.
Então, para abrir meu relatório, fiz uso de uma Classe que encontrei pela Internet, num tutorial:
public static void openReport(
String titulo,
InputStream inputStream,
Map<String, Object> parametros,
Connection conexao ) throws JRException {
/*
* Cria um JasperPrint, que é a versão preenchida do relatório,
* usando uma conexão.
*/
JasperPrint print = JasperFillManager.fillReport(
inputStream, parametros, conexao );
// abre o JasperPrint em um JFrame
viewReportFrame( titulo, print );
}
public static void openReport(
String titulo,
InputStream inputStream,
Map<String, Object> parametros,
JRDataSource dataSource ) throws JRException {
/*
* Cria um JasperPrint, que é a versão preenchida do relatório,
* usando um datasource genérico.
*/
JasperPrint print = JasperFillManager.fillReport(
inputStream, parametros, dataSource );
// abre o JasperPrint em um JFrame
viewReportFrame( titulo, print );
}
private static void viewReportFrame( String titulo, JasperPrint print ) {
/*
* Cria um JRViewer para exibir o relatório.
* Um JRViewer é uma JPanel.
*/
JRViewer viewer = new JRViewer( print );
// cria o JFrame
JFrame frameRelatorio = new JFrame( titulo );
// adiciona o JRViewer no JFrame
frameRelatorio.add( viewer, BorderLayout.CENTER );
// configura o tamanho padrão do JFrame
frameRelatorio.setSize( 500, 500 );
// maximiza o JFrame para ocupar a tela toda.
frameRelatorio.setExtendedState( JFrame.MAXIMIZED_BOTH );
// configura a operação padrão quando o JFrame for fechado.
frameRelatorio.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
// exibe o JFrame
frameRelatorio.setVisible( true );
}
}
E no meu método, escrevi da seguinte maneira:
public void abrirRelatorioClientesDS() {
InputStream inputStream = getClass().getResourceAsStream( "relatorioVendaDetalhado.jasper" );
Map parametros = new HashMap();
List<Venda> dados = new ArrayList<Venda>();
List<Produto> produtos = new ArrayList<Produto>();
//Fake Dados Produto
Produto p = new Produto();
p.setCodigo(102);
p.setCor("AZUL");
p.setNomeProduto("VESTIDO DE FESTA");
p.setQuantidade(1.0);
p.setTamanho("M");
p.setValor(new BigDecimal(90.0));
produtos.add(p);
//Fake Dados Venda
Venda v1 = new Venda();
v1.setCodigo(1);
v1.setDataVenda(new Date());
v1.setNomeCliente("MARCOS ROBERTO DA FONSECA");
v1.setValorTotal(new BigDecimal(10.0));
v1.setProdutos(produtos);
dados.add(v1);
// criando o datasource com os dados criados
JRDataSource ds = new JRBeanArrayDataSource(dados.toArray());
try {
// passando o datasource para o método de criação e exibição do relatório
ReportUtils.openReport( "Vendas - Bean Collection Data Source", inputStream, parametros,ds);
} catch (JRException ex) {
ex.printStackTrace();
}
}
Fiz então uma lista chamada DADOS, que seria minha lista de Vendas, e dentro de cada objeto venda há uma lista com seus respectivos produtos. Ainda teria que haver, dentro da Venda uma segunda lista, com as formas de pagamento, mas eu acredito que conseguindo fazer funcionar dessa maneira, a outra lista será tranquilo, pois em comentários anteriores, o usuário erico_kl me deu a dica de as formas de pagamento, serem colocadas num subrelatorio e colocar esse subrelatorio com a propriedade Position Type = Float.
Pra ficar mais organizado, visualmente falando, nos subrelatórios, você pode zerar as propriedades:
- Right Margin, que é a margem da direita
- Left MArgem que é a margem da esquerda
- Top Margin que é a margem do topo
- Bottom margin que é a margem do rodapé do relatórios
Basta selecionar, no relatório principal, o subrelatório, e na Aba Properties, alterar os valores.
Até o término da escrita desse post, eu consegui fazer o subrelatorio de formas de pagamento. E useu, como o usuário erico_kl me deu a dica de as formas de pagamento, serem colocadas num subrelatorio e colocar esse subrelatorio com a propriedade Position Type = Float.
Espero que essas informações tenham sido de boa serventia.
Agradeço e muito a ajuda dos usuários que me reponderam anteriormente. Muito obrigado!