Why does a JButton under a JPanel still react? - java

I looked around for my problem, and i couldn't find an answer, so here I go:
I have a JLayeredPane, and in there there are 2 JPanels.
The deepest one ( furthest down ) has JButtons on there.
The second one ( The one on top ) has a partially transparent background color ( although i don't think this should influence it ).
Now when I hover over my JButtons ( which are behind the other JPanel ), they still fire events to the MouseListener I added to them. I don't know why...
Why is this the case? What can I do to make it stop?
Here I add both the panels to the layered pane, and this refers to my class which extends a JFrame.
JLayeredPane layer = this.getLayeredPane();
layer.removeAll();
this.gamePanel = new GamePanel(game);
this.ghostPanel = new GhostPanel();
this.ghostPanel.setOpaque(true);
this.ghostPanel.setVisible(true);
layer.add(this.gamePanel, new Integer(0));
layer.add(this.ghostPanel, new Integer(1));
Here I have some buttons ( with an absolute layout ) added to the lowest panel
this.setLayout(null);
for (int j = 0; j < 5; j++) {
for (int i = 0; i < 5 + j; i++) {
this.add(this.buttons[i][j]);
}
}
for (int j = 1; j < 5; j++) {
for (int i = j; i < 9; i++) {
this.add(this.buttons[i][4 + j]);
}
}
Here this refers to the most bottom JPanel
The purpose of this is a game called gipf, and the layout I went with is absolute because it was very hard to align everything in a hexagonal shape.

Now when I hover over my JButtons ( which are behind the other JPanel ), they still fire events to the MouseListener I added to them
When an event is generated in needs to be passed to a component, so Swing searches from the bottom of the parent/child hierarchy to the top until it finds a component that wants to handle the event.
What can I do to make it stop?
Add a MouseMotionListener to the top panel to intercept events like mouseEntered/mouseExited. This way you will still be able to handle button clicks in the other panel.

Related

How to rewrite the text of buttons that are not separately defined

I have started trying to write a code similar to the game 2048, however the size of the board can have any value depending on what the user inputs. I decided to make the numbers on the board, for style purposes, separate buttons.
This is the current GUI:
How can I make it so that when the buttons: up, down left, or right are pressed each of the button's in the board texts are changed? I know about event listeners I just mean how can I replace the button's in the same grid with different values when I defined the buttons on the board as:
`for(int i = 2; i < rows + 2; i++) {
for(int j = 2; j < columns + 2; j++) {
gbc.gridx = j;
gbc.gridy = i;
num = new JButton(board.board[j-2][i-2].getValue()+"");
num.setFont(new Font("monospaced", Font.PLAIN, screenSize.height/50));
num.setEnabled(false);
this.add(num, gbc);
}
}`
The only ideas I've had was to create an array of buttons and then change the button's text in the array of buttons and then replace the old array of buttons with the new one. Also sorry if it has some super simple answer that I just couldn't find, I am just about finished with one semester of coding courses in college.
You could store the JButtons on a HashMap and use column number and row number as a key to find the correct button.
Something like:
Map<String, JButton> grid = new HashMap<String, JButton>;
for(int i = 2; i < rows + 2; i++) {
for(int j = 2; j < columns + 2; j++) {
grid.put(String.valueOf(i) + String.valueOf(i), new JButton("some text"));
// we transform the integers into String, otherwise the operator "+" will sum them
// instead of concatenate them.
}
}
Now you cant get the desired button with grid.get(row + column);
JButton bt;
JButton bt = grid.get("4" + "6");
bt.setText("different text");
grid.put("4" + "6", bt);
I don't think you should use Buttons to do such a game button it's something that you can click on it since your are not supposed to click on numbers. If I were you I would use a gamePanel which contains fixed labels since it's easier changing text of label than moving label.
I would add MouseListener to the gamePanel and then fill implemented methods in order to manage when the mouse left button is pressed and move to left and so on.
So create an array of Label.
Create a method which add and move numbers according to the direction of the move. For instance if you make a left to right move you will start to add the numbers of the first column into the second column when they have same values. Next you just have to do it recursively until the last column.
If you need a bit more explainations ,I'll be pleased to help you.

mixing gridlayout and borderlayout

I was tired but before quitting just stuck in the nearly-last 3 lines in the code snippet below to make a "refresh" button on my tictactoe panel, hoping to get away with it but expecting errors, since it mixes layout managers on a single container.
But it WORKED.
ButtonPanel.setLayout(new GridLayout(3, 3));
guiFrame.add(ButtonPanel);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
button[i][j] = addButton(ButtonPanel, i, j);
}
}
JButton refreshbutton = new JButton("Refresh");
guiFrame.add(refreshbutton, BorderLayout.SOUTH); // ... border layout worked. Hm.
refreshbutton.addActionListener(this);
guiFrame.setVisible(true); }
Should I be surprised? (Keep in mind my newbieness.)
(BOY, did I learn/stumble onto a buncha stuff in writing this silly game's program!!!--for instance, using setActionCommand to "label" each button internally [as 11,12,13,21,...33] so the ONE actionPerformed method could use getActionCommand to correctly label [with X or O] whatever button was pushed by whoever's turn it was.)
guiFrame.add(refreshbutton, BorderLayout.SOUTH); // ... border layout worked. Hm.
Just because you used BorderLayout.SOUTH does not make a panel a BorderLayout. Your code worked because the default layout manager for the content pane of a JFrame (JDialog) is a BorderLayout. So you are just taking advantage of the default layout.
since it mixes layout managers on a single container.
Yes, this is a common practice. In fact it is almost impossible to create a reasonably complex GUI if you don't use different layout managers on different panels that you add to a GUI.

