Imprimir conteúdo JFrame

Pessoal, eu tenho um JFrame que tem um JPanel o qual possui várias JTables e JLabels. Gostaria de imprimir o conteúdo mas não sei se preciso imprimi o conteúdo do JPanel ou do JFrame.

Pesquisei e li muitos materiais porém não sei como fazer para imprimir. Eu queria que ao clicar no botão “Imprimir” chamasse o serviço so sistema operacional para imprimir, mas não sei com fazer isso.

Se alguém puder me ajudar agradeceria.

Abaixo segue minha classe, sendo que o JFrame foi criado usando o NetBeans e o resto por código.

public class TelaBoletim extends javax.swing.JFrame{

    FormatacaoConteudo conteudoCentralizado = new FormatacaoConteudo();
    FormatacaoConteudo corNomes = new FormatacaoConteudo();
    Color nomesCor = new Color (202, 225, 255);

    public TelaBoletim() {        
        
    }

    public TelaBoletim(List<AlunoBoletimVisualizacao> alunos){
        final JButton Imprimir = new JButton("Imprimir");
        JLabel nome = null;
        JLabel turma = null;
        JPanel panel = new JPanel();
        JTable table = null;
        JScrollPane jstable = null;
        JScrollPane jspane = null;
        BoletimTabelModel modelBoletim = null;
        List<DisciplinaBoletimVisualizacao> disciplinasBoletim = null;
        corNomes.setBackground(nomesCor);
        conteudoCentralizado.setHorizontalAlignment(SwingConstants.CENTER);
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.setBorder(new EmptyBorder(40, 60, 40, 60));
        panel.add(Imprimir);
        panel.add(Box.createRigidArea(new Dimension(30, 10)));
        for (AlunoBoletimVisualizacao alunoBoletimVisualizacao : alunos) {
            nome = new JLabel("Aluno: " + alunoBoletimVisualizacao.getNome());            
            turma = new JLabel("Turma: " + alunoBoletimVisualizacao.getTurma());
            panel.add(new JLabel("Escola Municipal Amadeu Bolognesi"));
            panel.add(nome);
            panel.add(turma);
            disciplinasBoletim = alunoBoletimVisualizacao.getDisciplinas();            
            modelBoletim = new BoletimTabelModel(disciplinasBoletim);
            table = new JTable();
            table.setModel(modelBoletim);
            table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            table.getColumnModel().getColumn(0).setPreferredWidth(150);
            table.getColumnModel().getColumn(1).setPreferredWidth(57);
            table.getColumnModel().getColumn(2).setPreferredWidth(90);
            table.getColumnModel().getColumn(3).setPreferredWidth(57);
            table.getColumnModel().getColumn(4).setPreferredWidth(57);
            table.getColumnModel().getColumn(5).setPreferredWidth(90);
            table.getColumnModel().getColumn(6).setPreferredWidth(57);
            table.getColumnModel().getColumn(7).setPreferredWidth(57);
            table.getColumnModel().getColumn(8).setPreferredWidth(90);
            table.getColumnModel().getColumn(9).setPreferredWidth(57);
            table.getColumnModel().getColumn(10).setPreferredWidth(75);
            table.getColumnModel().getColumn(11).setPreferredWidth(90);
            table.setPreferredScrollableViewportSize(new Dimension(927,128));
            table.getColumnModel().getColumn(0).setCellRenderer(corNomes);
            table.getColumnModel().getColumn(1).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(2).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(3).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(4).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(5).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(6).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(7).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(8).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(9).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(10).setCellRenderer(conteudoCentralizado);
            table.getColumnModel().getColumn(11).setCellRenderer(conteudoCentralizado);
            jstable = new JScrollPane();
            jstable.setViewportView(table);
            panel.add(jstable);
            panel.add(Box.createRigidArea(new Dimension(30, 100)));
        }
        jspane = new JScrollPane();
        jspane.setViewportView(panel);
        this.add(jspane);
        this.setLocation(100, 5);
        initComponents();
    }

    @SuppressWarnings("unchecked")
        private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Boletins");
        setMinimumSize(new java.awt.Dimension(700, 300));
        setResizable(false);
        getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.LINE_AXIS));

        pack();
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TelaBoletim().setVisible(true);
            }
        });
    }

}

