Adding multiple JPanels to JLayeredPane - java

I am writing a chess program. For displaying the chessboard I am using two JPanels:
chessboard: This panel displays an image of an empty chessboard
chessmen: This panel displays an array of JLabels with chessmen images
So for this I need the two panels on top of each other. Therefore I am presently using a JLayeredPane. But the problem is I can only view only one of the layers at once.
My present code for the constructor is:
public ChessBoard(){
setLayout(new FlowLayout());
gamescreen = new JLayeredPane();
gamescreen.setPreferredSize(new Dimension(200,200));
chessboard = new JPanel(new GridBagLayout());
chessmen = new JPanel(new GridBagLayout());
//chessboard.setLocation(0, 0);
//chessmen.setLocation(0,0);
chessboardImage = new ImageIcon(getClass().getResource("chessboard.jpg"));
chessboardDisplay = new JLabel(chessboardImage);
chessboard.add(chessboardDisplay);
GridBagConstraints constraint = new GridBagConstraints();
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
imageSet[i][j] = new ImageIcon(getClass().getResource(""+i+(j+1)+".png"));
image = imageSet[i][j].getImage().getScaledInstance(100, 100, Image.SCALE_SMOOTH);
imageSet[i][j]= new ImageIcon(image);
}
}
for(int i=0;i<2;i++){
constraint.gridy=i+3000;
for(int j=0;j<2;j++){
chessmenPos[i][j] = new JLabel(imageSet[i][j]);
constraint.gridx=j;
chessmen.add(chessmenPos[i][j],constraint);
}
chessboard.setBounds(0, 0, 200, 200);
chessmen.setBounds(0, 0, 200, 200);
gamescreen.add(chessboard, 1);
gamescreen.add(chessmen, 0);
gamescreen.setOpaque(false);
chessboard.setVisible(true);
chessmen.setVisible(true);
add(gamescreen);
}
EventHandling eventHandler = new EventHandling();
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
chessmenPos[i][j].addMouseListener(eventHandler);
}
Where am I going wrong and what changes can I make?

But the problem is I can only view only one of the layers at once.
The top layer needs to be transparent. So you would need:
chessmen.setOpaque( false );
You can check out: Asking for some clarification in java about jlabel and parent for an example of a simple chessboard. It uses a slightly different approach. Each square is a component.

Related

