Moving jLabel to a different place in the jPanel (Pacman like game) - java

I'm making a game like pacman and so far I am just starting with the grid. I got the grid started but I need to figure out how to move something to a different place in the grid so that when the user clicks or my ghosts move, it will display on the screen. How do I make it move? I have tried a bunch of different ways but none worked for me.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.BevelBorder;
public class GUI {
public static void main(String[] args) {
final JFrame f = new JFrame("Frame Test");
GridLayout Layout = new GridLayout(50,50);
JPanel panel = new JPanel(new GridLayout(50, 50, 1, 1));
//Not sure if I need this or not?
//panel.setLayout(new GridBagLayout());
//first set of black
for (int i = 0; i < 1000; i++) {
JLabel a = new JLabel(new ImageIcon("black-square.jpg"), JLabel.CENTER);
panel.add(a);
}
//adds pacman
JLabel b = new JLabel(new ImageIcon("pacman.png"), JLabel.CENTER);
panel.add(b);
//next set of black
for (int i = 0; i < 1000; i++) {
JLabel c = new JLabel(new ImageIcon("black-square.jpg"), JLabel.CENTER);
panel.add(c);
}
//do the thing
f.setContentPane(panel);
f.setSize(1000, 1000);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}

Start by taking a look at Concurrency in Swing and How to Use Swing Timers
The next problem you're going to have is the fact that the container is under the control of a LayoutManager. While it's possible to achieve movement using this, it will be blocky, as each component will jump cells.
If you want smooth movement, you're going to have to devise your own layout logic, this can be very complicated.
None the less, what you should be aiming for is maintaining the a "virtual" view of the game. This allows you to know the shape of the maze and the position of the characters without need to do a lot of comparisons with the UI. You should then simply render the state of this "virtual" view or model
Updated with VERY BASIC example
This is a basic example, which uses a GridLayout and setComponentZOrder to move to components about the panel...There is no collision detection and the "AI" is pathetic...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PacMan101 {
public static void main(String[] args) {
new PacMan101();
}
public PacMan101() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new MazePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MazePane extends JPanel {
private JLabel pacMan;
private JLabel ghost;
public MazePane() {
pacMan = new JLabel(new ImageIcon(getClass().getResource("/PacMan.png")));
ghost = new JLabel(new ImageIcon(getClass().getResource("/Ghost.png")));
setLayout(new GridLayout(8, 8));
add(pacMan);
for (int index = 1; index < (8 * 8) - 1; index++) {
add(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(32, 32);
}
});
}
add(ghost);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
move(pacMan);
move(ghost);
revalidate();
repaint();
}
protected void move(Component obj) {
int order = getComponentZOrder(obj);
int row = order / 8;
int col = order - (row * 8);
boolean moved = false;
while (!moved) {
int direction = (int) (Math.round(Math.random() * 3));
int nextRow = row;
int nextCol = col;
switch (direction) {
case 0:
nextRow--;
break;
case 1:
nextCol++;
break;
case 2:
nextRow++;
break;
case 3:
nextCol--;
break;
}
if (nextRow >= 0 && nextRow < 8 && nextCol >= 0 && nextCol < 8) {
row = nextRow;
col = nextCol;
moved = true;
}
}
order = (row * 8) + col;
setComponentZOrder(obj, order);
}
});
timer.start();
}
}
}

It might be simpler to put labels at each spot in the grid, and then just change the icons associated with each label as your creatures move. See Add and remove an icon on a JLabel

Related

How to make all images in Grid Overlay flush?

