How to Overlap Panels in Swing? - java

I am attempting to have multiple JPanels that can "overlap", also allowing me to perform custom painting.
For this I am using a MainPanel, which extends JLayeredPane, and from what I can see, I have set bounds and index correctly.
The expected result, would be two rectangles painting at the same time to the screen.
The result I get, is flickering on one of the two OverlappingPanels, which I assume is from the RepaintManager fighting on which panel to draw (Found this here).
My question is, How can I properly overlap panels and retain painting capabilties, using Swing?
EDIT:
Code in question:
import javax.swing.*;
import java.awt.*;
public class Example extends JFrame {
public static class MainPanel extends JLayeredPane implements Runnable {
public OverlappingPanel1 overlappingPanel1;
public OverlappingPanel2 overlappingPanel2;
Thread mainThread;
public void startMainThread() {
mainThread = new Thread(this);
mainThread.start();
}
public MainPanel() {
this.setPreferredSize(new Dimension(1920,720));
this.setBackground(Color.BLACK);
this.setDoubleBuffered(true);
overlappingPanel1 = new OverlappingPanel1();
overlappingPanel2 = new OverlappingPanel2();
overlappingPanel1.setBounds(0,0,1920,720);
overlappingPanel2.setBounds(0,720/2,1920,720);
add(overlappingPanel1,1);
add(overlappingPanel2,2);
}
#Override
public void run() {
while(mainThread != null) {
overlappingPanel1.repaint();
overlappingPanel2.repaint();
}
}
}
public static class OverlappingPanel1 extends JPanel {
public OverlappingPanel1() {
setDoubleBuffered(true);
setPreferredSize(new Dimension(1920,720));
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D graphics2D = (Graphics2D) g;
graphics2D.fillRect(0,0,200,200);
}
}
public static class OverlappingPanel2 extends JPanel {
public OverlappingPanel2() {
setDoubleBuffered(true);
setPreferredSize(new Dimension(1920,720));
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D graphics2D = (Graphics2D) g;
graphics2D.fillRect(0,80,200,200);
}
}
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
MainPanel mainPanel = new MainPanel();
window.add(mainPanel);
window.setBackground(Color.BLACK);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
mainPanel.startMainThread();
}
}

