My JPanel doesn't show up when my JButton is clicked. It does shows up when I add the JPanel in my go() method. However, once I tried to execute it by click the JButton, it doesn't work. The program does goes into the loop of the actionPeformed() method of the listener though.
public class MyShape
{
JFrame frame;
JPanel panel;
JButton drawButton;
public static void main (String[] args)
{
MyShape test = new MyRandomShape();
test.go();
}
public void go()
{
drawButton = new JButton("Draw Shape!");
drawButton.addActionListener(new DrawListener());
frame = new JFrame();
frame.add(drawButton, BorderLayout.NORTH);
frame.setSize(500,500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private class DrawListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if(empty)
{
System.out.print("IN");
panel = new DrawPanel();
frame.add(panel, BorderLayout.CENTER);
}
}
}
private class DrawPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponents(g);
int randNo = (int)(Math.random() * 3);
int width = (int)(Math.random() * getWidth());
int height = (int)(Math.random() * getHeight());
int xpos = getWidth()/2-width/2;
int ypos = getHeight()/2-height/2;
int v1 = (int)(Math.random() * 256);
int v2 = (int)(Math.random() * 256);
int v3 = (int)(Math.random() * 256);
g.setColor(new Color(v1, v2, v3));
if(randNo == 0)
{
g.fillOval(xpos, ypos, width, height);
}
else if(randNo == 1)
{
g.fillRect(xpos, ypos, width, height);
}
else
{
int startAngle = (int)(Math.random() * 360);
int arcAngle = (int)(Math.random() * 360);
g.fillArc(xpos, ypos, width, height, startAngle, arcAngle);
}
}
}
}
How do I get the JPanel to show up once the button is clicked?
You have to call parentComponent.revalidate() every time you do one or more parentComponent.add(childComponent) (or change its children in other ways, such as reorder or remove them).
In your case, your code should be
private class DrawListener implements ActionListener {
public void actionPerformed(ActionEvent event)
{
if(empty)
{
System.out.print("IN");
panel = new DrawPanel();
frame.add(panel, BorderLayout.CENTER);
frame.revalidate(); // <---------- important
}
}
}
Few changes, check this
public static void main(String[] args) {
MyShape test = new MyShape();
test.go();
}
public void go() {
drawButton = new JButton("Draw Shape!");
drawButton.addActionListener(new DrawListener());
frame = new JFrame();
frame.getContentPane().add(drawButton, BorderLayout.NORTH);
panel = new DrawPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.setSize(500, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private class DrawListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
frame.getContentPane().remove(1);
panel = new DrawPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.repaint();
frame.validate();
}
}
Related
Hello I am new to JAVA and recently studied graphics but got stuck on how to draw a circle (I learn on my own through Google) I would be happy if you help me with the following lines of code
(Do not refer to the background sub button)
public class Panel_ {
static JPanel panel1 = new JPanel();
public static Color randomColor() {
int r = (int) Math.round(Math.random() * 255 - 1);
int g = (int) Math.round(Math.random() * 255 - 1);
int b = (int) Math.round(Math.random() * 255 - 1);
Color R_col = new Color(r, g, b);
System.out.println(R_col);
return R_col;
}
public static void Panel() {
var color_changer = new JButton("To change color");
color_changer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel1.setBackground(randomColor());
}
});
var Panel = new JPanel();
Panel.add(color_changer);
Panel.setBackground(Color.blue);
panel1.setBackground(Color.black);
panel1.setPreferredSize(new Dimension(400, 430));
var frame = new JFrame("Color changer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel1, BorderLayout.NORTH);
frame.getContentPane().add(Panel, BorderLayout.SOUTH);
frame.pack();
frame.setSize(500, 500);
frame.setBackground(Color.blue);
frame.setVisible(true);
}
public void paintCircle(Graphics g) {
g.setColor(Color.blue);
g.fillOval(60, 80, 100, 100);
}
public static void main(String args[]) {
Panel();
}
}
Use paintComponent for panel1 which I changed the name to topPanel in the runnable code below:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class Panel extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel topPanel;
private JPanel panel;
private JButton color_changer;
public Panel() {
initializeForm();
}
private void initializeForm() {
setAlwaysOnTop(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(Color.blue);
color_changer = new JButton("To change color");
color_changer.addActionListener((ActionEvent e) -> {
topPanel.setBackground(randomColor());
});
topPanel = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.fillOval(60, 80, 100, 100);
};
};
panel = new JPanel();
panel.add(color_changer);
panel.setBackground(Color.blue);
topPanel.setBackground(Color.black);
topPanel.setOpaque(true);
topPanel.setPreferredSize(new Dimension(400, 430));
getContentPane().add(topPanel, BorderLayout.NORTH);
getContentPane().add(panel, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(() -> {
new Panel().setVisible(true);
});
}
public static Color randomColor() {
int r = (int) Math.round(Math.random() * 255 - 1);
int g = (int) Math.round(Math.random() * 255 - 1);
int b = (int) Math.round(Math.random() * 255 - 1);
Color R_col = new Color(r, g, b);
System.out.println(R_col);
return R_col;
}
}
Whenever I try to move the array lifegrid, the complier gives errors and something goes wrong with the window. Not sure what the array has to do with that as I am not yet using it to change the displayed information.
I want to be able to call my code in the class LifeRunningCode but because my array is defined in MyPanel it is not visible in CreateAndShowGUI. I need it to be visible to both methods. Can I place it just before the MAIN method?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SwingPaintDemo3 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
static void createAndShowGUI() {
System.out.println("Created GUI on EDT? " + SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
JPanel subPanel = new JPanel();
JButton seed = new JButton("SEED");
subPanel.add(seed);
seed.setPreferredSize(new Dimension(70, 50));
seed.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Seed");
}
});
JButton start = new JButton("START");
subPanel.add(start);
start.setPreferredSize(new Dimension(70, 50));
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae1) {
System.out.println("Start");
//lifegrid = LifeRunningCode.changeValues(lifegrid);
}
});
start.setPreferredSize(new Dimension(70, 50));
JButton stop = new JButton("STOP");
subPanel.add(stop);
stop.setPreferredSize(new Dimension(70, 50));
JButton reset = new JButton("RESET");
subPanel.add(reset);
reset.setPreferredSize(new Dimension(70, 50));
f.add(subPanel, BorderLayout.EAST);
f.setVisible(true);
}
}
class MyPanel extends JPanel {
int lifegrid[][][] = new int[62][42][2];
int squareX = 1280;
int squareY = 800;
int gridX = 0;
int gridY = 0;
public MyPanel() {
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
squareX = e.getX();
squareY = e.getY();
if ((squareX > 20 & squareX < 920) & (squareY > 50 & squareY < 650)) {
gridX = (squareX - 20) / 15 + 1;
gridY = (squareY - 50) / 15 + 1;
squareX = (squareX - 20) / 15 * 15 + 20;
squareY = (squareY - 50) / 15 * 15 + 50;
lifegrid[gridX][gridY][0] = 1;
System.out.println(gridX + " " + gridY);
repaint(squareX, squareY, 15, 15);
}
else {}
}
});
}
public Dimension getPreferredSize() {
return new Dimension(1280, 800);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(squareX, squareY, 13, 13);
g.setColor(Color.BLACK);
g.drawRect(squareX, squareY, 13, 13);
}
}
All the UI objects are localized in createAndShowGUI method.
If you need to access the array inside an instance of MyPanel class you should:
create a getter for this array in MyPanel
store an instance of MyPanel inside main class SwingPaintDemo3 and refer it as necessary:
// MyPanel
class MyPanel extends JPanel {
// ...
public int[][][] getLifegrid() {
return lifegrid;
}
}
// SwingPaintDemo3
public class SwingPaintDemo3 {
static MyPanel myPanel = new MyPanel();
static void createAndShowGUI() {
System.out.println("Created GUI on EDT? " + SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(myPanel);
// ...
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae1) {
System.out.println("Start");
LifeRunningCode.changeValues(myPanel.getLifegrid());
}
});
// ...
}
}
I am trying to add a Rectangle in the panel by button press and remove it with another one. It should work but it doesn't render anything, and I absolutely don't know why.
Can someone explain what I am doing wrong and give me some nice tips what I can improve with my code?
public class GUI extends JPanel {
public static boolean isRecVisible = false;
public static void main(String[] args) {
createGui();
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g);
g2d.drawRect(10, 10, 200, 200);
}
public static void createGui() {
int frameWidth = 550;
int frameHeight = 400;
int buttonWidth1 = 250;
int buttonHeight1 = 30;
int buttonWidth2 = 500;
int buttonHeight2 = 30;
int displayWidth = frameWidth - 20;
int displayHeight = frameHeight - 105;
GUI drawRec = new GUI();
JFrame f = new JFrame("Rectangle");
JPanel p = new JPanel();
JPanel display = new JPanel();
JButton addRec = new JButton("Add Rectangle");
JButton removeRec = new JButton("Remove Rectangle");
JButton colorRec = new JButton("Color Rectangle");
f.add(p);
p.add(addRec);
p.add(removeRec);
p.add(colorRec);
p.add(display);
display.setBackground(Color.LIGHT_GRAY);
f.setSize(frameWidth, frameHeight);
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
display.setBounds(frameWidth / 2 - displayWidth / 2, 10, displayWidth, displayHeight);
addRec.setBounds(frameWidth / 2 - buttonWidth1 / 2 - 250 / 2, frameHeight - 85, buttonWidth1, buttonHeight1);
removeRec.setBounds(frameWidth / 2 - buttonWidth1 / 2 + 250 / 2, frameHeight - 85, buttonWidth1, buttonHeight1);
colorRec.setBounds(frameWidth / 2 - buttonWidth2 / 2, frameHeight - 60, buttonWidth2, buttonHeight2);
addRec.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (isRecVisible == false) {
isRecVisible = true;
display.add(drawRec);
display.repaint();
System.out.println("Rectangle has been drawn!");
} else {
System.out.println("Rectangle has already been drawn!");
return;
}
}
});
removeRec.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (isRecVisible == true) {
isRecVisible = false;
System.out.println("Rectangle has been removed!");
} else {
System.out.println("Rectangle has already been removed");
return;
}
}
});
}
}
display.add(drawRec);
display.repaint();
When you add (or remove) components to a visible frame then the basic logic is:
display.add(...);
display.revalidate();
display.repaint(); // sometimes needed
The revalidate() is the key method because it invokes the layout manager so the size/location of the component can be set.
However, that still won't fix the problem because your custom panel doesn't have a preferred size, so there is nothing to paint for your component.
You need to override the getPreferredSize() method of your custom panel to return the preferred size of your custom component. So in your case you might set the preferred size to be (220, 220) so the rectangle is centered in the panel.
Read the section from the Swing tutorial on Custom Painting for more information and complete working examples.
Note: the tutorial example will also show you how to better structure your code to make sure the GUI is created on the Event Dispatch Thread.
Rather than adding or removing components, it would make more sense here to add the custom painted panel on construction, and use the isRecVisible boolean as a flag to test for drawing the rectangle.
Something like shown here:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUI extends JPanel {
public static boolean isRecVisible = false;
public static void main(String[] args) {
createGui();
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g);
if (isRecVisible) {
g2d.drawRect(10, 10, 200, 200);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600,400);
}
public static void createGui() {
int frameWidth = 550;
int frameHeight = 400;
GUI drawRec = new GUI();
drawRec.setBackground(Color.LIGHT_GRAY);
JFrame f = new JFrame("Rectangle");
JPanel p = new JPanel();
JButton addRec = new JButton("Add Rectangle");
JButton removeRec = new JButton("Remove Rectangle");
JButton colorRec = new JButton("Color Rectangle");
f.add(p, BorderLayout.PAGE_START);
p.add(addRec);
p.add(removeRec);
p.add(colorRec);
f.add(drawRec);
f.setSize(frameWidth, frameHeight);
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
addRec.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
isRecVisible = true;
drawRec.repaint();
}
});
removeRec.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
isRecVisible = false;
drawRec.repaint();
}
});
}
}
I have three JPanels.
The left and right panels are hidden. Only center panel is visible by default.
When I press one button, the frame width will be increased by the right panel's width and the right panel becomes visible.
My problem is with the left panel because the frame cannot be increased in the left direction.
My solution is:
public void mousePressed(MouseEvent e) {
int frameWidth = frame.getBounds().width;
int frameHeight = frame.getBounds().height;
int panelWidth = leftPanel.getPreferredSize().width;
Point currCoords = frame.getLocationOnScreen();
if(!_leftPanelOpened) {
frame.setSize(new Dimension(frameWidth + panelWidth, frameHeight));
leftPanel.setVisible(true);
frame.setLocation(currCoords.x - panelWidth, currCoords.y);
_leftPanelOpened = true;
}
else {
leftPanel.setVisible(false);
frame.setSize(new Dimension(frameWidth - panelWidth, frameHeight));
frame.setLocation(currCoords.x + panelWidth, currCoords.y);
_leftPanelOpened = false;
}
}
It works, but the frame shortly blinks. Can I avoid this short blink?
Edit:
public class Main {
private static JPanel leftoption = new JPanel();
private static JPanel rightoption = new JPanel();
private static JFrame frame = new JFrame();
private static JPanel leftPanel = new JPanel();
private static JPanel rightPanel = new JPanel();
private static JPanel _centerPanel = new JPanel();
private static boolean _leftPanelOpened = false;
private static boolean _rightPanelOpened = false;
public static void main(String[] args) {
leftoption.setPreferredSize(new Dimension(50, 40));
leftoption.setBackground(Color.CYAN);
leftoption.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
int frameWidth = frame.getBounds().width;
int frameHeight = frame.getBounds().height;
int panelWidth = leftPanel.getPreferredSize().width;
Point currCoords = frame.getLocationOnScreen();
if(!_leftPanelOpened) {
frame.setBounds(currCoords.x - panelWidth, currCoords.y, frameWidth + panelWidth, frameHeight);
leftPanel.setVisible(true);
_leftPanelOpened = true;
}
else {
leftPanel.setVisible(false);
frame.setBounds(currCoords.x + panelWidth, currCoords.y, frameWidth - panelWidth, frameHeight);
_leftPanelOpened = false;
}
}
#Override
public void mouseReleased(MouseEvent e) {
}
});
rightoption.setPreferredSize(new Dimension(50, 40));
rightoption.setBackground(Color.ORANGE);
rightoption.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
int frameWidth = frame.getBounds().width;
int frameHeight = frame.getBounds().height;
int panelWidth = rightPanel.getPreferredSize().width;
if(!_rightPanelOpened) {
frame.setSize(new Dimension(frameWidth+panelWidth, frameHeight));
rightPanel.setVisible(true);
_rightPanelOpened = true;
}
else {
rightPanel.setVisible(false);
frame.setSize(new Dimension(frameWidth-panelWidth, frameHeight));
_rightPanelOpened = false;
}
}
#Override
public void mouseReleased(MouseEvent e) {
}
});
_centerPanel.setPreferredSize(new Dimension(300, 600));
_centerPanel.setBackground(Color.WHITE);
_centerPanel.add(leftoption);
_centerPanel.add(rightoption);
leftPanel.setPreferredSize(new Dimension(300, 600));
leftPanel.setBackground(Color.BLUE);
leftPanel.setVisible(false);
rightPanel.setPreferredSize(new Dimension(300, 600));
rightPanel.setBackground(Color.RED);
rightPanel.setVisible(false);
frame.add(leftPanel, BorderLayout.LINE_START);
frame.add(_centerPanel, BorderLayout.CENTER);
frame.add(rightPanel, BorderLayout.LINE_END);
frame.setSize(new Dimension(300, 600));
frame.getContentPane().setBackground(Color.WHITE);
frame.setVisible(true);
}
}
You can call setBounds(), which allows you to set position and size at the same time. Actually, under the hood, both setSize() and setLocation() call setBounds() in the end.
Furthermore, you can avoid calling setVisible(true) before the panel is in place.
Therefore, how about changing your method to:
if(!_leftPanelOpened) {
frame.setBounds(currCoords.x - panelWidth, currCoords.yframeWidth + panelWidth, frameHeight);
leftPanel.setVisible(true);
_leftPanelOpened = true;
}
I've hit a wall (in my brain) trying to update my board on button presses. Am I right in thinking that the GameBoard class is the one that needs to be repaint()ed?
GameBoard.java
public class GameBoard extends Panel {
static Compass compass = new Compass();
private static final long serialVersionUID = 1;
Graphics2D g2d;
static final Dimension WINDOW_SIZE = new Dimension(1150, 800);
public void boardMaker() throws Exception {
JFrame frame = new JFrame("Display image");
JPanel panel = new JPanel();
/* unimportant stuff
.....
*/
//
DieRoll roll = new DieRoll("Roll Dies");
roll.setC(compass);
roll.setG2D(g2d);
//
Button button = new Button("new");
button.setGameBoard(this);
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
buttonPanel.add(roll);
buttonPanel.setPreferredSize(new Dimension(200,100));
frame.getContentPane().add(buttonPanel, BorderLayout.NORTH);
//
frame.getContentPane().add(panel);
frame.setVisible(true);
}
public void paint(Graphics g) {
// not important I think
}
}
Button.java
public class Button extends JButton implements ActionListener {
private static final long serialVersionUID = 1L;
JPanel panel = new JPanel();
JFrame frame = new JFrame();
Compass c = new Compass();
GameBoard gb = new GameBoard();
Button(String text) {
this.setText(text);
this.addActionListener(this);
}
void setGameBoard(GameBoard gb) {
this.gb = gb;
}
#Override
public void actionPerformed(ActionEvent e) {
gb.g2d.setColor(Color.black);
gb.g2d.fillRect(100, 100, 100, 200);
gb.repaint();
}
}
This gives a null pointer exception. So any idea how to repaint my GameBoard? I'm not mad if I've to rewrite everything because of stupidity! ;)
Thanks
You have the wrong idea about how to draw in Java. Components like Panels draw themselves, and all drawing takes place on the UI thread.
Check out this tutorial: docs.oracle.com/javase/tutorial/2d/index.html
The article Painting in AWT and Swing may offer some perspective on application-triggered painting. The example below illustrates the principle. Note that setForeground() calls repaint() automatically because the foreground color is a bound property, but you can always call it yourself.
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class SwingPaint {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
final GamePanel gp = new GamePanel();
f.add(gp);
f.add(new JButton(new AbstractAction("Update") {
#Override
public void actionPerformed(ActionEvent e) {
gp.update();
}
}), BorderLayout.SOUTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class GamePanel extends JPanel {
private static final Random r = new Random();
public GamePanel() {
this.setForeground(new Color(r.nextInt()));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
public void update() {
this.setForeground(new Color(r.nextInt()));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension size = this.getSize();
int d = Math.min(size.width, size.height) - 10;
int x = (size.width - d) / 2;
int y = (size.height - d) / 2;
g.fillOval(x, y, d, d);
g.setColor(Color.blue);
g.drawOval(x, y, d, d);
}
}
}