I am trying to implement a GUI for a maze-based game I created that meets the following specific conditions:
The GUI itself has a set size and is not resizable (line 41) .
The master panel (line 57) that contains all the maze images is scrollable. All maze image components are flush with each other.
If maze is small enough, then entire maze will be visible in master panel.
If maze is very large, then user would need to scroll.
The master panel needs to be accessed by a mouse listener (line 130) that returns the component that is being clicked.
The following code seems to meet criteria 1 and 3, but fails criteria 2:
public class MazeGui extends JFrame implements DungeonView {
private final Board board;
public MazeGui(ReadOnlyModel m) {
//this.setSize(m.getNumRows()*100, m.getNumCols()*100);
this.setSize(600, 600);
this.setLocation(200, 200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.board = new Board(m);
JScrollPane scroller = new JScrollPane(board);
this.add(scroller, BorderLayout.CENTER);
setTitle("Dungeon Escape");
}
private class Board extends JPanel {
private ReadOnlyModel m;
public Board(ReadOnlyModel m) {
this.m = m;
GridLayout layout = new GridLayout(m.getNumRows(),m.getNumCols(), 0, 0);
// layout.setHgap(-100);
// layout.setVgap(-100);
this.setLayout(layout);
this.setSize(m.getNumRows()*64,m.getNumCols()*64);
for (int i = 0; i < m.getNumRows() * m.getNumCols(); i++) {
try {
// load resource from the classpath instead of a specific file location
InputStream imageStream = getClass().getResourceAsStream(String.format("/images/%s.png", m.getRoomDirections(i + 1)));
// convert the input stream into an image
Image image = ImageIO.read(imageStream);
// add the image to a label
JLabel label = new JLabel(new ImageIcon(image));
label.setPreferredSize(new Dimension(64, 64));
JPanel panel = new JPanel();
panel.setSize(64, 64);
String name = String.format("%d", i);
panel.setName(name);
panel.add(label);
// add the label to the JFrame
//this.layout.addLayoutComponent(TOOL_TIP_TEXT_KEY, label);
this.add(panel);
} catch (IOException e) {
JOptionPane.showMessageDialog(this, e.getMessage());
e.printStackTrace();
}
}
}
}
#Override
public void addClickListener(DungeonController listener) {
Board board = this.board;
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(String.format("(%d,%d)", e.getX(), e.getY()));
JPanel panel = (JPanel) board.getComponentAt(e.getPoint());
System.out.println(panel.getName());
}
};
board.addMouseListener(mouseListener);
}
#Override
public void refresh() {
this.repaint();
}
#Override
public void makeVisible() {
this.setVisible(true);
}
}
Here is an image of what it produces:
First, I'd make use of a different layout manager, one which would try and expand to fit the size of the underlying container.
Then, I would let the components do their jobs. I don't know why you're adding the label to another panel, the panel doesn't seem to be adding additional functionality/features and is just adding to the complexity.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
List<Maze.Direction> directions = new ArrayList<>(32);
directions.add(Maze.Direction.EAST_SOUTH);
directions.add(Maze.Direction.EAST_SOUTH_WEST);
directions.add(Maze.Direction.EAST_SOUTH_WEST);
directions.add(Maze.Direction.EAST_SOUTH_WEST);
directions.add(Maze.Direction.EAST_SOUTH_WEST);
directions.add(Maze.Direction.SOUTH_WEST);
directions.add(Maze.Direction.NORTH_EAST_SOUTH);
directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
System.out.println(directions.size());
Maze maze = new DefaultMaze(5, 6, directions);
MazeGui frame = new MazeGui(maze);
frame.addClickListener(null);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Maze {
enum Direction {
EAST_SOUTH("EastSouth.png"), EAST_SOUTH_WEST("EastSouthWest.png"), SOUTH_WEST("SouthWest.png"),
NORTH_EAST_SOUTH("NorthEastSouth.png"), NORTH_EAST_SOUTH_WEST("NorthEastSouthWest.png"),
NORTH_SOUTH_WEST("NorthSouthWest.png"), NORTH_SOUTH("NorthSouth.png"), NORTH("North.png");
private BufferedImage image;
private Direction(String name) {
try {
image = ImageIO.read(getClass().getResource("/images/" + name));
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
public BufferedImage getImage() {
return image;
}
}
public int getRows();
public int getColumns();
public Direction getRoomDirections(int index);
}
public class DefaultMaze implements Maze {
int rows;
int columns;
private List<Direction> directions;
public DefaultMaze(int rows, int columns, List<Direction> directions) {
this.rows = rows;
this.columns = columns;
this.directions = directions;
}
public int getRows() {
return rows;
}
public int getColumns() {
return columns;
}
#Override
public Direction getRoomDirections(int index) {
return directions.get(index);
}
}
public class MazeGui extends JFrame {
// Missing code
public interface DungeonController {
}
private final Board board;
public MazeGui(Maze m) {
this.setSize(600, 600);
this.setResizable(false);
this.board = new Board(m);
JScrollPane scroller = new JScrollPane(board);
this.add(scroller, BorderLayout.CENTER);
setTitle("Dungeon Escape");
}
public Board getBoard() {
return board;
}
public void addClickListener(DungeonController listener) {
Board board = getBoard();
board.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Component cell = board.getComponentAt(e.getPoint());
System.out.println(cell.getName());
board.highlight(cell.getBounds());
}
});
}
private class Board extends JPanel {
private Rectangle selectedCell;
private Maze maze;
public Board(Maze maze) {
this.maze = maze;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
for (int index = 0; index < maze.getRows() * maze.getColumns(); index++) {
Maze.Direction direction = maze.getRoomDirections(index);
JLabel label = new JLabel(new ImageIcon(direction.getImage()));
label.setName(direction.name());
add(label, gbc);
gbc.gridx++;
if (gbc.gridx >= maze.getColumns()) {
gbc.gridx = 0;
gbc.gridy++;
}
}
// addMouseListener(new MouseAdapter() {
// #Override
// public void mouseClicked(MouseEvent e) {
// Component component = getComponentAt(e.getPoint());
// selectedCell = null;
// if (component != null) {
// selectedCell = component.getBounds();
// }
// repaint();
// }
// });
}
public void highlight(Rectangle bounds) {
selectedCell = bounds;
repaint();
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (selectedCell != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(0, 0, 255, 128));
g2d.fill(selectedCell);
g2d.dispose();
}
}
}
}
}
The GUI itself has a set size and is not resizable
So the issue here is that you are forcing the "board" panel to have an arbitrary size.
this.setSize(600, 600);
The actual size of the panel should be 8 * 64 = 512. So extra space is being added to each grid.
Don't hardcode size values.
It is the job of the layout manager to determine the preferred size of each component.
So instead of using setSize(...) you should pack() the frame before making it visible:
this.pack();
this.setVisible(true);
When you do this you will see that the maze fits completely in the frame.
If you want extra space around the maze then you need to add a "border" to your board:
setBorder( new EmptyBorder(88, 88, 88, 88) );
GridLayout layout = new GridLayout(m.getNumRows(),m.getNumCols(), 0, 0);
Turns out I should have been using GridBagLayout!
There is no need to change layout managers, only use the layout managers more effectively.
If you really for some reason need to specify a fixed frame size then you can make the following change:
//this.add(scroller, BorderLayout.CENTER);
JPanel wrapper = new JPanel( new GridBagLayout() );
wrapper.add(scroller, new GridBagConstraints());
this.add(wrapper, BorderLayout.CENTER);
This will allow the "board" panel to be displayed at its preferred size and the "board" panel will be centered in its parent container.
Using these tips will help you effectively create more complicated layouts.

