i have an application that has graphics which are thought to be displayed at 1024x768.
I want to make the application flexible in size without rewriting all drawing code, position calculation etc..
To achieve that my attempt was overriding the paint method of the JFrame container in the following way:
@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);
}
while screenScale is an AffineTransform Object i created in the constructor which does the appropriate scaling according to the target size.
The problem now is: My child components get drawn and scaled, but with the limitations of the parent JFrame. 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 BufferedImage that it is painting on. I guess in some place the child components use getPreferredSize of the JFrame parent, because the child always has this values as bounds. So in the end my scaling strategy is in conflict with the painting behavior of the childs, because they fully ignore the bounds of the graphics object they get delivered for drawing on.
In the end, what ever i do, my child layers (derived from jpanel if that matters) get cut off when the target size is smaller than my "virtual" screen size.
Can anyone provide a better solution or hints how i can circumvent the strange behavior that the graphics bounds are ignored?
Edit: updated outcome of above code with unscaled output, expectet output and resulting output
expected output resulted output
update: working test code
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();
}
}
}
}
for some reason this code is working (except the button disappearing).. maybe my error is somewhere else in the child layers.. i'll go investigate that
Okay after some hours fiddling around with it, i came to the conclusion that the drawing limitations that the child panels get in their paint(Graphics g) method don't allow painting more than the parent's size. In the example it works but in the full application not. Seems some settings force that behaviour on my application, but not the demo app.