centre an image in the middle of a panel - java

I am coming to grips with Graphics in Java and created a circle on a JPanel.
How would a center the circle in the JPanel?
package exerciseninetwo;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
public class ExerciseNineTwo extends JFrame
{
public ExerciseNineTwo()
{
super("My Frame");
setSize(500, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new CanvasPanel());
setVisible(true);
}
public static void main(String[] args)
{
new ExerciseNineTwo();
}
}
class CanvasPanel extends JPanel
{
CanvasPanel()
{
setSize(120, 120);
//setBackground(Color.cyan);
}
protected void paintComponent(Graphics g)
{
Graphics2D comp = (Graphics2D)g;
Ellipse2D circle = new Ellipse2D.Float(200, 200, 200, 200);
comp.draw(circle);
comp.setColor(Color.cyan);
comp.fillRect(0,0,500,500);
comp.setClip(circle);
comp.setColor(Color.magenta);
comp.fillRect(0,0,500,500);
}
}

Just draw it in the middle of your panel.
float x = getWidth()/2 - ELLIPSE_WIDTH/2;
float y = getHeight()/2 - ELLIPSE_HEIGHT/2;
Ellipse2D circle = new Ellipse2D.Float(x, y, ELLIPSE_WIDTH, ELLIPSE_HEIGHT);

Use getWidth()/getHeight() of the panel.
int x=(getWidth()-ovalWidth)/2;
int y=(getHeight()-ovalHeight)/2;
Check that panel width is bigger than oval width, and the same with height.

Take the panel object and query the X and Y size parameters(, or width and height). Divide each by 2 will give you the center of the frame. Create a circle using the result as the X and Y coordinates.
like
float x = (width-width of oval) /2;
float y = (height-height of oval) /2;
now set the x and y in the constructor of eclipse

You may easily get the size of your panel and place the circle accordingly:
Dimension size = getSize();
Ellipse2D circle = new Ellipse2D.Float(
(size.width - 200) / 2, // -200 due to the width/height of the circle
(size.height - 200) / 2,
200, 200);

Related

Aren't Graphics/JPanel dimensions measured in pixels?

When I draw [drawRect(x, y, width, height)] a rectangle on an JPanel inside a JFrame, that has a width of e.g. 500, it is actually wider than 500 Pixels on my Screen. How is this measured?
Whilst messing around with a drawing Rectangles on an JPanel and the size of the JFrame around this, i recognized, that 500 "width" are different things, when it comes to JFrame and JPanel.
A JFrame that is created with a width of 1920 Pixels is exactly 1920 Pixels wide, means, as wide as my screen (1920x1080).
If i draw a rectangle with a width of 1920 on a JPanel, that is inside the JFrame, it extends my screen by exactly 385 Pixels. Respectively: a drawn rectangle as wide as my screen needs a width of 1535.
import javax.swing.*;
import java.awt.*
public class Main {
public static void main(String[] args){
JFrame window = new JFrame();
window.setSize(1920,1080); //Window as wide as the screen
window.add(new Canvas());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
}
public class Canvas extends JPanel {
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawRect(0, 0, 1920, 500); //Paints a rectangle on the JPanel
}
}
The window that opens is exactly as wide as my screen, but the rectangle inside extends it.
If I change the width of the rectangle to 1535 [drawRect(0, 0, 1535, 500)], it is as wide as the JFrame/screen. Why is that?
Edit: Since the Windows 10 Frame has no decorations at the side, just the standard menu-bar on top, I don't think this is the problem (as far as I understand decorations).
The short answer: Yes they are.
The explanation: Let us look deeper!
Running Java Swing on MacOS (tested with Metal LAF), the JFrame has insets of zero for left and right. This is similar to rendering for certain themes on Windows 10. I have included code below; the gap between the content pane and the panel's fill rectangle should remain 8 pixels. When the program is running, resize it, and check for yourself. Feel free to comment if this is not the behaviour you experience.
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
final String name;
name = javax.swing.plaf.metal.MetalLookAndFeel.class.getName();
try {
UIManager.setLookAndFeel(name);
}
catch (Throwable e) {
e.printStackTrace();
}
createAndShowWindow();
});
}
private static void createAndShowWindow() {
final int width = 1920;
final int height = 800;
final int padding = 8;
JFrame window = new JFrame();
window.setTitle("Hello World.");
window.setPreferredSize(new Dimension(width, height));
window.setSize(width, height); //Window as wide as the screen
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Canvas canvas = new Canvas(padding);
window.add(canvas, BorderLayout.CENTER);
window.pack();
window.setVisible(true);
System.out.println("w: " + window.getSize());
System.out.println("c: " + window.getContentPane().getSize());
System.out.println("p: " + canvas.getSize());
System.out.println("i: " + window.getInsets());
}
public static class Canvas extends JPanel {
private final int padding;
public Canvas(int padding) {
this.padding = padding;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new Color(180, 120, 16));
//Paints a rectangle on the JPanel
int x = padding;
int y = padding;
int w = getWidth() - 2 * padding;
int h = getHeight() - 2 * padding;
g.fillRect(x, y, w, h);
}
}