Talvez este post te ajude.

Obrigado pela dica, mas não ajudou não…

Eu imagino que deva ter algum comando mais simples que eu consiga chamar para mandar imprimir o conteúdo do meu JFrame ou JPanel, algo como

panel.print()… algo assim

Se alguém souber, por gentileza, estou precisando muito saber.

Grande abraço.

Obrigado pela dica, mas não ajudou não…

Eu imagino que deva ter algum comando mais simples que eu consiga chamar para mandar imprimir o conteúdo do meu JFrame ou JPanel, algo como

panel.print()… algo assim

Se alguém souber, por gentileza, estou precisando muito saber.

Grande abraço.[/quote]

infelizmente não existe isso.

Não? Puxa vida…bom, mas deve existir uma forma de imprimir o conteúdo de um JFrame ou de um JPanel certo?

Pesquisei muito na net e minha única esperança é que alguém aqui do fórum(que conhece muito mais do que eu) deva saber como fazer…

Estou precisando muito pessoal, muito mesmo…

Grande abraços a todos que tentaram ajudar e por favor, se alguém souber me ajude.

Sobre impressão: http://download.oracle.com/javase/tutorial/2d/printing/index.html

Impressão de GUI: http://download.oracle.com/javase/tutorial/2d/printing/gui.html

Muito obrigado pelas dicas, mas eu já tinha lido este material, porém não entendi como fazer na prática entende? Sou novato com java swing.

Poderia me explicar onde colocaria o código na minha classe e como faria?

Agradeço muito a ajuda, grande abraço.

olha esse link: http://www.guj.com.br/java/231315-como-capturar-a-tela-do-programa-com-o-bufferedimage-

é uma captura de imagem da tela, salva e imprime …

não sei se resolve.

Depois de gastar um tempinho tentando entender o assunto, vou tentar passar o resultado.

Não sei se chegou a ler tudo, mas para conseguir entender bem o assunto é interessante ler, principalmente, os primeiros tópicos, que passam o básico sobre a impressão.

De qualquer forma, vou postar o mesmo código que está na classe PrintUIWindow e colocar alguns comentários. Vou comentar por cima os pontos que considero importantes para o entendimento da classe.

PS.: Os comentários em inglês são os originais. Não achei necessário modificá-los.

[code]// Esta classe implementa a interface Printable, permitindo que possa ser impressa por um PrinterJob.
public class PrintUIWindow implements Printable, ActionListener {

// Instância do JFrame que será impresso.
JFrame frameToPrint;

// Método implementado da interface Printable
public int print(Graphics g, PageFormat pf, int page) throws
                                                    PrinterException {

    if (page > 0) { /* We have only one page, and 'page' is zero-based */
        return NO_SUCH_PAGE;
    }

    /* User (0,0) is typically outside the imageable area, so we must
     * translate by the X and Y values in the PageFormat to avoid clipping
     */
    Graphics2D g2d = (Graphics2D)g;
    g2d.translate(pf.getImageableX(), pf.getImageableY());

    /* Now print the window and its visible contents */
    frameToPrint.printAll(g); // Obs.: O exemplo usa JFrame para ser impresso, mas o método printAll é de java.awt.Component, portanto pode adaptar o exemplo para trabalhar com outros componentes além do JFrame.

    /* tell the caller that this page is part of the printed document */
    return PAGE_EXISTS;
}

public void actionPerformed(ActionEvent e) {
     // instancia um PrinterJob.
     PrinterJob job = PrinterJob.getPrinterJob();

     // seta este objeto como o Printable a ser impresso pelo PrinterJob.
     job.setPrintable(this);

     // o método printDialog() exibe o diálogo de impressão, que permite selecionar impressora, qtde de páginas, etc. Se tudo der certo na configuração da impressora, o retorno será true.
     boolean ok = job.printDialog();

     if (ok) { // verifica se o resultado foi ok.
         try {
              job.print(); // Chama o método print de PrinterJob, que vai chamar o método print que foi implementado acima já passando os parâmetros necessários.
         } catch (PrinterException ex) {
          /* The job did not successfully complete */
         }
     }
}

// Construtor que recebe o Frame a ser impresso.
public PrintUIWindow(JFrame f) {
    frameToPrint = f;
}

}[/code]
Resumindo, esta classe basicamente implementa Printable para que possa ser usada pelo PrinterJob, recebe o JFrame que vai ser impresso e implementa ActionListener para exibir o diálogo de impressão e mandar imprimir.

