Weird JLabel mouseclick problem

I'm making a GUI, and decided to use costum JLabels in some areas of the GUI instead of JButtons, and assign mouselisteners to them. The JLabel subclass looks like this;

[url=http://www.alienchild.com/temp/guiscreen.jpg]Screen of the buggers...[/url]

class JImageLabelextends JLabel

{

ImageIcon myimage;

Image image;

Canvas mycanvas;

public JImageLabel(String filepath)

{

myimage =new ImageIcon(filepath);

image = myimage.getImage();

}

protectedvoid paintComponent(Graphics g)

{

super.paintComponent(g);

g.drawImage(image,0,0,this.getSize().width,this.getSize().height,myimage.getImageObserver());

}

publicvoid setImage(String filepath)

{

myimage =new ImageIcon(filepath);

image = myimage.getImage();

repaint();

}

}

I have managed to place them perfectly in my application, and have assigned mouselisteners to each one like this;

showDesk1.addMouseListener(new MouseListener()

{

publicvoid mouseClicked(MouseEvent arg0)

{

cl.show(desktop, desk1);

showDesk1.setImage("data/workflow/images/desk1_activated.gif");

showDesk2.setImage("data/workflow/images/desk2_deactivated.gif");

showDesk3.setImage("data/workflow/images/desk3_deactivated.gif");

showDesk4.setImage("data/workflow/images/desk4_deactivated.gif");

}

publicvoid mousePressed(MouseEvent arg0){}publicvoid mouseReleased(MouseEvent arg0){}publicvoid mouseEntered(MouseEvent arg0){}publicvoid mouseExited(MouseEvent arg0){}

});

Now comes the problem;

About 50% of the times I click on them, nothing happens! Sometimes, I have to click on it 3-5 times for java to register it (tried it with a System.out.println, so its not a graphical bug afaik). Sometimes it works perfect for a few clicks. And no, Im not clicking like a maniac either :p

Question 1:

Why do I get this bug(?), and how do I solve it?

Question 2:

Are there any better way for me to structure my code, other than having one mouselistener with its own function on each JImageLabel? I figure thats part of the problem, although I'm not sure.

Thanks in advance!

Message was edited by:

alienchild

[3606 byte] By [alienchilda] at [2007-11-26 19:48:33]
# 1

Question 1:

Why do I get this bug(?), and how do I solve it?

It's not a bug.

Mouse events are relatively low-level, dealing with the mechanics of the mouse. You're interested in higher-level semantic events (as described by action events in buttons). The click event is not necessarily platform independent, but typically it is generated when the mouse button is pressed and then released without the mouse moving in between. This is why buttons handle states such as "armed" - check the source code to see how it works, but in practice it means if you're writing custom button-style mouse handling, mouseClicked() is the one method you don't need to use.

You would be better off using a JButton (or an AbstractButton of some description, perhaps your own implementation) with a custom ButtonUI implementation if you want it to appear differently to a normal button (to make it look like a JLabel, extend BasicButtonUI and override installDefaults() to configure the appearance as desired). Just call "button.setUI()" passing an instance of your UI class.

Question 2:

Are there any better way for me to structure my code, other than having one mouselistener with its own function on each JImageLabel? I figure thats part of the problem, although I'm not sure.

Well your JImageLabel is a waste of code, really, in fact it's not a good implementation (eg it doesn't take any notice of its image size). Just create an ImageIcon and then call setIcon() on a normal JLabel.

Using one listener per 'button' is fine.

itchyscratchya at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...
# 2

The JImageLabel does not take into account the size of the image, because I don't have too. In fact, I use the same kind of code that extends a JDesktopPane instead on my desktop there, and then the "wallpaper" automatically resizes according to screensize. It also doesn't take up any space in the container, like a ImageIcon does.

If I for example extend a JButton, I can set the button to be an image, then set any text I want on top of it without having to change the actual image being used. The button would also resize to the size I want, so that I wouldn't need to make a new image everytime I was making a new sized button (unless the stretching becomes too obvious).

I am fairly new to java (just a few weeks in now), so I'm not 100% sure of what you mean about "higher-level semantic events", but I think I got your point. However, I have absolutely no idea of how to implement your ideas into my application, so for the time being I am using the MousePressed instead of MouseClicked, and it works perfect.

Thank you :)

alienchilda at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...
# 3
I'd agree with itchyscratchy to use the ImageIcon as it should be normally if texts is all that u will add after. Just use a graphicsObject.drawString() in ur paintComponent() after the "super.paintComponent(g)" if u need to add ur texts.
Z.Ka at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...
# 4

Right, sorry, I see what you're doing now, you're scaling the image to fit the background. I'd suggest changing the paint call to the following,