Get click position in grid. Java Swing

I got this code witch creates a clickable grid that shows the mouse position, altough i am not able to get the position in the grid in where the mouse is clicked, trying to be both X and Y position. Any ideas? This is how the grid looks:
Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;
public class TestGrid02 {
public TestGrid02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private static final int ROWS = 20;
private static final int COLUMNS = 20;
private static GridBagConstraints gbc;
public TestPane() {
setLayout(new GridBagLayout());
gbc = new GridBagConstraints();
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLUMNS; col++) {
gbc.gridx = col;
gbc.gridy = row;
CellPane cellPane = new CellPane();
Border border = null;
if (row < ROWS-1) {
if (col < COLUMNS-1) {
border = new MatteBorder(1, 1, 0, 0, Color.GRAY);
} else {
border = new MatteBorder(1, 1, 0, 1, Color.GRAY);
}
} else {
border = new MatteBorder(1, 1, 1, 0, Color.GRAY);
}
cellPane.setBorder(border);
add(cellPane, gbc);
}
}
}
}
public class CellPane extends JPanel {
private Color defaultBackground;
public CellPane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
defaultBackground = getBackground();
setBackground(Color.RED);
}
#Override
public void mouseExited(MouseEvent e) {
setBackground(defaultBackground);
}
#Override
public void mouseClicked(MouseEvent e){
//Here is where it is supposed to be
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(30, 30);
}
}
}
In the CellPane class, witch is intended to be the one that listens to the mouse it is supposed to be the function that i need, at the mouseClicked listener, however i have tried with e.getX() or e.getLocationOnScreen() and these values were changing everytime i click in the same grid.
Well, that looks familiar 🤣
So, the basic idea would be to pass in the cell it's coordinates (ie, row/column) value via the constructor, for example...
public class CellPane extends JPanel {
private Color defaultBackground;
private Point cellCoordinate;
public CellPane(Point cellCoordinate) {
this.cellCoordinate = cellCoordinate;
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
defaultBackground = getBackground();
setBackground(Color.RED);
}
#Override
public void mouseExited(MouseEvent e) {
setBackground(defaultBackground);
}
#Override
public void mouseClicked(MouseEvent e) {
//Here is where it is supposed to be
System.out.println("Did click cell # " + getCellCoordinate().x + "x" + getCellCoordinate().y);
}
});
}
public Point getCellCoordinate() {
return cellCoordinate;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(30, 30);
}
}
The cell itself doesn't really care, not does it have any reasonable information available to it to determine how it's been laid out, so your best bet is to "tell" it the information you want it to represent.
For me, I'd just pass in the GridBagLayout row/col information, for example...
gbc.gridx = col;
gbc.gridy = row;
CellPane cellPane = new CellPane(new Point(col, row));
This way you remove all concept (and the issues associated with it) of how the cell is laid out
This approach (using buttons and action listeners) is better IMO. It uses the getButtonRowCol method to return a string indicating the button's location in an array (the buttonArray).
Use b.setBorderPainted(false); (uncomment that code line) to get rid of the borders around each button. Look to the values passed to the constructor of the GridLayout to remove the space between buttons.
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
public class GameGridLayout {
int size = 40;
int iconSize = 10;
JButton[][] buttonArray = new JButton[size][size];
ActionListener actionListener;
JLabel output = new JLabel("Click somewhere on the GUI");
GameGridLayout() {
JPanel gui = new JPanel(new BorderLayout(2,2));
gui.setBorder(new EmptyBorder(4,4,4,4));
gui.add(output,BorderLayout.PAGE_END);
JPanel gameContainer = new JPanel(new GridLayout(0,size,2,2));
gui.add(gameContainer);
actionListener = e -> output.setText(getButtonRowCol((JButton)e.getSource()));
for (int ii=0; ii<size*size; ii++) {
JButton b = getButton();
gameContainer.add(b);
buttonArray[ii%size][ii/size] = b;
}
JFrame f = new JFrame("GameGridLayout");
f.add(gui);
f.pack();
f.setMinimumSize(f.getSize());
f.setLocationByPlatform(true);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setVisible(true);
}
private String getButtonRowCol(JButton button) {
StringBuilder sb = new StringBuilder();
for (int xx=0; xx<size; xx++) {
for (int yy=0; yy<size; yy++) {
if (button.equals(buttonArray[xx][yy])) {
sb.append("User selected button at: ");
sb.append(xx+1);
sb.append(",");
sb.append(yy+1);
break;
}
}
}
return sb.toString();
}
private JButton getButton() {
JButton b = new JButton();
b.setIcon(new ImageIcon(
new BufferedImage(iconSize,iconSize,BufferedImage.TYPE_INT_ARGB)));
b.setRolloverIcon(new ImageIcon(
new BufferedImage(iconSize,iconSize,BufferedImage.TYPE_INT_RGB)));
b.setMargin(new Insets(0,0,0,0));
//b.setBorderPainted(false);
b.setContentAreaFilled(false);
b.addActionListener(actionListener);
return b;
}
public static void main(String[] args) {
Runnable r = () -> new GameGridLayout();
SwingUtilities.invokeLater(r);
}
}

