I've just finished a 2D vector/transformation library that I want to use on a simple example. I have a main loop that runs efficiently and update/render methods. I've always tried to understand what people are talking about when they use Java2D or jPanels or jFrames, but none of it makes sense to me.
I've made some 2D examples before, but it is using a jFrame with a Threaded canvas that I made when following a youtube tutorial. Its problem is that it is basically an integer array that allows for individual pixel setting and you can only use integers as positions, not floats like my library uses.
so my question is: how would I go about making a simple opening/closing window, that I can draw a sprite (should sprites just be some sort of slickUtil loaded thing, or will I have to load in individual pixels as I did before?) to, and that accepts float values for Cartesian coordinates with the origin at the centre.
Derive a class from JComponent and override the paintComponent method. It gets passed a Graphics object that can be cast into a Graphics2D object. The latter one has support for changing the coordinate system.
For drawing sprites: Loading individual pixels in a loop is very slow. There is a drawImage method in Graphics2D that supports everything you need for blitting sprites.
Here's an example to setup the Graphics2D object with a centered origin in a self-contained example:
import java.awt.BasicStroke;
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.geom.Line2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Draw2D extends JFrame {
public Draw2D() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(new DrawPane(), BorderLayout.CENTER);
pack();
}
public static void main(String[] args) {
Draw2D drawing = new Draw2D();
drawing.setVisible(true);
}
}
class DrawPane extends JComponent {
public DrawPane() {
setPreferredSize(new Dimension(640, 640));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// use anti-aliasing for smooth lines
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// move origin to center
g2.translate(getWidth() / 2, getHeight() / 2);
// scale as you need. Using negative y so that y points upward
// note that non-square window sizes will cause a different aspect ratio,
// you probably want to use Math.min(width, height) or something
g2.scale(getWidth() / 2, -getHeight() / 2);
// set color and thickness
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(0.001f));
// draw coordinate lines
g2.draw(new Line2D.Float(-1f, 0f, 1.0f, 0f));
g2.draw(new Line2D.Float(0, -1.0f, 0.0f, 1.0f));
// draw a vector
g2.draw(new Line2D.Float(0f, 0f, 0.25f, 0.25f));
}
}
Related
I'm in a beginner's class that is teaching java and in our reading they gave an example about using graphics to draw items. So, I posted the code into my IDE and tried it out.
The code they posted was supposed to create an alien face and
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;
/*
A component that draws an alien face
*/
public class FaceComponent extends JComponent
{
public void paintComponent(Graphics g)
{
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
// Draw the head
Ellipse2D.Double head = new Ellipse2D.Double(5, 10, 100, 150);
g2.draw(head);
// Draw the eyes
g2.setColor(Color.GREEN);
Rectangle eye = new Rectangle(25, 70, 15, 15);
g2.fill(eye);
eye.translate(50, 0);
g2.fill(eye);
// Draw the mouth
Line2D.Double mouth = new Line2D.Double(30, 110, 80, 110);
g2.setColor(Color.RED);
g2.draw(mouth);
// Draw the greeting
g2.setColor(Color.BLUE);
g2.drawString("Hello, World!", 5, 175);
}
}
However I am unsure how it is you create the Graphics to which you call the function. I had assumed that you would use
Graphics g = new Graphics();
Like how you call a new class, but this turned out to be an error. I tried looking into the documentation but it seems to gloss over what you use for 'g'.
Please help me understand.
Or is this a situation where this is a class I need to call from another class since I'm extending it?
paintComponent(Graphics g) is a method inherited from JComponent (Note that paintComponent should have #Override anotation), it is part of the draw system of the GUI. It's invoked from Java Swing Framework to ask for a Component to draw itself on the screen. The object past to the method is already instantiated and valid for usage.
You have to add your component to the screen with like JFrame/JPanel and make it visible to see it working.
Also that since you don't implement a measurable screen you need to add some space to it inside layout to see the result (setMinimumSize() after instiating, before frame.pack()).
Don't create a Graphics g with a new operator. It is passed in through the public void paintComponent(Graphics g) method.
Note that Java actually passes a Graphics2D object though this interface (which makes the cast possible) but for legacy reasons kept the Graphics interface by making the Graphics2D object inherit from Graphics.
The reason you don't create a new Graphics object is because the passed Graphics object is the one that is used by the rest of your widgets, and the AWT/Swing interface in general.
As far as "using" it, it is a standard Java object. Use it like a Java object, by calling methods on it.
g.setColor(...);
ect.
My application is a simple game of Brick Breaker. In order to paint the visuals of the application I'm using the paintComponent method. The application also has several buttons that are added using the following code:
levelMenu = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double scale = screenSize.getHeight()/1080;
Graphics2D g2d = (Graphics2D) g;
g2d.scale(scale, scale);
g2d.drawImage(background, 0, 0, null);
}
};
levelMenu.setLayout(new FlowLayout());
JPanel subPanel = new JPanel(new GridLayout(20, 2, 10, 10));
subPanel.setBackground(Constants.CLEAR);
subPanel.add(new JLabel());
subPanel.add(new JLabel());
for (JButton level: levelList) {
subPanel.add(level);
}
subPanel.add(new JLabel());
subPanel.add(back);
levelMenu.add(subPanel);
this.add(levelMenu);
The issue Im having is that the buttons are being added, but also they seem to be painted in the background image of the application:
The buttons on the right dont work, and are just images. Any clue how to fix this issue.
The primary issue comes down to...
Graphics2D g2d = (Graphics2D) g;
g2d.scale(scale, scale);
g2d.drawImage(background, 0, 0, null);
The Graphics context passed to the paintComponent method is a shared resource, all the components rendered within the paint pass will use it. This means that any changes you make to it will also affect them. You should be especially aware of transformations (like translate and scale).
A general practice is to make a snapshot of the state of Graphics context before you use it, this allows you to make changes to the copy with affecting the original, something like...
Graphics2D g2d = (Graphics2D) g.create();
g2d.scale(scale, scale);
g2d.drawImage(background, 0, 0, null);
g2d.dispose();
The other issue is subPanel.setBackground(Constants.CLEAR);. I'm assuming that this is a alpha based color. Swing component's don't support alpha based colors, they are either fully opaque or fully transparent (although you can fake it). This is controlled through the use of setOpaque
Now, I strongly recommend that you stop and go have a read through:
Performing Custom Painting
Painting in AWT and Swing
Use below code snippet for your reference:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicPanelUI;
class MyPanelUI extends BasicPanelUI {
public void paint(Graphics g, JComponent c) {
Toolkit toolkit = Toolkit.getDefaultToolkit();
Graphics2D g2d = (Graphics2D) g;
Image img = toolkit.getImage("/usr/share/backgrounds/warty-final-ubuntu.png");
g2d.drawImage(img, 0, 0, null);
}
public Dimension getPreferredSize(JComponent c) {
return super.getPreferredSize(c);
}
}
public class PanelBGTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setUI(new MyPanelUI());
panel.setLayout(new FlowLayout());
panel.add(new JButton("This is button"));
SwingUtilities.updateComponentTreeUI(frame);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
using paint component is not good practice so its always better to extent your component UI class from basic component UI class and override the paint() method. This way swing will take care of all the rendering / re-rendering part and your component(s) added to panel will be visible too.
Now, I strongly recommend that you stop and go have a read through:
Performing Custom Painting
Painting in AWT and Swing
BufferStrategy and BufferCapabilities
How to Use Layered Panes
I am trying to add a border to a Rectangle element and for some reason it will not work, is it not compatible with JFrame? I can set my entire JFrame to having a border, but it can't find setBorder with my rectangles. Here is my code:
package trivia;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.border.Border;
#SuppressWarnings("serial")
public class Main extends JFrame{
boolean mainMenu = true;
static Color tan = Color.decode("#F4EBC3");
static Color darkGreen = Color.decode("#668284");
static Color buttonColor = Color.decode("#A2896B");
Rectangle header = new Rectangle(0, 0, 500, 100);
Rectangle body = new Rectangle(0, 100, 500, 400);
Rectangle start = new Rectangle(150, 150, 200, 40);
public Main() {
setTitle("Trivia Game!");
setSize(500, 500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
#Override
public void paint(Graphics g) {
Dimension d = this.getSize();
Border blackline;
blackline = BorderFactory.createLineBorder(Color.black);
if(mainMenu = true){
g.setColor(darkGreen);
g.fillRect(header.x, header.y, header.width, header.height);
g.setFont(new Font("Courier", Font.BOLD, 24));
g.setColor(Color.BLACK);
drawCenteredString("Trivia Game!", d.width, 125, g);
g.setColor(tan);
g.fillRect(body.x, body.y, body.width, body.height);
g.setColor(buttonColor);
g.fillRect(start.x, start.y, start.width, start.height);
}
}
public void drawCenteredString(String s, int w, int h, Graphics g) {
FontMetrics fm = g.getFontMetrics();
int x = (w - fm.stringWidth(s)) / 2;
int y = (fm.getAscent() + (h- (fm.getAscent() + fm.getDescent())) / 2);
g.drawString(s, x, y);
}
public static void main(String[] args) {
#SuppressWarnings("unused")
Main m = new Main();
}
}
And when I add this in my paint function:
start.setBorder(blackline);
It gives me the error:
The method setBorder(Border) is undefined for the type Rectangle
I am not sure how I can make it recognize the setBorder function, can anyone help? All help is much appreciated!
Rectangle does not have a setBorder method, instead, set the color of the Graphics context using Graphics#setColor(Color) and either use Graphics#drawRect(int, int, int, int) or Graphics2D#draw(Shape)
You're breaking the paint chain. Painting is made up of a series of chained method calls, which when called correctly, paint the current component and its child components. By not calling super.paint you're preventing from doing this and could cause any number of nasty side effects, none of which you really want...
You should avoid overriding paint of top level containers, like JFrame, for a number of reasons; they're not double buffered; there a bunch of other components sitting on top of the frame which may paint over it; etc. Instead, create a custom component, extending from something like JPanel and override it's paintComponent method instead (ensuring that you call super.paintComponent first)...
See Painting in AWT and Swing,
Performing Custom Painting and 2D Graphics for more details
Sounds like you're trying to draw the rectangle referenced by start. In that case, you want to be invoking a method on a Graphics, not on a Rectangle. So:
g.drawRect(start.x, start.y, start.width, start.height);
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.