SWT event propagation - java

I'm trying to detect click events on a Composite control that contains a number of other composites. I tried:
topComposite.addMouseListener(new MouseListener() {
...
#Override
public void mouseUp(MouseEvent arg0) {
logger.info("HERE");
});
});
But the event never fires. I assumed that when a mouse event occurred on a child it would propagate up the chain but that doesn't happen. How do I do this?

In SWT, the general rule is that events do not propagate. The main exception to this, is the propagation of traverse events - which is pretty complicated to describe.
The easy answer to your problem is that you must add the listener to all the children of you Composite - recursively!
E.g. like this
public void createPartControl(Composite parent) {
// Create view...
final MouseListener ma = new MouseAdapter() {
#Override
public void mouseDown(MouseEvent e) {
System.out.println("down in " + e.widget);
}
};
addMouseListener(parent, ma);
}
private void addMouseListener(Control c, MouseListener ma) {
c.addMouseListener(ma);
if (c instanceof Composite) {
for (final Control cc : ((Composite) c).getChildren()) {
addMouseListener(cc, ma);
}
}
}
The clicked-upon widget is found in e.widget as seen above. An important issue is to remember to do this again if you add more Controls later.

Related

How can I add a MouseListener to every element (except one) inside an EditorPart?

When the user clicks somewhere outside a a Text widget, I want to deactivate its scrollbars.
It works like this:
public class RttProjectActionEditor extends EditorPart {
...
MouseListener exitCommandText = new MouseListener() {
#Override
public void mouseDoubleClick(MouseEvent e) {}
#Override
public void mouseDown(MouseEvent e) {}
#Override
public void mouseUp(MouseEvent e) {
if (e.widget != textArea) {
textArea.getVerticalBar().setEnabled(false);
}
}
};
labelGroup.addMouseListener(exitCommandText);
myComposite.addMouseListener(exitCommandText);
... // all widgets in my EditorPart
But this way I have to add them one by one to all widgets that this EditorPart is the owner of. Is there a better and simpler way?
You can recursively add listeners to a control and any children (if it is a composite) using something like this:
private void hookRecursively(Control c, MouseListener listener) {
c.addMouseListener(listener);
if (c instanceof Composite) {
Control[] children = ((Composite) c).getChildren();
for (Control element : children) {
hookRecursively(element, listener);
}
}
}

how to get mouse pointer component in swing application

my swing application one panel have 6 button. when cursor goes on the button i want to change default cursor to hand cursor and cursor is exit then it want to change default cursor. Now i am doing this thing using below code.
private void btnRegisterReceiptMouseEntered(java.awt.event.MouseEvent evt) {
btnRegisterReceipt.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
private void btnRegisterReceiptMouseExited(java.awt.event.MouseEvent evt) {
btnRegisterReceipt.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
Now i want to write this code to each and every button.
But I want to write common method to do this one. I already try to use MouseListener do this thing, but I can not get which is the mouse point component.
I don't know it is possible or not. if it is possible please anyone tell me how to do this things.
private void changeCursor() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered( MouseEvent e ) {
/*if ( mouse Entered compornent is button ) {
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
button.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}*/
}
});
}
Write a generic MouseListener (as an annonymouse class):
MouseListener ml = new MouseAdapter()
{
#Override
public void mouseEntered(MouseEvent e)
{
e.getComponent( setCursor(...) );
}
#Override
public void mouseExited(MouseEvent e)
{
e.getComponent( setCursor(...) );
}
};
Then you can just add the MouseListener to any component you want with:
btnRegisterReceipt.addMouseListener( ml );
anotherButton.addMouseListener( ml );
You can also make this as a reusable class:
public MousePointerListener extends MouseAdapter
{
#Override
public void mouseEntered(MouseEvent e)
{
e.getComponent( setCursor(...) );
}
#Override
public void mouseExited(MouseEvent e)
{
e.getComponent( setCursor(...) );
}
}
Then you use:
MouseListener ml = new MousePointerListener();
btnRegisterReceipt.addMouseListener( ml );
anotherButton.addMouseListener( ml );
The key point in both examples is that you can get the source of the event from the MouseEvent, which allows you to write generic code. You should look at this approach for all you listeners, instead of letting your IDE generate the listener code.

SWT/JFace: How to handle Keyevents for each ViewPart or Form?

I'm building an Eclipse application and I'm trying to make a shortcut for launching an action when pressing F5, and make that the default action when that Tab/ViewPart has the focus.
I have read that this is not possible, or very complex. Is there any simple/straight way of doing it?
I tried with:
Display.getCurrent().addFilter(...)
this.addKeyListener(new KeyAdapter() {...})
...
Making this in the constructor is my best:
this.getShell().addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if(e.keyCode == SWT.F5) {
//doAnything()
}
}
});
And this doesn't work when loaded, but if I switch from this to another View/Tab starts to work. But it works too when others have focus (which I don't want).
Is there anyway of making this work at the start, and only when the focus is in the View?
You should define work in a handler & then should use key bindings as given in this example. You can find a good example here. Hope it solves your need.
You should look at RetargetableActions. I think that's Eclipse way of doing it:
You need to look at extensions org.eclipse.ui.bindings and org.eclipse.ui.contexts.
Define a command and its handler
Define a binding for the command
define context (cxtId)
associate context with command so that command is available only when context is active
Activate context when you open the view or form.
If you get the listener of the events of the component it will listen on the events. And if the event occur for this component it will be notified.
To add listener of the key event on the ViewPart we should create the control which could be able listen on the event.
public class SampleView extends ViewPart {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "views.SampleView";
private Composite mycomposite;
public void createPartControl(Composite parent) {
mycomposite = new Composite(parent, SWT.FILL);
//then add listener
mycomposite.addKeyListener(keyListener);
}
private KeyListener keyListener = new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
showMessage("key pressed: "+ e.keyCode);
}
};
//the rest of focusing and handle event
private void showMessage(String message) {
MessageDialog.openInformation(
mycomposite.getShell(),
"Sample View",
message);
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
mycomposite.setFocus();
}
}
//the end