Change JButton Text and BackGround Color with Smooth Look

I am learning Swing from past week and I want desing some game like puzzle, 2048 for fun i have written puzzle sucessfully but when writting 2048 i encountered some problem, see below for sample code that is not orginal but it states the problem.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
#SuppressWarnings("serial")
class Panel extends JPanel implements ActionListener
{
JButton[] button = new JButton[4];
boolean flag = true;
public Panel()
{
this.setLayout(new GridLayout(1,4));
for(int i = 0; i < 4; ++i)
{
button[i] = new JButton("");
button[i].setBackground(Color.WHITE);
button[i].addActionListener(this);
button[i].setPreferredSize(new Dimension(100,100));
add(button[i]);
}
button[0].setText("2");
button[0].setBackground(Color.GREEN);
}
#Override
public void actionPerformed(ActionEvent Ae)
{
if(flag)
{
flag = false;
button[0].setText("");
button[0].setBackground(Color.WHITE);
//for(long i = 0; i < 100000000L; ++i);
button[1].setText("2");
button[1].setBackground(Color.GREEN);
//for(long i = 0; i < 100000000L; ++i);
button[1].setText("");
button[1].setBackground(Color.WHITE);
//for(long i = 0; i < 100000000L; ++i);
button[2].setText("2");
button[2].setBackground(Color.GREEN);
//for(long i = 0; i < 100000000L; ++i);
button[2].setText("");
button[2].setBackground(Color.WHITE);
//for(long i = 0; i < 100000000L; ++i);
button[3].setText("2");
button[3].setBackground(Color.GREEN);
}
else
{
flag = true;
button[0].setText("2");
button[0].setBackground(Color.GREEN);
button[1].setText("");
button[1].setBackground(Color.WHITE);
button[2].setText("");
button[2].setBackground(Color.WHITE);
button[3].setText("");
button[3].setBackground(Color.WHITE);
}
}
}
public class Grid
{
public Grid()
{
// I cannot ascess JFrame reference in real code too but it is not
// must, it would be better that i can do the thing without
// JFrame reference.
JFrame jFrame = new JFrame("Grid");
jFrame.add(new Panel());
jFrame.pack();
jFrame.setResizable(false);
jFrame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> new Grid());
}
}
In above code the change of button text and color is not smooth that is first button suddenly becomes white and last button suddnley becomes Green, so i have tested that second and third button is actullay changing or not by the delay loop but still second and third button is not changing but it waits some time to change first button and last button. I Hope that the problem is understandable.
Note: In real i use keybord by keybinding not button click i used it here for state the problem.
How To switch text and color of button with smooth look like 2048 game ?
Thanks.
Hopefully I understood your problem. What you want is animation. To do this you need to use a timer.
The following code demonstrates. Note that I changed the class name to MyPanel so as not to clash with class java.awt.Panel.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MyPanel extends JPanel implements ActionListener {
JButton[] button = new JButton[4];
boolean flag = true;
Timer timer;
int currentIndex;
int delta;
public MyPanel() {
this.setLayout(new GridLayout(1, 4));
for (int i = 0; i < 4; ++i) {
button[i] = new JButton("");
button[i].setBackground(Color.WHITE);
button[i].addActionListener(this);
button[i].setPreferredSize(new Dimension(100, 100));
add(button[i]);
}
button[0].setText("2");
button[0].setBackground(Color.GREEN);
timer = new Timer(500, event -> {
button[currentIndex].setText("");
button[currentIndex].setBackground(Color.WHITE);
currentIndex += delta;
button[currentIndex].setText("2");
button[currentIndex].setBackground(Color.GREEN);
if (currentIndex == 0 || currentIndex == 3) {
timer.stop();
}
});
timer.setInitialDelay(0);
}
#Override
public void actionPerformed(ActionEvent e) {
if (flag) {
flag = false;
delta = 1;
}
else {
flag = true;
delta = -1;
}
timer.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame jFrame = new JFrame("Grid");
jFrame.add(new MyPanel());
jFrame.pack();
jFrame.setResizable(false);
jFrame.setVisible(true);
});
}
}

