JPanel custom drawing using Graphics - java

I have a custom JPanel and sometimes throughout my program, I need to call a method which paints the screen black, that's it.
public void clearScreen() {
Graphics g = getGraphics();
g.setColor(Color.black);
g.fillRect(0,0,getWidth(),getHeight());
}
When I launch the program, I call this method.
However, I find that sometimes it works, and sometimes it doesn't. It's very odd. I also found out that when it doesn't work, the graphics object is NOT null, and the width and height are also correctly defined (from getWidth() and getHeight()).
Why would this sometimes work and sometimes not work?
What is the correct way to make a custom drawing on my JPanel at some point in the program? Is it correct to use getGraphics() as I am doing? My JPanel (at some point) has JComponents, but later on I remove those JComponents and do some custom graphics drawing. Why would this sometimes only work?

Don't get your Graphics object by calling getGraphics on a component such as a JPanel since the Graphics object obtained will not persist on the next repaint (which is likely the source of your problems).
Instead, consider doing all of your drawing in a BufferedImage, and then you can use getGraphics() to your heart's content. If you do this, don't forget to dispose of the Graphics object when you're done painting with it.
e.g.,
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class MyPaint extends JPanel {
public static final int IMG_WIDTH = 400;
public static final int IMG_HEIGHT = IMG_WIDTH;
private BufferedImage image = new BufferedImage(IMG_WIDTH, IMG_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
public MyPaint() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(IMG_WIDTH, IMG_HEIGHT);
}
public void clearScreen() {
Graphics g = image.getGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.dispose();
repaint();
}
private class MyMouseAdapter extends MouseAdapter {
// code to draw on the buffered image.
// Don't forget to call repaint() on the "this" JPanel
}
}

Related

Graphics2d Rotation rotates all objects [duplicate]

I have searched everywhere and I just cant find the answer.
How do I rotate a Rectangle in java?
Here is some of my code:
package net.chrypthic.Space;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Space extends JPanel implements ActionListener{
Timer time;
public Space()
{
setVisible(true);
setFocusable(true);
addMouseMotionListener(new ML());
addMouseListener(new ML());
addKeyListener(new AL());
time=new Timer(5, this);
time.start();
}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.WHITE);
Rectangle rect2 = new Rectangle(100, 100, 20, 20);
g2d.draw(rect2);
g2d.fill(rect2);
}
public void actionPerformed(ActionEvent ae) {
repaint();
}
public class AL extends KeyAdapter
{
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
public class ML extends MouseAdapter
{
public void mouseMoved(MouseEvent e) {
}
public void mousePressed(MouseEvent e){
}
}
}
I tried g2d.rotate(100D); but it didnt work.
Thanks in advance.
Here's my edited code:
package net.chrypthic.Space;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Space extends JPanel implements ActionListener{
Timer time;
public Space()
{
setVisible(true);
setFocusable(true);
setSize(640, 480);
setBackground(Color.BLACK);
time=new Timer(5, this);
time.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
Rectangle rect1 = new Rectangle(100, 100, 20, 20);
g2d.setColor(Color.WHITE);
g2d.translate(rect1.x+(rect1.width/2), rect1.y+(rect1.height/2));
g2d.rotate(Math.toRadians(90));
g2d.draw(rect1);
g2d.fill(rect1);
}
public void actionPerformed(ActionEvent e)
{
repaint();
}
}
For images you have to use drawImage method of Graphics2D with the relative AffineTransform.
For shape you can rotate Graphics2D itself:
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.WHITE);
Rectangle rect2 = new Rectangle(100, 100, 20, 20);
g2d.rotate(Math.toRadians(45));
g2d.draw(rect2);
g2d.fill(rect2);
}
And btw, you should override paintComponent method instead of paint.
Citing JComponent's API:
Invoked by Swing to draw components. Applications should not invoke
paint directly, but should instead use the repaint method to schedule
the component for redrawing.
This method actually delegates the work of painting to three
protected methods: paintComponent, paintBorder, and paintChildren.
They're called in the order listed to ensure that children appear on
top of component itself. Generally speaking, the component and its
children should not paint in the insets area allocated to the border.
Subclasses can just override this method, as always. A subclass that
just wants to specialize the UI (look and feel) delegate's paint
method should just override paintComponent.
Remember also than when you perform an affine transformation, like a rotation, the object is implicitly rotated around the axis origin. So if your intent is to rotate it around an arbitrary point, you should before translating it back to the origin, rotate it, and then re-traslating it to the desired point.
public void draw(Graphics2D g) {
Graphics2D gg = (Graphics2D) g.create();
gg.rotate(angle, rect.x + rect.width/2, rect.y + rect.height/2);
gg.drawRect(rect.x, rect.y, rect.width, rect.height);
gg.dispose();
gg = (Graphics2D) g.create();
... other stuff
}
Graphics.create() and Graphics.dispose() allow you to save the current transformation parameters (as well as current font, stroke, paint, etc), and to restore them later. It is the equivalent of glPushMatrix() and glPopMatrix() in OpenGL.
You can also apply an inverse rotation once you drew the rectangle to revert the transformation matrix back to its initial state. However, floating point approximations during substractions may lead to a false result.
Another way is by using Path2D, with it you can rotate the path only and not the entire graphics object:
Rectangle r = new Rectangle(x, y, width, height);
Path2D.Double path = new Path2D.Double();
path.append(r, false);
AffineTransform t = new AffineTransform();
t.rotate(angle);
path.transform(t);
g2.draw(path);
The only problem with g2d.rotate is that it doesn't rotate it around a specific point. It will mostly mess up where you want your Image and then force you to move the x and y coordinates of the image. I would not use it,expecially for a game. What you should look into is rotating a point in java.

