I realize this is a repeat question, but my circumstances are a little bit different. I need to have a MouseListener in another class that can altar the background color of the object that calls it. Please help me.
public class LeftListPanel extends JPanel {
public LeftListPanel() {
setBackground(Settings.BACKGROUND_COLOR);
setLayout(null);
addPersonalStatsTab();
}
private void addPersonalStatsTab() {
JPanel personalStatsPanel = new JPanel();
personalStatsPanel.addMouseListener(new CustomMouseListener());
JLabel personalStatsText = new JLabel("Text");
personalStatsPanel.add(personalStatsText);
add(personalStatsPanel);
}
Then I have an inner-nested class for the MouseListener because this is the only place this MouseListener will be called.
class CustomMouseListener implements MouseListener {
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
setBackground(Settings.BACKGROUND_COLOR.brighter());
}
#Override
public void mouseExited(MouseEvent e) {
setBackground(Settings.BACKGROUND_COLOR);
}
}
The setBackground(COLOR) lines are those who don't work... this.setBack and super.setBack ARE NOT working in this case.. I'M DESPERATE FOR HELP!
The reason you don't see the background changes is that when you call setBackground, you are de-referring (implicitly) the this object, i.e. the instance of LeftListPanel. So, you are actually changing its background, but you don't see it because inside the LeftListPanel instance there is another JPanel (instantiated at the addPersonalStatsTab method) which occupies the whole visible space (or even it is not visible at all, because of that weird null layout; I don't know exactly).
Fist of all, I recommend to you not to set null as a layout. Chose a proper layout, or let it be defaulted - do not call setLayout(null).
Then, set personalStatsPanel as a private member of LeftListPanel. And when calling to setBackground, use it as the scope reference:
LeftListPanel.this.personalStatsPanel.setBackground(...);
This works, I instead just created a private method where I pass in the panel I want to apply it too.
private void CustomMouseListener(JPanel panel) {
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
panel.setBackground(Settings.BACKGROUND_COLOR.brighter());
}
#Override
public void mouseExited(MouseEvent e) {
panel.setBackground(Settings.BACKGROUND_COLOR);
}
});
}
Thank you all for your time and suggestions :)
You could...
Pass a reference of the component you want changed to the CustomMouseListener
class CustomMouseListener implements MouseListener {
private JPanel panel;
public CustomMouseListener(JPanel panel) {
this.panel = panel;
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
panel.setBackground(Settings.BACKGROUND_COLOR.brighter());
}
#Override
public void mouseExited(MouseEvent e) {
panel.setBackground(Settings.BACKGROUND_COLOR);
}
}
This is okay if you want to use the listener on a limited number of components, but if you want to use the same listener on a number of components...
You could...
Use the source property of the MouseEvent to get which component triggered the event
#Override
public void mouseEntered(MouseEvent e) {
if (!(e.getSource() instanceof JPanel)) {
return;
}
JPanel panel = (JPanel)e.getSource();
panel.setBackground(Settings.BACKGROUND_COLOR.brighter());
}
or, a better solution would be to do something more like...
#Override
public void mouseEntered(MouseEvent e) {
e.getComponent().setBackground(Settings.BACKGROUND_COLOR.brighter());
}
since the information is already provided to you (just not, this returns an instance of Component, so if you need to access the Swing specific properties, you'd still need to cast it).
Why is this approach better?
CustomMouseListener listener = new CustomMouseListener();
panel1.addMouseListener(listener);
panel2.addMouseListener(listener);
panel3.addMouseListener(listener);
panel4.addMouseListener(listener);
panel5.addMouseListener(listener);
panel6.addMouseListener(listener);
panel7.addMouseListener(listener);
because it's agnostic, meaning you can create a single instance of the listener and re-use on multiple components
Related
I'm having serious issues with adding a keylistener to my Java program.
I would like to avoid the addKeyListener() method, so I tried the following solutions:
public class game implements KeyListener{
#Override
public void keyTyped(KeyEvent e) {
return;
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("test");
return;
}
#Override
public void keyReleased(KeyEvent e) {
return;
}
}
And:
public class game{
KeyListener listener = new KeyListener(){
#Override
public void keyTyped(KeyEvent e) {
return;
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("test");
return;
}
#Override
public void keyReleased(KeyEvent e) {
return;
}
}
}
None of them worked for me.
Do I really have to use the addKeyListener() in a graphics class? I'm trying to avoid that.
Thanks in advance.
Is there a particular reason you want to avoid using addKeyListener()?
It's an essential part of KeyListener so you won't be able to avoid using it.
Should be relatively easy to implement though. If you're using JFrame, the following code within your constructor should work:
public class Game implements KeyListener{
public Game(){
JFrame jframe = new JFrame();
jframe.addKeyListener(this);
}
//implement other KeyListener methods
}
This way, the Game class itself acts as the listener and can implement all of the necessary methods.
Hope this helps!
Hi I'm trying to program a game using java. This is my first time using java, I am used to C#. In C# I would call Mouse.getLocation() and create a rect using the mouses location. Then by using if(Mouse.Left().toString() == "Pressed") I would then check if the mouse rect intersected with any other objects and act accordingly.
I've noticed in java you aren't provided with methods like these. So I was wondering, is the best way to approach mouse input simply to add listeners on all my clickable objects? I understand listeners and have a good idea how to use them but I was just wanting to check if there are more efficient ways to handle input or ways geared more towards what I'm most conformable with.
let your frame implement the MouseListener interface
implement all abstract methods, but in your case it is probably the mouseClicked event
identify if the button clicked is a left click, using the SwingUtilities class
if it is a left click, then set the x and y, which is the location of your click relative to the frame, not the screen.
public class MouseListeningObject extends JFrame implements MouseListener {
int x, y;
public MouseListeningObject () {
addMouseListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
if(SwingUtilities.isLeftMouseButton(e)){
x = e.getX();
y = e.getY();
}
}
#Override
public void mousePressed(MouseEvent e) {
// Some codes here
}
#Override
public void mouseReleased(MouseEvent e) {
// Some codes here
}
#Override
public void mouseEntered(MouseEvent e) {
// Some codes here
}
#Override
public void mouseExited(MouseEvent e) {
// Some codes here
}
}
You want your frame to implement MouseListener then add it in the constructor.
class MyFrame extends JFrame implements MouseListener {
MyFrame() {
addMouseListener(this);
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
}
I need help to understand the event propagation in Swing. I know that each event is handled by only one component. Thus, when I have a panel outside with some child panel inside and I add mouseListeners to both of them, the one of inside will be called. That's nice and that's the expected behavior.
But I don't understand the behavior in the following situation:
inside registers a MouseMotionListener and outside registers a MouseListener. I expect inside to consume all MouseMotionEvents and outside to receive the MouseEvents, because there is no listener for normal MouseEvents on inside. But that's not the case, inside somehow consumes all MouseEvents not only the MouseMotionEvents.
The following code illustrates the problem:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventTest {
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
JComponent inside = new JPanel();
inside.setBackground(Color.red);
inside.setPreferredSize(new Dimension(200,200));
MouseMotionListener mm = new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent arg0) {
System.err.println("dragged");
}
#Override
public void mouseMoved(MouseEvent arg0) {
System.err.println("moved");
}
};
// next line disables handling of mouse clicked events in outside
inside.addMouseMotionListener(mm);
JComponent outside = new JPanel();
outside.add(inside);
outside.setPreferredSize(new Dimension(300,300));
outside.addMouseListener( new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.err.println("clicked");
}
});
JFrame frame = new JFrame();
frame.add(outside);
frame.pack();
frame.setVisible(true);
}
});
}
}
I could work around the problem by registering a listeners on inside for all events the parent component might be interested in and then calling dispatchEvent to forward the event to the parent.
a) can someone point me to some docs, where this behavior is described? The javadocs of MouseEvent made me think that my expectations were right. So, I need a different description to understand it.
b) is there a better solution than the one sketched above?
Thanks,
Kathrin
Edit: It is still unclear, why Swing behaves this way. But as it looks, the only way to get the stuff working is to manually forward the events, I will do it.
a) By design, Java mouse events "bubble up" only if there in no mouse listener on the child component.
b) You can forward events to another component, as shown here and below.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventTest {
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JComponent outside = new JPanel();
JComponent inside = new JPanel();
inside.setBackground(Color.red);
inside.setPreferredSize(new Dimension(200, 200));
inside.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
System.err.println("dragged");
}
#Override
public void mouseMoved(MouseEvent e) {
System.err.println("moved inside");
outside.dispatchEvent(e);
}
});
outside.add(inside);
outside.setPreferredSize(new Dimension(300, 300));
outside.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent arg0) {
System.err.println("moved outside");
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(outside);
frame.pack();
frame.setVisible(true);
}
});
}
}
Very similar to trashgod's answer - you can use a MouseAdapter as your motion listener, and override it to forward any events you want to be handled by the parent. This should only add a minimal amount to your code.
MouseAdapter mm = new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent arg0) {
System.err.println("dragged");
}
#Override
public void mouseMoved(MouseEvent arg0) {
System.err.println("moved");
}
#Override
public void mouseClicked(MouseEvent e) {
outside.dispatchEvent(e);
}
};
// For forwarding events
inside.addMouseListener(mm);
// For consuming events you care about
inside.addMouseMotionListener(mm);
I too couldn't find any way around using the dispatchEvent(e) method. I think you're stuck with that route.
This worked out for me:
Ellipse2D mCircle = new Ellipse2D.Double(x,y,size,size);
void PassMouseEvent(MouseEvent e) {
getParent().dispatchEvent(e);
}
public void mousePressed(MouseEvent arg0) {
if(mCircle.contains(arg0.getX(), arg0.getY())) {
// Do stuff if we click on this object
} else {
// Pass to the underlying object to deal with the mouse event
PassMouseEvent(arg0);
}
}
I'm developing a Swing based application in which I want to add JToolBar with images in JButton but it's not looking good. JToolBar is having some dots at the starting part.
How can I get rid of the dots?
Two things:
The "dots" you describe are probably due to the JToolbar being floatable by default. If you wish to disable this you can call setFloatable(false).
Here's a utility method I use to decorate JButtons prior to adding them to JToolBars (or JPanels, etc):
decorateButton(AbstractButton)
public static void decorateButton(final AbstractButton button) {
button.putClientProperty("hideActionText", Boolean.TRUE);
button.setBorder(BorderFactory.createEmptyBorder());
button.setBackground(null);
button.setOpaque(true);
button.setPreferredSize(BUTTON_SIZE);
button.setMaximumSize(BUTTON_SIZE);
button.setMinimumSize(BUTTON_SIZE);
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
button.setBackground(COLOR_BUTTON_MOUSEOVER);
}
#Override
public void mousePressed(MouseEvent e) {
button.setBackground(COLOR_BUTTON_PRESSED);
}
#Override
public void mouseEntered(MouseEvent e) {
button.setBorder(button.isEnabled() ? BORDER_BUTTON_MOUSEOVER_ENABLED : BORDER_BUTTON_MOUSEOVER_DISABLED);
button.setBackground(COLOR_BUTTON_MOUSEOVER);
}
#Override
public void mouseExited(MouseEvent e) {
button.setBorder(BorderFactory.createEmptyBorder());
button.setBackground(null);
}
});
}
I'd like to create an app where some events are supposed to be handled as if they were delivered to parent containers. For example I've got a JPanel which contains JLabel. The top JPanel implements mousepress and dragging right now. What do I need to do, in order to make the events look like they arrived to JPanel instead of the label itself. (changing source object is important)
Is there some better solution than actually implementing the events and replicating them in the parent? (this would get tedious after some objects with >5 children).
At your event listener, you can dispatch the event to the parent component.
Being myEvent the event handling function argument:
Component source=(Component)myEvent.getSource();
source.getParent().dispatchEvent(myEvent);
But this solution implies creating a new EventListener for each element to add.
So, you could create a single event handler and reuse it, adding it to all the chosen children, like this:
final Container parent=this; //we are a the parent container creation code
MouseListener myCommonListener=new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
parent.dispatchEvent(e);
}
#Override
public void mouseEntered(MouseEvent e) {
parent.dispatchEvent(e);
}
#Override
public void mouseExited(MouseEvent e) {
parent.dispatchEvent(e);
}
#Override
public void mousePressed(MouseEvent e) {
parent.dispatchEvent(e);
}
#Override
public void mouseReleased(MouseEvent e) {
parent.dispatchEvent(e);
}
};
JLabel label=new JLabel("This is the first Label");
label.addMouseListener(myCommonListener);
JLabel label2=new JLabel("This is the second Label");
label2.addMouseListener(myCommonListener);
//... and so on
You should convert event before dispatching it to the parent. Conversion includes coordinates translation to parent-relative.
public class RedispatchingMouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener{
public void mouseClicked(MouseEvent e) {
redispatchToParent(e);
}
public void mousePressed(MouseEvent e) {
redispatchToParent(e);
}
public void mouseReleased(MouseEvent e) {
redispatchToParent(e);
}
public void mouseEntered(MouseEvent e) {
redispatchToParent(e);
}
public void mouseExited(MouseEvent e) {
redispatchToParent(e);
}
public void mouseWheelMoved(MouseWheelEvent e){
redispatchToParent(e);
}
public void mouseDragged(MouseEvent e){
redispatchToParent(e);
}
public void mouseMoved(MouseEvent e) {
redispatchToParent(e);
}
private void redispatchToParent(MouseEvent e){
Component source = (Component) e.getSource();
MouseEvent parentEvent = SwingUtilities.convertMouseEvent(source, e, source.getParent());
source.getParent().dispatchEvent(parentEvent);
}
}
Mouse events are automatically targeted to the deepest component that has mouse listeners.
Because of this, to achieve your goal, you can simply remove all mouse listeners on the JLabel and it will never get picked as the target for mouse events.
The following code will disable mouse listeners on the given components and their children recursively:
public static void disableMouseForComponent(Component... components) {
for (Component c : components) {
if (c instanceof Container) {
disableMouseForComponent(((Container) c).getComponents());
}
for (MouseListener l : c.getMouseListeners()) {
c.removeMouseListener(l);
}
for (MouseMotionListener l : c.getMouseMotionListeners()) {
c.removeMouseMotionListener(l);
}
}
}