JPanel打印附加的画布显示为空白。

huangapple go评论71阅读模式
英文:

JPanel print attached canvases shows up as blank

问题

I am trying to help my son do math, so I made a small program.
我正在尝试帮助我的儿子做数学,所以我做了一个小程序。

I have a JPanel with 12 Canvases and a giant print button on the bottom.
我有一个包含12个画布和底部巨大打印按钮的JPanel。

This is the listener I have attached to my print button.
这是我附加到打印按钮的监听器。

I have followed an example from here, and sadly, it doesn't work.
我已经按照这里的示例做了,但遗憾的是它不起作用。

When I pass JFrame as the component, it prints the whole window!
当我将JFrame作为组件传递时,它会打印整个窗口!

When I pass JPanel as the component, it only prints the print button!
当我将JPanel作为组件传递时,它只打印打印按钮!

If it is of any relevance, I attach everything to the JFrame and JPanel like so:
如果相关的话,我会像这样将所有东西附加到JFrame和JPanel上:

I have even tried following examples from here and here, and nothing works.
我甚至尝试过按照这里这里的示例操作,但什么都不起作用。

I can't seem to just print JPanel with the canvas showing up, and I sure as heck do not want to print the whole window.
我似乎无法只打印出带有显示的画布的JPanel,而且我肯定不想打印整个窗口。
Any advice on how to fix this?
有关如何解决这个问题的建议吗?

Here is a small example code with the same problem.
这是一个具有相同问题的小示例代码。

英文:

I am trying to help my son do math, so I made a small program.
I have a JPanel with 12 Canvases and a giant print button on the bottom.

JPanel打印附加的画布显示为空白。

This is the listener I have attached on my print button.

	print.addActionListener(new ActionListener()
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			panel.remove(print);
			window.pack();
			printComponent(panel, false);
			panel.add(print);
			window.pack();
		}
	});

I have followed example from here and sadly it doesn't work.
When I pass JFrame as the component then it prints the whole window!
JPanel打印附加的画布显示为空白。
When I pass JPanel as the component then it only prints the print button!
JPanel打印附加的画布显示为空白。

If it is of any relevance I attach everything to the JFrame and JPanel like so:

panel.setBackground(Color.WHITE);
panel.setLayout(/*layout stuff*/);
window.setContentPane(panel);
for (int i = 0; i < 12; i++)
{
	panel.add(/*canvas class which renders one single question*/);
}
panel.add(print, /*layout constraints*/);

I have even tried following examples from here and here and nothing works.
I can't seem to just print jpanel with the canvas showing up, and I sure as heck do not want to print the whole window.
Any advice on how to fix this?

Here is small example code with same problem.

package carefree.school;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.io.File;
import java.io.IOException;

public class TestWindow
{
	public static void main(String[] args)
	{
		JFrame frame = new JFrame();
		JPanel panel = new JPanel();
		Canvas canvas = new Canvas()
		{
			@Override
			public void paint(Graphics g)
			{
				super.paint(g);
				g.drawOval(3, 3, 94, 94);
			}
		};
		canvas.setSize(100, 100);
		JButton print = new JButton("Print");
		frame.setContentPane(panel);
		panel.add(canvas);
		panel.add(print);
		frame.setVisible(true);
		frame.pack();
		print.addActionListener(e -> printComponentToFile(panel, false));
	}

	public static void printComponentToFile(Component comp, boolean fill)
	{
		Paper paper = new Paper();
		paper.setSize(8.3 * 72, 11.7 * 72);
		paper.setImageableArea(18, 18, 559, 783);

		PageFormat pf = new PageFormat();
		pf.setPaper(paper);
		pf.setOrientation(PageFormat.PORTRAIT);

		BufferedImage img = new BufferedImage((int) Math.round(pf.getWidth()), (int) Math.round(pf.getHeight()),
											  BufferedImage.TYPE_INT_RGB);

		Graphics2D g2d = img.createGraphics();
		g2d.setColor(Color.WHITE);
		g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
		ComponentPrinter cp = new ComponentPrinter(comp, fill);
		try
		{
			cp.print(g2d, pf, 0);
		}
		finally
		{
			g2d.dispose();
		}

		try
		{
			ImageIO.write(img, "png", new File("Page-" + (fill ? "Filled" : "") + ".png"));
		}
		catch (IOException ex)
		{
			ex.printStackTrace();
		}
	}