Moving labels in nested panels [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I've made two grids and added them to a window using nested panels. The only issue is that I can't move the grid in the center and can't get the labels under their respective grids. Tried using setBounds but that's not working. Any advice? I've added an image of the current state. I want to display the player and opponent label under the first and second grid respectively.
public static void main(String[] args) {
window = new JFrame();
window.setTitle("Battleship.exe");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setPreferredSize(new Dimension(800, 800));
P1_container = new JPanel(new GridLayout(10,10));
P1_container.setPreferredSize(new Dimension(400, 400));
P1_container.setBorder(BorderFactory.createLineBorder(Color.black, 5));
compContainer = new JPanel(new GridLayout(10,10));
compContainer.setPreferredSize(new Dimension(400, 400));
compContainer.setBorder(BorderFactory.createLineBorder(Color.black, 5));
grid = new JPanel[10][10];
for (int i =0; i< 10; i++) {
for (int j =0; j< 10; j++) {
grid[i][j] = new JPanel();
grid[i][j].setBackground(Color.white);
grid[i][j].setBorder(BorderFactory.createLineBorder(Color.blue, 2));
grid[i][j].setPreferredSize(new Dimension(35,35));
P1_container.add(grid[i][j]);
}
}
enemyGrid = new JPanel[10][10];
for (int i =0; i< 10; i++) {
for (int j =0; j< 10; j++) {
enemyGrid[i][j] = new JPanel();
enemyGrid[i][j].setBackground(Color.lightGray);
enemyGrid[i][j].setBorder(BorderFactory.createLineBorder(Color.red, 2));
enemyGrid[i][j].setPreferredSize(new Dimension(35, 35));
compContainer.add(enemyGrid[i][j]);
}
}
GridLayout layout = new GridLayout(1, 2);
layout.setHgap(150);
mainPanel = new JPanel(layout);
mainPanel.add(P1_container);
mainPanel.add(compContainer);
player = new JLabel("PLAYER");
player.setBounds(100, 410, 5, 5);
opponent = new JLabel("OPPONENT");
opponent.setBounds(100, 410, 5, 5);
panel = new JPanel();
panel.setPreferredSize(new Dimension(100, 100));
panel.add(mainPanel, BorderLayout.CENTER);
panel.add(player, BorderLayout.WEST);
panel.add(opponent, BorderLayout.WEST);
window.add(panel, BorderLayout.CENTER);
window.pack();
window.setVisible(true);
}
Please mark your previous questions as solved if they are. People have taken the time to help you out and it's the least you can do. Read here for more information on What should I do when someone answers my question?
You are STILL calling setPreferredSize you should instead override getPreferredSize and ONLY where necessary. If your grid JPanels are sized via getPreferredSize there is no need to call setPreferredSize on their respective containers or the JFrame also you are still not creating your Swing components on the EDT.
As others have mentioned, you cannot use setBounds when using a LayoutManager. To achieve what you want, you need to nest layouts, as you have been told before.
So you probably want to create two JPanels with a BorderLayout. These two new containers will hold each grid and its label respectively:
JPanel p1Container = new JPanel(new BorderLayout());
p1Container.add(P1_container, BorderLayout.CENTER);
p1Container.add(player, BorderLayout.SOUTH);
JPanel opponentContainer = new JPanel(new BorderLayout());
opponentContainer.add(compContainer, BorderLayout.CENTER);
opponentContainer.add(opponent, BorderLayout.SOUTH);
...
panel.add(p1Container);
panel.add(opponentContainer);
Also the below code makes no sense:
panel = new JPanel();
panel.setPreferredSize(new Dimension(100, 100));
panel.add(mainPanel, BorderLayout.CENTER);
panel.add(player, BorderLayout.WEST);
panel.add(opponent, BorderLayout.WEST);
By default, a JPanel uses FlowLayout so BorderLayout.XXX means nothing here.
Again take the time to read A Visual Guide to Layout Managers but the code I showed corrects this by not passing in any extra parameters to add()

Creating a board game layout using JLayeredPane

I have an assignment which requires me to create the layout that you see in the image as part of the development of a game. I've never worked with Java for desktop applications before so i'm a complete noob when it comes to using the Swing & AWT libraries. The image suggests that we use a JLayeredPane as our root container and then add the rest on top of it. My issue is that i've tried starting with the background image and the gridLayout but i can't seem to make anything other than the background show up. The grid doesn't show up at all (no border line, no background of the cells) and any other component i've added to it has failed. Can somebody point me in the right direction here? I've read the docs & saw some example of various layouts,containers and components but i can't seem to make all of them work together.
Here's my code so far:
public class BoardView extends JFrame{
// Constructor
public BoardView() {
JFrame window = new JFrame("Sorry Game"); // create a new Jwindow instance
ImageIcon appIcon = new ImageIcon(getClass().getClassLoader().getResource("res/icon.png")); // create the icon for the app
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when the 'X' button is clicked, the app stops
window.setSize(new Dimension(1000, 700)); // setting the size of the window
window.setResizable(false); // Window won't be resizable
window.setIconImage(appIcon.getImage()); // set the icon for the app
window.setLayout(new BorderLayout());
JLayeredPane layeredPane = new JLayeredPane();
JLabel background = new JLabel();
background.setSize(1000,700);
background.setIcon(new ImageIcon(getClass().getClassLoader().getResource("res/background.png"))); for the JLabel
layeredPane.add(background,0);
JPanel gridPanel = new JPanel(new GridLayout(16,16));
gridPanel.setSize(650,700);
layeredPane.add(gridPanel);
for(int i = 0; i < 256; i++) {
JLabel tile = new JLabel();
tile.setBackground(Color.red);
tile.setBorder(new LineBorder(Color.black));
gridPanel.add(tile);
}
JLabel logo = new JLabel();
logo.setIcon(new ImageIcon(getClass().getClassLoader().getResource("res/sorryImage.png")));
layeredPane.add(logo);
window.add(layeredPane);
window.setLocationRelativeTo(null); // centers the window to the screen
window.setVisible(true); // make the window visible
}
}
My thought process was that i could set the JFrame's layout to a BorderLayout so that i can brake the final layout down into two parts, the West one and the East one. The West one would contain the Grid and the various JLabels and Buttons and the East one would contain the rest of the components. I've tried using the BorderLayout.WEST & EAST parameters when adding components to the JFrame but none has worked or changed a single thing. I've also tried using an index for the depth when adding components to the JLayeredPane as per the docs but again nothing changes.
P.S. Please note that i'm not looking for someone to create the layout for me. I want someone to help me understand what i'm doing wrong and what the best way of creating such layouts is.
In order to initialize the cells of the grid that i want to have images in, don't i need to add them manually in those positions?
If you use a GridLayout every cell must have a component and the components must be added in sequential order. That is as components are added they will wrap automatically to the next row as required.
So even if you don't want an image in a cell you would need to add a dummy component, lets say a JLabel with no text/icon.
An easier approach might be to use a GridBagLayout. The GridBagLayout can be configured to "reserve" space for cells that don't have components. So you can add a component to a specific cell.
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class GridBagLayoutSparse extends JPanel
{
public GridBagLayoutSparse()
{
setBorder( new LineBorder(Color.RED) );
GridBagLayout gbl = new GridBagLayout();
setLayout( gbl );
/*
// Set up a grid with 5 rows and columns.
// The minimimum width of a column is 50 pixels
// and the minimum height of a row is 20 pixels.
int[] columns = new int[5];
Arrays.fill(columns, 50);
gbl.columnWidths = columns;
int[] rows = new int[5];
Arrays.fill(rows, 20);
gbl.rowHeights = rows;
*/
// Add components to the grid at top/left and bottom/right
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
addLabel("Cell 0:0", gbc);
gbc.gridx = 3;
gbc.gridy = 4;
addLabel("Cell 3:4", gbc);
}
private void addLabel(String text, GridBagConstraints gbc)
{
JLabel label = new JLabel(text);
label.setBorder( new LineBorder(Color.BLUE) );
add(label, gbc);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("GridBagLayoutSparse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout( new GridBagLayout() );
frame.add(new GridBagLayoutSparse());
frame.setSize(300, 300);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
Run the code as is and the components will be grouped together in the center.
Uncomment the block comment and run again. The components will be positioned in the appropriate cell.

JFrame labels appear overlapped

i just programmed a program which has a JFrame containing an array of JLabel components. The array gets the position of the single labels assigned by a for-loop:
for(int i=0; i<label_entries.length; i++){
label_entries[i].setLocation(10, i*30);
label_entries[i].setSize(120,30);
dialog.add(label_entries[i]);
}
Do not get confused, my frame's name is "dialog".
There is one simple problem: The for-loop doesn't work like a for-loop should, and I don't know why, here is the result in my frame:
Imgur.
Don't care about the single label entries, the interesting thing is the position of Telefon.
If I set the beginning of the loop to the following, it is the same problem, just with another label.
for(int i=0; i<label_entries.length-1; i++){...}
Here is the full code
JFrame dialog = new JFrame();
dialog.setBounds(25, 50, 500, 500);
dialog.setTitle("Eintrag hinzufügen");
dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
JLabel[] label_entries = new JLabel[11];
JTextField[] textfields = new JTextField[11];
label_entries[0] = new JLabel("Vorname :");
label_entries[1] = new JLabel("Nachname :");
label_entries[2] = new JLabel("Nummer :");
label_entries[3] = new JLabel("Geburtstag :");
label_entries[4] = new JLabel("Land :");
label_entries[5] = new JLabel("PLZ :");
label_entries[6] = new JLabel("Stadt :");
label_entries[7] = new JLabel("Strasse :");
label_entries[8] = new JLabel("Hausnummer :");
label_entries[9] = new JLabel("E-Mail :");
label_entries[10] = new JLabel("Telefon :");
for(int i=0; i<label_entries.length; i++){
label_entries[i].setLocation(10, i*30);
label_entries[i].setSize(120,30);
dialog.add(label_entries[i]);
}
This should be easier to understand.
One obvious problem is that you are setting absolute positions of your components. Typically a LayoutManager is used for this purpose.
To clear whatever the default layout manager of a JFrame's content pane is, set it to null just after creating the frame.
JFrame dialog = new JFrame();
dialog.setLayout(null);
As the javadoc of JFrame says:
The default content pane will have a BorderLayout manager set on it.
Javadoc of BorderLayout says:
A border layout lays out a container, arranging and resizing its components to fit in five regions: north, south, east, west, and center. Each region may contain no more than one component, and is identified by a corresponding constant: NORTH, SOUTH, EAST, WEST, and CENTER. When adding a component to a container with a border layout, use one of these five constants, for example:
Panel p = new Panel();
p.setLayout(new BorderLayout());
p.add(new Button("Okay"), BorderLayout.SOUTH);
As a convenience, BorderLayout interprets the absence of a string specification the same as the constant CENTER:
Panel p2 = new Panel();
p2.setLayout(new BorderLayout());
p2.add(new TextArea()); // Same as p.add(new TextArea(), BorderLayout.CENTER);
Since you call the 1-arg version of add(), all your JLabels are added with BorderLayout.CENTER, and so the last one wins, and the BorderLayout manager then auto-positions it at left-center.
To prevent that from happening, just remove the layout manager:
dialog.setLayout(null);

How Do You Change The Color on The Swatches Component of JColorChooser?

I'm trying to make a drawing application involving JColorChooser Swatches Component, and I'm trying to make my UI a certain color. I was able to change the color through setting the background pretty much everywhere except for one small area around the "Recent" box.
Screenshot
Any help would be appreciated, I'll paste part of my code below for context:
//Sets up color chooser
chooser = new JColorChooser(Color.BLACK);
AbstractColorChooserPanel[] panels = chooser.getChooserPanels();
for (int i = 0; i < panels.length; i++) {
if (!panels[i].getDisplayName().equalsIgnoreCase("Swatches"))
chooser.removeChooserPanel(panels[i]);
else {
panels[i].setBackground(new Color(0, 155, 228));
}
}
chooser.setPreviewPanel(new JPanel());
//Sets up size slider
sizeSlide = new JSlider(1, 45);
//Adds Color/Size to one control panel, adds new panel to bottom of
//main
optionP = new JPanel();
optionP.setBackground(new Color(0, 155, 228));
optionP.setLayout(new BorderLayout());
optionP.add(sizeSlide, BorderLayout.EAST);
optionP.add(chooser, BorderLayout.WEST);
this.add(optionP, BorderLayout.SOUTH);
I don't think this can be done without some sophisticated search through the JComponent tree. But even than I was not able to change the background color.
EDIT:
I finally managed to change the background color for the recent panel with below code:
JColorChooser chooser = new JColorChooser(Color.BLACK);
AbstractColorChooserPanel[] panels = chooser.getChooserPanels();
for (int i = 0; i < panels.length; i++) {
if (!panels[i].getDisplayName().equalsIgnoreCase("Swatches")) {
chooser.removeChooserPanel(panels[i]);
} else {
panels[i].setBackground(new Color(0, 155, 228));
// placing code to change recent panel background color here
// will not work for some odd reason
// JComponent component = (JComponent) panels[i].getComponent(0);
// component.setBackground(new Color(0, 155, 228));
}
}
AbstractColorChooserPanel panel = chooser.getChooserPanels()[0];
JComponent component = (JComponent) panel.getComponent(0);
component.setBackground(new Color(0, 155, 228));
Another approach worked but it will change the background of all your Panels across the application. Use the UIManager to change the Background:
UIManager.put("Panel.background", new ColorUIResource(0, 155, 228));

can i replace labels ? or can i give a GUI and ID ? like in html?

The following code lays out the JLabels using the GridLayout. The arguments to the GridLayout are the following: rows, cols, horizontal gap, vertical gap. In the example below I have 3 pixels wide gap between labels both vertically and horizontally.
To use images instead of numbers, you could pass an ImageIcon to the constructor of the JLabel instead of the text.
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.border.BevelBorder;
public class FrameTest {
public static void main(String[] args) {
final JFrame f = new JFrame("Frame Test");
JPanel panel = new JPanel(new GridLayout(4, 4, 3, 3));
for (int i = 0; i < 16; i++) {
JLabel l = new JLabel("" + i, JLabel.CENTER);
// JLabel l = new JLabel(new ImageIcon("image_file.png"),
// JLabel.CENTER);
l.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
l.setFont(l.getFont().deriveFont(20f));
panel.add(l);
}
f.setContentPane(panel);
f.setSize(200, 200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
in that code the applets build up like a stack , but I want to make it replaceable like if I have a moving robot and I only want to replace the label where the robot moves instead of building a whole new grid ? or can I do that with any other GUI in java ?
First of all, I'd suggest to use an array of JLabel to keep track of the references of each label.
JLabel[] labels = JLabel[16];
Then, when an event happens, you could use the JLabel#setIcon method to change the Icon dynamically.

Categories