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>
*/
Related
How can I customize a JDialog with round corners, no title, and no control buttons. Like the one below.
As with most things in life, this is an illusion.
You're actually asking three questions...
How to remove a windows decorations
How to make a window transparent
How to draw a "rounded" rectangle
All of things are relatively easy to do, knowing you need to them, that's another issue.
So, for the first two...
JDialog dialog = new JDialog();
dialog.setUndecorated(true);
dialog.setBackground(new Color(0, 0, 0, 0));
dialog.setModal(true);
dialog.setSize(640, 480);
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
You need to remove the window decorations and set the background to a transparent color. If you run the above code, you will see, nothing, kind of spooky actually. That's because the window has not decorations and is transparent.
The next step will require a custom component. Again, this is an illusion. We're going to make the component transparent, BUT, we're going to manually fill it.
public class RoundedPane extends JPanel {
private int radius = 20;
public RoundedPane() {
setOpaque(false);
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new BorderLayout());
}
public void setRadius(int radius) {
this.radius = radius;
setBorder(new EmptyBorder(radius / 2, radius / 2, radius / 2, radius / 2));
revalidate();
repaint();
}
public int getRadius() {
return radius;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground());
g2.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, getRadius(), getRadius());
g2.setColor(getForeground());
g2.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, getRadius(), getRadius());
super.paintComponent(g);
}
}
So, simply put, this will create a JPanel, make it transparent (setOpaque(false)) and then override it's paintComponent so we can paint our rounded effect.
Now, if you put it altogether, you'll end up with something looking like this...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JDialog dialog = new JDialog();
dialog.setUndecorated(true);
dialog.setBackground(new Color(0, 0, 0, 0));
dialog.setModal(true);
dialog.setContentPane(new RoundedPane());
dialog.setSize(640, 480);
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
}
});
}
public class RoundedPane extends JPanel {
private int radius = 20;
public RoundedPane() {
setOpaque(false);
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new BorderLayout());
}
public void setRadius(int radius) {
this.radius = radius;
setBorder(new EmptyBorder(radius / 2, radius / 2, radius / 2, radius / 2));
revalidate();
repaint();
}
public int getRadius() {
return radius;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground());
g2.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, getRadius(), getRadius());
g2.setColor(getForeground());
g2.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, getRadius(), getRadius());
super.paintComponent(g);
}
}
}
So, some immediate notes about the above example.
I've used setSize for this example deliberately. The RoundedPane should defer calculating the required size based on the Border and it's content, so we don't want to modify it, but since it will gave a preferred size of 0x0, I set the size of the dialog myself. You should rely on pack to get a better effect.
I've set RoundedPane to be dialog's contentPane. This will allow you to continue to add content directly to the dialog like you normally would. You can add content directly to the RoundedPane, but this also ensures that the existing contentPane doesn't interfere with our work.
You should also have a look at:
How to Create Translucent and Shaped Windows
The JFrame JavaDocs
The 2D Graphics Trail
Performing Custom Painting and Painting in AWT and Swing
in this way i found this undecorated all the font type change ,how can i set font type in whole dialog.
The font is managed by the installed look and feel. If you do have issues with the font then either, you've done something wrong it's a platform specific issue (ie a bug)
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.
When using AffineTransform in Java, it gets applied to everything drawn onto the Graphics object. It affects for example the width of lines or flips around the text and makes it much larger.
This is an example:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
public class Test extends JFrame {
public Test() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
add(new DrawPanel());
pack();
}
private class DrawPanel extends JComponent {
public DrawPanel() {
setPreferredSize(new Dimension(1200, 600));
}
#Override
protected void paintComponent(Graphics g) {
AffineTransform scale = AffineTransform.getScaleInstance(1200 / 360.0, 600 / 180.0);
AffineTransform mirrorY = new AffineTransform(1, 0, 0, -1, 0, 600);
AffineTransform worldToPixel = new AffineTransform(mirrorY);
worldToPixel.concatenate(scale);
Graphics2D g2 = (Graphics2D) g;
g2.setTransform(worldToPixel);
g2.setColor(Color.RED);
g2.drawString("50x50", 50, 50);
g2.drawString("100x100", 100, 100);
}
}
public static void main(String[] args) {
Test test = new Test();
test.setVisible(true);
}
}
The translation of the coordinates works perfectly: On a 1200x600 pixel component, the above transformation puts 0,0 in the lower left corner and 360,180 in the upper right corner. But the text is mirrored and stretched, too. Also, lines get thicker because of the "scale" transformation.
Text flipped and stretched
Is there a way to prevent AffineTransform to get applied on text and line styles? So that it works only on coordinates and not on styles?
Hello im trying to make a simple background split in half using a Jframe
How do i make the background move and adjust with my opened window.
import javax.swing.JFrame;
public class Concert
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(1000, 800);
frame.setTitle("Concert!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Concertbackground component = new Concertbackground();
frame.add(component);
frame.setVisible(true);
}
}
Background: Ignore all the other imported things for now please.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
import java.awt.GradientPaint;
/*
component that draws the concert background
*/
public class Concertbackground extends JComponent
{
public void paintComponent(Graphics g)
{
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
//Background Top
g2.setColor(Color.BLUE);
Rectangle backgroundTop = new Rectangle (0, 0, 1000, 400);
g2.fill(backgroundTop);
// Background bottom
g2.setColor(Color.GREEN);
Rectangle backgroundBottom = new Rectangle (0, 400, 1000, 800);
g2.fill(backgroundBottom);
}
}
First, beware, that by default JComponent is transparent (this is very important for the next part).
Second, you should be calling super.paintComponent to ensure that the graphics context you are about to paint to has being prepared properly...
Thirdly, you shouldn't be relying on magic numbers...
For example...
public class Concertbackground extends JComponent
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
//Background Top
g2.setColor(Color.BLUE);
Rectangle backgroundTop = new Rectangle (0, 0, getWidth(), getHeight() / 2);
g2.fill(backgroundTop);
// Background bottom
g2.setColor(Color.GREEN);
Rectangle backgroundBottom = new Rectangle (0, getHeight() / 2, getWidth(), getHeight() / 2);
g2.fill(backgroundBottom);
}
}
If your intention is to use the component as the background of the frame, you should consider using JFrame#setContentPane instead of adding it to the frame...
How do i make the background move and adjust with my opened window.
Don't hardcode values. Use:
int width = getWidth();
int height = getHeight();
Then you can paint the top part the full width and the height from 0 to height / 2.
And the bottom part would be the full width with the height from height /2 to height.
Also, don't forget to set a layout manager for this component so you can add other components to it. Typically the main panel of the frame would use a BorderLayout.
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.