Why does this not show my circle in the window? [duplicate]

I have a JPanel for which I set some image as the background. I need to draw a bunch of circles on top of the image. Now the circles will be positioned based on some coordinate x,y, and the size will be based on some integer size. This is what I have as my class.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
class ImagePanel extends JPanel {
private Image img;
CircleList cList; //added this
public ImagePanel(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
cList = new CircleList(); //added this
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
cList.draw(null); //added this
}
}
How can I create some method that can performed this?
Your approach can be something similar to this, in which you use a class CircleList to hold all the circles and the drawing routine too:
class CircleList
{
static class Circle
{
public float x, y, diameter;
}
ArrayList<Circle> circles;
public CirclesList()
{
circles = new ArrayList<Circle>();
}
public void draw(Graphics2D g) // draw must be called by paintComponent of the panel
{
for (Circle c : circles)
g.fillOval(c.x, c.y, c.diameter, c.diameter)
}
}
Easiest thing to do would be to place something along these lines into your paintComponent method.
int x = ...;
int y = ...;
int radius = ...;
g.drawOval(x, y, radius, radius);
Well, you will probably want to create an ArrayList to store the information about the circles to be drawn. Then when the paintComponent() method is invoked you just loop through the ArrayList and draw the circles.
Custom Painting Approaches shows how this might be done for a rectangle. You can modify the code for an oval as well you would probably add methods to update the Array with the location information rather than by doing it dynamically.
Have you looked at JXLayer? It's an awesome library that allows you to layer special painting on top of any GUI element in an obvious way. I believe that will be included in the main java libraries for JDK7

Create a curved window [duplicate]

