英文:
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.
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!
When I pass JPanel as the component then it only prints the print button!
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));
通过这些修复,现在输出...
我也认为 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...
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论