I am trying to write a Battleship program using Java Swing and currently I have a class that makes two grids. I am trying to find out the location of which button was clicked so I can use this later to place shots etc... Unfortunately I am having a fair bit of trouble with this.
I have got the object to print out every thing that is in it by using the actionPerformed method but I only want the grid[x][y]. How do I go about this?
Thanks in advance for any help.
package testapp;
/**
*
* #author Craig
*/
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.Border;
public class menu extends JPanel implements ActionListener{
JButton[][] grid;
TextField text = new TextField(20);
public menu(int width, int length) {
Border playerBorder = BorderFactory.createTitledBorder("Player");
Border comBorder = BorderFactory.createTitledBorder("Com");
JPanel player = new JPanel();
player.setBorder(playerBorder);// set border round player grid
player.setLayout(new GridLayout(4,4));
grid=new JButton[width][length]; //allocate the size of grid
for(int y=0; y<length; y++){
for(int x=0; x<width; x++){
grid[x][y]=new JButton(); //creates new button
player.add(grid[x][y]); //adds button to grid
grid[x][y].setBackground(Color.BLUE);//sets grid background colour
grid[x][y].setPreferredSize(new Dimension(40, 40));//sets each grid buttons dimensions
add(text);
grid[x][y].addActionListener(this);
}
}
JPanel com = new JPanel();
com.setBorder(comBorder);// set border round com grid
com.setLayout(new GridLayout(4,4));
grid=new JButton[width][length]; //allocate the size of grid
for(int y=0; y<length; y++){
for(int x=0; x<width; x++){
grid[x][y]=new JButton(); //creates new button
com.add(grid[x][y]); //adds button to grid
grid[x][y].setBackground(Color.BLUE);//sets grid background colour
grid[x][y].setPreferredSize(new Dimension(40, 40));//sets each grid buttons dimensions
}
}
//this.setLayout(new FlowLayout());
this.add(player);
this.add(com);
}
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof JButton) {
JButton btn = (JButton)source;
text.setText("IN THE BOX ");
}
}
}
There are different options. Extending JButton should IMHO be the last resort, and hardly ever necessary. Looping through the grid[][] array and checking whether they are the source of the respective event may be OK. But another (IMHO simple and elegant) solution is to use anonymous listeners:
// Where the grid buttons are created:
....
grid[x][y].addActionListener(createActionListener(x, y));
private ActionListener createActionListener(final int x, final int y)
{
return new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
clickedButton(x, y);
}
};
}
private void clickedButton(int x, int y)
{
System.out.println("Clicked "+x+" "+y);
}
EDIT: Again, in form of a http://sscce.org/ (you could have created one, then I could have integrated my answer in your example...)
/**
*
* #author Craig and me :D
*/
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.Border;
public class menu extends JPanel {
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new menu(4,4));
f.setLocationRelativeTo(null);
f.pack();
f.setVisible(true);
}
JButton[][] grid;
TextField text = new TextField(20);
public menu(int width, int length) {
Border playerBorder = BorderFactory.createTitledBorder("Player");
Border comBorder = BorderFactory.createTitledBorder("Com");
JPanel player = new JPanel();
player.setBorder(playerBorder);// set border round player grid
player.setLayout(new GridLayout(4,4));
grid=new JButton[width][length]; //allocate the size of grid
for(int y=0; y<length; y++){
for(int x=0; x<width; x++){
grid[x][y]=new JButton(); //creates new button
player.add(grid[x][y]); //adds button to grid
grid[x][y].setBackground(Color.BLUE);//sets grid background colour
grid[x][y].setPreferredSize(new Dimension(40, 40));//sets each grid buttons dimensions
add(text);
grid[x][y].addActionListener(
createActionListener(x, y, "Player"));
}
}
JPanel com = new JPanel();
com.setBorder(comBorder);// set border round com grid
com.setLayout(new GridLayout(4,4));
grid=new JButton[width][length]; //allocate the size of grid
for(int y=0; y<length; y++){
for(int x=0; x<width; x++){
grid[x][y]=new JButton(); //creates new button
com.add(grid[x][y]); //adds button to grid
grid[x][y].setBackground(Color.BLUE);//sets grid background colour
grid[x][y].setPreferredSize(new Dimension(40, 40));//sets each grid buttons dimensions
grid[x][y].addActionListener(
createActionListener(x, y, "Computer"));
}
}
//this.setLayout(new FlowLayout());
this.add(player);
this.add(com);
}
private ActionListener createActionListener(
final int x, final int y, final String name)
{
return new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
clickedButton(x, y, name);
}
};
}
private void clickedButton(int x, int y, String name)
{
System.out.println("Clicked "+x+" "+y+" for "+name);
}
}
Related
I have a matrix of JToggleButton as components of a JPanel.
I want to call setSelected() for a group of those buttons
but I want the changes to be visually simultaneous.
How can I achieve this?
Consider the following code:
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
public class Main {
private static final JToggleButton buttons[][] = new JToggleButton[8][8];
public static void main(String args[]){
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JPanel panel = new JPanel();
panel.setLayout(new java.awt.GridLayout(8, 8, 0, 0));
//Initialize buttons and add them to panel
for(int i = 0; i < 8; ++i){
for(int j = 0; j < 8; ++j){
buttons[i][j] = new JToggleButton(){
public JToggleButton setRowAndColumn(int row, int column){
addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent evt){
onClick(row, column);
}
});
return this;
}
}.setRowAndColumn(i, j);
buttons[i][j].setPreferredSize(new java.awt.Dimension(40, 40));
panel.add(buttons[i][j]);
}
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
});
}
//This method is called when the JToggleButton at [row][column] is clicked
private static void onClick(int row, int column){
//In this example all other buttons at the same row or column
//as the clicked one, are also selected
for(int i = 0; i < 8; ++i){
buttons[i][column].setSelected(true);
buttons[row][i].setSelected(true);
//I don't want to see visual changes yet
}
//All changes should be visualized now
}
}
Basically I want onClick to be executed as a transaction (visually).
Thanks in advance.
Currently displays a GUI with an 8x8 grid of randomized colored buttons. The newButton is to reset the score display to 0 and reset the grid with a fresh like it does on startup after being clicked. I haven't been able to find many solutions other than that it's to do with the way Java displays it's buttons and the way layering works. Here are the 2 classes I'm using.
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.Color;
public class ShinyButtonsApp extends JFrame implements ActionListener {
private static byte ROWS = 8;
public int useThis;
ShinyButtons shiny = new ShinyButtons();
public static ImageIcon[] icons = {new ImageIcon("RedButton.png"),
new ImageIcon("OrangeButton.png"),
new ImageIcon("YellowButton.png"),
new ImageIcon("GreenButton.png"),
new ImageIcon("BlueButton.png"),
new ImageIcon("LightGrayButton.png"),
new ImageIcon("DarkGrayButton.png")};
public ShinyButtonsApp(String title) {
super(title); // Set title of window
setDefaultCloseOperation(EXIT_ON_CLOSE); // allow window to close
setSize(578, 634); // Set size of window
setResizable(false);
getContentPane().setLayout(null);
JLabel aLabel = new JLabel("Score: ");
aLabel.setLocation(10, 570);
aLabel.setSize(80,30);
getContentPane().add(aLabel);
JTextField scoreField = new JTextField();
scoreField.setText(Integer.toString(shiny.score));
scoreField.setEditable(false);
scoreField.setHorizontalAlignment(JTextField.RIGHT);
scoreField.setLocation(60, 570);
scoreField.setSize(120,30);
scoreField.setBackground(Color.WHITE);
getContentPane().add(scoreField);
JButton newButton = new JButton("New Game");
newButton.addActionListener(this);
newButton.setLocation(348,570);
newButton.setSize(110,30);
getContentPane().add(newButton);
JButton quitButton = new JButton("Quit");
quitButton.setLocation(468,570);
quitButton.setSize(80,30);
getContentPane().add(quitButton);
resetButtons2();
}
public void actionPerformed(ActionEvent e) {
shiny.score = 0;
shiny.resetButtons();
resetButtons2();
}
public void resetButtons2() {
for (int r=0; r<ROWS; r++) {
for (int c=0; c<ROWS; c++) {
ImageIcon image1 = icons[(int)shiny.getButton(r,c)];
JButton button = new JButton(image1);
button.setLocation(10+(69*r),10+(69*c));
button.setSize(69,69);
button.setBorder(BorderFactory.createLineBorder(Color.GRAY,1));
getContentPane().add(button);
}
}
}
public static void main(String[] args) {
ShinyButtonsApp frame;
frame = new ShinyButtonsApp("Shiny Buttons"); // Create window
frame.setVisible(true); // Show window
}
}
and
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.Color;
public class ShinyButtons extends JPanel{
public static byte RED = 0;
public static byte ORANGE = 1;
public static byte YELLOW = 2;
public static byte GREEN = 3;
public static byte BLUE = 4;
public static byte LIGHT_GRAY = 5;
public static byte DARK_GRAY = 6;
public static byte ROWS = 8;
public byte[][] buttonTable;
public int score = 0;
public ShinyButtons() {
buttonTable = new byte[ROWS][ROWS];
resetButtons();
}
public void resetButtons() {
for (int r=0; r<ROWS; r++)
for (int c=0; c<ROWS; c++)
buttonTable[r][c] = (byte)(Math.random()*7);
}
public byte getButton(int r, int c) { return buttonTable[r][c]; }
public int getScore() { return score; }
}
Building on to what this answer points out (using layout managers instead of setting size, as you should be doing) you could reset the the images just by looping through the components (JLabels) of the JPanel and changing their icons.
This particular example uses JLabels with MouseListeners but it could easily be switched to JButtons with ActionListeners
newGame.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
reset(iconPanel, icons); <--- call reset method from below
score = 0;
scoreField.setText(String.valueOf(score));
}
});
....
private void reset(JPanel panel, ImageIcon[] icons) {
Component[] comps = panel.getComponents();
Random random = new Random();
for(Component c : comps) {
if (c instanceof JLabel) {
JLabel button = (JLabel)c;
int index = random.nextInt(icons.length);
button.setIcon(icons[index]);
}
}
}
Here's the complete running code. You just need to replace the image paths.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class CircleImages {
private int score = 0;
private JTextField scoreField = new JTextField(10);
public CircleImages() {
scoreField.setEditable(false);
final ImageIcon[] icons = createImageIcons();
final JPanel iconPanel = createPanel(icons, 8);
JPanel bottomLeftPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
bottomLeftPanel.add(new JLabel("Score: "));
bottomLeftPanel.add(scoreField);
JPanel bottomRightPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
JButton newGame = new JButton("New Game");
bottomRightPanel.add(newGame);
JButton quit = new JButton("Quit");
bottomRightPanel.add(quit);
JPanel bottomPanel = new JPanel(new GridLayout(1, 2));
bottomPanel.add(bottomLeftPanel);
bottomPanel.add(bottomRightPanel);
newGame.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
reset(iconPanel, icons);
score = 0;
scoreField.setText(String.valueOf(score));
}
});
JFrame frame = new JFrame();
frame.add(iconPanel);
frame.add(bottomPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void reset(JPanel panel, ImageIcon[] icons) {
Component[] comps = panel.getComponents();
Random random = new Random();
for(Component c : comps) {
if (c instanceof JLabel) {
JLabel button = (JLabel)c;
int index = random.nextInt(icons.length);
button.setIcon(icons[index]);
}
}
}
private JPanel createPanel(ImageIcon[] icons, int gridSize) {
Random random = new Random();
JPanel panel = new JPanel(new GridLayout(gridSize, gridSize));
for (int i = 0; i < gridSize * gridSize; i++) {
int index = random.nextInt(icons.length);
JLabel label = new JLabel(icons[index]);
label.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e) {
score += 1;
scoreField.setText(String.valueOf(score));
}
});
label.setBorder(new LineBorder(Color.GRAY, 2));
panel.add(label);
}
return panel;
}
private ImageIcon[] createImageIcons() {
String[] files = {"blackcircle.png",
"bluecircle.png",
"greencircle.png",
"greycircle.png",
"orangecircle.png",
"redcircle.png",
"yellowcircle.png"
};
ImageIcon[] icons = new ImageIcon[files.length];
for (int i = 0; i < files.length; i++) {
icons[i] = new ImageIcon(getClass().getResource("/circles/" + files[i]));
}
return icons;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CircleImages();
}
});
}
}
You are creating a new set of buttons in resetButtons2() and placing them on top (or rather under) of the already existing set of buttons in the same locations. You should create the set of buttons once and only update their icons upon reset.
You should do a number of things:
Use a proper layout manager, e.g., GridLayout
Create the 8x8 grid of buttons only once and replace their icons when needed
Call invalidate/repaint to refresh the content pane
And for a JFrame you don't need getContentPane().add(...), you can directly do add(...)
Two things.
First, make sure you remove the existing buttons first. Alternatively, you could simply update the state of the buttons. This would require you to create an array or List of buttons first, which your reset method would then iterate over and update their properties as required.
Second, make use of an appropriate layout manager. A null layout ias a very bad idea. You do not control the font metrics of the underlying platform and this will change how your buttons look on different systems, making your UI less dynamic then it should be
I am trying to create a program with three buttons and a label with a CompositeIcon that at the start is empty.
When you click one of the buttons there will be added a square at the screen (with the described color), when another button is pressed there is gonna be added another square and so on. That means, when i press a button five times, there will be created five squres at the given colors.
If any one will read my code i will be thankful.
/*
This program creates a window with three buttons - red, green and blue - and a label with an icon.
This icon is a CompositeIcon that at the start is empty. When we press one of the three buttons, there will
be added a square at the specified color.
*/
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ResponsiveFrame extends JFrame {
static SquareIcon icon;
static int number; // this
static Color awtColor; // this
public static void main(String[] args) {
final JFrame frame = new JFrame();
final JLabel label = new JLabel();
JButton redButton = new JButton("RED");
JButton greenButton = new JButton("GREEN");
JButton blueButton = new JButton("BLUE");
/*
this is the part that i am not sure about!
not sure about the parameters.
*/
icon = new SquareIcon(number, awtColor);
redButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
icon.addIcon(new SquareIcon(20, Color.RED));
label.setIcon(icon);
frame.repaint();
frame.pack();
}
});
greenButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
icon.addIcon(new SquareIcon(20, Color.GREEN));
label.setIcon(icon);
frame.repaint();
frame.pack();
}
});
blueButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
icon.addIcon(new SquareIcon(20, Color.BLUE));
label.setIcon(icon);
frame.repaint();
frame.pack();
}
});
frame.setLayout(new FlowLayout());
frame.add(redButton);
frame.add(greenButton);
frame.add(blueButton);
frame.add(label);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
And here is the part with the SquareIcon.
import java.util.*;
import java.awt.*;
import javax.swing.*;
public class SquareIcon implements Icon {
private ArrayList<Icon> icons;
private int width;
private int height;
public SquareIcon(int number, Color awtColor) {
icons = new ArrayList<Icon>();
number = number;
awtColor = awtColor;
}
public void addIcon(Icon icon) {
icons.add(icon);
width += icon.getIconWidth();
int iconHeight = icon.getIconHeight();
if (height < iconHeight)
height = iconHeight;
}
public int getIconHeight() {
return height;
}
public int getIconWidth() {
return width;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
for (Icon icon : icons) {
icon.paintIcon(c, g, x, y);
x += icon.getIconWidth();
}
}
}
The program does compile, but when i press the buttons, nothing happens!
You create a JLabel but add it to nothing.
I suggest that you create a new JLabel each time you need one, and be sure to add it to the GUI after creating it. You will want to add it to a JPanel that is displayed in the JFrame/GUI, and will want to call revalidate() and repaint() on the JPanel after adding the label so that the panel knows to re-layout all its components, including the new one, and to re-draw itself and its children.
I am trying to create a GUI that will take in the number of circles to draw, and draw them in drawPanel with random locations/sizes. On my actionListener, when I try to draw the circle, it gives me red lines on my drawOval
1st class:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;
/**
*
* #author Chris
*
*/
public class CirclesPanel extends JPanel{
private JButton draw, clear;
private JTextArea textArea;
private JPanel panel, drawPanel, buttonPanel;
private int count;
/**constructor
* builds the frame
*/
public CirclesPanel(){
//creates buttons and textArea
draw = new JButton("Draw");
clear = new JButton("Clear");
textArea = new JTextArea(1,10);
textArea.setBorder(BorderFactory.createTitledBorder("Circles"));
//creats panel
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
setPreferredSize(new Dimension(620, 425));
//creates subpanel drawPanel
JPanel drawPanel = new JPanel();
drawPanel.setPreferredSize(new Dimension(450,400));
drawPanel.setBackground(Color.BLACK);
//creates subpanel buttonPanel
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(3,1));
//adds all the content to the frame
add(panel);
add(buttonPanel, BorderLayout.WEST);
add(drawPanel, BorderLayout.EAST);
buttonPanel.add(textArea);
buttonPanel.add(draw);
buttonPanel.add(clear);
//reads if the draw button is clicked
draw.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
count =Integer.parseInt(textArea.getText());//takes the count in
repaint();//repaints the picture to add the circles
}
});
//reads if the clear button is clicked
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
count=0;//sets the count to 0 so nothing is painted
repaint();//repaints the window
}
});
}
/**Paint component
* draws the random circles
*/
public void paintComponent(Graphics g) {
Random generator = new Random();
int x, y, diameter;
for(int i = 0; i < count; i++){ //loop that takes the count and does this "x" times
g.setColor(Color.BLUE);//sets color to blue
x = generator.nextInt(90);//random location for x
y = generator.nextInt(90);//random location for y
diameter = generator.nextInt(30);//random size
g.fillOval(x, y, diameter, diameter);//draws the circle
}
}
}
2nd class
import javax.swing.JFrame;
public class Circles {
public static void main(String[]args){
JFrame frame = new JFrame("Cicles HW9");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CirclesPanel());
frame.pack();
frame.setVisible(true);
}
}
So in your, I did little addition, first of all, I made the whole program in one class(CIRLCES PANEL), IF You want to use the second class, you can use it....
Problem is coming, your program is not the reading the ActionPerformed method for the drawing, means it is not located with the button, now I directly added it with your button(DRAW), now whenever you click on the button, it automatically reads the your textArea value, and draw your circles. I made your text area FINAL, So you can use it anywhere......
Now things that you need to do----
- this program is drawing circle on the whole frame, means not on your drawing Panel, you need to set the values, so it will draw on your draw panel area
- Also you need to add color for your oval, because it will either draw black color circle, which you will not able to see.....
and also one thing I forget to mentioned you, is that your, you also need to add code for your clear method...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class CirclesPanel extends JPanel{
private JButton draw, clear;
private JTextArea textArea;
private JPanel panel, drawPanel, buttonPanel;
private int count;
public CirclesPanel(){
JButton draw = new JButton("Draw");
JButton clear = new JButton("Clear");
final JTextArea textArea = new JTextArea(1,10);
textArea.setBorder(BorderFactory.createTitledBorder("Circles"));
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
setPreferredSize(new Dimension(620, 425));
JPanel drawPanel = new JPanel();
drawPanel.setPreferredSize(new Dimension(450,400));
drawPanel.setBackground(Color.BLACK);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(3,1));
add(panel);
add(buttonPanel, BorderLayout.WEST);
add(drawPanel, BorderLayout.EAST);
buttonPanel.add(textArea);
buttonPanel.add(draw);
buttonPanel.add(clear);
draw.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
count =Integer.parseInt(textArea.getText());
repaint();
}
});
}
public void paintComponent(Graphics g) {
Random generator = new Random();
int x, y, diameter;
for(int i = 0; i < count; i++){
x = generator.nextInt(90);
y = generator.nextInt(90);
diameter = generator.nextInt(30);
g.drawOval(x, y, diameter, diameter);
}
}
}
What you want to do is drawing some random circles on the drawPanel when button clicked. I write you a simplified version to show how things work.
I only keep the drawButton and paintPanel to keep things simple.
public class PaintFrame extends JFrame {
private JPanel content = new JPanel();
private JButton drawButton = new JButton("Draw");
private PaintPanel paintPanel = new PaintPanel();
public PaintFrame() {
getContentPane().add(content);
content.setLayout(new BorderLayout());
drawButton.setSize(100, 500);
drawButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// drawButton is fired, repaint the paintPanel
paintPanel.repaint();
}
});
content.add(drawButton, BorderLayout.WEST);
content.add(paintPanel, BorderLayout.CENTER);
}
}
You need a new class extending the JPanel and override the paintComponent method to do the paint job for you. This makes sure you are drawing on the panel.
class PaintPanel extends JPanel {
public PaintPanel() {
setSize(500, 500);
setBackground(Color.BLACK);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Random random = new Random();
g.setColor(Color.WHITE);
// draw 5 random circles
int count = 5;
for (int i = 0; i < count; i++) {
g.drawOval(random.nextInt(250), random.nextInt(250),
random.nextInt(250), random.nextInt(250));
}
}
}
Main class
public class DrawMain {
public static void main(String[] args) {
JFrame frame = new PaintFrame();
frame.setDefaultCloseOperation(PaintFrame.EXIT_ON_CLOSE);
frame.setSize(600, 500);
frame.setVisible(true);
}
}
I am developing a program where if the menu item "show grid line" is clicked, the drawing area below the menu bar will draw grid lines on the grid.
EDIT: Below are the components to the program. I turned any parts that are not important for this issue into comments.
import java.awt.Color;
import java.awt.Image;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
//main initializer
public class lineFollower {
frameDesign frame;
//private static Image icon = new ImageIcon("images/icon copy.jpg").getImage();
public static void main(String[] args) {
//make new frame
JFrame frame = new frameDesign();
frame.setSize(1000,700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLocale(null);
frame.setTitle("Line Follower Program 1.0");
//frame.setIconImage(icon);
}
}
This is the frame design (omitting parts as well):
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import javax.swing.*;
public class frameDesign extends JFrame {
//data fields
//JPanel DataPanel;
//ListPanel ListPanel;
DrawingPanel DrawingPanel;
grid gridbox;
menuPanel menu;
//ArrayList<Rectangle> Rectangles;
//ArrayList<Circle> Circles;
//ArrayList<Triangle> Triangles;
public int newvalue = 0;
public int[] griddim;
public int gridwidth, gridheight;
BorderLayout layout;
//combine data into frame
public frameDesign(){
//Rectangles = new ArrayList<Rectangle>();
//Circles = new ArrayList<Circle>();
//Triangles = new ArrayList<Triangle>();
//Layout: Border
BorderLayout layout = new BorderLayout();
setLayout(layout);
//Assemble the Menu
menu = new menuPanel();
//Assemble the List Panel which also includes the animation buttons
//ListPanel = new ListPanel();
//Create the gridbox
gridbox = new grid();
gridbox.setPreferredSize(new Dimension(200,200));
gridbox.setSize(500,200);
griddim = gridbox.getgriddim();
gridwidth = griddim[0];
gridheight = griddim[1];
//Data Panel consists of ListPanel, AnimatePanel, and DrawingPanel
//DataPanel = new JPanel(new FlowLayout());
//DataPanel.add(DrawingPanel= new DrawingPanel());
//DataPanel.add(ListPanel = new ListPanel());
//DataPanel.setSize(250,700);
//DataPanel.setBackground(Color.getHSBColor(150f, 100f, 100f));
//DataPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 5));
add(gridbox, BorderLayout.CENTER);
add(menu, BorderLayout.NORTH);
//add(DataPanel, BorderLayout.EAST);
//getPoints pointfinder = new getPoints();
//pointgrabber pointfinder2 = new pointgrabber();
//gridbox.addMouseListener(pointfinder2);
//gridbox.addMouseMotionListener(pointfinder);
//ActionListeners for Menus
menu.ShowLine.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
//show the grid
if (gridbox.isgridline()==true){
gridbox.gridline(false);
}
else if (gridbox.isgridline()==false){
gridbox.gridline(true);
}
}
});
}
The next pile of code is for the grid creation:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/*
* This is the design for the grid
*/
public class grid extends JPanel {
//data fields
boolean isgridline;
private static int startX = 50;
private static int startY = 50;
private int intervalline;
private int[] griddim;
//gridPanel
grid(){
setBorder(BorderFactory.createLineBorder(Color.BLACK));
griddim = new int[2];
griddim[0] = 500;
griddim[1] = 500;
isgridline = false;
intervalline = 20;
}
//Paints grid
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
//GridBox
g.setColor(Color.BLACK);
g.drawRect(50, 50, griddim[0], griddim[1]);
g.setColor(Color.WHITE);
g.fillRect(50, 50, griddim[0], griddim[1]);
//draw grid lines
if (isgridline){
g.setColor(Color.getHSBColor(150, 150, 200));
//vertical lines
for (int v = 0; v <griddim[0]; v = v+intervalline){
g.drawLine(startX, 50,
startX, 50+griddim[1]);
startX = startX+intervalline;
}
//horizontal lines
for (int v=0; v<griddim[1]; v=v+intervalline){
g.drawLine(50, startY, 50+griddim[0], startY);
startY = startY+intervalline;
}
}
}
//set grid dimensions
public void setgridbox(int[] dim){
griddim=dim;
}
//get grid dimensions
public int[] getgriddim(){
return griddim;
}
//set the grid line true or false
public void gridline(boolean islines){
isgridline=islines;
repaint();
}
//get gridline true or false
public boolean isgridline(){
return isgridline;
}
//set grid line intervals
//public void setinterval(int interval){
//intervalline=interval;
//repaint();
//}
}
Lastly, the menu:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.event.MenuEvent;
/*
* Class just for the menu panel
*/
public class menuPanel extends JMenuBar {
JMenuItem New, Save, Open, Exit;
JMenu fileMenu, gridMenu;
JMenuItem GridDim, GridLine, ShowLine;
menuPanel(){
//Assemble file menu
fileMenu = new JMenu("File");
New = new JMenuItem("New");
Save = new JMenuItem("Save");
Open = new JMenuItem("Open");
Exit = new JMenuItem("Exit");
fileMenu.add(New);
fileMenu.add(Save);
fileMenu.add(Open);
fileMenu.addSeparator();
fileMenu.add(Exit);
add(fileMenu);
//Assemble grid menu
gridMenu = new JMenu("Grid");
GridDim = new JMenuItem("Dimension");
GridLine = new JMenuItem("Change Grid Line Interval");
ShowLine = new JMenuItem("Show Grid Lines");
gridMenu.add(GridDim);
gridMenu.add(GridLine);
gridMenu.add(ShowLine);
add(gridMenu);
}
}
When the "show grid lines" button in the menu bar under grid is clicked, it turns on the grid lines and turns off the grid lines once each. It stops working after that... What can I do such that the grid lines show up on and off again more than just once?
I did a really quick test, but because you've not provided us with runnable example, it's not possible to reproduce your problem.
What I "suspect" is your for-loop is crashing for some reason (the griddim is null or there's an out bounds exception) which is causing the EDT to become unstable.
Until you enlighten use with a repeatable, runnable example, we're never going to be sure
public class TestGridLine {
public static void main(String[] args) {
new TestGridLine();
}
public TestGridLine() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new GridPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GridPane extends JPanel {
private boolean gridline;
public GridPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Grid");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setGridLine(!isGridLine());
}
});
add(btn);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth() - 1;
int height = getHeight() - 1;
//GridBox
g.setColor(Color.BLACK);
g.drawRect(0, 0, width - 1, height - 1);
g.setColor(Color.WHITE);
g.fillRect(1, 1, width - 1, height - 1);
//draw grid lines
if (gridline) {
g.setColor(Color.getHSBColor(150, 150, 200));
//vertical lines
for (int v = 0; v < width - 2; v += 10) {
g.drawLine(v, 1, v, height - 2);
}
//horizontal lines
for (int v = 0; v < height - 2; v += 10) {
g.drawLine(1, v, width - 2, v);
}
}
}
//returns boolean gridline
public boolean isGridLine() {
return gridline;
}
//set the grid line true or false
public void setGridLine(boolean islines) {
if (islines != gridline) {
gridline = islines;
repaint();
}
}
}
}