So yes, a JLayeredPane would allow easy overlap of Swing components such as JPanels, and there are also layouts others have created that allow this, one called "overlay layout", but that's not what you want to for your currently stated problem.
Yours is an XY Problem type question where you ask "how do I solve X problem" when the best solution is not to solve it in this way, but rather to do Y, something completely different. Here, to paint multiple different images, your best solution is not to create and overlap heavier-weight Swing components such as JPanels, but rather to draw in one single JPanel and overlap sprite images. Otherwise you're just making things unnecessarily harder for yourself and your code than is needed.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Example2 extends JPanel {
private static final int MY_WIDTH = 1600;
private static final int MY_HEIGHT = 720;
List<Rectangle> rectangles = new ArrayList<>();
public Example2() {
setPreferredSize(new Dimension(MY_WIDTH, MY_HEIGHT));
setBackground(Color.WHITE);
rectangles.add(new Rectangle(0, 0, 200, 200));
rectangles.add(new Rectangle(0, 80 + MY_HEIGHT / 2, 200, 200));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle rectangle : rectangles) {
g2.fill(rectangle);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
Example2 example = new Example2();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(example);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
And yes, as suggested in comments, override paintComponent, not paint. This reduces the risk of unwanted side effects that might come from painting child components or borders, and also allows for automatic double-buffering for when you do animation.
Also, a while (true) loop is not a healthy construct within an event-driven GUI program, not as you've written it. If you need repeated actions in a Swing program (which you don't in your example, not yet), use a Swing Timer instead.
So doing this this way gives you good flexibility. For instance, if you wanted to modify the above program to allow addition of shapes on mouse click, it would be easy to do so:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Example3 extends JPanel {
private static final int MY_WIDTH = 1600;
private static final int MY_HEIGHT = 720;
List<ColorShape> colorShapes = new ArrayList<>();
public Example3() {
setPreferredSize(new Dimension(MY_WIDTH, MY_HEIGHT));
setBackground(Color.WHITE);
addMouseListener(new MyMouse());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (ColorShape colorShape : colorShapes) {
colorShape.draw(g2);
}
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
// create a random color
float hue = (float) Math.random();
float saturation = 1f;
float brightness = (float) (0.5 * Math.random() + 0.5);
Color color = Color.getHSBColor(hue, saturation, brightness);
// create a new ColorShape, add to list, and repaint:
colorShapes.add(new ColorShape(e.getPoint(), color));
repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
Example3 example = new Example3();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(example);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
class ColorShape {
private int width = 80;
private Point location;
private Color color;
private Shape shape;
public ColorShape(Point location, Color color) {
this.location = location;
this.color = color;
int x = location.x - width / 2;
int y = location.y - width / 2;
shape = new Ellipse2D.Double(x, y, width, width);
}
public void draw(Graphics2D g2) {
g2.setColor(color);
g2.fill(shape);
}
public Point getLocation() {
return location;
}
}

The last two parameteres in setBounds(int x,int y, int width, int height) are the width and height of your panel. In your case, these are the dimensions of your rectangle , thus you should set them to 200, as below:
overlappingPanel1.setBounds(0,0,200,200);
overlappingPanel2.setBounds(0,720/2,200,200);
Also, remove setPreferredSize(new Dimension(1920,720)); in the OverlappingPanel1 and OverlappingPanel2 classes, as they are not needed.

Related

What will be the Main of this program in java |How do i call the line method in main?

package drawinglinebymethods;
import java.awt.*;
import javax.swing.JFrame;
public class DrawingLineByMethods extends Frame {
public JFrame f=new JFrame();
void fra_size()
{
f.setSize(450, 300);
}
void fra_visible()
{
f.setVisible(true);
}
void fra_title()
{
f.setTitle(" java frame");
}
void exit()
{
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void line(Graphics g) {
g.drawLine(10, 10, 20, 300);
}
public static void main(String[] args) {
DrawingLineByMethods obj = new DrawingLineByMethods();
obj.fra_size();
obj.fra_title();
obj.fra_visible();
obj.fra_exit();
obj.line(g); // <-- error here
}
}
Your question suggests that you are not yet clear on how graphics and drawing works in Swing GUI's. Some suggestions for you:
Don't have your class extend java.awt.Frame as this makes no sense. You're not creating an AWT Frame window and have no need of this.
Create a class that extends JPanel and draw in its paintComponent method as the Swing painting tutorials (link now added) show you.
You never call drawing code directly but rather it is indirectly called by the JVM.
If you want to draw from outside of the GUI itself, then draw to a BufferedImage, one that is then displayed within the GUI.
Don't use a Graphics object obtained by calling getGraphics() on a GUI component as the object thus obtained will not persist, and this risks you creating unstable graphics or worse -- throwing a NullPointerException.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class LineDraw extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
public LineDraw() {
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use rendering hints to draw smooth lines
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// do drawing here
g.drawLine(10, 10, 20, 300);
}
private static void createAndShowGui() {
LineDraw mainPanel = new LineDraw();
JFrame frame = new JFrame("Line Draw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
If you want to add lines as the program runs, again, use a BufferedImage that is drawn within the JPanel's paintComponent method. When you need to add a new line to the GUI, extract the Graphics or Graphics2D object from the BufferedImage using getGraphics() or createGraphics() respectively (it's OK to do this), draw with this Graphics object, dispose of the Graphics object, and repaint the GUI. For example in the code below, I draw a new line when the button is pressed by adding code within the JButton's ActionListener (actually its AbstractAction which is similar to an ActionListener but more powerful):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class LineDraw extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
private BufferedImage img;
private int yDistance = 20;
private int deltaY = 10;
public LineDraw() {
img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
add(new JButton(new DrawLineAction("Draw Line", KeyEvent.VK_D)));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// draw the buffered image here
if (img != null) {
g.drawImage(img, 0, 0, this);
}
// use rendering hints to draw smooth lines
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// do drawing here
g.drawLine(10, 10, 20, 300);
}
public void drawNewLines() {
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
yDistance += deltaY;
g2.drawLine(10, 10, yDistance, PREF_H);
g2.dispose();
repaint();
}
private class DrawLineAction extends AbstractAction {
public DrawLineAction(String name, int mnemonic) {
super(name); // give button its text
putValue(MNEMONIC_KEY, mnemonic); // alt-hot key for button
}
#Override
public void actionPerformed(ActionEvent e) {
drawNewLines();
}
}
private static void createAndShowGui() {
LineDraw mainPanel = new LineDraw();
JFrame frame = new JFrame("Line Draw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
Line is a non-static method, the only way to call it from a static method (main here) is to have an instance of the class.

JavaSwing Game: JFrame not showing

I am trying to write a simple game. I am in the beginning of everything and my goal is to create a box that listens to my keyboard. While trying to just draw a box in a JPanel, the JFrame launches and then closes in 3 seconds. Can someone please help? I am lost in this Java Swing JFrame, JPanel situation.
package abbygail;
public class Abbygail {
public static void main(String[] args) {
GUI gui = new GUI();
}
}
Different class:
package abbygail;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GUI extends JFrame {
public GUI(){
setSize(640, 480);
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Game_Board brd = new Game_Board();
setContentPane(brd);
getContentPane().setLayout(null);
}
}
Different class:
package abbygail;
import javax.swing.JPanel;
public class Game_Board extends JPanel{
public Game_Board(){
setSize(640, 480);
Blue_Box blbx = new Blue_Box();
add(blbx);
}
}
Different class:
package abbygail;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
public class Blue_Box extends JPanel{
/**
*
* #param g
*/
private Point p1 = new Point(100, 100);
private Point p2 = new Point(540, 380);
public Blue_Box(){
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(8,BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
g2d.draw(new Rectangle2D.Double(p1.x, p1.y, 40, 30));
}
}
You never call setVisible(true); on your GUI instance.
So:
public class Abbygail {
public static void main(String[] args) {
GUI gui = new GUI();
gui.setVisible(true);
}
}
Also, a small side issue regarding your use of null layouts, while null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Regarding your blue box -- your Blue_Box JPanel is sized at 0, 0. Give it a getPreferredSize method and return a decent size:
public class Blue_Box extends JPanel {
private static final int PREF_W = 640;
private static final int PREF_H = 480;
private Point p1 = new Point(100, 100);
private Point p2 = new Point(540, 380);
public Blue_Box() {
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
g2d.draw(new Rectangle2D.Double(p1.x, p1.y, 40, 30));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}
and get rid of null layouts

How can I close a window which is using a for loop and thread.sleep

For a school project I have to create a simple canvas on which I have to draw random circles. For this I am using a for loop where I kept spawning circles. To keep my PC from crashing, I used the Thread.sleep(20) method. It worked well but had one flaw: it is unable to close itself using the close button.
public class CanvasDraw extends Canvas {
private Random rand = new Random();
public void paint(Graphics graph){
setBackground(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
for(int i = 0; i<9999; i++){
graph.setColor(new Color(rand.nextInt(255),
rand.nextInt(255), rand.nextInt(255)));
graph.fillOval(rand.nextInt(480), rand.nextInt(480), 120, 120);
}
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
CanvasDraw drawing = new CanvasDraw();
frame.setSize(600, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.getContentPane().add(drawing);
}
}
How can I fix this?
In your code you paint 10000 ovals each time paint is invoked (which can be quite often). This will clog the event dispatch thread. Paint your ovals on a BufferedImage in your main, and paint that instead. Also extend JComponent instead of Canvas and overwrite paintComponent instead of paint.
Here you go:
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
public class CircleDraw {
public static void main(String[] args) throws InterruptedException {
Random rand = new Random();
BufferedImage bufferedImage = new BufferedImage(600, 600, BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.getGraphics();
g.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
g.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
for (int i = 0; i < 9999; i++) {
g.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
g.fillOval(rand.nextInt(480), rand.nextInt(480), 120, 120);
}
JComponent component = new JComponent() {
#Override
protected void paintComponent(Graphics g) {
g.drawImage(bufferedImage, 0, 0, null);
}
};
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(component);
frame.setSize(bufferedImage.getWidth(), bufferedImage.getHeight());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Try running your spawning circles loop to run on separate thread.
Don't run it on MAIN thread!!
I created a simple circle animation using Java Swing. Here's what the GUI looks like.
The circle repaints every second with a different color and a different circle radius. The drawing area is 420 x 420 pixels. The color varies randomly. The circle radius varies randomly from 42 pixels to 140 pixels.
The JFrame is created in the run method of the CircleAnimation class.
The drawing panel Is created in the DrawingPanel class. All of the custom painting happens in the paintComponent method of the DrawingPanel class.
The animation is set up as a java.swing.Timer after the JFrame is created. The Animation class holds the ActionListener for the Timer. The actionPerformed method creates a new random color and circle radius.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class CircleAnimation implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CircleAnimation());
}
#Override
public void run() {
JFrame frame = new JFrame("Circle Animation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel drawingPanel = new DrawingPanel();
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
Timer timer = new Timer(1000, new Animation(drawingPanel));
timer.setInitialDelay(1000);
timer.start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private int radius;
private Color color;
private Random random;
public DrawingPanel() {
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(420, 420));
this.random = new Random();
setRandomColorAndRadius();
}
public void setRandomColorAndRadius() {
this.color = new Color(getRandom(0, 255),
getRandom(0, 255), getRandom(0, 255));
int start = getPreferredSize().width / 10;
int limit = getPreferredSize().width / 3;
this.radius = getRandom(start, limit);
}
private int getRandom(int start, int limit) {
return random.nextInt(limit - start) + start;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = getWidth() / 2 - radius;
int y = getHeight() / 2 - radius;
int width = radius + radius;
int height = width;
g.setColor(color);
g.fillOval(x, y, width, height);
}
}
public class Animation implements ActionListener {
private DrawingPanel drawingPanel;
public Animation(DrawingPanel drawingPanel) {
this.drawingPanel = drawingPanel;
}
#Override
public void actionPerformed(ActionEvent event) {
drawingPanel.setRandomColorAndRadius();
drawingPanel.repaint();
}
}
}

How to update java canvas dynamically?

Problem: I am trying to update the canvas with new painting objects based on user action. The canvas dosent get updated.
What i have done: The user interacts with the DnD action,The transferrable object reaches the canvas, Calls an update graphics method created by me. And the method simply uses the aldready created graphics 2d object and draws images using it.I have checkd the DnD action,the object is properly recived at canvas class and i was able to print them out using System.out.println.
A sample code,that has a similar function to that of mine,
Paint class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class PaintPanel extends JPanel{
private Graphics2D drawImage;
public PaintPanel()
{
}
#Override
public void paint(Graphics g) {
drawImage = (Graphics2D) g;
drawImage.setColor(Color.WHITE);
drawImage.fillRect(0, 0, getWidth(), getHeight());
}
public void updateGraphics(int length,int width)
{
drawImage.setColor(Color.black);
drawImage.drawRect(100, 150, length, width);
repaint();
}
}
mainframe class:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class MainPaint extends JFrame{
public MainPaint()
{
setTitle("test paint");
setSize(400,400);
setLayout(new BorderLayout());
final PaintPanel paintPan = new PaintPanel();
JButton testButon = new JButton("Display shape");
add(paintPan,BorderLayout.CENTER);
add(testButon,BorderLayout.PAGE_END);
testButon.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
paintPan.updateGraphics(50,50);
repaint();
}
});
setVisible(true);
}
public static void main(String[] args)
{
new MainPaint();
}
}
Graphics2D drawImage; //source of the problem!
Don't attempt to cache a Graphics (or Graphics2D) instance! Instead:
Add the new objects to a list
Call repaint().
In paintComponent(Graphics) draw the list of objects.
An alternative to that is to use a BufferedImage as the drawing object. See this answer for an example.
Update - SSCCE based on latest code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MainPaint extends JFrame {
public MainPaint() {
setTitle("test paint");
setSize(400, 400);
setLayout(new BorderLayout());
final PaintPanel paintPan = new PaintPanel();
JButton testButon = new JButton("Display shape");
add(paintPan, BorderLayout.CENTER);
add(testButon, BorderLayout.PAGE_END);
testButon.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
paintPan.updateGraphics(50, 50);
repaint();
}
});
setVisible(true);
}
public static void main(String[] args) {
new MainPaint();
}
}
class PaintPanel extends JPanel {
private int x, y;
private Color color = null;
public PaintPanel() {
setBackground(Color.ORANGE);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D drawImage = (Graphics2D) g;
if (color != null) {
drawImage.setColor(color);
drawImage.drawRect(100, 150, x, y);
}
}
public void updateGraphics(int length, int width) {
color = Color.RED;
x = length;
y = width;
repaint();
}
}
Note
There are still a number of things about that code that need changing. I decided to stop at the earliest variant that worked to display the rectangle on button click.
I think you need to call the validate() method.

How do I draw a circle and rectangle with specified radius?

I am trying to draw a circle of a radius 60 centerd in the lower right quarter of the frame, and a square of radius 50 centered in the upper half of the frame.
The frame size is 300 x 300.
I've done this till now.
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
public class Test {
public static void main ( String[] args){
JFrameTest5 frame = new JFrameTest5();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setTitle("Test");
}
}
class JFrameTest5 extends JFrame {
public JFrameTest5()
{
setLocation(0,0);
setSize(300,300);
PanelTest1 panel = new PanelTest1();
add(panel);
}
}
class PanelTest1 extends JPanel
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
Ellipse2D circle = new Ellipse2D.Double(250, 225, 120,120);
g2.draw(circle);
Rectangle2D rect = new Rectangle2D.Double(75,0,100,100);
g2.draw(rect);
}
}
The problem is the circle and the rectangle don't seem to be right , are there another methods to set the exact radius ?
The example below includes several important changes:
Use constants wherever possible.
Use panel-relative geometry.
Use initial threads correctly.
Use pack() to size the enclosing frame.
Code:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see http://stackoverflow.com/a/10255685/230513 */
public class Test {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrameTest frame = new JFrameTest();
}
});
}
}
class JFrameTest extends JFrame {
public JFrameTest() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Test");
this.add(new JPanelTest());
this.pack();
this.setLocationByPlatform(true);
this.setVisible(true);
}
}
class JPanelTest extends JPanel {
private static final int R = 60;
private static final int D = 2 * R;
private static final int W = 50;
private static final int E = 2 * W;
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Ellipse2D circle = new Ellipse2D.Double(
getWidth() - D, getHeight() - D, D, D);
g2.draw(circle);
Rectangle2D rect = new Rectangle2D.Double(0, 0, E, E);
g2.draw(rect);
}
}

Categories