Resize Images without JLabel

Im writing a River-Raid-Like game, and all images are drew with g.drawImage(...).
My question is: How to keep the content aspect ratio, and scale the content to fit the new window size ,when someone will resize the JFrame?
Is there any option like that? Can i do this without using JLabels and Layouts? If not, how to do this other way?
My code to draw things on the JPanel
private void doDrawing(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
drawStrings(g2);
mapa.drawMap(g2);
ArrayList ms = craft.getMissiles();
for (Object m1 : ms) {
Missile m = (Missile) m1;
g2.drawImage(m.getImage(), m.getX(), m.getY(), this);
}
g2.drawImage(craft.getImage(), craft.getX(), craft.getY(), this);
for (EnemyJet enemy : enemies) {
g2.drawImage(enemy.getImage(), enemy.getX(), enemy.getY(), this);
}
for (Fuel fuel : fuels) {
g2.drawImage(fuel.getImage(), fuel.getX(), fuel.getY(), fuel.getHeight(), fuel.getHeight(), this);
}
for (Obstacle o : obst) {
g2.drawImage(o.getImage(), o.getX(), o.getY(), this);
}
drawStrings(g2);
}
Also Jpanel constructor:
private void initBoard() {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.WHITE);
setLayout(new GridBagLayout());
craft = new Craft(ICRAFT_X, ICRAFT_Y);
mapa = new Mapa();
setMinimumSize(new Dimension(WIDTH, HEIGHT));
initEnemiesAndAddThem();
czas = new Timer(delay, this);
czas.start();
}
JFrame constructor:
private void initGame()
{
add(new Plansza());
setTitle("Reeevah Raaid");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setLocationRelativeTo(null);
pack();
setVisible(true);
//setExtendedState(JFrame.MAXIMIZED_BOTH);
//setResizable(false);
}
You can scale the entire thing:
private void doDrawing(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform originalTransform = g2.getTransform();
g2.scale(getWidth() / (double) WIDTH, getHeight() / (double) HEIGHT);
// Do all drawing here
g2.setTransform(originalTransform);
}
Some notes:
The g2.setTransform(originalTransform) at the end is important. The Graphics object does not belong to you—it may be used to draw other components, so you need to leave it in the same state it had when it was given to you.
WIDTH and HEIGHT need to be cast to double, because in Java, if any operand of a division operation is a double, the result is double, but if they are both int, integer division is performed, which is definitely not what you want. (For instance, 3 / (double) 2 is 1.5, but 3 / 2 is exactly 1.)
Any image needs to be drawn as follows:
double fct=1.0*image.getWidth()/getWidth();
double fct2=1.0*image.getHeight()/getHeight();
if(fct2>fct) fct=fct2;
g2.drawImage(image, x, y, (int)(1.0*image.getWidth()/fct), (int)(1.0*image.getHeight()/fct), this);
This will leave a lot of empty area - but that is if you want to keep the aspect ratio.
--
To center the image you do the following:
int newWidth=(int)(1.0*image.getWidth()/fct);
int newHeight=(int)(1.0*image.getHeight()/fct);
g2.drawImage(image, getWidth()/2-newWidth()/2, getHeight()/2-newHeight()/2, newWidth, newHeight, this);

Add extended rectangle class to jpanel