How could I make non-rectangular windows with soft borders in Java?
Soft borders (also known as soft clipping) are borders without aliasing artifacts.
I searched the web a lot and found several posts about translucent and/or
non-rectangular windows.
The topic "soft border" is confusing. It seems that the information I found deals
with applying soft borders to component which are inside another Java components.
But, can I, or can I not apply soft borders to custom shaped JWindow which is
placed just on the desktop?
I am primely referring to following post:
http://today.java.net/pub/a/today/2008/03/18/translucent-and-shaped-swing-windows.html
When it comes to soft clipping, the article forwards to
http://weblogs.java.net/blog/campbell/archive/2006/07/java_2d_tricker.html
But here, soft clipping on an existing Graphics2D object is described.
Here's my take on a soft-clipped, shaped, top-level window. Note: shaped windows use a proprietary API (com.sun.awt.AWTUtilities) and is not guaranteed to work on non-Sun JVMs. However, in JDK 7 it becomes part of the Window class.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MySoftClippedWindow extends JPanel {
public MySoftClippedWindow() {
super();
setLayout(new GridBagLayout());
JButton button = new JButton(new AbstractAction("Close") {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
button.setOpaque(false);
add(button);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
// Create a soft clipped image for the background
BufferedImage img = java_2d_tricker(g2d, width, height);
g2d.drawImage(img, 0, 0, null);
g2d.dispose();
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JWindow w = new JWindow();
Container cp = w.getContentPane();
cp.setLayout(new BorderLayout());
cp.add(new MySoftClippedWindow());
w.setAlwaysOnTop(true);
com.sun.awt.AWTUtilities.setWindowOpaque (w, false);
w.setSize(200, 200);
w.setVisible(true);
}
});
}
/*
* This code is taken from
* http://weblogs.java.net/blog/campbell/archive/2006/07/java_2d_tricker.html
*/
private BufferedImage java_2d_tricker(Graphics2D g2d, int width, int height) {
GraphicsConfiguration gc = g2d.getDeviceConfiguration();
BufferedImage img = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
Graphics2D g2 = img.createGraphics();
g2.setComposite(AlphaComposite.Clear);
g2.fillRect(0, 0, width, height);
g2.setComposite(AlphaComposite.Src);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.WHITE);
g2.fillOval(width / 4, height / 4, width / 2, height / 2);
g2.setComposite(AlphaComposite.SrcAtop);
g2.setPaint(new GradientPaint(0, 0, Color.RED, 0, height, Color.YELLOW));
g2.fillRect(0, 0, width, height);
g2.dispose();
return img;
}
}
Have you read this article:
http://www.pushing-pixels.org/?p=272
It mentions soft clipping and the previous articles you mentioned, but also includes some source code to implement a soft clipped window, the direct link is here:
http://www.pushing-pixels.org/wp-content/uploads/2008/03/softclippedwindow.java
That should provide you with a possible solution for what you want to do.
import java.awt.*;
public class First extends Applet
{
public void paint(Graphics g)
{
g.drawRect(100,50,500,800);
}
}
/*<Applet code="First.class"height=500 width=500>
</Applet>
*/

Incorrect behavior of JPanel#paintChildren(Graphics) when a JMenu is present?