g.drawImage(image, 0, 0, getWedth(), getHeight(), this);

I am fairly new to java (just a few weeks in now), so I'm not 100% sure of what you mean about "higher-level semantic events", but I think I got your point. However, I have absolutely no idea of how to implement your ideas into my application, so for the time being I am using the MousePressed instead of MouseClicked, and it works perfect.

Ok, let's take an example here. One standard JButton and your label with custom handling. Using mousePressed they'll behave differently - if you move the mouse over each of them and press (but don't release) the mouse button, your label will behave as if it was clicked but the button won't. Move the cursor off the button and release the mouse, and the button won't be clicked. Also, if you're not checking which button was pressed, right- or middle-clicking your button wil be a click.

The best way to do what you want is probably the custom ButtonUI approach - then you don't have to worry about all the button behaviour, you just worry about the painting. Or even a custom JButton extension - you still get the button behaviour for free (plus of course other benefits like configuration from Actions, programmatic clicking etc). There's no point reinventing it, because, as we've established, thisngs like this generally aren't as simple as they seem :o)

itchyscratchya at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...
# 5

Well argued, since I want the JTable to behave like a button, I really *should* use a button. However, it is not so simple;

I have seen that JButtons can change their apperance quite dramatically when changing L&F. While I want that change to happen throughout the rest of my application, this is one of the cases where I want it to stay fixed, for obvious reasons. No insane borders, no resizing, no nothing. I guess you can set a fixed L&F for components if you want to, although I haven't looked into that yet.

What I've tried to do before though, is to use my custom class that - although it might be horrible coding, works like a charm and doesn't give me any trouble (I have added your proposed change by the way). Well, except for when I try it with a JButton. Although I do get the expected result (a JButton with a background image), I get an unwanted effect: whenever I hold my mouse over the button in metal L&F (havent tried others yet), I get this border-thingy over my image. It doesn't look good. I guess that if I can remove that, and make sure that the button stays fixed even when the user changes L&F, I would be very happy.

btw, the JImageButton code;

class JImageButton extends JButton

{

ImageIcon myimage;

Image image;

Canvas mycanvas;

public JImageButton(String filepath)

{

myimage = new ImageIcon(filepath);

image = myimage.getImage();

}

protected void paintComponent(Graphics g)

{

super.paintComponent(g);

g.drawImage(image,0,0, getWidth(), getHeight(), this);

}

public void setImage(String filepath)

{

myimage = new ImageIcon(filepath);

image = myimage.getImage();

repaint();

}

}

alienchilda at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...
# 6

Although this might be the way it is done in java, I simply refuse to work that way. Instead of "adding a background image to a button with text," you want me to "add text on top of a button with an image in it". This way of thinking for me is wrong, because;

1) Buttons size should vary depending on the amoung of text. JButtons already have this feature, so if I added it through a custom painter, I would have to write the function over again.

2) It makes no sense.

alienchilda at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...
# 7

I have seen that JButtons can change their apperance quite dramatically when changing L&F... this is one of the cases where I want it to stay fixed

No problem.

JButton b = new JButton();

b.setUI(new MyButtonUI());

Assuming you don't allow the user to change L&F at runtime, that will always result in your UI being used.

whenever I hold my mouse over the button in metal L&F I get this border-thingy over my image... if I can remove that, and make sure that the button stays fixed even when the user changes L&F, I would be very happy.

No problem ;o)

I mentioned the installDefaults() method above; there's also an installListeners() method and indeed more. All you need to do is override them to add or remove what you do or don't want, and/or override the paint() method.

Though if you extend BasicButtonUI to implement your own UI, I *think* that doesn't add a mouseover border anyway, so it shouldn't be a problem.

It's worth downloading the JDK source to have a look at what goes on in the ComponentUI classes. They look a bit scary to start with but once you break it down it's generally fairly straightforward - you often don't need to do much to get the effect you want. There are some useful tutorials out there so Googling for some things like "custom basicbuttonui example" or whatever should help.

itchyscratchya at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...
# 8
Although this might be the way it is done in java, I simply refuse to work that way.Sorry, I missed what that was replying to...?If it's Z.K's reply then I agree, you shouldn't be going near the drawString() method.
itchyscratchya at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...
# 9

Sorry, that was in reply to Z.K's post.

I'm gonna be experimenting with overriding the buttonUI and see what I can come up with. Hopefully its not as confusing as I think it is ;)

(like java not having variable length of normal arrays! (no, ArrayList is NOT the same) *hoots fist in air*)

alienchilda at 2007-7-9 22:36:20 > top of Java-index,Desktop,Core GUI APIs...