Set the size of JButton to the length and width of the label

I am working on adding buttons to a button panel to be more familiar with java.swing class. Is there a way to set the size of JButton to the length and width of the button label?
Similar to setting height and width view in the xml file to wrap_content or match_parent.Setting a View or Layouts size based on either it's contents or the parent's dimensions rather than explicitly specifying a dimension.
android:layout_width="wrap_content"
android:layout_height="match_parent"
Is there a way to set the size of JButton to the length and width of the button label using button.setPreferredSize() without explicitly specifying the dimension?
button = new JButton[buttonName.length];
RadioButtonAction radioButtonEventO=new RadioButtonAction(); //O for operation
buttonPanelS=new JPanel();
buttonPanelS.setLayout(new GridLayout(4,1));
for(int i=0; i<buttonName.length;i++){
button[i]=new JButton(buttonName[i]);
button[i].setMargin(new Insets(0,0,0,0));
button[i].addActionListener(radioButtonEventO);
//button[i].setPreferredSize();
buttonPanelS.add(button[i]);
}
operationPanel.add(buttonPanelS);
I'm not 100% I understand, but GridLayout will, by design, size the all the components to occupy the available space of the container, evenly.
It sounds more like what you're after is GridBagLayout...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton[] button = new JButton[5];
JPanel buttonPanelS = new JPanel();
buttonPanelS.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
for (int i = 0; i < 5; i++) {
button[i] = new JButton(random());
button[i].setMargin(new Insets(0, 0, 0, 0));
buttonPanelS.add(button[i], gbc);
}
add(buttonPanelS);
}
private Random rnd = new Random();
public String random() {
int length = rnd.nextInt(20) + 1;
StringBuilder sb = new StringBuilder(length);
for (int index = 0; index < length; index++) {
sb.append(('a' + rnd.nextInt(52)));
}
return sb.toString();
}
}
}
If that's not what you're after either, then consider providing a drawing, to better illustrate your question