What I want to do:
Create a JPanel's subclass to draw a simple overlay on top of contained components.
Why don't I use JLayeredPane?
See JComponent#isOptimizedDrawingEnabled().
When a JMenu is present in a JFrame, adding a JPanel with an overridden paintChildren(Graphics) method, an incorrect coordinate starting point is provided in the passed Graphics object, as observed with this code sample:
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public final class Sscce {
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
// a normal frame
JFrame f = new JFrame();
// set up a simple menu
JMenuBar mb = new JMenuBar();
JMenu m = new JMenu("Test");
JMenuItem mi = new JMenu("Whatever");
m.add(mi);
mb.add(m);
f.setJMenuBar(mb);
// a panel with a simple text overlay over components.
// works much faster than JLayeredPane, which doesn't have
// isOptimizedDrawingEnabled()
JPanel p = new JPanel() {
#Override
public void paint(Graphics g) {
// I'm not so stupid to draw stuff here
super.paint(g);
// JavaDoc: delegates to paintComponent, paintBorder, paintChildren
// in that order
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// it is common knowledge that children are painted after parent
Graphics tmp = g.create();
try {
tmp.setColor(Color.MAGENTA);
tmp.fillRect(0, 0, getWidth(), getHeight());
} finally {
tmp.dispose();
}
}
#Override
protected void paintChildren(Graphics g) {
super.paintChildren(g);
// draw some text
FontMetrics fm = g.getFontMetrics();
// will be drawn outside panel; under menu
g.drawString("TEST TOP/LEFT", 0 + getX(), 0 + getY());
final String s = "TEST BOTTOM/RIGHT";
// will be drawn noticeably above the bottom
g.drawString(s,
getWidth() - fm.charsWidth(s.toCharArray(), 0, s.length()),
getHeight() - fm.getHeight());
}
};
// add something to the panel
p.add(new JTextArea(10, 15));
f.add(p);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
} catch (Throwable t) {
// this is a SSCCE
}
}
}
The first string is drawn outside of JPanel (under the JMenu), even though both coordinates are non-negative.
The second string is NOT drawn at the bottom right corner. It is pushed up by the height of the JMenu.
Image
Even though:
When AWT invokes this method, the Graphics object parameter is pre-configured with the appropriate state for drawing on this particular component:
The Graphics object's color is set to the component's foreground
property.
The Graphics object's font is set to the component's font
property.
The Graphics object's translation is set such that the
coordinate (0,0) represents the upper left corner of the component.
The Graphics object's clip rectangle is set to the area of the
component that is in need of repainting.
Programs must use this Graphics object (or one derived from it) to render output. They are free to change the state of the Graphics object as necessary.
What am I doing wrong?
The first string is drawn outside of JPanel (under the JMenu), even though both coordinates are non-negative. The second string is NOT drawn at the bottom right corner. It is pushed up by the height of the JMenu.
In both cases, note that drawString() expects the coordinates to represent the baseline of the String. The font;s ascent and descent are useful in this context. It may be a coincidence that mb.getHeight() and fm.getHeight() are of comparable magnitude.
#Override
protected void paintChildren(Graphics g) {
super.paintChildren(g);
// draw some text
FontMetrics fm = g.getFontMetrics();
// will be drawn outside panel; under menu
g.drawString("TEST TOP/LEFT", 0, fm.getAscent());
final String s = "TEST BOTTOM/RIGHT";
// will be drawn noticeably above the bottom
g.drawString(s, getWidth() - fm.stringWidth(s),
getHeight() - fm.getDescent());
}

java JFrame scaled UI display with virtual drawing space

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.
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
create JFrame --> put there JScrollPane --> to the JScrollPane put :
1) JPanel or JComponent with override paintComponentn(Graphics g) not paint(Graphics g)
2) you wrote about BufferedImage, then better way is put BufferedImage as Icon to the JLabel
As you've observed, a component can be rendered in a scaled graphics context, but the result is effectively useless: the UI delegate has no knowledge of the altered geometry. As #mKorbel suggests, a JScrollPane is the traditional alternative.
You might also look at the scheme used in this game or the technique used in this scalable label. If you are willing to make your own components, you may be able to adapt the approach shown in this ScaledView.
My problem got completely solved after asking some ppl about this.
The solution was:
1.
Create a new Class which you can draw on and make the manipulation there, example:
private class ScaledPane extends JPanel
{
public ScaledPane(Window parent)
{
super();
setPreferredSize(new Dimension(parent.getDesiredWidth(), parent.getDesiredHeight()));
setSize(this.getPreferredSize());
}
#Override
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g.create(0, 0, getWidth(), getHeight());
g2.setTransform(screenScale);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); //
System.out.println(g2.getClip());
super.paint(g2);
}
}
after that set an instance of that class to your contentpane:
setScreenScale(AffineTransform.getScaleInstance((double) width / (double) desiredWidth, (double) height / (double) desiredHeight));
setContentPane(new ScaledPane(this));
after doing that everything just went fine, as the components of the window us the contentpanes paint method to draw themselves with the new graphics object that is set there
With that done i can scale my window to any desired size without manipulation of the movement formulas or positions of any child.

Categories