Esta classe já faz o que você precisa em relação a impressão. No seu frame basta adicioná-la como um ActionListener no botão.

Qualquer coisa, torne a postar.

Obrigado pela dica cara.

Grande abraço.

Primeiramente queria agradecer a ajuda e esclarecer que li todo material, na verdade mais de uma vez, mas não compreendia os detalhes, pois tinha tentado usar a classe que me passou mas não tinha conseguido…estou iniciando em java, então muitas coisas não compreendo.

Bom, eu coloquei na minha aplicação e funcionou, ou seja, eu passo o JFrame pra e ele imprime. Na verdade não testei na impressora pq não tenho, tentei gerar um pdf como sempre faço quando quero levar algum documento pra imprimir…O que aconteceu é que eu tinha 5 tabelas de conteúdo e ele imprimiu apenas duas e meia e cortou tb o lado direito, ou seja, não pegou o tamanho todo do JFrame. Estou enviando em anexo o pdf gerado.

Existe algum detalhe para ele imprimir todo conteúdo do JFrame?

Outra coisa, vc colocou nos comentários que poderia imprimir outros componentes, ou seja, eu tentei então imprimir o JPanel e para isso alterei a declaração do JFram na classe e tentei passar ele no construtor mas deu erro, ele não aceita. Precisa mudar alguma coisa na lógica para poder passar um JPanel pra ele imprimir? Pergunto, pois pensei em tentar imprimir o JPanel pra ver se o conteúdo sai direitinho.

Agradeço muito a atenção e a ajuda e fico no aguardo

Grande abraço.

[quote=Robertdm]Bom, eu coloquei na minha aplicação e funcionou, ou seja, eu passo o JFrame pra e ele imprime. Na verdade não testei na impressora pq não tenho, tentei gerar um pdf como sempre faço quando quero levar algum documento pra imprimir…O que aconteceu é que eu tinha 5 tabelas de conteúdo e ele imprimiu apenas duas e meia e cortou tb o lado direito, ou seja, não pegou o tamanho todo do JFrame. Estou enviando em anexo o pdf gerado.

Existe algum detalhe para ele imprimir todo conteúdo do JFrame?[/quote]

Aparentemente o problema é que a folha acabou mesmo, quer dizer, a largura do JFrame está maior que a largura da folha.

Esta parte eu acabei deduzindo, já que o método vem da Classe Component. Apesar que o próprio artigo do Java Tutorials cita isso.

Estou meio ocupado agora. Mas da metade para o fim da tarde vou fazer uns testes e analisar melhor como isso funciona, aí eu retorno.

E se conseguir solucionar o problema, não deixe de postar.

Falou…

Agradeço por tudo…

Bom, corrigindo o que eu havia dito antes, eu consegui passar o JPanel para imprimir, estava comento um erro no código, mas mesmo assim, ele imprime cortando o tamanho e a largura exatamente o que ocorre quando passo o JFrame.

Vou continuar tentando e caso consiga eu posto aqui sim.

Fico no aguardo caso tenha alguma novidade quando vc puder mexer.

Grande abraço.

Achei mais dois artigos sobre impressão bem interessantes:

http://java.sun.com/developer/onlineTraining/Programming/JDCBook/render.html

http://java.sun.com/developer/onlineTraining/Programming/JDCBook/advprint.html

Tomei como base o segundo link (Advanced Printing) e adaptei o esquema que eles usaram para redimensionar a JTable, só que aplicando ao componente, caso ele seja maior que a folha. O problema é que se a tela for muito grande, após o redimensionamento vai ficar ruim de ler o conteúdo. Uma forma de contornar isso é pedir para imprimir em landscape (paisagem).

Eu aproveitei também para usar a referência de um Component para ser impresso, permitindo que passe um JFrame, JPanel ou qualquer outro Component pelo construtor. E criei uma cópia do Graphics ao invés de utilizá-lo diretamente.

