在我的节目,我经常需要打印各种JComponents(一般JPanels),我想他们是整版。 我现在做的方法是使用下面的代码:
g2d.scale(pf.getImageableWidth()/componentToPrint.getWidth(), pf.getImageableHeight()/componentToPrint.getHeight());
但是这往往绵延或以其他方式发生变形不管我试图打印,我会更喜欢做一些调整大小智能,也许功能的版本:
componentToPrint.setSize(pf.ImageableWidth(), pf.ImageableHeight);
或者说添加组件到一个新的JFrame,然后设置帧大小(问题是组件不能在两处存在在一次)。 我不会介意的大小调整将使GUI的其他人看起来很可怕,只要它是什么,可以很容易地被重置。
有没有办法做到这一点?
我认为你正在寻找的解决方案是构建一个包含所需内容的新JPanel并打印复印件。 如果你这样做使用的CellRendererPane你可以得到它听起来像你正在寻找的确切大小调整行为。
如果您JComponents得到合理写得那么它不应该是新的一个新的一个问题,并设置其模式是跟原来一样的。
CellRendererPane cellRendererPane = new CellRendererPane();
// It's important to add the cell renderer pane to something
// you can use the same one for all of your exporting if you like and just
// add it to your main frame's content pane - it won't show up anywhere.
add(cellRendererPane);
JPanel printPanel = createCopy(panel);
cellRendererPane.paintComponent(g, printPanel, null, 0, 0, exportDim.width, exportDim.height, true);
下面是一个完整的工作示例。 该createPanel()方法应该创建它是任何组件,要渲染。 一个真实的例子应该是一定要使用相同的模型,而不是再造一个新模式暴殄天物组件。
public class SCCE {
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
final JFrame f = new JFrame("SCCE");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(SCCE.createPanel());
final CellRendererPane backgroundRenderer = new CellRendererPane();
// Add the renderer somewhere where it won't be seen
f.getContentPane().add(backgroundRenderer, BorderLayout.NORTH);
f.getContentPane().add(createSaveButton(backgroundRenderer), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// Create your custom component from whatever model here..
private static final Component createPanel() {
DefaultListModel model = new DefaultListModel();
for (int i = 0; i < 10; i++) {
model.addElement("Item number " + i);
}
return new JList(model);
}
private static JButton createSaveButton(final CellRendererPane backgroundRenderer) {
return new JButton(new AbstractAction("Save image to file") {
@Override
public void actionPerformed(ActionEvent e) {
Dimension d = new Dimension(400, 300);
BufferedImage img = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
backgroundRenderer.paintComponent(g, createPanel(), null, 0, 0, d.width, d.height, true);
g.dispose();
try {
File output = new File("test.png");
System.err.println("Saved to " + output.getAbsolutePath());
ImageIO.write(img, "png", output);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
}
我认为你面临的问题无关,与规模化经营。 这是你的逻辑是不正确。 在大多数情况下,你的X和Y比例会有所不同,因为可成像和规模,您的组件的规模将是不一样的。 这是你的组件是规模化经营后扭曲的原因。 你必须做一些事情,如:
double factorX = pf.getImageableWidth() / component.getWidth();
double factorY = pf.getImageableHeight() / component.getHeight();
double factor = Math.min( factorX, factorY );
g2.scale(factor,factor);
之后,你可以在你的图片到合适的坐标,根据它的新的大小转换。 希望能帮助到你...
我将重构绘图代码出的paintComponent()
的执行的方法JPanel
到在面板中的公共/封装保护方法,其可以绘制成任意Graphics
对象的任何宽度/高度(大概是,附图代码是一般的,足够)。
这个例子中有一个框架,包含面板,其具有一些绘图逻辑(大X,所述面板的尺寸)。 这个例子的主要方法显示了一种方式来获得图像并将其写入文件,即使图像尺寸比面板的大小不同。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MockFrame extends JFrame {
// throws Exception, as just an example (not really advised to do this)
public static void main(String[] args) throws Exception {
MockFrame frame = new MockFrame();
frame.setVisible(true);
// different sizes from the frame
int WIDTH = 500;
int HEIGHT = 500;
BufferedImage b = new BufferedImage(WIDTH, HEIGHT,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) b.getGraphics();
// should set some background, as the panel's background
// is dealt with by super.paintComponent()
g2d.setBackground(Color.white);
frame.getPanel().drawingLogic(b.getGraphics(), WIDTH, HEIGHT);
ImageIO.write(b, "png", new File("test.png"));
}
private MockPanel panel;
public MockFrame() {
this.setSize(200, 200);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new MockPanel();
getContentPane().add(panel);
}
public MockPanel getPanel() {
return panel;
}
private class MockPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
drawingLogic(g, getWidth(), getHeight());
}
public void drawingLogic(Graphics g, int width, int height) {
g.setColor(Color.black);
g.drawLine(0, 0, width, height);
g.drawLine(0, height, width, 0);
}
}
}
这允许对象外部的GUI挂接到其绘图算法。 一个缺点我看到的是,您将创建想面板打印到实际执行的面板中的任意对象之间的依赖关系。 但它仍然比调整上飞板(我已经试过了,似乎有一些问题更好-我认为这需要一些时间setSize()
更改为传播。
编辑:
响应于该评论,我提供了上面的片段的代码的修改版本。 这可能是不这样做的最佳方式,而不是很方便(这样我就不会在最终用户的应用程序中使用),但它确实根据的布局管理器的规则框架调整一切。
/* This code snippet describes a way to resize a frame for printing at
* a custom size and then resize it back.
*
* Copyright (C)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import java.awt.Container;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class MockFrame extends JFrame {
// throws Exception, as just an example (not really advised to do this)
public static void main(String[] args) throws Exception {
final MockFrame frame = new MockFrame();
frame.setVisible(true);
// different sizes from the frame
final int WIDTH = 500;
final int HEIGHT = 700;
final BufferedImage b = new BufferedImage(WIDTH, HEIGHT,
BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = (Graphics2D) b.getGraphics();
final int previousWidth = frame.getWidth();
final int previousHeight = frame.getHeight();
frame.setSize(WIDTH, HEIGHT);
frame.repaint();
JOptionPane.showMessageDialog(null,
"Press OK when the window has finished resizing");
frame.print(g2d);
frame.setSize(previousWidth, previousHeight);
ImageIO.write(b, "png", new File("test.png"));
}
public MockFrame() {
this.setSize(200, 200);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
boolean shouldFill = true;
boolean shouldWeightX = true;
Container pane = getContentPane();
// code from
// http://java.sun.com/docs/books/tutorial/uiswing/layout/gridbag.html
// just to add some components in the frame... :)
// left out in here for brevity
}
}
码基本上调整大小的帧,向用户显示一个确认消息,以便该线程可以被阻止,直到重画完成(可通过进行Thread.sleep()
,但它使用消息的更透明的)。 然后它打印框架和调整其大小恢复到原来的形状。 哈克了一点,但它的工作原理。
-- Flaviu Cipcigan
我想你回答了你自己的问题。 每个组件都有一个方法:
setSize(int width, int height);
文章来源: Resizing JPanel to prepare for printing without removing it from its original position