How to add zooming and panning functions to a JPanel?

So I have a program in Java which uses a grid bag layout to create cells(like graph paper), and if a mouse is over one of the cell said cell will change its color. I would like to implement a zoom function, using mouse scroll wheel. Also I would like to add a function that, when your zoomed in, you can pan around by clicking and dragging the zoomed in canvas. To specify panning around, think of clicking and dragging to move around a zoomed in map, like google maps.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;
public class Testing {
public int RowI = 10;
public int ColI = 10;
public static void main(String[] args) {
new Testing();
}
public Testing() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
for (int row = 0; row < RowI; row++) {
for (int col = 0; col < ColI; col++) {
gbc.gridx = col;
gbc.gridy = row;
CellPane cellPane = new CellPane();
Border border = null;
if (row < 4) {
if (col < 4) {
border = new MatteBorder(1, 1, 0, 0, Color.GRAY);
} else {
border = new MatteBorder(1, 1, 0, 1, Color.GRAY);
}
} else {
if (col < 4) {
border = new MatteBorder(1, 1, 1, 0, Color.GRAY);
} else {
border = new MatteBorder(1, 1, 1, 1, Color.GRAY);
}
}
cellPane.setBorder(border);
add(cellPane, gbc);
}
}
}
}
public class CellPane extends JPanel { //The CellPane class changes the color of an individual cell based on whether or no the mouse I on a cell.
private Color defaultBackground; //This is a private color that is only used by the mouseListener.
public CellPane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) { //If mouse is on cell turn cell the given color(in this case green).
defaultBackground = getBackground();
setBackground(Color.GREEN);
}
#Override
public void mouseExited(MouseEvent e) { //If mouse is not on cell revert to default background.
setBackground(defaultBackground);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50); //Cell size on x and y axis.
}
}
}
Maybe this question will answer what you're looking for.

Categories

Resources