Ficou assim:

[code]
import java.awt.;
import java.awt.event.
;
import javax.swing.;
import java.awt.print.
;

public class ComponentPrinter implements Printable, ActionListener {

Component componentToPrint;

public ComponentPrinter(Component comp) {
	componentToPrint = comp;
}

/* Quando mandamos uma página ser impressa pelo PrinterJob,
 * ele vai executando continuamente este método até que o retorno
 * seja a constante NO_SUCH_PAGE
 */
public int print(Graphics g, PageFormat pf, int page)
		throws PrinterException {


	/* Teremos apenas uma página, que começa em zero, por isso
	 * quando a página for maior que zero retornamos NO_SUCH_PAGE
	 */
	if (page > 0) {
		return NO_SUCH_PAGE;
	}

	Graphics2D g2d = (Graphics2D) g.create();
	
	/* As coordenadas (0, 0) costumam ficar fora da área de impressão,
	 * portanto traduzimos as coordenadas (X, Y) de acordo com o PageFormat
	 */
	g2d.translate(pf.getImageableX(), pf.getImageableY());

	// Carrega a largura e a altura da página com base no PageFormat
	double pageWidth = pf.getImageableWidth();
	double pageHeight = pf.getImageableHeight();

	// Carrega a largura e a altura do componente a ser impresso
	double compWidth = (double) componentToPrint.getWidth();
	double compHeight = (double) componentToPrint.getHeight();

	/* Redimensiona o graphics se a largura do componente for
	 * maior que a largura da página 
	 */
	if (compWidth >= pageWidth) {
		double scale =  pageWidth / compWidth;
		g2d.scale(scale,scale);
		compHeight *= scale;
	}

	/* Redimensiona o graphics se a altura do componente for
	 * maior que a altura da página 
	 */
	if (compHeight >= pageHeight) {
		double scale =  pageHeight / compHeight;
		g2d.scale(scale,scale);
	}

	/* Now print the window and its visible contents */
	componentToPrint.printAll(g2d);

	g2d.dispose();

	return PAGE_EXISTS;
}

public void actionPerformed(ActionEvent e) {
	PrinterJob job = PrinterJob.getPrinterJob();
	job.setPrintable(this);
	boolean ok = job.printDialog();
	if (ok) {
		try {
			job.print();
		} catch (PrinterException ex) {
			/* The job did not successfully complete */
		}
	}
}

}[/code]Agora é questão de ir adaptando conforme as necessidades.

Só para lembrar, se for imprimir um JTable ou um JTextComponent, não precisa utilizar esta classe, basta chamar o método print(), que já foi implementado para este fim.

Falou…

Bom dia cara, primeiramente quero te agradecer por estar dedicando um grande tempo pra me ajudar, muito obrigado mesmo e desculpa pelo incômodo.

Bom, com relação ao que me passou, eu testei aqui e agora ele imprime a largura direitinho, ou seja, ele imprime a largura da janela que eu deixar, muito bom. Mas a altura aqui ele corta, não sei exatamente o que ele faz, mas percebi que ele imprime apenas a altura que é mostrado na tela, ou seja, caso eu role a página um pouco mais pra baixo e mando imprimir, ele imprime o que estou vendo. Parece que ele tira um print da janela e manda imprimir…

Não sei se quando vc testou ocorria o mesmo e gostaria de saber se sabes o pq isso acontece, ou seja, preciso alterar alguma coisa na classe pra ele pegar o conteúdo inteiro do JFram e não apenas o que é visto? Confesso que não entendi muitas partes da classe, e realmente não sei onde poderia alterar. Até te peço desculpas, pois vc mesmo disse que agopra era só ir adaptando, eu tentei mexer em alguns lugares na classe e testei mas nada…

Muito obrigado

Grande abraço…

é complicado para imprimir…, e nao deveria ser mas de uma olhadinha aqui: http://javafree.uol.com.br/topic-865229-Ajuda-a-imprimir-em-java.html

Valeu pela ajuda, mas esse link é pra impressão de textos de documentos e o que preciso é imprimir conteúdo de componentes swing.

Abraço.

