I am referencing this link, however this won't ultimately fix my problem (i.e I run my program from someone else's computer). How to deal with "java.lang.OutOfMemoryError: Java heap space" error (64MB heap size). Right now, I have a game board that has 10x10 squares, but I need to increase this to 100x100, but when I do, I get this error. What is the best way to increase my game board size while avoiding this error? Current output is below, Code should compile and run. Thanks!
GameBoard Class:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.*;
public class GameBoard {
private final JPanel board = new JPanel(new BorderLayout(3, 3));
private JButton[][] c1squares = new JButton[10][10];
private JPanel c1Board, c2Board;
private final JLabel messagec1 = new JLabel("Player 1 Board");
JToolBar tool = new JToolBar();
Insets Margin = new Insets(0,0,0,0);
int squares = 10;
int space = 100;
ImageIcon icon = new ImageIcon(new BufferedImage(space, space, BufferedImage.TYPE_INT_ARGB));
GameBoard() {
initializeGui();
}
public final void initializeGui() {
board.setBorder(new EmptyBorder(5, 5, 5, 5));
tool.setFloatable(false);
board.add(tool, BorderLayout.PAGE_START);
tool.add(messagec1);
c1Board = new JPanel(new GridLayout(0, 10));
c1Board.setBorder(new LineBorder(Color.BLACK));
board.add(c1Board);
for (int i = 1; i < c1squares.length; i++) {
for (int j = 0; j < c1squares[i].length; j++) {
JButton b = new JButton();
b.setMargin(Margin);
b.setIcon(icon);
if ((j % 2 == 1 && i % 2 == 1) || (j % 2 == 0 && i % 2 == 0)) {
b.setBackground(Color.WHITE);
} else {
b.setBackground(Color.BLACK);
}
c1squares[j][i] = b;
}
}
for (int i = 1; i < squares; i++) {
for (int j = 0; j < squares; j++) {
c1Board.add(c1squares[j][i]);
}
}
public final JComponent getGui() {
return board;
}
public final JComponent getGui2() {
return board2;
}
}
BattleShipFinal Class:
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class BattleshipFinal {
public static void main(String[] args) {
GameBoard gb = new GameBoard();
JFrame frame = new JFrame("Battleship - Server");
frame.add(gb.getGui());
frame.setLocationByPlatform(true);
frame.setMinimumSize(frame.getSize());
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(900,900));
frame.setMinimumSize(new Dimension(900,900));
frame.setLocation(50,50);
frame.pack();
frame.setVisible(true);
}
}
In case you are curious, and to illustrate what people said in the comments, you could have a custom JPanel painting the squares.
If you ever need to respond to mouse events, add a MouseListener to your panel, which will take care of the selected square (haven't added that part, but the selected field inside the Square class is a hint).
I removed stuff from your code, just to demonstrate this painting part.
GameBoard :
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class GameBoard {
private JPanel board;
private final Square[][] c1squares = new Square[10][10];
GameBoard() {
initializeGui();
}
public final void initializeGui() {
for (int i = 0; i < c1squares.length; i++) {
for (int j = 0; j < c1squares[i].length; j++) {
Square square = new Square();
if ((j % 2 == 1 && i % 2 == 1) || (j % 2 == 0 && i % 2 == 0)) {
square.setBackground(Color.WHITE);
} else {
square.setBackground(Color.BLACK);
}
c1squares[i][j] = square;
}
}
board = new BoardPanel(c1squares);
board.setBorder(new EmptyBorder(5, 5, 5, 5));
}
public final JComponent getGui() {
return board;
}
private class BoardPanel extends JPanel {
Square[][] squares;
public BoardPanel(final Square[][] squares) {
this.squares = squares;
}
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
for (int i = 0; i < squares.length; i++) {
for (int j = 0; j < squares[i].length; j++) {
Square currentSquare = squares[i][j];
System.out.println("Managing square " + i + " " + j);
g.setColor(currentSquare.getBackground());
g.fillRect(i * width / squares.length, j * height / squares.length, width / squares.length,
height / squares.length);
}
}
}
}
private class Square {
boolean isSelected;
Color background;
public boolean isSelected() {
return isSelected;
}
public void setSelected(final boolean isSelected) {
this.isSelected = isSelected;
}
public Color getBackground() {
return background;
}
public void setBackground(final Color background) {
this.background = background;
}
}
}
BattleshipFinal :
import java.awt.Dimension;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class BattleshipFinal {
public static void main(final String[] args) {
GameBoard gb = new GameBoard();
JFrame frame = new JFrame("Battleship - Server");
JComponent board = gb.getGui();
frame.add(board);
frame.setLocationByPlatform(true);
//frame.setMinimumSize(frame.getSize());
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
//frame.setPreferredSize(new Dimension(100, 100));
board.setMinimumSize(new Dimension(100, 100));
board.setPreferredSize(new Dimension(100, 100));
frame.setMinimumSize(new Dimension(100, 100));
frame.setLocation(50, 50);
frame.pack();
frame.setVisible(true);
}
}
Okay, I figured out the solution for this. Here is the output:
The way I fixed this was by changing these lines of code:
private JButton[][] c1squares = new JButton[100][100];
int squares = 100;
int space = 1000;
c1Board = new JPanel(new GridLayout(0, 100));
Related
I can't get two images to overlap each other in a JFrame. I have tried using one JPanel and two JPanels, and nothing has worked. I have looked into trying out JLayeredPane(s), but to no avail. I have lots of classes that interact so I don't know if showing my code will help, but here is my not-fully-implemented code:
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLayeredPane;
import javax.swing.ImageIcon;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
public class MazeDisplay implements KeyListener
{
static JFrame window;
static JPanel backPanel, userPanel;
JLabel user, cpu, maze1, maze2;
User u;
public MazeDisplay(String x, Cell[][] maize1, Cell[][] maize2) throws IOException
{
maze1 = new JLabel(new ImageIcon(createMazeImage(maize1)));
maze2 = new JLabel(new ImageIcon(createMazeImage(maize2)));
user = new JLabel(new ImageIcon("user.png"));
cpu = new JLabel(new ImageIcon("cpu.png"));
u = new User(maize1);
window = new JFrame(x);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(400, 400, 986, 509);
backPanel = (JPanel) window.getContentPane();
backPanel.setLayout(null);
maze1.setBounds(0, 0, 480, 480);
maze2.setBounds(500, 0, 480, 480);
backPanel.add(maze1);
backPanel.add(maze2);
userPanel = new JPanel(null);
user.setBounds(0, 0, 30, 30);
cpu.setBounds(500, 0, 30, 30);
userPanel.add(user);
userPanel.add(cpu);
window.add(userPanel);
window.setResizable(false);
window.setVisible(true);
}
public void keyPressed(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public boolean isLegal(int dir)
{
boolean ret = false; Cell[][] maze = u.getMaize();
if(0 <= u.xPos() && u.xPos() < maze.length && 0 <= u.yPos() && u.yPos() < maze.length)
{
if(dir == 0) ret = (maze[u.xPos()][u.yPos()].isOpen(dir) && maze[u.xPos()][u.yPos()-1].isOpenO(dir));
else if(dir == 1) ret = (maze[u.xPos()][u.yPos()].isOpen(dir) && maze[u.xPos()+1][u.yPos()].isOpenO(dir));
else if(dir == 2) ret = (maze[u.xPos()][u.yPos()].isOpen(dir) && maze[u.xPos()][u.yPos()+1].isOpenO(dir));
else if(dir == 3) ret = (maze[u.xPos()][u.yPos()].isOpen(dir) && maze[u.xPos()-1][u.yPos()].isOpenO(dir));
}
return ret;
}
public static BufferedImage createMazeImage(Cell[][] maze) throws IOException
{
BufferedImage[][] iMaze = new BufferedImage[maze.length][maze.length];
for(int i = 0; i < iMaze.length; i++)
for(int j = 0; j < iMaze.length; j++)
{
String cellDir = maze[i][j] + ".png";
iMaze[i][j] = new BufferedImage(30, 30, BufferedImage.TYPE_INT_RGB);
Graphics2D icon = iMaze[i][j].createGraphics();
icon.drawImage(ImageIO.read(new File(cellDir)), 0, 0, null);
}
int xOff = 0, yOff = 0;
BufferedImage mazeImage = new BufferedImage(maze.length * 30, maze.length * 30, BufferedImage.TYPE_INT_RGB);
Graphics2D g = mazeImage.createGraphics();
for(int r = 0; r < iMaze.length; r++)
{
for(int c = 0; c < iMaze.length; c++)
{
g.drawImage(iMaze[r][c], xOff, yOff, null);
yOff += 30;
}
yOff = 0;
xOff += 30;
}
return mazeImage;
}
public static void main(String[] args) throws IOException
{
MazeGen g = new MazeGen(16);
MazeGen h = new MazeGen(16);
MazeDisplay m = new MazeDisplay("Maze Game", g.getMaze(), h.getMaze());
}
}
Edit: My apologies for being so vague, I was extremely tired and irritated at the time. Even though I was vague, the help was very much appreciated, as I got it working using GridBagLayout as MadProgrammer suggested.
So, this is a really quick example.
It makes use of a GridBagLayout to allow two components to occupy the same space at the same time. It then uses a simple Timer to update the location of the player, to demonstrate that the basic concept works.
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
private JLabel player;
public TestPane() throws IOException {
BufferedImage tileImg = ImageIO.read(getClass().getResource("Tile.jpg"));
BufferedImage playerImg = ImageIO.read(getClass().getResource("Mario.png"));
Icon tileIcon = new ImageIcon(tileImg);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
player = new JLabel(new ImageIcon(playerImg));
gbc.gridx = 0;
gbc.gridy = 0;
add(player, gbc);
for (int row = 0; row < 10; row++) {
for (int col = 0; col < 10; col++) {
gbc.gridx = col;
gbc.gridy = row;
add(new JLabel(tileIcon), gbc);
}
}
Timer timer = new Timer(500, new ActionListener() {
private int x = 0;
private int y = 0;
#Override
public void actionPerformed(ActionEvent e) {
x++;
if (x > 9) {
x = 0;
y++;
}
if (y > 9) {
y = 0;
}
GridBagLayout layout = (GridBagLayout) getLayout();
GridBagConstraints gbc = layout.getConstraints(player);
gbc.gridx = x;
gbc.gridy = y;
layout.setConstraints(player, gbc);
revalidate();
}
});
timer.start();
}
}
}
Because of the way that the API works, components are displayed in LIFO order, this means that the player component must be added first.
You could also combine this with a JLayeredPane which would give you control over the z-ordering of the components
Disclaimer...
While this solution does work, it's not very easy to maintain or manage. A better solution would be to follow a custom painting route, this will give you much more control over what is painted and when and where.
Take a look at Performing Custom Painting for some basic details
Layered panes should work fine if well-implemented, here is more information about it, how to use it and some examples and codes for it:
https://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html
I'm working on a really basic bar chart which has to display 6 values. The problem I'm running into is that when i put the bars on the screen once they stay on the screen, and i cannot get them off. I've tried using the remove, repaint and revalidate functions but these all do not work.
What do I have to do to remove the bars so they don't clog up?
My code:
import javax.swing.*;
import java.awt.*;
import java.util.Collections;
public class BarChart extends JPanel
{
private JLabel[] bars;
public BarChart(int[] data)
{
update(data);
}
public void update(int[] data)
{
this.setSize(190, 155);
this.setLayout(null);
int max = 0;
for (int i = 0; i < 6; i++) {if (data[i] > max) {max = data[i];}}
bars = new JLabel[6];
for (int i = 0; i < 6; i++)
{
bars[i] = new JLabel();
bars[i].setOpaque(true);
bars[i].setBackground(Color.RED);
int height = (max != 0) ? (data[i]*155)/max : 0;
System.out.printf("%d, %d, %d,... ", height, data[i], max);
this.add(bars[i]);
bars[i].setSize(25, height);
bars[i].setLocation((31*i)+5, 155-height);
}
System.out.println("");
}
}
For your current code, you would need to call removeAll(), then revalidate() and repaint() on the JPanel would "solve" your problem, but you have other unrelated problems:
You're setting a component's size when you should be producing a preferred size -- this is what layout managers generally work with
You're using null layouts, a very dangerous thing
You're using a "magic" number as a for loop ending condition -- a VERY dangerous thing to do. How do you know that the data array has 6 and only items within it. What harm is there in simply using the data array's length as you've likely done hundreds of times before?
Instead, consider using more flexible code that will adapt to any size of data you give it and that avoids null layouts. For example consider the following code that draws the bars within the JPanel's paintComponent method:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestBarChart extends JPanel {
private static final int[] INIT_DATA = { 1, 2, 4, 5, 6, 9 };
protected static final int MIN_DATA_lENGTH = 5;
protected static final int MAX_DATA_LENGTH = 9;
private static final int MAX_VALUE = 9;
private static final int PREF_W = 300;
private static final int PREF_H = 240;
private BarChart2 barChart2 = new BarChart2(INIT_DATA, MAX_VALUE, PREF_W, PREF_H);
public TestBarChart() {
barChart2.setBorder(BorderFactory.createLineBorder(Color.BLUE));
JPanel chartsPanel = new JPanel(new GridLayout(1, 0));
chartsPanel.setLayout(new GridLayout(1, 0));
chartsPanel.add(barChart2);
JButton resetDataBtn = new JButton(new AbstractAction("Reset Data") {
#Override
public void actionPerformed(ActionEvent e) {
int dataLength = (int) ((MAX_DATA_LENGTH - MIN_DATA_lENGTH) * Math.random()) + MIN_DATA_lENGTH;
int[] data = new int[dataLength];
for (int i = 0; i < data.length; i++) {
data[i] = (int) (MAX_VALUE * Math.random()) + 1;
}
barChart2.setData(data, MAX_VALUE);
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(resetDataBtn);
setLayout(new BorderLayout());
add(chartsPanel);
add(btnPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
TestBarChart mainPanel = new TestBarChart();
JFrame frame = new JFrame("Test");
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());
}
}
#SuppressWarnings("serial")
class BarChart2 extends JPanel {
private static final double BAR_WIDTH = 0.90;
private int prefW;
private int prefH;
private static final Color BAR_COLOR = Color.RED;
private int[] data;
private int maxValue;
public BarChart2(int[] data, int maxValue, int prefW, int prefH) {
setData(data, maxValue);
this.prefW = prefW;
this.prefH = prefH;
}
public final void setData(int[] data, int maxValue) {
this.data = data;
this.maxValue = maxValue;
repaint();
}
public int[] getData() {
return data;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(BAR_COLOR);
// simple algebraic calculations on where to place the bars
double denom = data.length + 1 - BAR_WIDTH;
int barWidth = (int) ((getWidth() * BAR_WIDTH) / denom);
for (int i = 0; i < data.length; i++) {
int x = (int) (getWidth() * (i + 1 - BAR_WIDTH) / denom);
int height = (int) (getHeight() * data[i] / (double) maxValue);
int y = (int) (getHeight() - height);
g.fillRect(x, y, barWidth, height);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
}
Note that the bar charts re-size to fill the GUI if you re-size the GUI. Note that the chart accomodates any number of data bars, all depending on the length of the data array passed into it.
You need to repaint the component.
getContentPane().validate();
getContentPane().repaint();
Please Help. When I run this GUI the numbers run off the frame. I know I have to use JTextArea and append but where do I put that in my code. can someone explain to me in simple terms and show me? I want to make it scroll vertically and horizontally?
import java.io.*;
import java.util.*;
import java.lang.*;
import java.text.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class prime extends JFrame
{
public static void main(String[] args)
{
prime frame = new prime();
}
private TextPanel panel;
private JPanel inPanel;
private JTextField inField;
public prime()
{
final int width = 500;
final int height = 500;
setSize(width, height);
setTitle("Find Prime Numbers");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new TextPanel();
add(panel, "Center");
inPanel = new JPanel();
inPanel.add(new JLabel("Enter Your Number", SwingConstants.RIGHT));
inField = new JTextField(20);
ActionListener inListener = new TextListener();
inField.addActionListener(inListener);
inPanel.add(inField);
add(inPanel, "South");
setVisible(true);
}
private class TextListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
String message = inField.getText();
inField.setText("");
panel.setMessage(message); }
}
class TextPanel extends JPanel
{
private String message;
private Color backGroundColor;
public TextPanel()
{
message = "";
backGroundColor = Color.white;
}
public TextPanel(String x, Color background)
{
message = x;
backGroundColor = background;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
int width = getWidth();
int height = getHeight();
setBackground(backGroundColor);
g2.setColor(Color.black);
Font x = new Font("TimesNewRoman", Font.BOLD,20);
g2.setFont(x);
FontMetrics fm = g2.getFontMetrics(x);
g2.drawString(message,50, 50);
if(!(message.equals("")))
g2.drawString(previousPrime(message),50,78);
}
public void setMessage(String message) {
if (isPrime(Integer.parseInt(message))){
this.message = message + " is a prime number.";
}
else
this.message = message + " is not a prime number.";
repaint();
}
public boolean isPrime(int num){
for(int i = 2; i < num; i++){
if (num % i == 0)
return false;
}
if(num < 2)
return false;
return true;
}
public String previousPrime(String message){
String totalPrimeNum = "";
int finalNum = Integer.parseInt(message.substring(0,message.indexOf(" ")));
int count = 0;
for(int i = 2; i < finalNum; i++){
if(isPrime(i)) {
totalPrimeNum += " " + i;
count++;
}
if(count == 10) {
totalPrimeNum += "\n";
count = 0;
}
}
if (isPrime(Integer.parseInt(message.substring(0,message.indexOf(" ")))))
totalPrimeNum += " " + finalNum;
System.out.println(totalPrimeNum);
return totalPrimeNum;
}}}
Replace your TextPanel with JTextArea, wrap the JTextArea in a JScrollPane
private JTextArea panel;
//...
panel = new JTextArea(20, 10);
add(new JScrollPane(panel), "Center");
Use either setText or append to update the JTextArea. You will need to extract your calculation code from your existing TextPanel and re-use it
See How to Use Text Areas and How to Use Scroll Panes for more details
I found this source code from http://zetcode.com/tutorials/javagamestutorial/puzzle/
And I wanted to play around with it. It's a picture puzzle game, however when I run the program, it doesn't show up scrambled and I was wondering how will I go about this to get it scrambled? I'm still new to programming and I just wanted to play around with this to learn a bit. Thank you!
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Puzzle extends JFrame implements ActionListener {
private JPanel centerPanel;
private JButton button;
private JLabel label;
private Image source;
private Image image;
int[][] pos;
int width, height;
public Puzzle() {
pos = new int[][] {
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
{9, 10, 11}
};
centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(4, 4, 0, 0));
ImageIcon sid = new ImageIcon(Puzzle.class.getResource("icesid.jpg"));
source = sid.getImage();
width = sid.getIconWidth();
height = sid.getIconHeight();
add(Box.createRigidArea(new Dimension(0, 5)), BorderLayout.NORTH);
add(centerPanel, BorderLayout.CENTER);
for ( int i = 0; i < 4; i++) {
for ( int j = 0; j < 3; j++) {
if ( j == 2 && i == 3) {
label = new JLabel("");
centerPanel.add(label);
} else {
button = new JButton();
button.addActionListener(this);
centerPanel.add(button);
image = createImage(new FilteredImageSource(source.getSource(),
new CropImageFilter(j*width/3, i*height/4,
(width/3)+1, height/4)));
button.setIcon(new ImageIcon(image));
}
}
}
setSize(325, 275);
setTitle("Puzzle");
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Puzzle();
}
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
Dimension size = button.getSize();
int labelX = label.getX();
int labelY = label.getY();
int buttonX = button.getX();
int buttonY = button.getY();
int buttonPosX = buttonX / size.width;
int buttonPosY = buttonY / size.height;
int buttonIndex = pos[buttonPosY][buttonPosX];
if (labelX == buttonX && (labelY - buttonY) == size.height ) {
int labelIndex = buttonIndex + 3;
centerPanel.remove(buttonIndex);
centerPanel.add(label, buttonIndex);
centerPanel.add(button,labelIndex);
centerPanel.validate();
}
if (labelX == buttonX && (labelY - buttonY) == -size.height ) {
int labelIndex = buttonIndex - 3;
centerPanel.remove(labelIndex);
centerPanel.add(button,labelIndex);
centerPanel.add(label, buttonIndex);
centerPanel.validate();
}
if (labelY == buttonY && (labelX - buttonX) == size.width ) {
int labelIndex = buttonIndex + 1;
centerPanel.remove(buttonIndex);
centerPanel.add(label, buttonIndex);
centerPanel.add(button,labelIndex);
centerPanel.validate();
}
if (labelY == buttonY && (labelX - buttonX) == -size.width ) {
int labelIndex = buttonIndex - 1;
centerPanel.remove(buttonIndex);
centerPanel.add(label, labelIndex);
centerPanel.add(button,labelIndex);
centerPanel.validate();
}
}
}
Create each Icon and add the Icon to an ArrayList.
Then you can use the Collections.shuffle(...) method
Then iterate through the shuffled ArrayList and create your buttons add add the Icons to each button.
Edit:
Simple example showing the concept:
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
setLayout( new GridLayout(3, 4) );
ArrayList<Integer> numbers = new ArrayList<Integer>();
for (int i = 0; i < 12; i++)
numbers.add( new Integer(i) );
Collections.shuffle(numbers);
for (int i = 0; i < 12; i++)
add( new JLabel( "" + numbers.get(i) ) );
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.setLocationByPlatform( true );
frame.setSize(300, 300);
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
So I am trying to click and drag a JLabel around a JFrame. The following code allows a JLabel to be moved around the screen when the mouse is pressed / dragged at any point on the screen, but I am not sure how to add a second ActionListener to check if the mouse is clicking on the label, assuming that is the solution.
I would like to have multiple JLabels on the screen so that the only label being moved is the one that the mouse has clicked and is now dragging.
Thanks.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class test extends JFrame implements MouseMotionListener {
private JPanel panel = new JPanel(null);
private JLabel dragLabel = new JLabel("drag test");
private int mouseX = 200;
private int mouseY = 200;
public test() {
this.add(panel);
panel.setBackground(Color.WHITE);
panel.add(dragLabel);
dragLabel.setForeground(Color.RED);
dragLabel.setBounds(mouseX, mouseY, 100, 50);
panel.addMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
dragLabel.setBounds(mouseX, mouseY, 100, 50);
}
#Override
public void mouseMoved(MouseEvent e) {}
public static void main(String[] args) {
test frame = new test();
frame.setVisible(true);
frame.setSize(600, 400);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Another way to do this is to add the JLabel to a JLayeredPane or to a JPanel held by a JLayeredPane and add a MouseAdapter as the JLayeredPane's MouseListener and MouseMotionListener. Then when clicking on the label, move it to the JLayeredPane's JLayeredPane.DRAG_LAYER so it moves on top of everything else, then place the JLabel on whichever is the most appropriate level on mouse release. I've found this to work well when moving chess pieces on a chess board, for instance, and you want to make sure that the piece you're moving is displayed above all the other pieces when dragging.
Addition: You've probably left this thread, but if you come back, or for the benefit of others, I wanted to clarify what I meant by using a JLayeredPane by posting an example.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DragLabelOnLayeredPane extends JLayeredPane {
public static final int WIDTH = 680;
public static final int HEIGHT = 480;
private static final int GRID_ROWS = 8;
private static final int GRID_COLS = 6;
private static final int GAP = 3;
private static final Dimension LAYERED_PANE_SIZE = new Dimension(WIDTH, HEIGHT);
private static final Dimension LABEL_SIZE = new Dimension(60, 40);
private GridLayout gridlayout = new GridLayout(GRID_ROWS, GRID_COLS, GAP, GAP);
private JPanel backingPanel = new JPanel(gridlayout);
private JPanel[][] panelGrid = new JPanel[GRID_ROWS][GRID_COLS];
private JLabel redLabel = new JLabel("Red", SwingConstants.CENTER);
private JLabel blueLabel = new JLabel("Blue", SwingConstants.CENTER);
public DragLabelOnLayeredPane() {
backingPanel.setSize(LAYERED_PANE_SIZE);
backingPanel.setLocation(2 * GAP, 2 * GAP);
backingPanel.setBackground(Color.black);
for (int row = 0; row < GRID_ROWS; row++) {
for (int col = 0; col < GRID_COLS; col++) {
panelGrid[row][col] = new JPanel(new GridBagLayout());
backingPanel.add(panelGrid[row][col]);
}
}
redLabel.setOpaque(true);
redLabel.setBackground(Color.red.brighter().brighter());
redLabel.setPreferredSize(LABEL_SIZE);
panelGrid[4][3].add(redLabel);
blueLabel.setOpaque(true);
blueLabel.setBackground(Color.blue.brighter().brighter());
blueLabel.setPreferredSize(LABEL_SIZE);
panelGrid[1][1].add(blueLabel);
backingPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setPreferredSize(LAYERED_PANE_SIZE);
add(backingPanel, JLayeredPane.DEFAULT_LAYER);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
private class MyMouseAdapter extends MouseAdapter {
private JLabel dragLabel = null;
private int dragLabelWidthDiv2;
private int dragLabelHeightDiv2;
private JPanel clickedPanel = null;
#Override
public void mousePressed(MouseEvent me) {
clickedPanel = (JPanel) backingPanel.getComponentAt(me.getPoint());
Component[] components = clickedPanel.getComponents();
if (components.length == 0) {
return;
}
// if we click on jpanel that holds a jlabel
if (components[0] instanceof JLabel) {
// remove label from panel
dragLabel = (JLabel) components[0];
clickedPanel.remove(dragLabel);
clickedPanel.revalidate();
clickedPanel.repaint();
dragLabelWidthDiv2 = dragLabel.getWidth() / 2;
dragLabelHeightDiv2 = dragLabel.getHeight() / 2;
int x = me.getPoint().x - dragLabelWidthDiv2;
int y = me.getPoint().y - dragLabelHeightDiv2;
dragLabel.setLocation(x, y);
add(dragLabel, JLayeredPane.DRAG_LAYER);
repaint();
}
}
#Override
public void mouseDragged(MouseEvent me) {
if (dragLabel == null) {
return;
}
int x = me.getPoint().x - dragLabelWidthDiv2;
int y = me.getPoint().y - dragLabelHeightDiv2;
dragLabel.setLocation(x, y);
repaint();
}
#Override
public void mouseReleased(MouseEvent me) {
if (dragLabel == null) {
return;
}
remove(dragLabel); // remove dragLabel for drag layer of JLayeredPane
JPanel droppedPanel = (JPanel) backingPanel.getComponentAt(me.getPoint());
if (droppedPanel == null) {
// if off the grid, return label to home
clickedPanel.add(dragLabel);
clickedPanel.revalidate();
} else {
int r = -1;
int c = -1;
searchPanelGrid: for (int row = 0; row < panelGrid.length; row++) {
for (int col = 0; col < panelGrid[row].length; col++) {
if (panelGrid[row][col] == droppedPanel) {
r = row;
c = col;
break searchPanelGrid;
}
}
}
if (r == -1 || c == -1) {
// if off the grid, return label to home
clickedPanel.add(dragLabel);
clickedPanel.revalidate();
} else {
droppedPanel.add(dragLabel);
droppedPanel.revalidate();
}
}
repaint();
dragLabel = null;
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("DragLabelOnLayeredPane");
frame.getContentPane().add(new DragLabelOnLayeredPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
Please feel free to post any questions, need for clarification, or corrections.
Inspired by your code and user compilex's answer, follows demonstration:
Full code:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
/**
* A demonstration of moving around labels in a panel.
* <p>
* Some labels show up layed out in a grid. Then the
* user can drag any label anywhere on the panel.
* </p>
*/
public class LabelDragger {
public static void main(final String[] args) {
final int labelRows = 5, //How many rows of labels.
labelColumns = 5, //How many columns of labels.
labelWidth = 55, //Width for each label.
labelHeight = 20; //Height for each label.
//Border colors for labels:
final Color[] colors = new Color[]{Color.BLUE, Color.GREEN, Color.BLACK, Color.GRAY};
final Random prng = new Random(); //For selecting border color for each label.
final JPanel dragP = new JPanel(null); //Nicely set to null! :D Did not know that trick.
//Creating the listener for the panel:
final MouseAdapter ma = new MouseAdapter() {
private JLabel selectedLabel = null; //Clicked label.
private Point selectedLabelLocation = null; //Location of label in panel when it was clicked.
private Point panelClickPoint = null; //Panel's click point.
//Selection of label occurs upon pressing on the panel:
#Override
public void mousePressed(final MouseEvent e) {
//Find which label is at the press point:
final Component pressedComp = dragP.findComponentAt(e.getX(), e.getY());
//If a label is pressed, store it as selected:
if (pressedComp != null && pressedComp instanceof JLabel) {
selectedLabel = (JLabel) pressedComp;
selectedLabelLocation = selectedLabel.getLocation();
panelClickPoint = e.getPoint();
//Added the following 2 lines in order to make selectedLabel
//paint over all others while it is pressed and dragged:
dragP.setComponentZOrder(selectedLabel, 0);
selectedLabel.repaint();
}
else {
selectedLabel = null;
selectedLabelLocation = null;
panelClickPoint = null;
}
}
//Moving of selected label occurs upon dragging in the panel:
#Override
public void mouseDragged(final MouseEvent e) {
if (selectedLabel != null
&& selectedLabelLocation != null
&& panelClickPoint != null) {
final Point newPanelClickPoint = e.getPoint();
//The new location is the press-location plus the length of the drag for each axis:
final int newX = selectedLabelLocation.x + (newPanelClickPoint.x - panelClickPoint.x),
newY = selectedLabelLocation.y + (newPanelClickPoint.y - panelClickPoint.y);
selectedLabel.setLocation(newX, newY);
}
}
};
dragP.addMouseMotionListener(ma); //For mouseDragged().
dragP.addMouseListener(ma); //For mousePressed().
//Filling the panel with labels:
for (int row = 0; row < labelRows; ++row)
for (int col = 0; col < labelColumns; ++col) {
//Create label for (row, col):
final JLabel lbl = new JLabel("Label" + (row * labelColumns + col));
lbl.setHorizontalAlignment(JLabel.CENTER);
//lbl.setVerticalAlignment(JLabel.CENTER);
lbl.setBounds(col * labelWidth, row * labelHeight, labelWidth, labelHeight); //Grid-like positioning.
lbl.setBorder(new LineBorder(colors[prng.nextInt(colors.length)], 2)); //Set a border for clarity.
//Add label to panel:
dragP.add(lbl);
}
//Creating and showing the main frame:
final JFrame frame = new JFrame(LabelDragger.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//The size of the content pane adds some extra room for moving the labels:
final Dimension paneSize = new Dimension((int)(1.5 * labelWidth * labelColumns),
(int)(1.5 * labelHeight * labelRows));
frame.getContentPane().setPreferredSize(paneSize);
frame.getContentPane().add(dragP);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Explanations are added as comments.
Tips:
Take a look at the documentation on Container.findComponentAt(int x, int y), if you are going to add Components on the dragP Container, other than "draggable" labels.
Also, you can instead use Container.getComponentAt(int x, int y), in this case. I suggest you read their (small) documentation first.
Add a mouse listener to the label instead of the panel. (You might still need a mouse listener on the panel for the dragging but at least the one on the label can tell you if it was selected).
Create two global variables:
int x_pressed = 0;
int y_pressed = 0;
then create two events (mousePressed and mouseDragged over JLabel):
lbl_banner.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e) {
//catching the current values for x,y coordinates on screen
x_pressed = e.getX();
y_pressed = e.getY();
}
});
lbl_banner.addMouseMotionListener(new MouseMotionAdapter(){
#Override
public void mouseDragged(MouseEvent e){
//and when the Jlabel is dragged
setLocation(e.getXOnScreen() - x_pressed, e.getYOnScreen() - y_pressed);
}
});