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);
}
}
}
Related
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
This question already has answers here:
How to use Key Bindings instead of Key Listeners
(4 answers)
KeyListener not working (requestFocus not fixing it)
(3 answers)
Closed 5 years ago.
I am making a large program with multiple classes and am having issues with some code that I wrote. My Mouse listener works just fine and using the same steps, my key listener does not. My code is as follows;
main method
public static void main(String[] args) {
window._init_(panel);
}
Window init method:
public void _init_(JPanel panel){
window = new JFrame("Asteroid");
window.setPreferredSize(size);
window.setDefaultCloseOperation(closeOpp);
window.add(panel);
window.getContentPane();
window.setResizable(resizable);
window.setFocusable(focusable);
window.pack();
window.setLocationRelativeTo(location);
window.setVisible(visibility);
}
Panel init method:
public MainPanel(){
//panel initialization
System.out.println("inside constructor");
panel = new JPanel();
this.add(panel);
this.addKeyListener(this);
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.setSize(Window.size);
this.setFocusable(Window.focusable);
this.add(b);
this.setVisible(Window.visibility);
}
Panel listener methods
#Override
public void keyPressed(KeyEvent e) {
System.out.println("key pressed");
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("key released");
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("mouse clicked");
}
public void keyTyped(KeyEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseDragged(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
ps. The panel implements all of the used listeners, all variables are defined, and the program runs with no errors
Your setting you focus to your frame rather than the JPanel, But even changing the focus to the JPanel will provide a level of unpredictable behavior because it is really easy to lose focus of the JPanel. I suggest you use Key Binding or Change your keylistner method and other override methods to attach to the JFrame rather than the JPanel to assure focus is kept during use of application.
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) {}
}
for(int k=0;k< dtm.getRowCount();k++) //dtm is object of default table model
{
if(String.valueOf(dtm.getValueAt(k,1)).equalsIgnoreCase("Today") && check==0 )
{
cnt++;
JLabel jp=new JLabel();
panel.add(jp);
panel.setLayout(null);
if(cnt<=12)
{
jp.setBounds(j,500,100,100);
j=j+115;
jp.addMouseListener(this);
}
else
{
j=j-115;
jp.setBounds(j,400,100,100);
}
String b="<html><body text=#FDFA0B>"+String.valueOf(dtm.getValueAt(k,0))+"'s Birthday";
jp.setText(b);
jp.setFont(new java.awt.Font("comicbd",Font.ITALIC+Font.BOLD, 14));
}
}
It will not work mouselister only apply for last placed Label...
I want to apply mouse listener for all label how can I do that ..
please help me ....
Without SSCCE I can tell you that you're adding listener on 3 conditions:
String.valueOf(dtm.getValueAt(k,1)).equalsIgnoreCase("Today")
check == 0
and if(cnt<=12)
Other JLabels (that don't pass these conditions) haven't assigned your listener.
Make sure that you're clicking correct labels.
Or move jp.addMouseListener(this); just after JLabel creation (if you want to add listener to all your JLabels).
You certainly can add the same MouseListener to multiple components - here's an example in it's simplest form:
MouseListener ml = new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {System.out.println("Released!");}
#Override
public void mousePressed(MouseEvent e) {System.out.println("Pressed!");}
#Override
public void mouseExited(MouseEvent e) {System.out.println("Exited!");}
#Override
public void mouseEntered(MouseEvent e) {System.out.println("Entered!");}
#Override
public void mouseClicked(MouseEvent e) {System.out.println("Clicked!");}
};
JLabel j1 = new JLabel("Label1");
j1.addMouseListener(ml);
JLabel j2 = new JLabel("Label2");
j2.addMouseListener(ml);
BUT according to your code, you're messing with a JTable - and JTable's act differently than you're thinking. The labels you're trying to edit are actually part of a TableCellEditor. The JTable uses the single TableCellEditor (read: single JLabel) to display every cell in the JTable. This is why you're only seeing the Listener applied to the last cell (because that's the only the last cell has a full component any more - the rest are just ghosts of where the component was applied before).
The good news is you can add a MouseListener to the JTable, and obtain information from there:
final JTable table = new JTable();
MouseListener ml = new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
System.out.println(table.getModel().getValueAt(table.getSelectedRow(), table.getSelectedColumn()));
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println(table.getModel().getValueAt(table.getSelectedRow(), table.getSelectedColumn()));
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println(table.getModel().getValueAt(table.getSelectedRow(), table.getSelectedColumn()));
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println(table.getModel().getValueAt(table.getSelectedRow(), table.getSelectedColumn()));
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(table.getModel().getValueAt(table.getSelectedRow(), table.getSelectedColumn()));
}
};
table.addMouseListener(ml);
One Option is to add another inner class:
class MListener extends MouseAdapter{
public void mouseReleased(MouseEvent e) {}
//other mouse evetns
}
then rather then:
jp.addmousListener(this);
do:
jp.addMouseListener(new MListener());
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);
}
});
}