Por nada. Impressão é um dos assuntos que estavam na minha lista de coisas para estudar em breve, só adiantei um pouco.

É mais ou menos por aí sim. O que a classe faz é desenhar no papel a área visível do componente.

Ele está imprimindo o JFrame inteiro sim, que está exibindo o JScrollPane, que está “cortando” o JPanel.

Se você não se importar de perder a decoração do JFrame, pode imprimir diretamente o JPanel que está dentro do JScrollPane. Assim, a impressão não sofrerá influência do scroll.

Testei o que vc sugeriu, ou seja, imprimir o JPanel, mas mesmo assim, não sei pq, ele imprime tudo como se fosse o JFrame.

Onde eu chamava assim:

btnImprimir.addActionListener(new ComponentPrinter(this));

Chamei de duas formas pra testar:

Imprimir.addActionListener(new ComponentPrinter((JPanel)this.getContentPane()));

e

Imprimir.addActionListener(new ComponentPrinter(pane)); //pane é meu JPanel como pode ver na minha classe.

Aqueles links que me passou eu li bem aquele último e percebi que tem alguma coisa sobre paginação, ou seja, tem uma forma de ir dizendo o que é pra imprimir, como se fosse alterando as coordenadas do conteúdo usando algo sobre “translate” e “setClip”. Tentei entender e testart uns exemplos mas nada…

Quando vc falou:

Fiquei pensando o seguinte, como o conteúdo do meu JFrame será algo em torno de 20 JTables, mesmo que ele conseguisse imprimir acredito que em termos de altura, devido à escala, iria ficar muito pequeno certo? Acho que o lance seria mesmo ter o esquema de paginação pra imprimir sem redução de escala com relação à altura.

Cara, que coisa bem complicada esta de imprimir quando tem bastante conteúdo…

E vou te dar a real, se não fosse a sua ajuda estaria travado, pois não consegui encontrar outras pessoas que já tivessem mexido com isso pra dar uma ajuda.

Se descobrir alguma coisa por favor, posta aí, pois farei o mesmo.

Muito obrigado novamente.

Grande Abraço.

Só lembrando que o getContentPane, retorna o container com conteúdo do JFrame, que possui o scrollPane dentro, por isso continua cortando.

Fiz um teste rápido com um panel com 150 labels uma abaixo da outra e só cortou quando foi impresso o scrollPane, quando foi impresso apenas o panel apareceram todas, ficaram miúdas como esperado, mas apareceram. (finja que as variáveis tem um nome descente :lol: )

[code] public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame(“Teste”);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

			JPanel p = new JPanel(new GridLayout(0, 1));
			for (int i=1;i<=150;i++) {
				p.add(new JLabel("Linha " + i));
			}
			
			JScrollPane s = new JScrollPane(p);
			f.getContentPane().add(s);
			
			JPanel p2 = new JPanel();
			JButton b = new JButton("Imprimir JFrame");
			b.addActionListener(new ComponentPrinter(f));
			JButton b2 = new JButton("Imprimir JScrollPane");
			b2.addActionListener(new ComponentPrinter(s));
			JButton b3 = new JButton("Imprimir JPanel");
			b3.addActionListener(new ComponentPrinter(p));
			
			p2.add(b);
			p2.add(b2);
			p2.add(b3);
			f.add(p2, BorderLayout.SOUTH);
			
			f.pack();
			f.setVisible(true);
		}
	});
}[/code]

Se for uma JTable só, pode usar o método print, que já exibe o diálogo de impressão, redimensiona, faz a paginação e imprime:

table.print();Porém se a questão é imprimir o JPanel, imagino que a solução seja desenvolver uma lógica para fazer a paginação mesmo.

Cara, muito estranho eu estar passando o pane direto como mostrei antes e mesmo assim imprimir tudo normal…

Bom, acho que a saída mesmo é paginar, senão vai ficar muito pequeno a altura…

Eu vou ler e estudar mais pra ver se consigo entender como funciona direitinho o lance da paginação e caso consiga alguma coisa eu posto aqui…

Caso vc resolva testar algo sobre paginação por gentileza, posta aí, pois estou precisando muito e como vc viu, o negócio é meio coplicadinho…

Muito obrigado por tudo por enquanto.

Abração.