I wanted to draw a rectangle with 80% width and 80% height of the original window in the JPanel.
Here's my driver class
public class driver {
public static void main(String[] args) {
System.out.println("test");
Window myWindow = new Window();
myWindow.add(new GraphPanel());
myWindow.settings();
}
}
Here's my JPanel:
import javax.swing.*;
public class Window extends JFrame {
private static final int width = 1100;
private static final int height = 600;
public void settings(){
setSize(width,height);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static int[] getWindowSize(){
int[] output = new int[]{width, height};
return output;
}
}
and the rectangle canvas:
import java.awt.*;
public class GraphPanel extends Canvas {
public void paint(Graphics g){
setBackground(Color.WHITE);
setForeground(Color.DARK_GRAY);
int[] windowSize = Window.getWindowSize();
//Not working as intented
g.drawRect(windowSize[0]/10, windowSize[1]/10, 8*windowSize[0]/10, 8*windowSize[1]/10);
}
}
And here's the result,
I can't post image so here's a link
https://i.imgur.com/6D1gEF7.png
As you can see, this is clearly not centered, the height is off by about 30 pixels and width about 20. I have no idea how this happened, so my question is, does anyone know what might have caused this?
You might want to start by having a quick read of this to get a better understand of why you current approach isn't going to work (the way you expect).
The first thing I would do is change your GraphPanel so it defines it's preferredSize, independent of the window. This way you give control to the layout management system instead.
Next, I would use the actual physical size of the component to base your calculations on
int width = (int) (getWidth() * 0.8);
int height = (int) (getHeight() * 0.8);
I'd also recommend moving the setBackground and setBackground out of the paint method. This will cause a new pain cycle to occur and will make a mess of things.
public class GraphPanel extends Canvas {
private static final int PREF_WIDTH = 1100;
private static final int PREF_HEIGHT = 600;
public GraphPanel() {
setBackground(Color.WHITE);
setBackground(Color.DARK_GRAY);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_WIDTH, PREF_HEIGHT);
}
#Override
public void paint(Graphics g) {
super.paint(g);
int width = (int) (getWidth() * 0.8);
int height = (int) (getHeight() * 0.8);
int x = (getWidth() - width) / 2;
int y = (getHeight() - height) / 2;
//Not working as intented
g.drawRect(x, y, width, height);
}
}
I would then update your Window class so it used pack instead of setSize. This will "pack" the window around the content, taking into consideration the frame decorations.
public class Window extends JFrame {
public void settings() {
pack();
setLocationRelativeTo(null);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Although, I'd question the point of extending from JFrame, but I'm getting of topic.
Speaking of which, unless you're intending to high performance graphics which requires you to have complete control over the painting sub system, I'd recommend starting with Swing based components or even JavaFX
Related
Can't get the program to print more than one square.
My code right now
import java.awt.*;
import javax.swing.*;
public class MyApplication extends JFrame {
private static final Dimension WindowSize = new Dimension(600, 600);
private int xCord=9, yCord=32, width=80, height=80;
public MyApplication() {
//Create and set up the window
this.setTitle("Squares");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display the window centered on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width / 2 - WindowSize.width / 2;
int y = screensize.height / 2 - WindowSize.height / 2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
}
public static void main(String args[]) {
MyApplication window = new MyApplication();
}
public void paint(Graphics g) {
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
g.setColor(Color.getHSBColor(red, green, blue));
g.fillRect(xCord, yCord, width, height);
while((yCord+height)<600){
if((xCord+width)>600){
xCord=9;
yCord+=80;
}
else xCord+=80;
repaint();
}
}
}
I'm trying to fill a 600x600 window with squares of different colours that go to a new line once a row is full.
First of all, don't.
Don't override paint of top level containers, like JFrame.
JFrame is a composite component, meaning that they're a number of layers between its surface and the user and because of the way the paint system works, these can be painted independent of the frame, which can produce weird results.
Top level containers are not double buffered, meaning your updates will flash.
DO call a paint methods super method, unless you are absolutely sure you know what you're doing.
Start by taking a look at Performing Custom Painting and Painting in AWT and Swing for more details about how painting works in Swing and how you should work with it.
This...
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width / 2 - WindowSize.width / 2;
int y = screensize.height / 2 - WindowSize.height / 2;
setBounds(x, y, WindowSize.width, WindowSize.height);
is a bad idea on a number of levels.
Toolkit#getScreenSize does not take into consideration the size of other UI elements which will reduce the available viewable area available on the screen, things like the taskbar/dock or menu bar on some OS
Using setBounds(x, y, WindowSize.width, WindowSize.height); on a window based class is also a bad idea, as the avaliable viewable area is the window size MINUS the window's decorations, meaning the actually viewable area is smaller then you have specified and because you're painting directly to the frame, you run the risk of painting under the frame decorations.
You can have a look at How can I set in the midst? for more details
One thing you should now about painting, painting is destructive, that is, each time a paint cycle occurs, you are expected to completely repaint the current state of the component.
Currently, this...
public void paint(Graphics g) {
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
g.setColor(Color.getHSBColor(red, green, blue));
g.fillRect(xCord, yCord, width, height);
while ((yCord + height) < 600) {
if ((xCord + width) > 600) {
xCord = 9;
yCord += 80;
} else {
xCord += 80;
}
repaint();
}
}
will only paint a single rectangle, base on the last value of xCord and yCord most likely AFTER the paint method has exited.
Swing uses a passive rendering engine, meaning that the system will make determinations about what to paint and when, you don't control it. You can make a "request" to the system through the use repaint, but it's up to the system to decide when and what will get painted, this means that multiple requests can be optimised down to a single paint pass.
Also, painting should do nothing more than paint the current state. It should avoid changing the state, directly or indirectly, especially if that change triggers a new paint pass, as this can suddenly reduce the performance of your program to 0, crippling it.
So, what's the answer?
Well, change everything...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MyApplication {
public static void main(String[] args) {
new MyApplication();
}
public MyApplication() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
private static final Dimension DESIRED_SIZE = new Dimension(600, 600);
private int width = 80, height = 80;
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return DESIRED_SIZE;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int xCord = 0, yCord = 0;
while ((yCord) < getHeight()) {
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
g2d.setColor(Color.getHSBColor(red, green, blue));
g2d.fillRect(xCord, yCord, width, height);
if ((xCord + width) > getWidth()) {
xCord = 0;
yCord += 80;
} else {
xCord += 80;
}
}
g2d.dispose();
}
}
}
Break down...
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
This creates an instance of Jframe, you don't really want extend from JFrame, you're not adding any new functionality to the class
frame.pack() is packing the window around the content, this ensures that the frame is always larger (by the amount of the frame decorations) then the desired content size
frame.setLocationRelativeTo(null); will centre the window in a system independent manner.
Next...
private static final Dimension DESIRED_SIZE = new Dimension(600, 600);
private int width = 80, height = 80;
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return DESIRED_SIZE;
}
I've used DESIRED_SIZE to provide a sizing hint to the parent containers layout manager.
Finally...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int xCord = 0, yCord = 0;
while ((yCord) < getHeight()) {
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
g2d.setColor(Color.getHSBColor(red, green, blue));
g2d.fillRect(xCord, yCord, width, height);
if ((xCord + width) > getWidth()) {
xCord = 0;
yCord += 80;
} else {
xCord += 80;
}
}
g2d.dispose();
}
Note here, I've changed the xCord and yCord positions to zero, I no longer need to "guess" at the frame decorations. As well as making the local variables, so that when ever the method is called again, the values are reset to zero.
You don't "have" to cast the Graphics reference to Graphics2D, but Graphics2D is a more powerful API. I also like to copy it's state, but that's me, your code is simple enough so it's unlikely to have adverse effects on anything else that might be painted after your component.
Notice also, I've use getWidth and getHeight instead of "magic numbers", meaning you can resize the window and the painting will adapt.
You could try placing the whole paint mechanism inside your loop to get it done with in a one call. Therefore you wont need to call repaint inside the paint method itself:
public void paint(Graphics g) {
while((yCord+height)<600){
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
g.setColor(Color.getHSBColor(red, green, blue));
g.fillRect(xCord, yCord, width, height);
if((xCord+width)>600){
xCord=9;
yCord+=80;
}
else xCord+=80;
}
}
I cannot seem to get a rectangle to be displayed in the JFrame. Per the parameters of this project, I have to have this class implement the Icon interface. When I run the code as is, I get the JFrame, but nothing shows up inside. It should display a black square. I'm assuming the problem has something to do with how I am initializing the graphics instance variable. I don't have much experience working with GUI graphics, so I'm not entirely clear on how to do this correctly.
And yes, I do know that the getIconWidth and getIconHeight methods are redundant since I am using constants, but I have to have these methods in order to implement the interface.
public class MugDisplay extends JFrame implements Icon {
private int width;
private int height;
private JPanel panel;
private Graphics graphics;
private static final int ICON_WIDTH = 100;
private static final int ICON_HEIGHT = 100;
public MugDisplay() {
this.configureGui();
this.panel = new JPanel();
this.panel.setLayout(new BorderLayout());
this.add(this.panel, BorderLayout.CENTER);
this.graphics = this.getGraphics();
int xPos = (this.panel.getWidth() - this.getIconWidth()) / 2;
int yPos = (this.panel.getHeight() - this.getIconHeight()) / 2;
this.paintIcon(this.panel, this.graphics, xPos, yPos);
}
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
g2.fillRect(x, y, ICON_WIDTH, ICON_HEIGHT);
}
#Override
public int getIconWidth() {
return ICON_WIDTH;
}
#Override
public int getIconHeight() {
return ICON_HEIGHT;
}
private void configureGui() {
this.setPreferredSize(new Dimension(600, 600));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().setLayout(new BorderLayout());
this.pack();
this.setVisible(true);
}
}
In the interest of having a MCVE, here is the driver class that calls this class.
public class Main {
public static void main(String[] args) {
MugDisplay md = new MugDisplay();
md.setVisible(true);
}
}
this.graphics = this.getGraphics() is not how custom painting works in Swing. What you should do is create a panel, override its paintComponent method, make the call to super, and then do your painting. For instance:
panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int xPos = ...
paintIcon(this, g, xPos, yPos);
}
}
Calling getGraphics will provide you with a short-lived Graphics object that can soon become invalid, which is why you should opt for overriding paintComponent instead, which will always give you a usable Graphics object. See Performing Custom Painting.
On a separate note, it looks like you're calling setVisible(true) before you're finished adding the necessary components to the JFrame. To ensure that your components show up, call setVisible(true) after adding them all to the frame.
I'm new to Java and I want to try some graphic things with it. I want to generate two circles with two different colors and different positions. My code:
Paint Class:
package de.test.pkg;
import javax.swing.*;
public class paint {
public static void main(String[] args) throws Exception{
JFrame frame = new JFrame("Titel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Circle d = new Circle();
Circle r = new CircleRed();
frame.add(d);
frame.add(r);
frame.setSize(600,200);
frame.setVisible(true);
}
}
Circle class
package de.test.pkg;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Circle extends JPanel {
private double iconRadius = 100;
private Color defaultColor = new Color(89,104,99);
private int positionX = 0;
private int positionY = 0;
private Ellipse2D iconBody = new Ellipse2D.Double(getPositionX(),getPositionY(),iconRadius,iconRadius);
public Icon(){
}
public Color getDefaultColor() {
return defaultColor;
}
public void setDefaultColor(Color defaultColor) {
this.defaultColor = defaultColor;
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d);
this.setBackground(new Color(255,255,255));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(getDefaultColor());
g2d.draw(iconBody);
g2d.fill(iconBody);
}
}
CircleRed class
package de.design.pkg;
import java.awt.Color;
public class CircleRed extends Circle {
private Color defaultColor = Color.RED;
private int positionX = 120;
private int positionY = 0;
public CircleRed() {
}
public Color getDefaultColor() {
return defaultColor;
}
public void setDefaultColor(Color defaultColor) {
this.defaultColor = defaultColor;
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
}
The Result is that the Circles have the same positions.
My questions are:
Why do they have the same positions?
Is this a good way to do that or are there better solutions? I want to use a class so please don't gave me answers with do all that paint thing in the Main.
Is there a better way to hold the position. Maybe in an array? But how should the setter and getter look like if I want to return array[position]?
If I want to set the Position from the Main function. How can I do this?
The Result is that the Circles have the same positions.
(1) Why do they have the same positions?
Not really. The result is that only CircleRed is displayed. Your problem here is not with painting, it's with adding components to a container with a suitable layout manager. The lines
Circle d = new Circle();
Circle r = new CircleRed();
frame.add(d);
frame.add(r);
add r instead of d. This is because JFrame uses BorderLayout by default and you are replacing the center component d with r the line after. Just to show the point, add the line
frame.setLayout(new GridLayout(1, 2));
(2) Is this a good way to do that or are there better solutions? I want to use a class so please don't gave me answers with do all that paint thing in the Main.
It depends on what you are aiming to do. I would venture a guess that if you want to practice inheritance, it would be better for you to create an abstract class for a general circle with shared code and then subclass it with concrete implementation and specific code for the various types. Otherwise, you can just create a single customizable circle class and instantiate that one with different parameters.
It's not a good practical approach in any case because the placement of the circles (which are JPanels) will be determined by the layout manager. The painting only determines the location of the painted shape in the panel. It would be better to just paint the shapes on a single big panel and not with using multiple panels.
There are a few very good answers on the site about moving components around.
(3) Is there a better way to hold the position. Maybe in an array? But how should the setter and getter look like if i want to return array[position]?
There are effectively 2 positions in your design. One is for the panels in the frame, the other is for the shapes in the panels.
For the latter, I would use a Point or just an int x, y fields in the class itself. Getters and setters are the standard ones, the setters will control the position (you will need to call repaint() though).
For the first, it is determined by the layout manager and you don't (shouldn't) control it in a pixel-prefect way. You just instruct the layout manager with "guidelines" and it does the calculations for you.
(4) If I want to set the Position from the Main function. How can i do this?
Again, depends on which position you are talking about. See above.
What your doing is very overkill for just creating two colored circles. You can just use the paint method in java.awt
public void paint(Graphics g){
g.setColor(Color.YELLOW);
g.fillOval(20,20,160,160);
g.setColor(Color.RED);
g.fillOval(60,60,80,80);
}
fillOval takes the following parameters (int x, int y, int width, int height)
You can use g.setColor(Color.NAME) to change the color of your circle. Just call this method before your draw calls.
They're in the same position because the paintComponent() method in Circle is being used for both - and it's using the position variables defined in Circle. When you have CircleRed extend Circle, you don't need to define the position variables again - you inherit them from Circle. Instead, call the setPosition() methods on CircleRed. (You don't need to define these either, they're also inherited.)
There are a variety better solutions, I think the biggest improvement would be to improve your use of inheritance.
That's a fine way to hold the position. If anything else, you could also use a Point object. (Already in Java)
To set the position from the main function, you just call for example
Circle c = new Circle();
c.setPositionX(120);
c.setPositionY(40);
You are going wrong way. You can simply draw two circles by overriding paint method of JFrame class.
Here is a sample demo program.
import java.awt.*;
/**
*
* #author Pankaj
*/
public class TestFrame extends javax.swing.JFrame {
/**
* Creates new form NewJFrame
*/
public TestFrame() {
initComponents();
setTitle("Graphics Demo");
setSize(200,200);
}
/**
* You need to override this method.
*/
#Override
public void paint(Graphics g) {
int X1 = 10; //X coordinate of first circle
int X2 = 60; //X coordinate of second circle
int Y1 = 100; //Y coordinate of first circle
int Y2 = 100; //Y coordinate of second circle
int width = 50; //Width of the circle
int height = 50; //Height of the circle
Color color1 = Color.RED; //Color of first circle
Color color2 = Color.BLUE; //Color of second circle
g.setColor(color1);
g.fillOval(X1, Y1, width, height);
g.setColor(color2);
g.fillOval(X2, Y2, width, height);
}
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setResizable(false);
pack();
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
}
And here's the output
I am working on a lab to practice inheritance, in which we are to create a horizontal ellipse as "Shape1" and then create a "Shape2" which extends Shape1 which draws it's superclass Shape1, and then draws a vertical ellipse over top to create a new looking shape. The shape is displaying fine in terms of inheritance and looks (color/location etc) however when running the program, the frame width is set to 1000, and the height is set to 700, but If I drag the frame by the corner to enlarge it, the shape is drawn over and over again as I keep dragging the frame larger. Ideally the shape should just stay where it is relative to the frame size. I think this is happening because while I drag the frame larger, the draw method is being called over and over again by the system, but I am not sure where this is happening or how to fix it. Any suggestions?
All classes are displayed below:
Shape1:
public class Shape1 {
private double x, y, r;
protected Color col;
private Random randGen = new Random();
public Shape1(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
this.col = new Color(randGen.nextFloat(), randGen.nextFloat(), randGen.nextFloat());
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
public double getR() {
return this.r;
}
public void draw(Graphics2D g2){
//Create a horizontal ellipse
Ellipse2D horizontalEllipse = new Ellipse2D.Double(x - 2*r, y - r, 4 * r, 2 * r);
g2.setPaint(col);
g2.fill(horizontalEllipse);
}
}
Shape2:
public class Shape2 extends Shape1 {
public Shape2(double x, double y, double r) {
super(x, y, r);
}
public void draw(Graphics2D g2) {
//Create a horizontal ellipse
Ellipse2D verticalEllipse = new Ellipse2D.Double(super.getX() - super.getR(),
super.getY() - 2*super.getR(),
2 * super.getR(), 4 * super.getR());
super.draw(g2);
g2.fill(verticalEllipse);
}
}
ShapeComponent:
public class ShapeComponent extends JComponent {
//Instance variables here
private Random coordGen = new Random();
private final int FRAME_WIDTH = 1000;
private final int FRAME_HEIGHT = 700;
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Shape2 myShape = new Shape2(1 + coordGen.nextInt(FRAME_WIDTH), 1 + coordGen.nextInt(FRAME_HEIGHT), 20);
//Draw shape here
myShape.draw(g2);
}
}
ShapeViewer(Where the JFrame is created):
public class ShapeViewer {
public static void main(String[] args) {
final int FRAME_WIDTH = 1000;
final int FRAME_HEIGHT = 700;
//A new frame
JFrame frame = new JFrame();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Lab 5");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ShapeComponent component = new ShapeComponent();
frame.add(component);
//We can see it!
frame.setVisible(true);
}
}
because while I drag the frame larger, the draw method is being called over and over again by the system,
Correct, all components are repainted when the frame is resized.
Any suggestions?
Painting code should be based on properties of your class. If you want the painting to be a fixed size then you define the properties that control the painting and set these properties outside the painting method.
For example, you would never invoke Random.nextInt(...) in the painting method. This means the value will change every time the component is repainted.
So the Shape should be created in the constructor of your class and its size would be defined there, not each time you paint it.
I am trying to draw a circle in the center of a window, and I can't seem to get it right, should be really easy! My understanding is that if you set a JPanel as the content pane of a JFrame, the default layout is a flowLayout and that drawing should start from the top left of the screen as 0,0. To try and figure out what's going on I drew a blue background filling the JPanel, but it seems to have a margin like so:
When the window gets smaller than the blue rectangle, the drawing starts to get clipped from the opposite side:
What's going on! Here is my code:
import javax.swing.*;
import java.awt.*;
public class Test extends JFrame {
public static void main(String args[])
{
Test test = new Test();
test.Start();
}
public void Start()
{
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500, 500);
CirclePanel circlePanel = new CirclePanel();
this.setContentPane(circlePanel);
this.setVisible(true);
}
public class CirclePanel extends JPanel
{
private int radius = 200;
public void paintComponent(Graphics g) {
g.setColor(Color.blue);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.red);
int diameter = radius * 2;
g.fillOval(getX(), getY(), diameter, diameter);
}
public int getX()
{
return (this.getWidth()/2) - radius;
}
public int getY()
{
return (this.getHeight()/2) - radius;
}
}
}
One big issue, you're unknowingly overriding two critical methods used by the layout managers to position components, the getX() and getY() methods, and thereby you're messing with the JPanel's placement.
So first and foremost, rename these methods so you don't accidentally move the JPanel.
Also, don't forget to call the super's paintComponent method, and avoid calling setSize(). Instead override getPreferredSize on your JPanel, and pack your JFrame.
e.g.,
public int getMyX() {
return myX;
}
public int getMyY() {
return myY;
}
For example
import javax.swing.*;
import java.awt.*;
public class Test extends JFrame {
public static void main(String args[]) {
//!!
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test test = new Test();
test.Start();
}
});
}
public void Start() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// this.setSize(500, 500);
CirclePanel circlePanel = new CirclePanel();
setContentPane(circlePanel);
pack();
setVisible(true);
}
public class CirclePanel extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private int radius = 200;
public void paintComponent(Graphics g) {
super.paintComponent(g); //!!
g.setColor(Color.blue);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.red);
int diameter = radius * 2;
g.fillOval(getMyX(), getMyY(), diameter, diameter);
}
//!!
public int getMyX() {
return (this.getWidth() / 2) - radius;
}
//!!
public int getMyY() {
return (this.getHeight() / 2) - radius;
}
//!!
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}
}
The problem is that you're overriding getX() and getY(). Rename those to something else, and your code will work as expected. Also, it's a good idea to turn on compiler warnings for missing #Override annotations, and heed those warnings. (That would have notified the methods override superclass methods).
Try using this.add(circlePanel) instead if this.setContentPane(circlePanel) and set the size of the JPanel to be the same size as the JFrame