I have a class, SheetGood, which extends Rectangle. At the moment I place these SheetGoods onscreen using absolute positions based off of the users resolution, but I'd like to let a layoutmanager take over this aspect.
To do so I'd like to add a SheetGood object to a JPanel, but can't as SheetGood does not extend JComponent.
Any ideas as to how I can get around this?
//edit//
Will I run into issues if I force my program to run at a certain size and remove resizing options?
Ie, a fixed size of 1280x1024 so I can continue placing SheetGoods how I have been and not have to worry about the other controls clipping them when their layout manager moves them around.
To use absolute positioning, dont use a layout manager. You should set layout to null.
I suggest that: extends JPanel as rectangle and set a background color, and set bounds to the positions you want to place.
static class MyRectangle extends JPanel {
int x,
y,
width,
height;
Color bg;
public MyRectangle(int x, int y, int width, int height, Color bg) {
super();
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.bg = bg;
setBounds(x, y, width, height);
setBackground(bg);
}
}
public static void main(String[] args) throws Exception {
JFrame frame = new JFrame("Test rectangle");
MyRectangle rect1 = new MyRectangle(10, 10, 90, 90, Color.red),
rect2 = new MyRectangle(110, 110, 90, 90, Color.yellow);
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setLayout(null); //to make things absolute positioning
contentPane.add(rect1);
contentPane.add(rect2);
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}

Rectangle getting drawn in the wrong spot

I am creating a game inside a JFrame (854 x 480). I am trying to draw a Rectangle in the upper right hand corner of the screen. like so:
int x, y;
Rectangle rect;
public Foo() {
x = 0;
y = 0;
rect = new Rectangle(x, y, 63, 27);
}
....
public void draw(Graphics g) {
g.drawRect(rect.x, rect.y, rect.width, rect.height);
}
But when I do this, the box gets drawn off the screen (x co-ords are right, but y co-ords too high :
When I change the y co-ords to 27 (the height of the rectangle), it moves down to where I want it to go:
Any idea why this is happening? Or how to fix it?
Do you override the paint(..) method of your JFrame? The coordinates seem to be in the coordinate space of the window/JFrame, where 0/0 includes the non-client area (the close box, title bar and so on).
You should create a separate component and add this to the content pane of your main frame - just a very tiny example - note that I am using paintComponent(..):
public static class MyPanel extends JPanel {
#Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
final Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.draw(new Rectangle2D.Float(8,8, 128, 64));
}
}
Add to JFrame content pane (use default or custom LayoutManager):
public class MyFrame extends JFrame {
public MyFrame() {
...
// since JDK 1.4 you do not need to use JFrame.getContentPane().add(..)
this.add(new MyPanel());
}
}
This should do the trick. Here's the corresponding section of the Java SE tutorial.
This is because the JFrames co-ordinates are starting at the top left corner including the title bar. You need to add the height of the title bar to your y co-ordinate to make it show in the top left corner.
Draw the Rect in a JPanel.
JPanel panel = new JPanel();
this.add(panel) //Add the panel to the frame and draw from there
//Provided the class extends a JFrame

how to get the image of a Swing widget? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Java Swing : Obtain Image of JFrame
I am working on a little drag-and-drop Java GUI builder. It works so far, but the widgets I'm dragging and dropping are just rectangles I'm dynamically drawing on a canvas.
If I have a rectangle that represents a widget like a JButton, is there a way for me to create a JButton, set the size and get the image of that JButton if it was drawn on the screen? Then I could paint the image to the screen instead of just my boring rectangle.
For example, I'm currently doing this to draw a (red) rectangle:
public void paint(Graphics graphics) {
int x = 100;
int y = 100;
int height = 100;
int width = 150;
graphics.setColor(Color.red);
graphics.drawRect(x, y, height, width);
}
How can I do something like:
public void paint(Graphics graphics) {
int x = 100;
int y = 100;
int height = 100;
int width = 150;
JButton btn = new JButton();
btn.setLabel("btn1");
btn.setHeight(height); // or minHeight, or maxHeight, or preferredHeight, or whatever; swing is tricky ;)
btn.setWidth(width);
Image image = // get the image of what the button will look like on screen at size of 'height' and 'width'
drawImage(image, x, y, imageObserver);
}
Basically, you'll paint your component to an image, and then paint that image wherever you want. In this case it's okay to call paint directly because you're not painting to the screen (but to a memory location).
If you wanted to optimize your code more than I've done here, you can save the image, and just repaint it in a different location whenever it's moved (instead of calculating the image from the button every time the screen repaints).
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MainPanel extends Box{
public MainPanel(){
super(BoxLayout.Y_AXIS);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// Create image to paint button to
BufferedImage buttonImage = new BufferedImage(100, 150, BufferedImage.TYPE_INT_ARGB);
final Graphics g2d = buttonImage.getGraphics();
// Create button and paint it to your image
JButton button = new JButton("Click Me");
button.setSize(button.getPreferredSize());
button.paint(g2d);
// Draw image in desired location
g.drawImage(buttonImage, 100, 100, null);
}
public static void main(String[] args){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

Categories