I have made a turtle graphics panel which allows a turtle move from user inputs such as forward <distance>, turnright, turnleft, etc. However, I don't know how to move the turtle as it is stuck at the top left of the screen. Does anyone know what I am doing wrong with the code and could adjust it for me? I want it to be directly in the center with the pen down
Here is a picture of the application so far Turtle Graphics
First class
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
* Represents the graphics display panel within the turtle program. This panel contains an image which is updated to reflect user commands.
*
*
*
*/
#SuppressWarnings("serial")
public class GraphicsPanel extends JPanel
{
private JTextField console = new JTextField(15);
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
JMenuBar myMenuBar;
JMenu file;
JMenu help;
JMenuItem load;
JMenuItem save;
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Turtle Graphics");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new GraphicsPanel());
f.pack();
f.setVisible(true);
}
/**
* The default BG colour of the image.
*/
private final static Color BACKGROUND_COL = Color.DARK_GRAY;
private final static int TURTLE_X_SIZE = 8, TURTLE_Y_SIZE = 8;
/**
* The underlying image used for drawing. This is required so any previous drawing activity is persistent on the panel.
*/
private BufferedImage image, turtleDisplay;
//djm added
private Color PenColour = Color.RED;
private boolean penDown = false;
private int xPos=0, yPos=0;
private int direction = 180; //robot pointing down the screen;
private JMenuItem newfile;
private JMenuItem exit;
private JMenuItem about;
/**
* Draw a line on the image using the given colour.
*
* #param color
* #param x1
* #param y1
* #param x2
* #param y2
*/
public void drawLine(Color color, int x1, int y1, int x2, int y2)
{
Graphics g = image.getGraphics();
g.setColor(color);
g.drawLine(x1, y1, x2, y2);
}
//djm added commands
public void penDown()
{
penDown = true;
}
public void penUp()
{
penDown = false;
}
public void turnRight()
{
direction +=90;
if (direction >= 360)
direction = 0;
}
public void turnLeft()
{
direction -=90;
if (direction < 0)
direction = 270;
}
public void forward(int distance)
{
//Graphics g = image.getGraphics();
int x=xPos,y=yPos;
//stored xPos and yPos are current location
if (direction == 0) //robot facing up the screen, so forward subtracts y
{
y = yPos-distance;
}
else if (direction == 90) //robot facing right so forward add x
{
x = xPos + distance;
}
else if (direction == 180) //robot facing down the screen, so forwards adds to y
{
y = yPos + distance;
}
else if (direction == 270) //robot facing left, so forwards subtracts from x
{
x = xPos - distance;
}
else
{
System.out.println("strange, shouldn't get here");
}
if (penDown)
{
//x=400; y=400;
drawLine(PenColour, xPos, yPos, x, y);
//g.drawLine(xPos,yPos,x,y);
}
//now robot has moved to the new position
xPos = x;
yPos = y;
}
/**
* Clears the image contents.
*/
public void clear()
{
Graphics g = image.getGraphics();
g.setColor(BACKGROUND_COL);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
}
public void setTurtleColour(Color col)
{
Graphics g = turtleDisplay.getGraphics();
g.setColor(col);
g.fillRect(0, 0, turtleDisplay.getWidth(), turtleDisplay.getHeight()); }
public void green()
{
setTurtleColour(Color.GREEN);
Graphics g = image.getGraphics();
g.setColor(Color.GREEN);
PenColour = Color.GREEN;
}
public void black()
{
setTurtleColour(Color.BLACK);
Graphics g = image.getGraphics();
g.setColor(Color.BLACK);
PenColour = Color.BLACK;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
g.drawImage(turtleDisplay, xPos-TURTLE_X_SIZE/2, yPos-TURTLE_Y_SIZE/2, null);
repaint();
// render the image on the panel.
g.drawImage(image, 0, 0, null);
g.drawImage(turtleDisplay, xPos-TURTLE_X_SIZE/2, yPos-TURTLE_Y_SIZE/2, null); }
/**
* Constructor.
*/
public GraphicsPanel() {
add(console);
console.addActionListener(new ActionListener()
//Command List//
{
public void actionPerformed(ActionEvent arg0)
{
if (console.getText().contains("penup"))
{
penUp();
}
else if (console.getText().contains("pendown"))
{
penDown();
}
else if (console.getText().contains("turnleft"))
{
turnLeft();
}
else if (console.getText().contains("turnright"))
{
turnRight();
}
else if (console.getText().contains("forward"))
{
forward(direction);
}
else if (console.getText().contains("reset"))
{
clear();
}
else if (console.getText().contains("red"))
{
setTurtleColour(PenColour);
}
else if (console.getText().contains("green"))
{
green();
}
else if (console.getText().contains("black"))
{
black();
}
else
{
JOptionPane.showMessageDialog(console, "Invalid command, try again");
}
console.setText("");
}
});
myMenuBar = new JMenuBar ();
file = new JMenu ("File");
help = new JMenu("Help");
load = new JMenuItem("Load");
save = new JMenuItem("Save");
newfile = new JMenuItem("New");
exit = new JMenuItem("Exit");
about = new JMenuItem("About");
file.add(load);
file.add(save);
file.add(newfile);
file.add(exit);
help.add(about);
myMenuBar.add(file);
myMenuBar.add(help);
add(myMenuBar);
setBorder(BorderFactory.createLineBorder(Color.black));}
public Dimension getPreferredSize() {
return new Dimension(800,400);
}
{
//main drawing area
image = new BufferedImage(800, 400, BufferedImage.TYPE_INT_RGB);
//small image to display on top of drawing area to represent the turtle
turtleDisplay = new BufferedImage(TURTLE_X_SIZE, TURTLE_Y_SIZE, BufferedImage.TYPE_INT_RGB);
//set up turtle
setTurtleColour(PenColour);
// Set max size of the panel, so that is matches the max size of the image.
setMaximumSize(new Dimension(image.getWidth(), image.getHeight()));
setSize(800,400);
setVisible(true);
clear();
}
}
Second Class
public class turtleClass {
public static void main(String[] args)
{
turtleClass m = new turtleClass();
m.go();
}
public void go ()
{
GraphicsPanel p = new GraphicsPanel ();
p.turnLeft();
p.forward(100);
p.turnRight();
p.penDown();
p.forward(400);
}
}
I would comment this, but I don't have enough rep points.
I don't see you calling repaint() after any of your methods, so this could be the problem.
~~EDIT~~
I was able to fix your code on my machine but I had to change the entire structure, the repaint() method is the problem, but you have quite a few structural problems as well.
heres an example of how you should structure it, I created 1 extra file that extends JFrame and added your JPanel to it I also deleted your main method in the JPanel class:
this is a rough draw up but I'll let you handle the rest.
public class myFrame extends JFrame{
public GraphicsPanel panel;
public myFrame() {
panel = new GraphicsPanel();
add(panel);
}
public void go ()
{
panel.turnLeft();
panel.forward(100);
panel.turnRight();
panel.penDown();
panel.forward(400);
repaint();
}
}
Original class without main and a few other modifications
/**
* Represents the graphics display panel within the turtle program. This panel contains an image which is updated to reflect user commands.
*
*
*
*/
#SuppressWarnings("serial")
public class GraphicsPanel extends JPanel
{
private JTextField console = new JTextField(15);
JMenuBar myMenuBar;
JMenu file;
JMenu help;
JMenuItem load;
JMenuItem save;
/**
* The default BG colour of the image.
*/
private final static Color BACKGROUND_COL = Color.DARK_GRAY;
private final static int TURTLE_X_SIZE = 8, TURTLE_Y_SIZE = 8;
/**
* The underlying image used for drawing. This is required so any previous drawing activity is persistent on the panel.
*/
private BufferedImage image, turtleDisplay;
//djm added
private Color PenColour = Color.RED;
private boolean penDown = false;
private int xPos=0, yPos=0;
private int direction = 180; //robot pointing down the screen;
private JMenuItem newfile;
private JMenuItem exit;
private JMenuItem about;
/**
* Draw a line on the image using the given colour.
*
* #param color
* #param x1
* #param y1
* #param x2
* #param y2
*/
public void drawLine(Color color, int x1, int y1, int x2, int y2)
{
Graphics g = image.getGraphics();
g.setColor(color);
g.drawLine(x1, y1, x2, y2);
}
//djm added commands
public void penDown()
{
penDown = true;
}
public void penUp()
{
penDown = false;
}
public void turnRight()
{
direction +=90;
if (direction >= 360)
direction = 0;
}
public void turnLeft()
{
direction -=90;
if (direction < 0)
direction = 270;
}
public void forward(int distance)
{
//Graphics g = image.getGraphics();
int x=xPos,y=yPos;
//stored xPos and yPos are current location
if (direction == 0) //robot facing up the screen, so forward subtracts y
{
y = yPos-distance;
}
else if (direction == 90) //robot facing right so forward add x
{
x = xPos + distance;
}
else if (direction == 180) //robot facing down the screen, so forwards adds to y
{
y = yPos + distance;
}
else if (direction == 270) //robot facing left, so forwards subtracts from x
{
x = xPos - distance;
}
else
{
System.out.println("strange, shouldn't get here");
}
if (penDown)
{
//x=400; y=400;
drawLine(PenColour, xPos, yPos, x, y);
//g.drawLine(xPos,yPos,x,y);
}
//now robot has moved to the new position
xPos = x;
yPos = y;
}
/**
* Clears the image contents.
*/
public void clear()
{
Graphics g = image.getGraphics();
g.setColor(BACKGROUND_COL);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
}
public void setTurtleColour(Color col)
{
Graphics g = turtleDisplay.getGraphics();
g.setColor(col);
g.fillRect(0, 0, turtleDisplay.getWidth(), turtleDisplay.getHeight()); }
public void green()
{
setTurtleColour(Color.GREEN);
Graphics g = image.getGraphics();
g.setColor(Color.GREEN);
PenColour = Color.GREEN;
}
public void black()
{
setTurtleColour(Color.BLACK);
Graphics g = image.getGraphics();
g.setColor(Color.BLACK);
PenColour = Color.BLACK;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
g.drawImage(turtleDisplay, xPos-TURTLE_X_SIZE/2, yPos-TURTLE_Y_SIZE/2, null);
// render the image on the panel.
g.drawImage(image, 0, 0, null);
g.drawImage(turtleDisplay, xPos-TURTLE_X_SIZE/2, yPos-TURTLE_Y_SIZE/2, null); }
/**
* Constructor.
*/
public GraphicsPanel() {
add(console);
console.addActionListener(new ActionListener()
//Command List//
{
public void actionPerformed(ActionEvent arg0)
{
if (console.getText().contains("penup"))
{
penUp();
}
else if (console.getText().contains("pendown"))
{
penDown();
}
else if (console.getText().contains("turnleft"))
{
turnLeft();
}
else if (console.getText().contains("turnright"))
{
turnRight();
}
else if (console.getText().contains("forward"))
{
forward(direction);
}
else if (console.getText().contains("reset"))
{
clear();
}
else if (console.getText().contains("red"))
{
setTurtleColour(PenColour);
}
else if (console.getText().contains("green"))
{
green();
}
else if (console.getText().contains("black"))
{
black();
}
else
{
JOptionPane.showMessageDialog(console, "Invalid command, try again");
}
console.setText("");
}
});
myMenuBar = new JMenuBar ();
file = new JMenu ("File");
help = new JMenu("Help");
load = new JMenuItem("Load");
save = new JMenuItem("Save");
newfile = new JMenuItem("New");
exit = new JMenuItem("Exit");
about = new JMenuItem("About");
file.add(load);
file.add(save);
file.add(newfile);
file.add(exit);
help.add(about);
myMenuBar.add(file);
myMenuBar.add(help);
add(myMenuBar);
setBorder(BorderFactory.createLineBorder(Color.black));}
public Dimension getPreferredSize() {
return new Dimension(800,400);
}
{
//main drawing area
image = new BufferedImage(800, 400, BufferedImage.TYPE_INT_RGB);
//small image to display on top of drawing area to represent the turtle
turtleDisplay = new BufferedImage(TURTLE_X_SIZE, TURTLE_Y_SIZE, BufferedImage.TYPE_INT_RGB);
//set up turtle
setTurtleColour(PenColour);
// Set max size of the panel, so that is matches the max size of the image.
setMaximumSize(new Dimension(image.getWidth(), image.getHeight()));
setSize(800,400);
setVisible(true);
clear();
}
}
Your turtle class
public class turtleClass {
public static void main(String[] args)
{
myFrame m = new myFrame();
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.pack();
m.setVisible(true);
m.go();
}
}
Whenever you're finished making changes to your graphics buffer, you need to call repaint() to make those changes visible to the user. Even when changing pen color, even though the color won't apply until the next thing we draw, we call repaint() so that the turtle cursor itself displays in the new color. Ditto for clear(), forward() (pen up or down), etc. If your turtle cursor had a non-symmetrical shape (eg. arrow or actual turtle) then even turnLeft() and turnRight() would need to trigger a repaint() to display the new turtle heading.
Along with adding missing calls to repaint(), here's my rework of your code that makes the commands you have operate correctly:
GraphicsPanel.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JTextField;
import javax.swing.JOptionPane;
import javax.swing.BorderFactory;
import javax.swing.SwingUtilities;
/*
* Represents the graphics display panel within the turtle program. This panel contains an image
* which is updated to reflect user commands.
*/
public class GraphicsPanel extends JPanel
{
private JTextField console = new JTextField(15);
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
JMenuBar menuBar;
JMenu file;
JMenu help;
JMenuItem load;
JMenuItem save;
private static void createAndShowGUI() {
JFrame frame = new JFrame("Turtle Graphics");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new GraphicsPanel());
frame.pack();
frame.setVisible(true);
}
/*
* The default BG colour of the image.
*/
private final static Color BACKGROUND_COL = Color.DARK_GRAY;
private final static int TURTLE_X_SIZE = 8, TURTLE_Y_SIZE = 8;
/*
* The underlying image used for drawing. This is required so
* any previous drawing activity is persistent on the panel.
*/
private BufferedImage image, turtleDisplay;
// djm added
private Color PenColour = Color.RED;
private boolean penDown = true;
private int xPos = 400 - TURTLE_X_SIZE/2, yPos = 200 - TURTLE_Y_SIZE/2;
private int direction = 180; // robot pointing down the screen
private JMenuItem newfile;
private JMenuItem exit;
private JMenuItem about;
private int distance = 100;
/*
* Draw a line on the image using the given colour.
*/
public void drawLine(Color color, int x1, int y1, int x2, int y2)
{
Graphics graphics = image.getGraphics();
graphics.setColor(color);
graphics.drawLine(x1, y1, x2, y2);
}
// djm added commands
public void penDown()
{
penDown = true;
}
public void penUp()
{
penDown = false;
}
public void turnRight()
{
direction += 90;
if (direction >= 360)
{
direction -= 360;
}
}
public void turnLeft()
{
direction -= 90;
if (direction < 0)
{
direction += 360;
}
}
public void forward(int distance)
{
int x = xPos, y = yPos;
// stored xPos and yPos are current location
if (direction == 0) // robot facing up the screen, so forward subtracts y
{
y = yPos - distance;
}
else if (direction == 90) // robot facing right so forward add x
{
x = xPos + distance;
}
else if (direction == 180) // robot facing down the screen, so forwards adds to y
{
y = yPos + distance;
}
else if (direction == 270) // robot facing left, so forwards subtracts from x
{
x = xPos - distance;
}
else
{
System.out.println("strange, shouldn't get here");
}
if (penDown)
{
drawLine(PenColour, xPos, yPos, x, y);
}
// now robot has moved to the new position
xPos = x;
yPos = y;
repaint();
}
/*
* Clear the image contents.
*/
public void clear()
{
Graphics graphics = image.getGraphics();
graphics.setColor(BACKGROUND_COL);
graphics.fillRect(0, 0, image.getWidth(), image.getHeight());
repaint();
}
public void setColour(Color color)
{
Graphics graphics = turtleDisplay.getGraphics();
graphics.setColor(color);
graphics.fillRect(0, 0, turtleDisplay.getWidth(), turtleDisplay.getHeight());
graphics = image.getGraphics();
graphics.setColor(color);
PenColour = color;
repaint();
}
public void green()
{
setColour(Color.GREEN);
}
public void red()
{
setColour(Color.RED);
}
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics.drawImage(image, 0, 0, null);
graphics.drawImage(turtleDisplay, xPos - TURTLE_X_SIZE/2, yPos - TURTLE_Y_SIZE/2, null);
}
/*
* Constructor.
*/
public GraphicsPanel() {
add(console);
console.addActionListener(new ActionListener()
/* Command List */
{
public void actionPerformed(ActionEvent arg0)
{
if (console.getText().contains("penup"))
{
penUp();
}
else if (console.getText().contains("pendown"))
{
penDown();
}
else if (console.getText().contains("turnleft"))
{
turnLeft();
}
else if (console.getText().contains("turnright"))
{
turnRight();
}
else if (console.getText().contains("forward"))
{
forward(distance);
}
else if (console.getText().contains("reset"))
{
clear();
}
else if (console.getText().contains("green"))
{
green();
}
else if (console.getText().contains("red"))
{
red();
}
else
{
JOptionPane.showMessageDialog(console, "Invalid command, try again");
}
console.setText("");
}
}
);
menuBar = new JMenuBar();
file = new JMenu("File");
load = new JMenuItem("Load");
save = new JMenuItem("Save");
newfile = new JMenuItem("New");
exit = new JMenuItem("Exit");
file.add(load);
file.add(save);
file.add(newfile);
file.add(exit);
menuBar.add(file);
help = new JMenu("Help");
about = new JMenuItem("About");
help.add(about);
menuBar.add(help);
add(menuBar);
setBorder(BorderFactory.createLineBorder(Color.black));
}
public Dimension getPreferredSize()
{
return new Dimension(800, 400);
}
{
// main drawing area
image = new BufferedImage(800, 400, BufferedImage.TYPE_INT_RGB);
// small image to display on top of drawing area to represent the turtle
turtleDisplay = new BufferedImage(TURTLE_X_SIZE, TURTLE_Y_SIZE, BufferedImage.TYPE_INT_RGB);
// set up turtle
setColour(PenColour);
// Set max size of the panel, so that is matches the max size of the image.
setMaximumSize(new Dimension(image.getWidth(), image.getHeight()));
setSize(800, 400);
setVisible(true);
clear();
}
}
TurtleClass.java
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class TurtleClass extends JFrame {
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TurtleClass();
}
});
}
public TurtleClass()
{
JFrame frame = new JFrame("Turtle Graphics");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphicsPanel panel = new GraphicsPanel();
frame.add(panel);
frame.pack();
frame.setVisible(true);
panel.turnLeft();
panel.forward(100);
panel.turnRight();
panel.penDown();
panel.forward(400);
}
}
You can still run this from the TurtleClass or GraphicsPanel as you originally designed:
I would drop the console when invoked as a library like TurtleClass does but keep it when invoked as an application as GraphicsPanel does. It could then be both and output device and an interactive environment depending on need.
Related
I have this code which is basically a home menu with two clickable rectangles.
Start Game
Info
Start Game works fine.
Info is what is not really working. When pressed, the info screen will appear, but the home menu buttons will still be there though not visible (can be clicked).. it seems that when the info menu is appearing, the home menu buttons are not getting cleared.
Also, any point on the info menu is clickable and will show the home menu again. (not what intended, only the back buttons should do that).
How can I fix those problems ?
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
public class HomeMenu extends JComponent implements MouseListener, MouseMotionListener {
private static final String GAME_TITLE = "BRICK DESTROY";
private static final String START_TEXT = "START";
private static final String INFO_TEXT = "INFO";
private static final String howtoPlay = """
1- Click Start\n
2- Choose the mode\n
3- Each mode has 3 levels\n
4- To play/pause press space, use 'A' and 'D' to move\n
5- To open pause menu press 'ESC'\n
6- To open DebugPanel press 'ALT-SHIFT-F1'""";
private static final String backText = "BACK";
private static final Color BORDER_COLOR = new Color(200,8,21); //Venetian Red
private static final Color DASH_BORDER_COLOR = new Color(255, 216, 0);//school bus yellow
private static final Color TEXT_COLOR = new Color(255, 255, 255);//white
private static final Color CLICKED_BUTTON_COLOR = Color.ORANGE.darker();;
private static final Color CLICKED_TEXT = Color.ORANGE.darker();
private static final int BORDER_SIZE = 5;
private static final float[] DASHES = {12,6};
private Rectangle menuFace;
private Rectangle infoFace;
private Rectangle startButton;
private Rectangle infoButton;
private Rectangle backButton;
private BasicStroke borderStoke;
private BasicStroke borderStoke_noDashes;
private Image img = Toolkit.getDefaultToolkit().createImage("1.jpeg");
private Font gameTitleFont;
private Font infoFont;
private Font buttonFont;
private Font howtoPlayFont;
private GameFrame owner;
private boolean startClicked;
private boolean infoClicked = false;
private boolean backClicked = false;
public HomeMenu(GameFrame owner,Dimension area){
this.setFocusable(true);
this.requestFocusInWindow();
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.owner = owner;
menuFace = new Rectangle(new Point(0,0),area);
infoFace = new Rectangle(new Point(0,0),area);
this.setPreferredSize(area);
Dimension btnDim = new Dimension(area.width / 3, area.height / 12);
startButton = new Rectangle(btnDim);
infoButton = new Rectangle(btnDim);
backButton = new Rectangle(btnDim);
borderStoke = new BasicStroke(BORDER_SIZE,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND,0,DASHES,0);
borderStoke_noDashes = new BasicStroke(BORDER_SIZE,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
gameTitleFont = new Font("Calibri",Font.BOLD,28);
infoFont = new Font("Calibri",Font.BOLD,24);
buttonFont = new Font("Calibri",Font.BOLD,startButton.height-2);
howtoPlayFont = new Font("Calibri",Font.PLAIN,14);
}
public void paint(Graphics g){
drawMenu((Graphics2D)g);
}
public void drawMenu(Graphics2D g2d){
if(infoClicked) {
drawInfoMenu(g2d);
return;
}else{
drawContainer(g2d);
Color prevColor = g2d.getColor();
Font prevFont = g2d.getFont();
double x = menuFace.getX();
double y = menuFace.getY();
g2d.translate(x,y);
//methods calls
drawText(g2d);
drawButton(g2d);
//end of methods calls
g2d.translate(-x,-y);
g2d.setFont(prevFont);
g2d.setColor(prevColor);
}
Toolkit.getDefaultToolkit().sync();
}
private void drawContainer(Graphics2D g2d){
Color prev = g2d.getColor();
//g2d.setColor(BG_COLOR);
g2d.drawImage(img,0,0,menuFace.width,menuFace.height,this);
//g2d.fill(menuFace);
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(menuFace);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(menuFace);
g2d.setStroke(tmp);
g2d.setColor(prev);
}
private void drawText(Graphics2D g2d){
g2d.setColor(TEXT_COLOR);
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D gameTitleRect = gameTitleFont.getStringBounds(GAME_TITLE,frc);
int sX,sY;
sY = (int)(menuFace.getHeight() / 4);
sX = (int)(menuFace.getWidth() - gameTitleRect.getWidth()) / 2;
sY += (int) gameTitleRect.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(gameTitleFont);
g2d.drawString(GAME_TITLE,sX,sY);
}
private void drawButton(Graphics2D g2d){
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D txtRect = buttonFont.getStringBounds(START_TEXT,frc);
Rectangle2D mTxtRect = buttonFont.getStringBounds(INFO_TEXT,frc);
g2d.setFont(buttonFont);
int x = (menuFace.width - startButton.width) / 2;
int y =(int) ((menuFace.height - startButton.height) * 0.5);
startButton.setLocation(x,y);
x = (int)(startButton.getWidth() - txtRect.getWidth()) / 2;
y = (int)(startButton.getHeight() - txtRect.getHeight()) / 2;
x += startButton.x;
y += startButton.y + (startButton.height * 0.9);
if(startClicked){
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(startButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(START_TEXT,x,y);
g2d.setColor(tmp);
}
else{
g2d.draw(startButton);
g2d.drawString(START_TEXT,x,y);
}
x = startButton.x;
y = startButton.y;
y *= 1.3;
infoButton.setLocation(x,y);
x = (int)(infoButton.getWidth() - mTxtRect.getWidth()) / 2;
y = (int)(infoButton.getHeight() - mTxtRect.getHeight()) / 2;
x += infoButton.getX();
y += infoButton.getY() + (startButton.height * 0.9);
if(infoClicked){
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(infoButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(INFO_TEXT,x,y);
g2d.setColor(tmp);
}
else{
g2d.draw(infoButton);
g2d.drawString(INFO_TEXT,x,y);
}
}
private void drawInfoMenu(Graphics2D g2d){
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D infoRec = infoFont.getStringBounds(INFO_TEXT,frc);
Color prev = g2d.getColor();
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(infoFace);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(infoFace);
g2d.fillRect(0,0,infoFace.width,infoFace.height);
g2d.setStroke(tmp);
g2d.setColor(prev);
g2d.setColor(TEXT_COLOR);
int sX,sY;
sY = (int)(infoFace.getHeight() / 15);
sX = (int)(infoFace.getWidth() - infoRec.getWidth()) / 2;
sY += (int) infoRec.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(infoFont);
g2d.drawString(INFO_TEXT,sX,sY);
TextLayout layout = new TextLayout(howtoPlay, howtoPlayFont, frc);
String[] outputs = howtoPlay.split("\n");
for(int i=0; i<outputs.length; i++) {
g2d.setFont(howtoPlayFont);
g2d.drawString(outputs[i], 40, (int) (80 + i * layout.getBounds().getHeight() + 0.5));
}
backButton.setLocation(getWidth()/3,getHeight()-50);
int x = (int)(backButton.getWidth() - infoRec.getWidth()) / 2;
int y = (int)(backButton.getHeight() - infoRec.getHeight()) / 2;
x += backButton.x+11;
y += backButton.y + (layout.getBounds().getHeight() * 1.35);
backButton.setLocation(getWidth()/3,getHeight()-50);
if(backClicked){
Color tmp1 = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(backButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(backText,x,y);
g2d.setColor(tmp1);
infoClicked = false;
repaint();
}
else{
g2d.draw(backButton);
g2d.drawString(backText,x,y);
}
}
#Override
public void mouseClicked(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p)){
owner.enableGameBoard();
}
else if(infoButton.contains(p)){
infoClicked = true;
}
else if(backButton.contains(p)){
infoClicked = false;
}
repaint();
}
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p)){
startClicked = true;
repaint(startButton.x,startButton.y,startButton.width+1,startButton.height+1);
}
else if(infoButton.contains(p)){
infoClicked = true;
}
else if(backButton.contains(p)){
infoClicked = false;
}
repaint();
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
if(startClicked){
startClicked = false;
repaint(startButton.x,startButton.y,startButton.width+1,startButton.height+1);
}
else if(infoClicked){
infoClicked = false;
}
else if(backClicked){
infoClicked = true;
}
repaint();
}
#Override
public void mouseEntered(MouseEvent mouseEvent) {
}
#Override
public void mouseExited(MouseEvent mouseEvent) {
}
#Override
public void mouseDragged(MouseEvent mouseEvent) {
}
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if(startButton.contains(p) || infoButton.contains(p) || backButton.contains(p)) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else {
this.setCursor(Cursor.getDefaultCursor());
}
}
}
Here are the images of both windows
main menu
info menu, pressing anywhere = back to home menu, pressing roughly in the middle = start game or back to main menu too
First read, Performing Custom Painting and Painting in AWT and Swing to get a better understanding how painting in Swing works and how you're suppose to work with it.
But I already have ...
public void paint(Graphics g){
drawMenu((Graphics2D)g);
}
would suggest otherwise. Seriously, go read those links so you understand all the issues that the above decision is going to create for you.
You're operating in a OO language, you need to take advantage of that and decouple your code and focus on the "single responsibility" principle.
I'm kind of tired of talking about it, so you can do some reading:
https://softwareengineering.stackexchange.com/questions/244476/what-is-decoupling-and-what-development-areas-can-it-apply-to
Cohesion and Decoupling, what do they represent?
Single Responsibility Principle
Single Responsibility Principle in Java with Examples
SOLID Design Principles Explained: The Single Responsibility Principle
These are basic concepts you really need to understand as they will make your live SOOO much easier and can be applied to just about any language.
As an example, from your code...
public HomeMenu(GameFrame owner,Dimension area){
//...
this.setPreferredSize(area);
There is no good reason (other than laziness (IMHO)) that any caller should be telling a component what size it should be, that's not their responsibility. It's the responsibility of the component to tell the parent container how big it would like to be and for the parent component to figure out how it's going to achieve that (or ignore it as the case may be).
The "basic" problem you're having is a simple one. Your "God" class is simply trying to do too much (ie it's taken on too much responsibility). Now we "could" add a dozen or more flags into the code to compensate for this, which is just going to increase the coupling and complexity, making it harder to understand and maintain, or we can take a step back, break it down into individual areas of responsibility and build the solution around those, for example...
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new HomePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HomePane extends JPanel {
public HomePane() {
setLayout(new BorderLayout());
navigateToMenu();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void navigateToMenu() {
removeAll();
HomeMenuPane pane = new HomeMenuPane(new HomeMenuPane.NavigationListener() {
#Override
public void navigateToInfo(HomeMenuPane source) {
HomePane.this.navigateToInfo();
}
#Override
public void navigateToStartGame(HomeMenuPane source) {
startGame();
}
});
add(pane);
revalidate();
repaint();
}
protected void navigateToInfo() {
removeAll();
HowToPlayPane pane = new HowToPlayPane(new HowToPlayPane.NavigationListener() {
#Override
public void navigateBack(HowToPlayPane source) {
navigateToMenu();
}
});
add(pane);
revalidate();
repaint();
}
protected void startGame() {
removeAll();
add(new JLabel("This is pretty awesome, isn't it!", JLabel.CENTER));
revalidate();
repaint();
}
}
public abstract class AbstractBaseMenuPane extends JPanel {
protected static final Color BORDER_COLOR = new Color(200, 8, 21); //Venetian Red
protected static final Color DASH_BORDER_COLOR = new Color(255, 216, 0);//school bus yellow
protected static final Color TEXT_COLOR = new Color(255, 255, 255);//white
protected static final Color CLICKED_BUTTON_COLOR = Color.ORANGE.darker();
protected static final Color CLICKED_TEXT = Color.ORANGE.darker();
protected static final int BORDER_SIZE = 5;
protected static final float[] DASHES = {12, 6};
private Rectangle border;
private BasicStroke borderStoke;
private BasicStroke borderStoke_noDashes;
private BufferedImage backgroundImage;
public AbstractBaseMenuPane() {
borderStoke = new BasicStroke(BORDER_SIZE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, DASHES, 0);
borderStoke_noDashes = new BasicStroke(BORDER_SIZE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
border = new Rectangle(new Point(0, 0), getPreferredSize());
// You are now responsible for filling the background
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
BufferedImage backgroundImage = getBackgroundImage();
if (backgroundImage != null) {
g2d.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
}
Color prev = g2d.getColor();
Stroke tmp = g2d.getStroke();
g2d.setStroke(borderStoke_noDashes);
g2d.setColor(DASH_BORDER_COLOR);
g2d.draw(border);
g2d.setStroke(borderStoke);
g2d.setColor(BORDER_COLOR);
g2d.draw(border);
g2d.dispose();
}
public void setBackgroundImage(BufferedImage backgroundImage) {
this.backgroundImage = backgroundImage;
repaint();
}
public BufferedImage getBackgroundImage() {
return backgroundImage;
}
}
public class HomeMenuPane extends AbstractBaseMenuPane {
public static interface NavigationListener {
public void navigateToInfo(HomeMenuPane source);
public void navigateToStartGame(HomeMenuPane source);
}
private static final String GAME_TITLE = "BRICK DESTROY";
private static final String START_TEXT = "START";
private static final String INFO_TEXT = "INFO";
private Rectangle startButton;
private Rectangle infoButton;
private Font gameTitleFont;
private Font buttonFont;
// Don't do this, this just sucks (for so many reasons)
// Use ImageIO.read instead and save yourself a load of frustration
//private Image img = Toolkit.getDefaultToolkit().createImage("1.jpeg");
private Point lastClickPoint;
private NavigationListener navigationListener;
public HomeMenuPane(NavigationListener navigationListener) {
this.navigationListener = navigationListener;
try {
setBackgroundImage(ImageIO.read(getClass().getResource("/images/BrickWall.jpg")));
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
lastClickPoint = p;
if (startButton.contains(p)) {
peformStartGameAction();
} else if (infoButton.contains(p)) {
performInfoAction();
}
repaint();
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
lastClickPoint = null;
repaint();
}
});
this.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (startButton.contains(p) || infoButton.contains(p)) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
setCursor(Cursor.getDefaultCursor());
}
}
});
Dimension area = getPreferredSize();
Dimension btnDim = new Dimension(area.width / 3, area.height / 12);
startButton = new Rectangle(btnDim);
infoButton = new Rectangle(btnDim);
gameTitleFont = new Font("Calibri", Font.BOLD, 28);
buttonFont = new Font("Calibri", Font.BOLD, startButton.height - 2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Color prevColor = g2d.getColor();
Font prevFont = g2d.getFont();
//methods calls
drawText(g2d);
drawButton(g2d);
//end of methods calls
g2d.setFont(prevFont);
g2d.setColor(prevColor);
g2d.dispose();
}
private void drawText(Graphics2D g2d) {
g2d.setColor(TEXT_COLOR);
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D gameTitleRect = gameTitleFont.getStringBounds(GAME_TITLE, frc);
int sX, sY;
sY = (int) (getHeight() / 4);
sX = (int) (getWidth() - gameTitleRect.getWidth()) / 2;
sY += (int) gameTitleRect.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(gameTitleFont);
g2d.drawString(GAME_TITLE, sX, sY);
}
private void drawButton(Graphics2D g2d) {
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D txtRect = buttonFont.getStringBounds(START_TEXT, frc);
Rectangle2D mTxtRect = buttonFont.getStringBounds(INFO_TEXT, frc);
g2d.setFont(buttonFont);
int x = (getWidth() - startButton.width) / 2;
int y = (int) ((getHeight() - startButton.height) * 0.5);
startButton.setLocation(x, y);
x = (int) (startButton.getWidth() - txtRect.getWidth()) / 2;
y = (int) (startButton.getHeight() - txtRect.getHeight()) / 2;
x += startButton.x;
y += startButton.y + (startButton.height * 0.9);
if (lastClickPoint != null && startButton.contains(lastClickPoint)) {
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(startButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(START_TEXT, x, y);
g2d.setColor(tmp);
} else {
g2d.draw(startButton);
g2d.drawString(START_TEXT, x, y);
}
x = startButton.x;
y = startButton.y;
y *= 1.3;
infoButton.setLocation(x, y);
x = (int) (infoButton.getWidth() - mTxtRect.getWidth()) / 2;
y = (int) (infoButton.getHeight() - mTxtRect.getHeight()) / 2;
x += infoButton.getX();
y += infoButton.getY() + (startButton.height * 0.9);
if (lastClickPoint != null && infoButton.contains(lastClickPoint)) {
Color tmp = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(infoButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(INFO_TEXT, x, y);
g2d.setColor(tmp);
} else {
g2d.draw(infoButton);
g2d.drawString(INFO_TEXT, x, y);
}
}
protected void peformStartGameAction() {
navigationListener.navigateToStartGame(this);
}
protected void performInfoAction() {
navigationListener.navigateToInfo(this);
}
}
public class HowToPlayPane extends AbstractBaseMenuPane {
public static interface NavigationListener {
public void navigateBack(HowToPlayPane source);
}
private static final String HOW_TO_PLAY_TEXT = """
1- Click Start\n
2- Choose the mode\n
3- Each mode has 3 levels\n
4- To play/pause press space, use 'A' and 'D' to move\n
5- To open pause menu press 'ESC'\n
6- To open DebugPanel press 'ALT-SHIFT-F1'""";
private static final String BACK_TEXT = "BACK";
private static final String INFO_TEXT = "INFO";
private Rectangle backButton;
private boolean backClicked = false;
private Font infoFont;
private Font howtoPlayFont;
private NavigationListener navigationListener;
public HowToPlayPane(NavigationListener navigationListener) {
this.navigationListener = navigationListener;
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (backButton.contains(p)) {
backClicked = true;
repaint();
performBackAction();
}
}
#Override
public void mouseReleased(MouseEvent e) {
backClicked = false;
}
});
this.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent mouseEvent) {
Point p = mouseEvent.getPoint();
if (backButton.contains(p)) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
setCursor(Cursor.getDefaultCursor());
}
}
});
Dimension btnDim = new Dimension(getPreferredSize().width / 3, getPreferredSize().height / 12);
backButton = new Rectangle(btnDim);
infoFont = new Font("Calibri", Font.BOLD, 24);
howtoPlayFont = new Font("Calibri", Font.PLAIN, 14);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(BORDER_COLOR);
g2d.fillRect(0, 0, getWidth(), getHeight());
FontRenderContext frc = g2d.getFontRenderContext();
Rectangle2D infoRec = infoFont.getStringBounds(INFO_TEXT, frc);
//
// Color prev = g2d.getColor();
//
// Stroke tmp = g2d.getStroke();
//
// g2d.setStroke(borderStoke_noDashes);
// g2d.setColor(DASH_BORDER_COLOR);
// g2d.draw(infoFace);
//
// g2d.setStroke(borderStoke);
// g2d.setColor(BORDER_COLOR);
// g2d.draw(infoFace);
//
// g2d.fillRect(0, 0, infoFace.width, infoFace.height);
//
// g2d.setStroke(tmp);
//
// g2d.setColor(prev);
//
g2d.setColor(TEXT_COLOR);
int sX, sY;
sY = (int) (getHeight() / 15);
sX = (int) (getWidth() - infoRec.getWidth()) / 2;
sY += (int) infoRec.getHeight() * 1.1;//add 10% of String height between the two strings
g2d.setFont(infoFont);
g2d.drawString(INFO_TEXT, sX, sY);
TextLayout layout = new TextLayout(HOW_TO_PLAY_TEXT, howtoPlayFont, frc);
String[] outputs = HOW_TO_PLAY_TEXT.split("\n");
for (int i = 0; i < outputs.length; i++) {
g2d.setFont(howtoPlayFont);
g2d.drawString(outputs[i], 40, (int) (80 + i * layout.getBounds().getHeight() + 0.5));
}
backButton.setLocation(getWidth() / 3, getHeight() - 50);
int x = (int) (backButton.getWidth() - infoRec.getWidth()) / 2;
int y = (int) (backButton.getHeight() - infoRec.getHeight()) / 2;
x += backButton.x + 11;
y += backButton.y + (layout.getBounds().getHeight() * 1.35);
backButton.setLocation(getWidth() / 3, getHeight() - 50);
if (backClicked) {
Color tmp1 = g2d.getColor();
g2d.setColor(CLICKED_BUTTON_COLOR);
g2d.draw(backButton);
g2d.setColor(CLICKED_TEXT);
g2d.drawString(BACK_TEXT, x, y);
g2d.setColor(tmp1);
repaint();
} else {
g2d.draw(backButton);
g2d.drawString(BACK_TEXT, x, y);
}
g2d.dispose();
}
protected void performBackAction() {
navigationListener.navigateBack(this);
}
}
}
Now, this example makes use of components to present different views (it even has a nice abstract implementation to allow for code re-use 😱), but it occurs to me, that, if you "really" wanted to, you could have a series of "painter" classes, which could be used to delegate the painting of the current state to, and mouse clicks/movements could be delegated to, meaning you could have a single component, which would simple delegate the painting (via the paintComponent method) to which ever painter is active.
And, wouldn't you know it, they have a design principle for that to, the Delegation Pattern
The above example also makes use of the observer pattern, so you might want to have a look into that as well
I'm having issues drawing some circles to my JFrame. I originally had it using the default layout and realized this was only adding the most recent circle, so I changed the layout to null, and now nothing gets drawn. I've also tried frame.setLayout(new FlowLayout()) which also doesn't draw anything. Any help would be appreciated!
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
* #author Christopher Nielson
*
*/
public class Main {
private static JFrame frame;
private static Random rand;
private static Jiggler jiggler;
private static ArrayList<JComponent> circles;
private static int fps;
public static void main(String[] args) {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setBounds(100, 100, 450, 450);
rand = new Random();
circles = new ArrayList<JComponent>();
int x = frame.getWidth();
int y = frame.getHeight();
for (int i = 0; i < Integer.parseInt(args[0]); i++) {
circles.add(new Circle(rand.nextInt(frame.getWidth()), rand.nextInt(frame.getHeight()),
rand.nextInt(frame.getWidth() / 10) + 100, rand.nextInt(frame.getHeight() / 10) + 100, null));
}
circles.forEach(current -> {
frame.add(current);
});
frame.setVisible(true);
jiggler = new Jiggler(circles, new JLabel("FPS: ")); // TODO add fps
jiggler.run();
}
}
And this is one reason you'll see us recommending time and time again to avoid using null layouts like the plague.
Having said that, your main problem is a design problem, not a layout problem, and that problem being that your Circle class shouldn't extend JComponent or any component for that matter, since if you want to draw multiple circles, you should have only one component, probably a JPanel doing the drawing, and the Circles should be logical classes, classes that have a public void draw(Graphics g) method, not component classes. You would pass the List of Circles to your drawing JPanel, and it would draw the Circles in its paintComponent method by calling the draw(g) methods of each Circle in the list.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawChit extends JPanel {
private static final int PREF_W = 900;
private static final int PREF_H = 700;
private static final int MAX_SHAPES = 30;
private List<MyShape> shapes = new ArrayList<>();
public DrawChit() {
setBackground(Color.WHITE);
for (int i = 0; i < MAX_SHAPES; i++) {
double x = (PREF_W - 100) * Math.random();
double y = (PREF_H - 100) * Math.random();
double w = 100 + (Math.random() * PREF_W) / 10;
double h = 100 + (Math.random() * PREF_H) / 10;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, w, h);
float hue = (float) Math.random();
double delta = 0.3;
float saturation = (float) (Math.random() * delta + (1 - delta));
float brightness = (float) (Math.random() * delta + (1 - delta));
Color color = Color.getHSBColor(hue, saturation, brightness);
shapes.add(new MyShape(ellipse, color));
}
// we'll throw a black square in the middle!
int rectW = 200;
int rectX = (PREF_W - rectW) / 2;
int rectY = (PREF_H - rectW) / 2;
shapes.add(new MyShape(new Rectangle(rectX, rectY, rectW, rectW), Color.BLACK));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use anti-aliasing to make graphics smooth
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the shapes list, filling all
for (MyShape shape : shapes) {
shape.fill(g2);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
private Point p0 = null;
private MyShape shape = null;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// iterate *backwards* so get top-most Shape
for (int i = shapes.size() - 1; i >= 0; i--) {
if (shapes.get(i).contains(e.getPoint())) {
p0 = e.getPoint();
shape = shapes.get(i);
// move selected shape to the top!
shapes.remove(shape);
shapes.add(shape);
repaint();
return;
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (p0 != null) {
moveShape(e.getPoint());
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p0 != null) {
moveShape(e.getPoint());
p0 = null;
shape = null;
}
}
// translates the shape
private void moveShape(Point p1) {
int deltaX = p1.x - p0.x;
int deltaY = p1.y - p0.y;
shape.translate(deltaX, deltaY);
p0 = p1;
repaint();
}
}
private static void createAndShowGui() {
DrawChit mainPanel = new DrawChit();
JFrame frame = new JFrame("Draw Chit");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyShape {
private Path2D path = new Path2D.Double();
private Color color;
public MyShape(Shape shape, Color color) {
path.append(shape, true);
this.color = color;
}
public boolean contains(Point p) {
return path.contains(p);
}
public void draw(Graphics2D g2) {
g2.setColor(color);
g2.draw(path);
}
public void fill(Graphics2D g2) {
g2.setColor(color);
g2.fill(path);
}
public void translate(int deltaX, int deltaY) {
path.transform(AffineTransform.getTranslateInstance(deltaX, deltaY));
}
}
So as you can see my painting program is working properly. It can draw shapes like oval and rectangle (oval shape looks kinda bug though if anyone could help me fix it as well). I want to know how to make a saving button. Right now, I don't even know what I'm doing. I have been research on how to save a drawn image, but none of the code on internet has an example of a java made drawing program with saving function. So here's my code:
Shapeframe class
package com.comp2526.assign2c.a.a00892238;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileWriter;
import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* This class creates the painting program's toolbar, buttons and stuffs.
* #author Fu Han
* #version 1.0
*/
public class ShapeFrame extends JFrame implements ActionListener {
/**
* the white board
*/
static DrawPad drawboard;
/**
* the constant string 'save'.
*/
static final private String SAVE = "Save";
/**
* the constant string 'save as'.
*/
static final private String SAVE_AS = "Save As";
/**
* the constant string 'new'.
*/
static final private String NEW = "New";
/**
* the constant string 'color'.
*/
static final private String color = "Color";
/**
* string oval for easy access for buttons.
*/
static String oval = new String("oval");
/**
* string line for easy access for buttons.
*/
static String line = new String("line");
/**
* string rectangle for easy access for buttons.
*/
static String rectangle = new String("rectangle");
/**
* string square for easy access for buttons.
*/
static String square = new String("square");
/**
* color.
*/
Color currentColor;
/**
* ShapeFrame constructor.
*/
public ShapeFrame(){
super();
}
/**
* method that add buttons.
* #param toolBar Jtoolbar.
* #param btn Jbuttons.
*/
protected void addButtons(JToolBar toolBar, JButton btn) {
toolBar.add(btn);
}
/**
* method that add radio buttons.
* #param toolBar Jtoolbar.
* #param btn JRadioButton.
*/
protected void addRadioButtons(JToolBar toolBar, JRadioButton btn) {
toolBar.add(btn);
}
/**
* method that creates button.
* #param btnNam button name.
* #param actionCommand calling from string constant.
* #param toolTipText the message that will appear if cursor was hover over.
* #param altText alternative text.
* #return button Jbutton.
*/
protected JButton btnmaker(String btnNam, String actionCommand, String toolTipText, String altText) {
//Create and initialize the button.
JButton button = new JButton(btnNam);
button.setActionCommand(actionCommand);
button.setToolTipText(toolTipText);
button.addActionListener(this);
return button;
}
/**
* action performed when clicked button.
* #param e mouse click.
*/
public void actionPerformed(ActionEvent e) {
}
public static void savebtn(DrawPad dp) {
DrawPad dp1 = dp;
//String sb = "gg";
/*
public void save() throws IOException{
ImageIO.write(paintImage, "PNG", new File("filename.png"));
}*/
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("/home/me/Documents"));
int retrieval = chooser.showSaveDialog(null);
if (retrieval == JFileChooser.APPROVE_OPTION) {
try {
//FileWriter fw = new FileWriter(chooser.getSelectedFile()+".png");
//fw.write(sb.toString());
//fw.close();
ImageIO.write((RenderedImage) dp1.image, "PNG", new File("filename.png"));
ImageIo.
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/**
* editlistener for menu bar.
* #author Fu Han
*
*/
private class EditListener implements ActionListener {
/**
* action performed when clicking menu button.
* #param e mouse click.
*/
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand() == SAVE) {
System.out.print("save");
}else{
System.out.println(e.getActionCommand());
}
}
}
/**
* radio listener for the radio buttons.
* #author Fu Han
*
*/
private class RadioListener implements ActionListener{
/**
* action performed when click the button.
* #param e mouse click.
*/
public void actionPerformed(ActionEvent e) {
System.out.print("ActionEvent received: ");
if (e.getActionCommand() == oval) {
System.out.println(oval + " pressed.");
drawboard.line = false;
drawboard.rectangle = false;
drawboard.square = false;
drawboard.oval = true;
}else if(e.getActionCommand() == rectangle){
System.out.println(rectangle + " pressed.");
drawboard.line = false;
drawboard.rectangle = true;
drawboard.square = false;
drawboard.oval = false;
}else if(e.getActionCommand() == square){
System.out.println(square + " pressed.");
drawboard.line = false;
drawboard.rectangle = false;
drawboard.square = true;
drawboard.oval = false;
}else{
System.out.println(line + " pressed.");
drawboard.line = true;
drawboard.rectangle = false;
drawboard.square = false;
drawboard.oval = false;
}
}
}
/**
* method for when changes of states that happened after clicking.
* #param e mouse click.
*/
public void stateChanged(ChangeEvent e) {
}
/**
* method for selecting color.
*/
private void selectColor(){
Color newColor = JColorChooser.showDialog(
ShapeFrame.this,
"Choose New Background Color",
currentColor);
if(newColor != null){
currentColor = newColor;
}
}
/**
* GUI initialization.
*/
public void init(){
Container content = getContentPane();
//Creates a new container
content.setLayout(new BorderLayout());
//sets the layout
final DrawPad drawPad = new DrawPad();
//creates a new padDraw, which is pretty much the paint program
content.add(drawPad, BorderLayout.CENTER);
JMenuBar menubar = new JMenuBar();
EditListener l = new EditListener();
JMenu filem = new JMenu("File");
JMenuItem mi;
mi = filem.add(new JMenuItem("New", 'n'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, Event.CTRL_MASK));
mi.addActionListener(l);
mi = filem.add(new JMenuItem("Open", 'o'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK));
mi.addActionListener(l);
mi = filem.add(new JMenuItem("Save", 's'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Event.CTRL_MASK));
mi.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
savebtn(drawPad);
}
});
mi = filem.add(new JMenuItem("Save As", 'a'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Event.CTRL_MASK));
mi.addActionListener(l);
mi = filem.add(new JMenuItem("Exit", 'e'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, Event.CTRL_MASK));
mi.addActionListener(l);
JMenu shapem = new JMenu("Shape");
JMenuItem smi;
smi = shapem.add(new JMenuItem("Line", 'l'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.CTRL_MASK));
smi.addActionListener(l);
smi = shapem.add(new JMenuItem("Circle", 'c'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK));
smi.addActionListener(l);
smi = shapem.add(new JMenuItem("Rectangle", 'r'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, Event.CTRL_MASK));
smi.addActionListener(l);
smi = shapem.add(new JMenuItem("Square", 'q'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, Event.CTRL_MASK));
smi.addActionListener(l);
smi = shapem.add(new JMenuItem("Shape Picker", 'p'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, Event.CTRL_MASK));
smi.addActionListener(l);
menubar.add(filem);
menubar.add(shapem);
menubar.add(Box.createHorizontalGlue());
setJMenuBar(menubar);
//Create the toolbar.
JPanel panel = new JPanel();
JPanel panel2 = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS));
JButton saveBtn = btnmaker("Save",SAVE, "save your paint", "Save");
JButton saveAsBtn = btnmaker("Save As",SAVE_AS, "save your paint to?","Save As");
JButton NewBtn = btnmaker("New",NEW,"new paint","New");
JButton colorbtn = btnmaker("Color",color,"choose color","Color");
colorbtn.setToolTipText("Click this button to select colors.");
colorbtn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg) {
selectColor();
drawPad.color(currentColor);
}
});
RadioListener myListener = new RadioListener();
JRadioButton ovalShape = new JRadioButton(oval);
ovalShape.addActionListener(myListener);
ovalShape.setMnemonic(KeyEvent.VK_A);
ovalShape.setActionCommand(oval);
//add(ovalShape);
JRadioButton rectangleShape = new JRadioButton(rectangle);
rectangleShape.addActionListener(myListener);
rectangleShape.setMnemonic(KeyEvent.VK_A);
rectangleShape.setActionCommand(rectangle);
//add(rectangleShape);
JRadioButton squareShape = new JRadioButton(square);
squareShape.addActionListener(myListener);
squareShape.setMnemonic(KeyEvent.VK_A);
squareShape.setActionCommand(square);
//add(squareShape);
JRadioButton lineShape = new JRadioButton(line);
lineShape.addActionListener(myListener);
lineShape.setMnemonic(KeyEvent.VK_B);
lineShape.setActionCommand(line);
lineShape.setSelected(true);
//add(lineShape);
ButtonGroup group = new ButtonGroup();
group.add(ovalShape);
group.add(lineShape);
group.add(rectangleShape);
group.add(squareShape);
JToolBar toolBar = new JToolBar("File");
JToolBar toolBar2 = new JToolBar("Shape",JToolBar.VERTICAL);
JToolBar toolbar3 = new JToolBar("colors",JToolBar.VERTICAL);
addButtons(toolBar,saveBtn);
addButtons(toolBar,saveAsBtn);
addButtons(toolBar,NewBtn);
addRadioButtons(toolBar2,ovalShape);
addRadioButtons(toolBar2,lineShape);
addRadioButtons(toolBar2,rectangleShape);
addRadioButtons(toolBar2,squareShape);
addButtons(toolbar3,colorbtn);
panel.add(toolBar);
panel2.add(toolBar2);
panel2.add(toolbar3);
content.add(panel, BorderLayout.NORTH);
content.add(panel2, BorderLayout.WEST);
}
}
DrawPad class:
package com.comp2526.assign2c.a.a00892238;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import javax.swing.JComponent;
/**
* the draw pad class for drawing
* #author Fu Han
* #version 1.0
*/
class DrawPad extends JComponent{
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* image
*/
Image image;
/**
* what user will be using to draw on
*/
Rectangle r = null;
Oval o = null;
Graphics2D graphics2D;
ArrayList<Rectangle> rectangleList = null;
/**
*mouse coordinates
*/
static boolean rectangle = false;
static boolean oval = false;
static boolean line = false;
static boolean square = false;
int currentX, currentY, oldX, oldY;
/**
* shape object
*/
/**
* constructor
*/
public DrawPad(){
rectangleList = new ArrayList<Rectangle>();
setDoubleBuffered(false);
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
oldX = e.getX();
oldY = e.getY();
if(rectangle == true){
r = new Rectangle(e.getX(), e.getY(),
e.getX(), e.getY(), graphics2D.getColor());
}else if(oval == true){
o = new Oval(e.getX(), e.getY(),
e.getX(), e.getY(), graphics2D.getColor());
}
}
});
//if the mouse is pressed it sets the oldX & oldY
//coordinates as the mouses x & y coordinates
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
currentX = e.getX();
currentY = e.getY();
if(graphics2D != null){
if(rectangle == true){
r = new Rectangle(r.getX1(),
r.getY1(), e.getX(), e.getY(),
r.getColor());
drawRectangle(r,graphics2D);
rectangleList.add(new Rectangle(r.getX1(),
r.getY1(), e.getX(), e.getY(),
graphics2D.getColor()));
repaint();
oval = false;
line = false;
square = false;
}
else if(line == true){
graphics2D.drawLine(oldX, oldY, currentX, currentY);
repaint();
oldX = currentX;
oldY = currentY;
rectangle = false;
oval = false;
square = false;
}
else if(oval == true){
o = new Oval(o.getX1(), o.getY1(),
e.getX(), e.getY(), o.getColor());
drawOval(o,graphics2D);
repaint();
rectangle = false;
square = false;
line = false;
}
}
}
});
//while the mouse is dragged it sets currentX & currentY as the mouses x and y
//then it draws a line at the coordinates
//it repaints it and sets oldX and oldY as currentX and currentY
}
/**
* painting dot
* #param g Graphic
*/
public void paintComponent(Graphics g){
if(image == null){
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image, 0, 0, null);
}
public void clear(){
graphics2D.setPaint(Color.white);
graphics2D.fillRect(0, 0, getSize().width, getSize().height);
graphics2D.setPaint(Color.black);
repaint();
}
public void drawRectangle(Rectangle rek, Graphics gr) {
Graphics2D g = null;
if (gr instanceof Graphics2D) {
g = (Graphics2D) gr;
}
else{ return; }
//g.setStroke(new BasicStroke(3));
g.drawRect(rek.getX1(), rek.getY1(), rek.getWidth(), rek.getHeight());
g.setColor(graphics2D.getColor());
g.fillRect(rek.getX1(), rek.getY1(), rek.getWidth(), rek.getHeight());
//g.drawLine(rek.getX1(), rek.getY1(), rek.getX2(), rek.getY1());
//g.drawLine(rek.getX1(), rek.getY1(), rek.getX1(), rek.getY2());
//g.drawLine(rek.getX2(), rek.getY2(), rek.getX2(), rek.getY1());
// g.drawLine(rek.getX2(), rek.getY2(), rek.getX1(), rek.getY2());
}
public void drawOval(Oval ovo, Graphics gr) {
Graphics2D g = null;
if (gr instanceof Graphics2D) {
g = (Graphics2D) gr;
}
else{ return; }
//g.setStroke(new BasicStroke(3));
g.drawOval(ovo.getX1(), ovo.getY1(), ovo.getWidth(), ovo.getHeight());
g.setColor(graphics2D.getColor());
g.fillOval(ovo.getX1(), ovo.getY1(), ovo.getWidth(), ovo.getHeight());
//g.drawLine(rek.getX1(), rek.getY1(), rek.getX2(), rek.getY1());
//g.drawLine(rek.getX1(), rek.getY1(), rek.getX1(), rek.getY2());
//g.drawLine(rek.getX2(), rek.getY2(), rek.getX2(), rek.getY1());
// g.drawLine(rek.getX2(), rek.getY2(), rek.getX1(), rek.getY2());
}
/**
* setting dot color
* #param color color
*/
public void color(Color color){
graphics2D.setPaint(color);
repaint();
}
}
Main class:
package com.comp2526.assign2c.a.a00892238;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import javax.swing.JFrame;
/**
* main class.
* #author Fu Han
* #version 1.0
*
*/
public class Main {
/**
* tookit
*/
private static final Toolkit TOOLKIT;
static {
TOOLKIT = Toolkit.getDefaultToolkit();
}
/**
* defaulth constructor.
*/
private Main() {}
/**
* main method.
* #param argv argv
*/
public static void main(final String[] argv) {
final ShapeFrame frame;
frame = new ShapeFrame();
position(frame);
frame.init();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
/**
* position for shapeframe.
* #param frame Shapeframe.
*/
private static void position(final JFrame frame) {
final Dimension size;
size = calculateScreenArea(0.80f,
0.80f);
frame.setSize(size);
frame.setLocation(centreOnScreen(size));
}
/**
* the amount of center on screen
* #param size space size.
* #return the complete calculated space.
*/
public static Point centreOnScreen(final Dimension size) {
final Dimension screenSize;
if (size == null) {
throw new IllegalArgumentException("Size cannot be null");
}
screenSize = TOOLKIT.getScreenSize();
return (new Point((screenSize.width - size.width) / 2, (screenSize.height - size.height) / 2));
}
/**
* method that calculating screen area.
* #param widthPercent width percentage.
* #param heightPercent height percentage.
* #return dimension the dimension.
*/
public static Dimension calculateScreenArea(final float widthPercent,
final float heightPercent) {
final Dimension screenSize;
final Dimension area;
final int width;
final int height;
final int size;
if ((widthPercent <= 0.0f) || (widthPercent > 100.0f)) {
throw new IllegalArgumentException("widthPercent cannot be " +
"<= 0 or > 100 - got: " +
widthPercent);
}
if ((heightPercent <= 0.0f) || (heightPercent > 100.0f)) {
throw new IllegalArgumentException("heightPercent cannot be " +
"<= 0 or > 100 - got: " +
heightPercent);
}
screenSize = TOOLKIT.getScreenSize();
width = (int)(screenSize.width * widthPercent);
height = (int)(screenSize.height * heightPercent);
size = Math.min(width,
height);
area = new Dimension(size,
size);
return (area);
}
}
Rectangle class:
package com.comp2526.assign2c.a.a00892238;
import java.awt.Color;
import java.awt.Graphics2D;
public class Rectangle extends Shape {
// Initialize variables
private int x1; // x coordinate of first endpoint
private int y1; // y coordinate of first endpoint
private int x2; // x coordinate of second endpoint
private int y2; // y coordinate of second endpoint
private Color colour; // colour of the shape
// A no-parameter constructor that sets all the coordinates of the shape to
// 0 and the
// colour to Color.BLACK
public Rectangle() {
x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
colour = Color.BLACK;
}
// A constructor that initializes the coordinates and colour to the values
// of the
// parameters supplied.
public Rectangle(int x1, int y1, int x2, int y2, Color col) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.colour = col;
}
public void setX1(int x1) {
this.x1 = x1;
}
public void setY1(int y1) {
this.y1 = y1;
}
public void setX2(int x2) {
this.x2 = x2;
}
public void setY2(int y2) {
this.y2 = y2;
}
public void setColor(Color colour) {
this.colour = colour;
}
public int getX1() {
return this.x1;
}
public int getY1() {
return this.y1;
}
public int getX2() {
return this.x2;
}
public int getY2() {
return this.y2;
}
public Color getColor() {
return this.colour;
}
public int getWidth() {
return (Math.abs(x2 - x1));
}
public int getHeight() {
return (Math.abs(y2 - y1));
}
public int getUpperLeftX() {
return (Math.min(x1, x2));
}
public int getUpperLeftY() {
return (Math.min(y1, y2));
}
}
Point class:
package com.comp2526.assign2c.a.a00892238;
public class Point {
private int x = 0;
private int y = 0;
public Point() {}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
Oval class:
package com.comp2526.assign2c.a.a00892238;
import java.awt.Color;
import java.awt.Graphics2D;
public class Oval {
// Initialize variables
private int x1; // x coordinate of first endpoint
private int y1; // y coordinate of first endpoint
private int x2; // x coordinate of second endpoint
private int y2; // y coordinate of second endpoint
private Color colour; // colour of the shape
// A no-parameter constructor that sets all the coordinates of the shape to
// 0 and the
// colour to Color.BLACK
public Oval() {
x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
colour = Color.BLACK;
}
// A constructor that initializes the coordinates and colour to the values
// of the
// parameters supplied.
public Oval(int x1, int y1, int x2, int y2, Color col) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.colour = col;
}
public void setX1(int x1) {
this.x1 = x1;
}
public void setY1(int y1) {
this.y1 = y1;
}
public void setX2(int x2) {
this.x2 = x2;
}
public void setY2(int y2) {
this.y2 = y2;
}
public void setColor(Color colour) {
this.colour = colour;
}
public int getX1() {
return this.x1;
}
public int getY1() {
return this.y1;
}
public int getX2() {
return this.x2;
}
public int getY2() {
return this.y2;
}
public Color getColor() {
return this.colour;
}
public int getWidth() {
return (Math.abs(x2 - x1));
}
public int getHeight() {
return (Math.abs(y2 - y1));
}
public int getUpperLeftX() {
return (Math.min(x1, x2));
}
public int getUpperLeftY() {
return (Math.min(y1, y2));
}
}
In your ShapeFrame class if you make your savebtn() method like this then your File->Save option will save the image where you pick from the save dialog, the other buttons and such you have to do but your File->Save option will save the file with this
public static void savebtn(DrawPad dp) {
DrawPad dp1 = dp;
//String sb = "gg";
/*
public void save() throws IOException{
ImageIO.write(paintImage, "PNG", new File("filename.png"));
}*/
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("/home/me/Documents"));
int retrieval = chooser.showSaveDialog(null);
if (retrieval == JFileChooser.APPROVE_OPTION) {
try {
//FileWriter fw = new FileWriter(chooser.getSelectedFile()+".png");
//fw.write(sb.toString());
//fw.close();
File f = chooser.getSelectedFile();
String filePath = f.getPath();
if(!filePath.toLowerCase().endsWith(".png"))
{
f = new File(filePath + ".png");
}
ImageIO.write((RenderedImage) dp1.image, "PNG", f);
//ImageIo.
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I want to click on the screen and have the character move to that destination. Not instantly, but rather "walk" to the given coordinate. Currently I'm using JLabels and they're fine if I only use static images, but everytime I click somewhere on the screen the image shows up at that exact point. Could someone give me some tips?
edit: Should I override the paint class and draw some items that way?
Here's some code:
package mod;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.awt.KeyboardFocusManager;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Board2 extends JPanel {
private Thread animator;
int x, y;
double ix, iy;
double dx, dy;
final int frameCount = 8;
BufferedImage flower;
private int[][] fPos = {{232, 15},{400, 200},{335, 335}}; // flower coordinates
private static int bWIDTH = 800; // width of window
private static int bHEIGHT = 600;// height of window
private Font font;
private FontMetrics metrics;
ImageIcon grassI = new ImageIcon(this.getClass().getResource("grass.png"));
ImageIcon riverI = new ImageIcon(this.getClass().getResource("river.png"));
private Image grass = grassI.getImage();
private Image river = riverI.getImage();
private House house = new House();
private River river1 = new River();
//private Flower flower = new Flower();
private TitleScreenLayer ts = new TitleScreenLayer();
private Player girlP = new Player();
private static int px = 250;
private static int py = 250;
private boolean visTl = false;
private boolean plant = false;
ArrayList<Flower> flowers= new ArrayList<Flower>();
private long period;
private volatile boolean running = false;
private volatile boolean gameOver = false;
private volatile boolean isPaused = false;
// New stuff for Board2 below
private JLayeredPane lpane;
private JLabel grassLabel;
private JLabel riverLabel;
private JLabel houseLabel;
private JLabel pear1Label;
private JLabel pear2Label;
private JLabel pear3Label;
private JLabel drivewayLabel;
private JLabel girlLabel;
private JProgressBar progressBar;
private JLabel toolLabel;
private JTextArea textBubble;
ImageIcon girlImage = new ImageIcon(girlP.getImage());
int mouseClicks = 0;
CountdownTimer cTimer;
private static String message;
public static String setMessage(String newMessage){
return message = newMessage;
}
private static ImageIcon playerTool = new ImageIcon("BradfordPear.png");
public ImageIcon getPlayerTool(){
return playerTool;
}
public static void setPlayerTool(String image){
playerTool = new ImageIcon(image);
}
public JTextArea getTextBubble(){
return textBubble;
}
public Player getPlayer(){
return girlP;
}
public static int getPlayerX(){
return px;
}
public static int getPlayerY(){
return py;
}
public JLayeredPane getLayeredPane(){
return lpane;
}
public Board2(){
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
//create the layered pane
lpane = new JLayeredPane();
lpane.setPreferredSize(new Dimension(800, 600));
//create the "background" image
ImageIcon image = new ImageIcon("grass.png");
grassLabel = new JLabel(image);
grassLabel.setBounds(0, 0, image.getIconWidth(), image.getIconHeight());
//create the house image
ImageIcon houseImage = new ImageIcon("house.png");
houseLabel = new JLabel(houseImage);
houseLabel.setBounds(-330, -150, image.getIconWidth(), image.getIconHeight());
//create the driveway image
ImageIcon drivewayImage = new ImageIcon("driveway.png");
drivewayLabel = new JLabel(drivewayImage);
drivewayLabel.setBounds(-335, 105, image.getIconWidth(), image.getIconHeight());
//create the river image
ImageIcon riverImage = new ImageIcon("river.png");
riverLabel = new JLabel(riverImage);
riverLabel.setBounds(360, 0, image.getIconWidth(), image.getIconHeight());
//create pear1 image
ImageIcon pear1Image = new ImageIcon("BradfordPear.png");
pear1Label = new JLabel(pear1Image);
pear1Label.setBounds(100, 100, image.getIconWidth(), image.getIconHeight());
//create pear2 image
ImageIcon pear2Image = new ImageIcon("BradfordPear.png");
pear2Label = new JLabel(pear2Image);
pear2Label.setBounds(50, -100, image.getIconWidth(), image.getIconHeight());
//create pear3 image
ImageIcon pear3Image = new ImageIcon("BradfordPear.png");
pear3Label = new JLabel(pear3Image);
pear3Label.setBounds(-100, -50, image.getIconWidth(), image.getIconHeight());
//create initial Player(girl) image
//ImageIcon girlImage = new ImageIcon(girlP.getImage());
girlLabel = new JLabel(girlImage);
girlLabel.setBounds((int)girlP.getPositionX(), (int)girlP.getPositionY(), image.getIconWidth(), image.getIconHeight());
//create progress bar
progressBar = new JProgressBar(JProgressBar.VERTICAL, 0, 10);
progressBar.setValue(0);
progressBar.setBounds(720, 50, 100, 500);
//create timer
JTextField timerField = new JTextField();
cTimer = new CountdownTimer(timerField);
timerField.setBounds(400, 0, 50, 50);
//create toolbox
Toolbox toolbox = new Toolbox();
toolbox.setBounds(550, 0, 250, 50);
//create the text bubble
textBubble = new JTextArea("IDPC is the best coding group ever");
textBubble.setLineWrap(true);
//textBubble.setBounds(200, 200, 100, 100);
//add the background & various images
lpane.add(grassLabel, new Integer(1));
lpane.add(houseLabel, new Integer(2));
lpane.add(riverLabel, new Integer(2));
lpane.add(drivewayLabel, new Integer(2));
lpane.add(pear1Label, new Integer(2));
lpane.add(pear2Label, new Integer(2));
lpane.add(pear3Label, new Integer(2));
lpane.add(progressBar, new Integer(3));
lpane.add(girlLabel, new Integer(3));
lpane.add(timerField, new Integer(2));
lpane.add(toolbox, new Integer(3));
add(lpane);
cTimer.start();
// listen for action events
new ActionListener() {
public void actionPerformed(ActionEvent e) {
girlP.move();
//girlLabel.setLocation(px, py);
}
};
// listen for mouse presses
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
//lpane.remove(textBubble);
mouseClicks+= 1;
testPress(e.getX(), e.getY());
//textBubble.setBounds(e.getX(), e.getY(), 40, 40);
updateProgressBar();
}
});
//listen for player action
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 2){
ImageIcon flowerImage = playerTool;
JLabel flowerPanel = new JLabel(flowerImage);
flowerPanel.setBounds((px -((int)girlP.getPositionX() / 2)),
(py - ((int)girlP.getPositionY() / 2)),
flowerImage.getIconWidth(),
flowerImage.getIconHeight());
lpane.add(flowerPanel, new Integer(3));
textBubble.setBounds(e.getX(), e.getY(), 200, 40);
textBubble.replaceSelection(message);
lpane.add(textBubble, new Integer(3));
//lpane.remove(textBubble);
}
}
});
x = 15;
y = 150;
ix = 0;
iy = 0;
dx = .05;
dy = .05;
girlP.setDestination(px, py);
}
public void testPress(int x, int y){
px = x;
py = y;
if (px < (ix + house.getImage().getWidth(this))
&& (py < (iy + house.getImage().getHeight(this)))) {
px = px + (house.getImage().getWidth(this)/3);
py = py + (house.getImage().getHeight(this)/3);
}
if (px > (bWIDTH - river1.getImage().getWidth(this))) {
px = px - 80 - (river1.getImage().getWidth(this)/2);
}
girlLabel.setBounds((px -((int)(girlP.getPositionX()*2.5))),
(py - ((int)(girlP.getPositionY()*2.5))),
girlImage.getIconWidth(), girlImage.getIconHeight());
girlP.setDestination((px-(girlP.getImage().getWidth(this)/2)),
(py-(girlP.getImage().getHeight(this)/2)));
girlP.pinned(x, y);
}
public void updateProgressBar(){
if(progressBar.getValue() == 3){
//progressBar.setBackground(Color.red);
//UIManager.put("progressBar.foreground", Color.RED);
UIDefaults defaults = new UIDefaults();
defaults.put("progressBar[Enabled].foregroundPainter", Color.RED);
progressBar.putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE);
progressBar.putClientProperty("Nimbus.Overrides", defaults);
}
progressBar.setValue(mouseClicks);
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new TitleScreenLayer();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Here's the player class:
package mod;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.ImageObserver;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
public class Player {
int tile;
double positionX;
double positionY;
int destinationX;//Used when moving from place to place
int destinationY;
Tool currentTool;
int direction; //Position the image is facing
double dx;
double dy;
int [] pin = new int[10];
private String girl = "girl.png";
ImageIcon ii = new ImageIcon(this.getClass().getResource(girl)); // load girl image
private Image image = ii.getImage();
private boolean visible = true;
public boolean plant = false;
Image playerImage;
public double getPositionX() {
return positionX;
}
public void setPositionX(double positionX) {
this.positionX = positionX;
}
public double getPositionY() {
return positionY;
}
public void setPositionY(double positionY) {
this.positionY = positionY;
}
public Player(){
positionX=30;
positionY=20;
dx = 0.2;
dy = 0.2;
destinationX=(int)positionX;
destinationY=(int)positionY;
//this.playerImage=playerImage;
}
public void doAction() {
//currentTool.getNum();
plant = true;
}
public void pinned(int x, int y) {
if (plant == true) {
pin[0] = x;
pin[1] = y;
}
//plant = false;
}
public void plant(Graphics g, ImageObserver io) {
int x = pin[0];
int y = pin[1];
if (plant == true) {
// g.drawImage(flower.getImage(), x, y, io);
}
}
public void ActionPerformed(ActionEvent e) {
positionX += dx;
positionY += dy;
}
public boolean isVisible() {
return visible;
}
public void setVisible(Boolean visible) {
this.visible = visible;
}
public Image getImage() {
return image;
}
public void move(){
//MOVE LEFT AND RIGHT
if(destinationX<positionX){
positionX-=dx;
}
if(destinationX>positionX){
positionX+=dx;
}
//MOVE UP AND DOWN
if(destinationY<positionY){
positionY-=dy;
}
if(destinationY>positionY){
positionY+=dy;
}
}
public double setDx(double speed) {
dx = speed;
return dx;
}
public double setDy(double speed) {
dy = speed;
return dy;
}
public void TileIn(int px, int py)
{
px=destinationX;
py=destinationY;
int tileX=1;
int tileY = 1;
int bWIDTH=800;
int bHEIGHT=600;
if(px >= 0 && px <= 800*.1)
{
tileX=2;
}
else if(px> bWIDTH*.1 && px <= bWIDTH*.2)
{
tileX=3;
}
else if(px > bWIDTH*.2 && px <= bWIDTH*.3)
{
tileX=4;
}
else if(px > bWIDTH*.3 && px <= bWIDTH*.4)
{
tileX=5;
}
else if(px > bWIDTH*.4 && px <= bWIDTH*.5)
{
tileX=6;
}
else if(px > bWIDTH*.5 && px <= bWIDTH*.6)
{
tileX=7;
}
else if(px > bWIDTH*.6 && px <= bWIDTH*.7)
{
tileX=8;
}
else if(px > bWIDTH*.7 && px <= bWIDTH*.8)
{
tileX=9;
}
else if(px > bWIDTH*.8 && px <= bWIDTH*.9)
{
tileX=10;
}
else if(px > bWIDTH*.9 && px <= bWIDTH)
{
tileX=11;
}
if(py >= 0 && py <= bHEIGHT*.1)
{
tileY=2;
}
else if(py> bHEIGHT*.1 && py <= bHEIGHT*.2)
{
tileY=3;
}
else if(py > bHEIGHT*.2 && py <= bHEIGHT*.3)
{
tileY=4;
}
else if(py > bHEIGHT*.3 && py <= bHEIGHT*.4)
{
tileY=5;
}
else if(py > bHEIGHT*.4 && py <= bHEIGHT*.5)
{
tileY=6;
}
else if(py > bHEIGHT*.5 && py <= bHEIGHT*.6)
{
tileY=7;
}
else if(py > bHEIGHT*.6 && py <= bHEIGHT*.7)
{
tileY=8;
}
else if(py > bHEIGHT*.7 && py <= bHEIGHT*.8)
{
tileY=9;
}
else if(py > bHEIGHT*.8 && py <= bHEIGHT*.9)
{
tileY=10;
}
else if(py > bHEIGHT*.9 && py <= bHEIGHT)
{
tileY=11;
}
System.out.println("Grid X: " + tileX + " Grid Y: " + tileY);
}
public void setDestination(int x, int y){
destinationX=x;
destinationY=y;
System.out.println(x + "," + y);
TileIn(x,y);
}
// public void tileIn(int a)
// {
//
// b=destinationY;
// return TileIn(x,y)
// }
public void draw(Graphics g,ImageObserver io){
g.drawImage(image, (int)positionX,(int) positionY,io);
}
}
Here is the main class:
package mod;
import java.awt.Container;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame;
public class Skeleton2 extends JFrame /*implements WindowListener*/{
private static int DEFAULT_FPS = 80;
private Board2 bd;
public Skeleton2(long period) {
super("Skeleton");
makeGUI(period);
//addWindowListener(this);
pack();
setResizable(false);
setVisible(true);
}
public void makeGUI(long period) {
Container c = getContentPane();
bd = new Board2();
c.add(bd, "Center");
} // end of makeGUI()
//==================================================================================
// Window Events
//==================================================================================
/*
public void windowActivated(WindowEvent e) {
bd.resumeGame();
}
public void windowDeactivated(WindowEvent e) {
bd.pauseGame();
}
public void windowDeiconified(WindowEvent e) {
bd.resumeGame();
}
public void windowIconified(WindowEvent e) {
bd.pauseGame();
}
public void windowClosing(WindowEvent e) {
bd.stopGame();
}
*/
public void windowClosed(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
//==================================================================================
public static void main(String[] args) {
int fps = DEFAULT_FPS;
long period = (long) 1000.0/fps;
new Skeleton2(period);
System.out.println("Period: " + period);
}
}
Not instantly, but rather "walk" to the given coordinate.
Then you need to use a Swing Timer. The Timer is used to schedule the animation. So you would need to calculate a path between the two points. Every time the Timer fires you would move the label a few pixels until it reaches it's destination.
There is no need to do custom painting for this. A JLabel will work fine. The hard part is calculating the path you want the character to take. Also make sure you use a null layout on the panel you add the JLabel to, which means you will also need to set the size of the label equal to the preferred size of the label.
You should rather use g.drawImage in your component paintComponent method.
I have a JFrame with BorderLayout as the layout manager.
In the south border, I have a JPanel, I want this JPanel's size to be adjustable by the user, i.e. the user can click on the edge of the border and drag it up to make it larger.
Is there any way you know that I can do this?
In order to make panels in a frame individually resizable you need to add them onto a JSplitPane.
Instead of putting it in the South portion of the Frame, put the JSplitPane in the Center. The split pane will make the bottom panel in the split seem like it is in the South, and the top panel in the split will be in the Center of the frame.
Make sure you set the orientation of the two panels with setOrientation(JSplitPane.VERTICAL_SPLIT ).
Then, you can resize the panels that are in the pane.
I think you meant to say JPanel. You can add a custom mouseListener and handle mouse clicks, drags and mouse releases and then resize the panel programmaticaly.
This will demonstrate this. Note that the jframe does NOT resize automatically with the JPanel. To make the effect more visible i painted the panel red and added a beveled border :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
#SuppressWarnings("serial")
public class ResizablePanel extends JPanel {
private boolean drag = false;
private Point dragLocation = new Point();
public ResizablePanel() {
setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
setPreferredSize(new Dimension(500, 500));
final JFrame f = new JFrame("Test");
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
drag = true;
dragLocation = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
drag = false;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (drag) {
if (dragLocation.getX()> getWidth()-10 && dragLocation.getY()>getHeight()-10) {
System.err.println("in");
setSize((int)(getWidth()+(e.getPoint().getX()-dragLocation.getX())),
(int)(getHeight()+(e.getPoint().getY()-dragLocation.getY())));
dragLocation = e.getPoint();
}
}
}
});
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(this,BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
new ResizablePanel();
}
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
I made a class for that if you want to take a look. It isn`t finished yet.
package projetoSplitPainel;
import java.awt.Component;
import java.util.ArrayList;
import javax.swing.JSplitPane;
/**
* This Components is based on the JSplitPane. JSplitPane is used to divide two
* (and only two) Components. This class intend to manipulate the JSplitPane in
* a way that can be placed as many Component as wanted.
*
* #author Bode
*
*/
public class JSplitPaneMultiTabs extends JSplitPane {
private ArrayList<JSplitPane> ecanpsulationList = new ArrayList<JSplitPane>();
private int numberOfComponents = 1;
private int sizeOfDivision = 6;
/**
* Builds the Pane
*/
public JSplitPaneMultiTabs() {
super();
this.setLeftComponent(null);
this.setBorder(null);
ecanpsulationList.add(this);
setAllBorders(sizeOfDivision);
}
/**
*
* #param comp - adds a Component to the Pane
*/
public void addComponent(Component comp) {
JSplitPane capsule = new JSplitPane();
capsule.setRightComponent(null);
capsule.setLeftComponent(comp);
capsule.setDividerSize(sizeOfDivision);
capsule.setBorder(null);
ecanpsulationList.get(numberOfComponents - 1).setRightComponent(capsule);
ecanpsulationList.add(capsule);
numberOfComponents++;
this.fixWeights();
}
/**
*
* #param orientation
* JSplitPane.HORIZONTAL_SPLIT - sets the orientation of the
* Components to horizontal alignment
* #param orientation
* JSplitPane.VERTICAL_SPLIT - sets the orientation of the
* Components to vertical alignment
*/
public void setAlignment(int orientation) {
for (int i = 0; i < numberOfComponents; i++) {
ecanpsulationList.get(i).setOrientation(orientation);
}
}
/**
*
* #param newSize - resizes the borders of the all the Components of the Screen
*/
public void setAllBorders(int newSize) {
this.setDividerSize(newSize);
for (int i = 0; i < numberOfComponents; i++) {
ecanpsulationList.get(i).setDividerSize(newSize);
}
}
/**
* each Component added needs to be readapteded to the screen
*/
private void fixWeights() {
ecanpsulationList.get(0).setResizeWeight(1.0);
for (int i = 1; i < numberOfComponents; i++) {
double resize = (double) 1 / (double) (i + 1);
ecanpsulationList.get(numberOfComponents - i - 1).setResizeWeight(
resize);
}
ecanpsulationList.get(numberOfComponents - 1).setResizeWeight(0.0);
}
}
So i Made a Class which does mostly what the OP wanted. Basically it is a Pannel which can be resized when clicking at the border. It also (tries) to resize all the components contained inside it to fit the new size. It also tries to detect collision between other components in the parent frame to prevent overlapping as much as possible.
Anyway here you go:
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JDesktopPane;
#SuppressWarnings("serial")
public class ResizablePanel extends JDesktopPane {
private boolean drag = false;
private boolean top =false;
private boolean bottom =false;
private boolean left=false;
private boolean right =false;
private Point dragLocation = new Point();
public ResizablePanel() {
setMinimumSize(new Dimension(200, 200));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
evaluateMousePress(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
drag = false;
setCursor(Cursor.getDefaultCursor());
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
evaluateMouseDrag(e.getPoint());
}
#Override
public void mouseMoved(MouseEvent e) {
evaluateMouseHover(e.getPoint());
}
});
}
#Override
public void setBounds(int x, int y, int width, int height) {
Rectangle oldBounds=getBounds();
Rectangle newBounds = new Rectangle(x, y, width, height);
super.setBounds(x, y, width, height);
resizeSingleComponent(this,oldBounds, newBounds);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Stroke stroke = g2.getStroke();
g2.setStroke(new BasicStroke(5));
g.drawRect(0, 0, getBounds().width, getBounds().height);
g2.setStroke(stroke);
}
private void resizeSingleComponent(Component component , Rectangle oldBounds , Rectangle newBounds) {
if(component instanceof Container) {
if(!component.equals(this)) {
Rectangle componentBounds = component.getBounds();
double x = getNew(componentBounds.getX(), oldBounds.getWidth(), newBounds.getWidth());
double y = getNew(componentBounds.getY(), oldBounds.getHeight(), newBounds.getHeight());
double width = getNew(componentBounds.getWidth(), oldBounds.getWidth(), newBounds.getWidth());
double height = getNew(componentBounds.getHeight(), oldBounds.getHeight(), newBounds.getHeight());
componentBounds.width = (int) Math.round(width);
componentBounds.height = (int) Math.round(height);
componentBounds.x = (int) Math.round(x);
componentBounds.y = (int) Math.round(y);
component.setBounds(componentBounds);
}
for(Component child:((Container) component).getComponents())
resizeSingleComponent(child, oldBounds, newBounds);
}
else {
Rectangle componentBounds = component.getBounds();
double x = getNew(componentBounds.getX(), oldBounds.getWidth(), newBounds.getWidth());
double y = getNew(componentBounds.getY(), oldBounds.getHeight(), newBounds.getHeight());
double width = getNew(componentBounds.getWidth(), oldBounds.getWidth(), newBounds.getWidth());
double height = getNew(componentBounds.getHeight(), oldBounds.getHeight(), newBounds.getHeight());
componentBounds.width = (int) Math.round(width);
componentBounds.height = (int) Math.round(height);
componentBounds.x = (int) Math.round(x);
componentBounds.y = (int) Math.round(y);
component.setBounds(componentBounds);
}
}
private void evaluateMouseDrag(Point point) {
if (drag) {
if (top || left || right || bottom) {
int heightIncrement=0;
int widthIncrement=0;
int posX = getBounds().x;
int posY = getBounds().y;
if(top || bottom)
heightIncrement = (int) (point.getY()-dragLocation.getY());
if(left || right)
widthIncrement = (int) (point.getX()-dragLocation.getX());
if(top) {
posY = posY+heightIncrement;
heightIncrement=-heightIncrement;
}
if(left) {
posX=posX+widthIncrement;
widthIncrement=-widthIncrement;
}
if(right)
dragLocation.x=(int) point.getX();
if(bottom)
dragLocation.y=(int) point.getY();
Rectangle bounds = new Rectangle(posX, posY, getWidth()+ widthIncrement,getHeight()+ heightIncrement);
justifyCollision(bounds,point);
}
}
}
private void evaluateMousePress(Point point) {
drag = true;
dragLocation = point;
top=dragLocation.getY() <=5;
left=dragLocation.getX() <=5;
bottom = dragLocation.getY() >=getHeight()-5;
right = dragLocation.getX() >=getWidth()-5;
setResizeCursor(point);
}
private void evaluateMouseHover(Point point) {
if(!drag) {
top=point.getY() <=5;
left=point.getX() <=5;
bottom = point.getY() >=getHeight()-5;
right = point.getX() >=getWidth()-5;
setResizeCursor(point);
}
}
private void justifyCollision(Rectangle bounds, Point point) {
//justify undersizing
if(bounds.width<getMinimumSize().width) {
if(left)
bounds.x= getBounds().x;
bounds.width=getWidth();
}
if(bounds.height<getMinimumSize().height) {
if(top)
bounds.y=getBounds().y;
bounds.height=getHeight();
}
Container parent = getParent();
//justify parent container bounds
if(bounds.x<0 ||bounds.width+bounds.x>parent.getWidth()) {
bounds.width = getWidth();
if(right &&!(bounds.width+bounds.x>parent.getWidth()))
dragLocation.x=(int) point.getX();
if(bounds.x<0)
bounds.x=0;
}
if(bounds.y<0 ||bounds.height+bounds.y>parent.getHeight()) {
bounds.height = getHeight();
if(bottom &&!(bounds.height+bounds.y>parent.getHeight()))
dragLocation.y=(int) point.getY();
if(bounds.y<0)
bounds.y=0;
}
//justify any other component in it's way
for(Component c:parent.getComponents()) {
if(!c.equals(this) &&c.getBounds().intersects(bounds)) {
evaluateOverlaps(bounds, c,point);
}
}
setBounds(bounds);
}
private Rectangle evaluateOverlaps(Rectangle bounds , Component component,Point point) {
if(bounds.intersects(component.getBounds())) {
if(component instanceof ResizablePanel) {
ResizablePanel panel=(ResizablePanel) component;
Rectangle panelBound=panel.getBounds();
if(top || bottom) {
panelBound.height = panelBound.height - bounds.intersection(panelBound).height;
if(panelBound.height<panel.getMinimumSize().height) {
panelBound.height=panel.getMinimumSize().height;
bounds.height = getHeight();
if(top) {
bounds.y = component.getBounds().y+component.getHeight();
}
}
else if(bottom) {
panelBound.y = panelBound.y + bounds.intersection(panelBound).height;
}
}
else if(left || right) {
panelBound.width = panelBound.width - bounds.intersection(panelBound).width;
if(panelBound.width<panel.getMinimumSize().width) {
panelBound.width=panel.getMinimumSize().width;
bounds.width = getWidth();
if(left) {
bounds.x = component.getBounds().x+component.getWidth();
}
}
else if(right) {
panelBound.x = panelBound.x + bounds.intersection(panelBound).width;
}
}
panel.setBounds(panelBound);
return bounds;
}
if(left || right) {
bounds.width = getWidth();
if(left) {
bounds.x = component.getBounds().x+component.getWidth();
}
}
if(top || bottom) {
bounds.height = getHeight();
if(top) {
bounds.y = component.getBounds().y+component.getHeight();
}
}
}
return bounds;
}
private void setResizeCursor(Point point) {
if(top) {
if(left)
setCursor(new Cursor(Cursor.NW_RESIZE_CURSOR));
else if(right)
setCursor(new Cursor(Cursor.NE_RESIZE_CURSOR));
else
setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
}
else if(bottom) {
if(left)
setCursor(new Cursor(Cursor.SW_RESIZE_CURSOR));
else if(right)
setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
else
setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
}
else if (left)
setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
else if (right)
setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
else
setCursor(Cursor.getDefaultCursor());
}
private long getNew(double size,double oldMax,double newMax) {
double value = ((size/oldMax)*newMax);
return Math.round(value);
}
}
You might have to specify JFrame.setResizeable = true; on both the Parent JFrame(the one with the border layout) and the child JFrame.
You also might want to use a JPanel in the south border.