	public static class ComponentPrinter
			implements Printable
	{
		private Component comp;
		private boolean   fill;

		public ComponentPrinter(Component comp, boolean fill)
		{
			this.comp = comp;
			this.fill = fill;
		}

		@Override
		public int print(Graphics g, PageFormat format, int page_index)
		{
			if (page_index > 0)
			{
				return Printable.NO_SUCH_PAGE;
			}

			Graphics2D g2 = (Graphics2D) g;
			g2.translate(format.getImageableX(), format.getImageableY());

			double width  = (int) Math.floor(format.getImageableWidth());
			double height = (int) Math.floor(format.getImageableHeight());

			if (!fill)
			{

				width = Math.min(width, comp.getPreferredSize().width);
				height = Math.min(height, comp.getPreferredSize().height);

			}

			comp.setBounds(0, 0, (int) Math.floor(width), (int) Math.floor(height));
			if (comp.getParent() == null)
			{
				comp.addNotify();
			}
			comp.validate();
			comp.doLayout();
			comp.printAll(g2);
			if (comp.getParent() != null)
			{
				comp.removeNotify();
			}

			return Printable.PAGE_EXISTS;
		}
	}
}

答案1

得分: 1

First, 不要使用 Canvas 进行这项操作,我不确定它是否适合“打印”,或者至少,它对我不起作用。

Instead, 可以选择从 JPanel 扩展...

JPanel canvas = new JPanel() {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawOval(3, 3, 94, 94);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(100, 100);
    }
};

Second, 要谨慎选择要打印的组件,例如,在您的可运行代码中,您正在传递 panel,这将打印按钮和圆圈,实际上,您应该只需传递 canvas

print.addActionListener(e -> printComponentToFile(canvas, false));

通过这些修复,现在输出...

JPanel打印附加的画布显示为空白。

我也认为 if (comp.getParent() != null) { 是一个错误,而应该是 if (comp.getParent() == null) {

在打印组件后,您可能还需要调用

comp.revalidate();
comp.repaint();

但这只是尝试打印“活动”组件的众多问题之一。

个人而言,我创建了一个“可渲染问题”的概念,它可以传递一个应该渲染到其中的 Graphics 上下文。

然后,您可以创建一个“可渲染问题表”,它将绘制多个“问题”。

这可以由自定义组件和 Printable 独立使用,但这只是我的建议。

英文:

First, Don't use Canvas for this, I'm not sure it's "printable", or at the very least, it didn't work for me.

Instead, extend from JPanel instead...

JPanel canvas = new JPanel() {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawOval(3, 3, 94, 94);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(100, 100);
    }
};

You should also avoid call setBounds and prefer to provide sizing hints instead.

Second, choose the component you want to print carefully, for example, in your runnable code, you're passing panel, which will print both the button and the circle, instead, you should really only need to pass canvas

print.addActionListener(e -> printComponentToFile(canvas, false));

With these couple of fixes, it now outputs...

JPanel打印附加的画布显示为空白。

I also thing that if (comp.getParent() != null) { is a mistake and instead should be if (comp.getParent() == null) {

You may also need to call

comp.revalidate();
comp.repaint();

after you've printed the component, but this is one of the many issues with trying to print a "live" component.

Personally, I create a concept of a "renderable question", which could be passed a Graphics context onto which it should be rendered.

You could then create a "renderable question sheet" which would paint multiple "questions".

This could then be used by both a custom component and Printable independently, but that's me.

huangapple
  • 本文由 发表于 2023年5月17日 10:55:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76268285.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定