我有一个应用程序,其图形被认为以 1024x768 显示。
我想让应用程序的大小灵活,而不需要重写所有绘图代码、位置计算等。
为了实现这一点,我尝试通过以下方式重写 JFrame 容器的绘制方法:
@Override
public void paint(Graphics g)
{
BufferedImage img = new BufferedImage(this.desiredWidth, this.desiredHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D gi = (Graphics2D) img.getGraphics();
gi.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
gi.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
gi.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
super.paint(gi);
gi.dispose();
((Graphics2D) g).drawImage(img, screenScale, null);
}
而 screenScale 是我在构造函数中创建的 AffineTransform 对象,它根据目标大小进行适当的缩放。
现在的问题是:我的子组件被绘制和缩放,但受到父 JFrame 的限制。因此,如果我的父框架的尺寸为 640x480,我添加到其中的子图层只能在其所绘制的 1024x768 BufferedImage 的 640x480 部分内进行绘制。 我猜想在某些地方子组件使用 JFrame 父组件的 getPreferredSize ,因为子组件始终将此值作为边界。所以最终我的缩放策略与 children 的绘画行为相冲突,因为他们完全忽略了他们所交付的用于绘画的图形对象的边界。
最后,无论我做什么,当目标尺寸小于我的“虚拟”屏幕尺寸时,我的子图层(如果重要的话,从 jpanel 派生)都会被切断。
任何人都可以提供更好的解决方案或提示我如何避免忽略图形边界的奇怪行为吗?
编辑:使用未缩放的输出、期望输出和结果输出更新上述代码的结果
expected output resulted output
更新:工作测试代码
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.print.attribute.standard.OrientationRequested;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class AffineTransformTest
{
private static TransformingFrame canvas;
private static JButton button;
private static TestLayer layer;
public static void main(String[] args)
{
canvas = new TransformingFrame();
canvas.addMouseWheelListener(new ScaleHandler());
layer=new TestLayer(canvas.originalSize);
canvas.getContentPane().add(layer);
layer.setVisible(true);
button = new JButton("asdf");
canvas.setUndecorated(true);
button.setVisible(true);
canvas.getContentPane().add(button);
canvas.pack();
canvas.setLayout(new BorderLayout());
canvas.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
canvas.setPreferredSize(canvas.originalSize);
canvas.setSize(canvas.originalSize);
canvas.setLayout(null);
canvas.setVisible(true);
canvas.validate();
}
@SuppressWarnings("serial")
private static class TransformingFrame extends JFrame
{
private double scale;
private final Dimension originalSize;
private AffineTransform tx = new AffineTransform();
TransformingFrame()
{
originalSize=new Dimension(800,600);
scale = 1;
}
@Override
public void paint(Graphics g)
{
BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
Graphics bufferGraphics=offscreenBuffer.getGraphics();
super.paint(bufferGraphics);
bufferGraphics.dispose();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
((Graphics2D) g).drawImage(offscreenBuffer, tx,null);
}
@Override
public void paintComponents(Graphics g)
{
BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
Graphics bufferGraphics=offscreenBuffer.getGraphics();
super.paintComponents(bufferGraphics);
bufferGraphics.dispose();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
((Graphics2D) g).drawImage(offscreenBuffer, tx,null);
}
@Override
public void paintAll(Graphics g)
{
BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
Graphics bufferGraphics=offscreenBuffer.getGraphics();
super.paintAll(bufferGraphics);
bufferGraphics.dispose();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
((Graphics2D) g).drawImage(offscreenBuffer, tx,null);
}
}
@SuppressWarnings("serial")
private static class TestLayer extends JPanel{
public TestLayer(Dimension originalSize)
{
this.setPreferredSize(originalSize);
this.setSize(originalSize);
setOpaque(false);
setDoubleBuffered(false);
}
@Override
public void paint(Graphics g)
{
Graphics2D ourGraphics = (Graphics2D) g;
super.paint(ourGraphics);
ourGraphics.setColor(Color.green);
ourGraphics.fillRect(0, 0, getWidth(), getHeight());
ourGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ourGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
ourGraphics.setColor(Color.BLACK);
ourGraphics.drawRect(50, 50, 50, 50);
ourGraphics.fillOval(100, 100, 100, 100);
ourGraphics.drawString("Test Affine Transform", 50, 30);
ourGraphics.drawString(canvas.tx.toString(), 50, 250);
}
}
private static class ScaleHandler implements MouseWheelListener
{
public void mouseWheelMoved(MouseWheelEvent e)
{
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL)
{
// make it a reasonable amount of zoom
// .1 gives a nice slow transition
canvas.scale += (.1 * e.getWheelRotation());
// don't cross negative threshold.
// also, setting scale to 0 has bad effects
canvas.scale = Math.max(0.00001, canvas.scale);
canvas.tx.setTransform(new AffineTransform());
canvas.tx.scale(canvas.scale, canvas.scale);
canvas.setPreferredSize(new Dimension((int)(canvas.originalSize.width*canvas.scale),(int)(canvas.originalSize.height*canvas.scale)));
canvas.setSize(new Dimension((int)(canvas.originalSize.width*canvas.scale),(int)(canvas.originalSize.height*canvas.scale)));
canvas.validate();
canvas.repaint();
}
}
}
}
由于某种原因,这段代码正在工作(除了按钮消失)..也许我的错误是在子层的其他地方..我会去调查
好吧,经过几个小时的摆弄,我得出的结论是,子面板在其 Paint(Graphics g) 方法中受到的绘图限制不允许绘制超过父面板的大小。在示例中它有效,但在完整的应用程序中则无效。似乎某些设置会在我的应用程序上强制执行该行为,但不会在演示应用程序上执行。
最佳答案
So if my parent frame has the dimension 640x480 the child layers that i have added to it can only draw inside a 640x480 fraction of the 1024x768
创建JFrame --> 放在那里JScrollPane --> 到 JScrollPane
中放置:
1) JPanel或 JComponent
覆盖 paintComponentn(Graphics g)
而不是 paint(Graphics g)
2) 你写了关于 BufferedImage
的内容,那么更好的方法是将 BufferedImage
写为 Icon到JLabel
关于java JFrame 具有虚拟绘图空间的缩放 UI 显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8403651/