problem with findComponentAt highlighting wrong JLabel
I've got a small 6 by 7 grid of jlabels that I would like to turn red if clicked on. In the japplet shown below, this works, sort of: it turns the label to its left red but not the label under the mouse. Any ideas on what I'm doing wrong? Thanks!
MyApplet.java
import javax.swing.JApplet;
publicclass MyAppletextends JApplet
{
MyPane2 pane =new MyPane2();
publicvoid init()
{
getContentPane().add(pane);
}
}
MyPane2.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyPane2extends JPanelimplements MouseListener
{
privatestaticfinalint MAX_ROW = 6;
privatestaticfinalint MAX_COL = 7;
private String whiteDot =".\\petes\\brief3\\whiteDot.jpg";
private String redDot =".\\petes\\brief3\\redDot.jpg";
private JLabel[][] myLabelGrid;
private JPanel gridPane =new JPanel();
public MyPane2()
{
super();
add(createLabelGridPane());
}
private JPanel createLabelGridPane()
{
gridPane =new JPanel();
GridLayout myGridLO =new GridLayout(MAX_ROW, MAX_COL);
myGridLO.setHgap(5);
myGridLO.setVgap(5);
gridPane.setLayout(myGridLO);
gridPane.addMouseListener(this);
myLabelGrid =new JLabel[MAX_COL][MAX_ROW];
for (int row = 0; row < MAX_ROW; row++)
{
for (int col = 0; col < MAX_COL; col++)
{
//myLabelGrid[col][row] = new JLabel(new ImageIcon(whiteDot));
myLabelGrid[col][row] =new JLabel("W");
gridPane.add(myLabelGrid[col][row]);
}
}
return gridPane;
}
publicvoid mouseClicked(MouseEvent me)
{
JPanel myPanel = (JPanel)me.getSource();
System.out.println(findComponentAt(me.getX(), me.getY()));
Component myComponent = findComponentAt(me.getX(), me.getY());
if (myComponentinstanceof JLabel)
{
//((JLabel)myComponent).setIcon(new ImageIcon(redDot));
((JLabel)myComponent).setText("R");
}
repaint();
}
publicvoid mouseEntered(MouseEvent arg0){}
publicvoid mouseExited(MouseEvent arg0){}
publicvoid mousePressed(MouseEvent arg0){}
publicvoid mouseReleased(MouseEvent arg0){}
}
[edited to use a label with "W" or "R" rather than images]
Message was edited by:
petes1234
[4943 byte] By [
petes1234a] at [2007-11-27 8:12:30]