Reorder items after mouse release

I am not sure what is wrong, so I will attempt to explain it, and you can test it in the following example:
The Project (3 MB): http://ryannaddy.com/downloads/dist.zip
Un-Zip and run the jar file
Open 2 image files within the application
On the right hand side is a list of all the open images, you can drag and drop the layers to eventually order z-order of the main picture.
If you drag the top layer below the bottom layer it gets moved back to the top (Should be moved below the bottom layer)
If you drag the top layer down a few pixels it will move the top layer below the bottom layer.
If you drag the bottom layer down it moves it above the top layer (Should be kept on the bottom)
In the end, I would like to drag those labels to any spot and there is where it will place the label.
Code block that gets executed after the mouse is released to organize the labels:
public void lblMouseReleased(MouseEvent evt){
if(dragging){
int componentCount = layers.getComponentCount() - 1;
LayerItem[] comps = new LayerItem[componentCount];
FocusTraversalPolicy focus = layers.getFocusTraversalPolicy();
Component comp = focus.getFirstComponent(layers);
for(int i = 0; i < componentCount; i++){
Component newComp = focus.getComponentAfter(layers, comp);
comp = newComp;
comps[i] = (LayerItem)newComp;
System.out.println(comps[i].layerID);
}
Layers.rebuild(layers, comps);
}
dragging = false;
}
Code for Layers.rebuild:
public static void rebuild(JPanel layers, Component[] list){
for(int i = 0; i < list.length; i++){
layers.remove(list[i]);
}
for(int i = 0; i < list.length; i++){
list[i].setBounds(0, i * 50 + 30, 198, 50);
layers.add(list[i]);
}
layers.revalidate();
layers.repaint();
}
This should be all the relevant code to the problem, let me know if you need more.
I got it! I it was because I wasn't getting all the items needed in the panel. The first item in my panel is a header with focus set to false, since it isn't apart of the grouping, so I was telling my code to only order items 1+ when it should have been 0+

UndoableEditListener - adding to JLabel and JTextPane

I have a 9x9 panel, which is panel1[][]
each panel has a JLabel, so label1[][]
and I add each label to the panel in for loop:
for (int y = 0; y < 9; y++) {
for (int x = 0; x < 9; x++) {
label[y][x] = new Grid(x, y);
panel1[y][x].add(label[y][x]);
}
}
The main goal is to be able to add a addUndoableEditListener() to each of these JLabels.
Users will select a number(int) to place in the JLabel, I want them to be able to undo/redo their selection, by clicking the undo/redo button.
I tried:
UndoManager manager = new UndoManager();
label1.addUndoableEditListener(manager);
However I saw that apprently you cannot add "UndoableEditListener" to JLabels. (Right?)
I saw some examples where you could add "UndoableEditListener" to JTextPane, so I though maybe I could create a JTextPane pane [9][9], and add a textpane to each of the JLabels(which are added to the JPanel). So this would solve the problem of UndoableEditListener.
Does this seem logical? I would really appreciate an easier approach to this, all suggestions welcome : )
I'm just having some problem with adding the UndoableEditListener to the components.
(I would prefer to keep the JLabel, since I need to be able to change the background color feature, otherwise is there a better way??)
Thanks.
It looks like you don't really want a JLabel. If you want it to be editable (and undoable), why not a JTextField?
A JTextField can have its background color changed as well as a JLabel:
JTextField tf = new JTextField();
tf.setColor(Color.RED);

JScrollPane always clears my Panel

Hy.. I have a JPanel, and in this contentPanel I added some other custom panels and give them locations etc. So now I added a JScrollPane to the contentPanel and always when I scroll down it clears my contentPanel, but the panels are still there but not visible...
How can I make them visible again?
That's my code to add the Panel into the contentPanel. The x,y,j are some settingsstuff for the location because I have an fixed window.
private void reloadContentPanel() {
int x = -200, y = 0, j = 1, row = 4;
EventPanel panel = null;
int i;
for(i=0; i < this.images.size();i++)
{
panel = new EventPanel(this.images.get(i).getAbsolutePath(),
this.images.get(i).getName());
panel.setLocation(x+(j*200), y);
j++;
if(i == row) {
x = -200;
y += 205;
j = 1;
row += 5;
}
this.contentPanel.add(panel);
}
this.repaint();
}
Thanks
it sounds like you are not using a LayoutManager correctly.
after creating your JFrame (i'm guessing within your constructor) add the following (for example):
this.setLayout(new FlowLayout());
this will certainly not be the best layout manager for what you are trying to do but will stop the add calls from overriding the displayed component.
you will need to read further about LayoutManagers
besides this, it's not really advisable to extend JFrame. It's better practice to treat JFrame as a member of your class just like all the other components.
I have the answer! :)
I use a GridLayout not a FlowLayout, so it's fine and it automatically refreshes the panels =)

Categories