Special method should be called after any AbstractAction-execution

Please excuse the vague question title, but usually I don't do such kind of stuff. So I have the following problem:
I'm designing a popupmenu for a specific app where each menu item is associated with a certain action:
public class CanvasMenu extends JPopupMenu {
public CanvasMenu(){
this.add(new AbstractAction("Do some operation") {
#Override
public void actionPerformed(ActionEvent arg0) {
doSomeStuff1();
cleanup(); // has to be done after every menu operation
}
});
this.add(new AbstractAction("Other operation") {
#Override
public void actionPerformed(ActionEvent e) {
doSomeOtherStuff();
cleanup(); // has to be done after every menu operation
}
});
}
}
I read somewhere that AbstractAction is used for such tasks where you want to add menu items and associate them with some action. In reality, I want not only two such actions, but some dozen of them.
The problem is the cleanup thing. cleanup should be after any of these actions has been chosen. This means, if I continue in the abovely described manner, I will have to write cleanup() for each AbstractAction.
Is there any (easy/elegant/nice) way or pattern to avoid writing cleanup() over and over again? I.e. is it possible to desing something that will only get the action and after executing it automatically call cleanup?
This is one of the patterns:
abstract class ActionWithCleanup extend AbstractAction {
#Override
public final void actionPerformed(ActionEvent arg0) {
myAction();
cleanup(); // has to be done after every menu operation
}
public abstract void myAction();
}
...
this.add(new ActionWithCleanup("Do some operation") {
#Override
public void myAction() {
doSomeStuff1();
}
});

Detect if Java Swing component has been hidden

Assume we have the following Swing application:
final JFrame frame = new JFrame();
final JPanel outer = new JPanel();
frame.add(outer);
JComponent inner = new SomeSpecialComponent();
outer.add(inner);
So in this example we simply have an outer panel in the frame and a special component in the panel. This special component must do something when it is hidden and shown. But the problem is that setVisible() is called on the outer panel and not on the special component. So I can't override the setVisible method in the special component and I also can't use a component listener on it. I could register the listener on the parent component but what if the outer panel is also in another panel and this outer outer panel is hidden?
Is there an easier solution than recursively adding component listeners to all parent components to detect a visibility change in SomeSpecialComponent?
Thanks aioobe for your answer - I got here via Google, looking for the same thing. :-) It's worth noting that Component.isShowing() does the same job as your amIVisible() though, so a revised code snippet (including a check on the nature of the HierarchyEvent) might be:
class SomeSpecialComponent extends JComponent implements HierarchyListener {
public void addNotify() {
super.addNotify();
addHierarchyListener(this);
}
public void removeNotify() {
removeHierarchyListener(this);
super.removeNotify();
}
public void hierarchyChanged(HierarchyEvent e) {
if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0)
System.out.println("Am I visible? " + isShowing());
}
}
To listen for this kind of events occuring in the hierarchy, you could do the following.
class SomeSpecialComponent extends JComponent implements HierarchyListener {
private boolean amIVisible() {
Container c = getParent();
while (c != null)
if (!c.isVisible())
return false;
else
c = c.getParent();
return true;
}
public void addNotify() {
super.addNotify();
addHierarchyListener(this);
}
public void removeNotify() {
removeHierarchyListener(this);
super.removeNotify();
}
public void hierarchyChanged(HierarchyEvent e) {
System.out.println("Am I visible? " + amIVisible());
}
}
You could even be more precise in the treatement of HierarchyEvents. Have a look at
http://java.sun.com/javase/6/docs/api/java/awt/event/HierarchyEvent.html
Have a look at the ComponentListener (or ComponentAdapter)
http://java.sun.com/docs/books/tutorial/uiswing/events/componentlistener.html
http://docs.oracle.com/javase/8/docs/api/java/awt/event/ComponentListener.html
And specifically the method:
void componentHidden(ComponentEvent e)
Invoked when the component has been made invisible.
A complete solution would look something like:
inner.addComponentListener(new ComponentAdapter() {
public void componentHidden(ComponentEvent ce) {
System.out.println("Component hidden!");
}
});
If the actions that should be carried out upon hiding is tightly coupled with the SomeSpecialCompnent, I would suggest to let SomeSpecialComponent implement ComponentListener, and add itself as a listener for the ComponentEvents in its constructor.
Another useful way (more related to add/remove operations and perhaps not suitable for your specific scenario) is to override addNotify() and removeNotify().

Categories