# 1
Well, I hate testing applets. I can't be bothered to created an HTML file to invoke the applet. So I don't. I just want to copy, paste one source file then compile and test it. So I did. I added the following code to the MyPane2 class and tested it as a JFrame:
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add( new MyPane2() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
And it worked fine.
All I can suggest is to display the mouse X, Y coordinates in the mouseClicked event to make sure they are reasonable. Maybe the coordinates are different in an applet than a frame.
# 2
> Well, I hate testing applets. I can't be bothered to
> created an HTML file to invoke the applet. So I
> don't. I just want to copy, paste one source file
> then compile and test it. So I did. I added the
> following code to the MyPane2 class and tested it as
> a JFrame:
..........................................
> All I can suggest is to display the mouse X, Y
> coordinates in the mouseClicked event to make sure
> they are reasonable. Maybe the coordinates are
> different in an applet than a frame.
Thanks. I'll try it as an application rather than a JApplet. I'm not crazy about applet's either, but I'm trying to see if I can implement a connect-four GUI / JApplet to educate me regarding applets and in answer to someone else's question in the "new to java" forum. He was actually using Applets which I know less about than JApplets (which I know little about).
The other thread:
http://forum.java.sun.com/thread.jspa?threadID=5185649&start=0&tstart=0
# 3
thank you camickr. you were right. everything works fine when set up as a JFrame but it's all off if it's a JApplet. Ah well, I guess there's no easy solution to having it run as a JApplet.
# 4
> I'm not crazy about applet's either
I guess that was sort of the point of my comment, It is easy to test it as an Application first and then as an Applet.
> but I'm trying to see if I can implement a connect-four GUI / JApplet to educate me regarding applets
From a GUI perspective there is nothing different between an Applicatiion and an Applet. The difference is the container used to display the GUI. An application uses a JFrame an Applet uses JApplet. So as long as you keep design you applications the way you did this time, that is to separate the GUI components into the UI and the container, its easy to build and test the program as an application (JFrame). Then you can test it as an Applet. Your current design makes this approach very easy.
Check out this posting for a discussion that is sort of related to this situation:
http://forum.java.sun.com/thread.jspa?forumID=57&threadID=5145907
Message was edited by:
camickr
# 5
Just had a brief power outage... back online now.> everything works fine when set up as a JFrame but it's all off if it's a JAppletDon't see why there's a difference. I'll create a JApplet and see if I can see anything strange going on.
# 6
again thanks. sorry, i forgot to add dukes stars to this post at the onset. (i don't think you can add them retrospectively).
# 7
// <applet code="FindComponentApplet" width="400" height="400"></applet>
//No html file necessary, just type
// appletviewer FindComponentApplet.java
//at the prompt and press enter.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FindComponentApplet extends JApplet
{
public void init()
{
getContentPane().setLayout(new BorderLayout());
getContentPane().add(new FindComponentPane());
}
}
class FindComponentPane extends JPanel implements MouseListener
{
private static final int MAX_ROW = 6;
private static final int MAX_COL = 7;
Component lastSelected;
public FindComponentPane()
{
super(new BorderLayout());
add(createLabelGridPane());
}
private JPanel createLabelGridPane()
{
JPanel gridPane = new JPanel(new GridLayout(MAX_ROW, MAX_COL, 5, 5));
gridPane.addMouseListener(this);
JLabel[][] myLabelGrid = new JLabel[MAX_COL][MAX_ROW];
for (int row = 0; row < MAX_ROW; row++)
{
for (int col = 0; col < MAX_COL; col++)
{
JLabel label = new JLabel("W", JLabel.CENTER);
label.setBorder(BorderFactory.createEtchedBorder());
myLabelGrid[col][row] = label;
gridPane.add(myLabelGrid[col][row]);
}
}
return gridPane;
}
public void mouseClicked(MouseEvent me)
{
JPanel panel = (JPanel)me.getSource();
Component component = panel.findComponentAt(me.getX(), me.getY());
System.out.println(component.getClass().getName());
if (component instanceof JLabel)
{
if(lastSelected != null)
((JLabel)lastSelected).setForeground(Color.black);
((JLabel)component).setForeground(Color.red);
// Since there are gaps among the labels we need this in here.
lastSelected = component;
}
repaint();
}
public void mouseEntered(MouseEvent arg0){}
public void mouseExited(MouseEvent arg0){}
public void mousePressed(MouseEvent arg0){}
public void mouseReleased(MouseEvent arg0){}
}
# 8
crwood. Many thanks. Your code works (as I'm sure you already know).
Another solution that I stumbled on prior to reading your solutionis to set the mouselistener for each label like so:
import java.awt.*;
import java.awt.event.*;
//import java.util.ArrayList;
//import java.util.List;
import javax.swing.*;
class MyPane3 extends JPanel implements MouseListener
{
private static final int MAX_ROW = 6;
private static final int MAX_COL = 7;
private String whiteDot = ".\\petes\\brief3\\whiteDot.jpg";
private String redDot = ".\\petes\\brief3\\redDot.jpg";
private JLabel[][] myLabelGrid;
private JPanel gridPane = new JPanel();
public MyPane3()
{
super();
add(createLabelGridPane());
}
private JPanel createLabelGridPane()
{
gridPane = new JPanel();
GridLayout myGridLO = new GridLayout(MAX_ROW, MAX_COL);
myGridLO.setHgap(5);
myGridLO.setVgap(5);
gridPane.setLayout(myGridLO);
//gridPane.addMouseListener(this);
myLabelGrid = new JLabel[MAX_COL][MAX_ROW];
for (int row = 0; row < MAX_ROW; row++)
{
for (int col = 0; col < MAX_COL; col++)
{
//myLabelGrid[col][row] = new JLabel(new ImageIcon(whiteDot));
myLabelGrid[col][row] = new JLabel("W");
myLabelGrid[col][row].addMouseListener(this);
gridPane.add(myLabelGrid[col][row]);
}
}
return gridPane;
}
public void mouseClicked(MouseEvent me)
{
JLabel myLabel = (JLabel)me.getSource();
//myLabel.setIcon(new ImageIcon(redDot));
myLabel.setText("R");
repaint();
}
public void mouseEntered(MouseEvent arg0){}
public void mouseExited(MouseEvent arg0){}
public void mousePressed(MouseEvent arg0){}
public void mouseReleased(MouseEvent arg0){}
}
# 9
Another power outage. Its been up a down like a yo yo today (had a pretty bad thunderstorm in the afternoon)
Anyway, I found the problem.
//Component myComponent = findComponentAt(p);
Component myComponent = myPanel.findComponentAt(p);
Basically you have a design problem. Your class extends JPanel but you still created a "child" panel and added that to the "base" panel. You then added the MouseListener to the child panel. When you used the findComponentAt(..) method you where then searching the "base" panel even though you where using the MouseEvent coordinates relative to the "child" panel.
So the JFrame test worked because the whole application was packed so the x coordinate was only off by a few pixels.
Try rerunning the Applet and widen the applet and shrink the width so that the icons are right up against the edge. Now when you click it should work correctly. Then try widening the applet and your click will select one previous and then two previous as you widen the applet.
Bottom line is that there is no need for the "child" panel. Just set the layout of your class to a GridLayout and add the components directly to the panel.
# 10
> Bottom line is that there is no need for the "child"
> panel. Just set the layout of your class to a
> GridLayout and add the components directly to the
> panel.
THAT'S IT!!!
You are the Swing Sensei, no doubt. Again, thanks!
addendum:
or if I wanted to keep the secondary panel due to adding other components (buttons, other labels, etc), if I just called the subpanel's own findComponentAt(), then again, no problems. Cool.
Message was edited by:
petes1234
# 11
> or if I wanted to keep the secondary panel due to adding other components
Yep, your right. I keep forgetting this is just a SSCCE and in your real app the MyPane2 class is really your "content pane" so you would want the ability to add other panels and components to it.
> if I just called the subpanel's own findComponentAt(), then again, no problems
Thats the real bottom line. Make sure the component you add the MouseLIstener to is the component you invoke the findComponentAt(...) method on.
# 12
@crwood:appletviewer FindComponentApplet.javaDoes not work for me. I'm using JDK1.4.2 on XP. Is this a new feature in a newer version?I always have to create an HTML file and then use:appletviewer FindComponentApplet.html
# 13
Is this a new feature in a newer version?
Not that I know of. I'm using j2se 1.5.0 and win xp. Seems I used it in j2se 1.4.2 okay in
the past. You do need the comment with the applet tag and the code attribute pointing to
the java file name: code="FindComponentApplet". Some folks add an html or
class extension to theirs but I've found it unnecessary. It's more typing but it
avoids all the headaches of applet caching in both the java console and the browser. The
other option is to add a main method to load and init the applet.
# 14
> You do need the comment with the applet tag and the code attribute
> pointing to the java file name: code="FindComponentApplet".
Wow, I didn't include the comment in my source file. I didn't realize that comments would ever be used as input to the appletviewer program. I even moved the comments to the bottom of the file and it still works.
A neat trick I'll have to remember for the future.