I regularly see the following code in blackberry development. It registers a listener on a field and when the listener is fired(in below example when focus is on a field) some code is executed. Is this part of a design pattern? How is focusChanged actually called ?
FocusChangeListener focusListener = new FocusChangeListener() {
public void focusChanged(Field field, int eventType) {
// TODO Auto-generated method stub
}
}
field.setFocusListener(focusListener);
Focus change is called by the OS, or some BB APIs that sit close to the OS. Whenever someone scrolls through, or touches a field the focus changes. Think of it kind of like tabbing through a window in a desktop app.
As you move through the controls, your app gets notified of the focus change, which notifies your base manager, and it bubbles up until it gets handled.
Similarly for ButtonClickListener etc. They're basically events that get fired (to think of it in the Windows parlance) and the ChangeListeners that subscribe to those events get called.
Related
I'm trying to make AccessibilityService get notified about clipboard copy event.
So far I've tried to make work around, so the service would be notified after "copy" button is clicked in popup, but no event is thrown in that situation, I checked all basic events (text selection, type view click etc.)
Is there any possibility to achieve that?
Accessibility services don't receive this event. What you could do is check the content of the clipboard after some subset of Accessibility Events.
#Override
public void onAccessibilityEvent(AccessibilityEvent e) {
switch (e.getEventType()) {
//This event alone may be enough!
case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
// If not fall through for these events as well, which would detect things like a "Copy" button activated.
case AccessibilityEvent.TYPE_VIEW_CLICKED:
case AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED:
checkContentsOfClipboard();
}
}
Sadly not possible, as the other answer has written (and from Android 10 you can't even check what's on the clipboard without having an Activity of your own in the foreground), so I've requested to add this API here:
https://issuetracker.google.com/issues/207842550
Please consider starring.
I have a SWT GUI, containing different elements (Text, Buttons, Labels...) which are themselves in different Composites.
I would like to make the navigation easier using some keybindings such as "Alt+c" to call the Cancel Button, "Alt+f" to call the finish button etc... When using a KeyListener on a specific component, the listener is triggered, but it implies that the component has the focus (and this is not very convenient !).
So I tried to register the listener on the shell itself, but the result is the same and nothing is triggered.
How should I proceed in order to get my listener triggered no matters what element is currently focused ?
Any hint would be appreciated.
Thanks for reading.
Edit
Regarding the comments, I tried to add the keylistener recursively to all the composites of the GUI, and it's working. However, I guess there is probably a "clever" way to do it.
You can use the Display addFilter or addListener methods to add a listener which is always called.
Display.getDefault().addListener(SWT.KeyDown, new Listener() {
#Override
public void handleEvent(final Event event) {
// TODO handle event
}
});
These listeners use the lower level Listener interface rather than KeyListener.
addFilter is similar to addListener but is called earlier and can change the event.
The easiest way is to add a event filter to the display:
Here is an example I use to activate a search field when a user types command-F in our main application window.
Display.getCurrent().addFilter(SWT.KeyDown, event -> {
// Only respond to key events for our shell.
if (getShell().equals(Display.getCurrent().getActiveShell())) {
// Activate the focus for our search widget when user types 'f'
// (control-f, command-f, or just f)
if (event.keyCode == 'f') {
if (!searchField.isFocusControl()) {
searchField.setFocus();
}
}
}
});
In my SWT based application, I have a Canvas-derived custom Widget, which is displaying a bunch of "items". The whole purpose of these items is for the user to drag them out of the widget. I had no trouble implementing a DragSource, DragDetectListener and all that stuff to make DND work. The problem I am trying to solve is that I want the drag to be detected much earlier, i.e. after a much shorter mouse drag distance, than the default platform behavior.
I know I can override dragDetect() of the Widget class. However, this only allows me to veto the super class implementation, not to notify that a drag already happened before the super class would think it has.
Basically, if I could generate the drag event myself, like if I could just use Widget.postEvent(SWT.DragDetect, eventWhichIAllocatedAndFilledOut) (which is package private), that would seem like my solution. I've looked at the code for drag detection in Widget, and it doesn't seem to be designed for this use-case. Is there a work around that let's me initiate drags anytime I want?
I have figured it out. It is possible to generate a custom event and distribute it to the DragDetect listener mechanism. The code below does the same as the internal implementation, but can be called at will from within the Widget implementation, for example from a MouseMoveListener's mouseMove(MouseEvent e) hook:
Event event = new Event();
event.type = SWT.DragDetect;
event.display = getDisplay();
event.widget = this;
event.button = e.button;
event.stateMask = e.stateMask;
event.time = e.time;
event.x = e.x;
event.y = e.y;
notifyListeners(SWT.DragDetect, event);
It is noteworthy that the built-in drag detection has to be disabled for this to work as intended. The default implementation is exposed via the dragDetect(MouseEvent e) method that can be called from a mouseDown() handler (as explained in the documentation for dragDetect()). It works by busy looping in the event thread until the drag is detected. It simply consumes mouse move events from the native event queue on the GTK backend at least. When a DragDetectListener is registered with the Widget, this will automatically be done, so unless one disables the mechanism via setDragDetect(false), a custom drag detection would only run after the built-in detection which imposes the delay because it is blocking the event thread, besides detecting the drag a second time, of course.
In my code, two comboboxes are added to actionListener( this );
In another part of my code, I call a combobox function that sets an index to a certain value. This in turn calls actionPerfoemed again and so getSource == comboBox is true. Every time I call a set function it calls actionPerformed again, creating a stack of function calls that then unwinds down to the first.
Is there a way to prevent this?
If the problem is just the initial setting, you can defer adding the listener until after both have been initialized. There's more discussion here.
From the Swing tutorial,
Combo boxes also generate item events, which are fired when any of the items' selection state changes.
These events will be generated either when a user clicks on the items with the mouse, or when your software calls setSelectedIndex().
Perhaps you don't want your actionPerformed() method in this to be called when your software calls setSelectedIndex(). You may need a Boolean eventInitiatedBySoftware. In your main (this) class, you could say
synchronized(eventInitiatedBySoftware) {
eventInitiatedBySoftware=true;
comboboxeditor.setSelectedIndex(n);
}
and then in your listener:
public void actionPerformed(ActionEvent ae) {
synchronized(eventInitiatedBySoftware) {
if (eventInitiatedBySoftware) {
eventInitiatedBySoftware=false; // clear your flag.
return; // don't want to process this event.
}
// the rest of your method goes here
}
When your software wants to adjust the value, it will set the Boolean to true. The actionPerformed method will be called, but your test will realise that this event was initiated by the software, and return before doing any of your existing code. It will clear the Boolean, so that if a user now uses the mouse to perform a selection action, your code will realise that it wasn't softwareInitiated.
BTW, It's possible that you misunderstand the event concept. For example, I suspect you are actually adding "this" as an event listener for each combobox, rather than adding comboboxes as listeners to "this". You might like to look at the Writing Event Listeners trail.
Here's the situation, I have a jFrame with a tabbed pane and within the tabs I have a couple of jTables and a jTree. I want to be able to chain the selections between the tables and the tree based on whether a user uses a ctrl/shift + click versus a regular click. (If you hold ctrl and click in the first table/tree, it adds to the overall selection, if you use a regular click it clears the selections in the other tables/tree). Currently I'm having an issue with Java's jTree component. I have added a TreeSelectionListener and a MouseListener with a class that implements both interfaces, call it MyBigListener;
i.e.
MyBigListener listener = new MyBigListener();
jTree1.addMouseListener( listener );
jTree1.addTreeSelectionListener( listener );
MyBigListener implements TreeSelectionListener, MouseListener {
private boolean chained = false;
public synchronized setChained(boolean ch){
chained = ch;
}
public synchronized boolean isChained(){
return chained
}
public void valueChanged(TreeSelectionEvent e){
if(isChained()){ blah... }
}
public void mousePressed(MouseEvent e){
setChained(e.isControlDown() || e.isShiftDown());
}
}
My plan was to set a boolean flag if the user uses a ctrl/shift + click that I could check during the valueChanged(TreeSelectionEvent e) implemented by the tree selection listener.
I want to be able to process the mouse events before the valueChanged TreeSelectionEvents, but the problem is that I receive the mouse events after the valueChanged treeSelection event. This seems weird to me that I receive the selection change before the mouse pressed event fires, when the selection change is actually initiated by the mouse pressed. (I've already synchronized the boolean flag setting, which ironically helped to highlight the mis-order of events.)
I've already tried alternatives like adding a keyListener, but this doesn't work when the focus is on a separate frame, which goofs me up when a user holds ctrl and then clicks into the jTree causing it to receive both the focus and fire any valueChanged selection events.
Any help would be appreciated, thanks!
--EDIT-- #akf
I have separate jTables and jTrees in a tabbed Pane that serve as a summary/control panel for data in a nodal-graph. I'm using these components in the tabbed Pane to do coordinated selection to a graph displayed in a separate jFrame. Individually each table works just fine for its selection as does the jTree. It's coordinating between the panes that's tricky. This works fine so far with jTable components because I fire the new selections as the result of a MouseEvent where I can tell if the shift/ctrl button was down, formulate my new selection, and pass it to the parent frame which coordinates selections between all panes and sends the final selection to the graph. However, the parent needs to know if it needs to chain a selection between panes, or squash the others. With the jTables it's fine again, because I fire selection changes as the result of a mouse click. The jTree is more of a problem because I'm doing some forced selections. If you click on a branch, it forces all leaves into the selection. I needed to implement a TreeSelectionListener to do that, but only get a valueChanged(TreeSelectionEvent) to realized changes. I added a mouseListener to listen for ctrl+clicks and shift+clicks, but apparently the events don't always happen in the same order.. at least so far I receive the valueChanged event before the mousePressed event, so checking to if a ctrl+click happened posts after the selection has already been modified.
Right now, I'm posting a pending selection change and then have the MouseListener grab that and send it up the chain, but if these events aren't guaranteed to happen in the same order, at some point it's going to fail. Implementing a delayer also rubs me the wrong way.
Thanks for the help so far.
--EDIT2-- #ykaganovich
I think overriding the fireValueChanged method is closer to the right way to go about things. Depending on my definition of what actions should cause a "chained" selection to the other components, I'd need to gather some context on what's going on before the valuedChanged method fires. This basically means calling it myself in all cases where I can define what it means by who triggers it. I.e. If a mouse event causes it and ctrl is down then set what I need to set (interpret) then fire. If it's going to change due to a keyboard event, again, set what I need to set, then fire. I don't think the TreeSelectionModel is the way to go, because I still won't know what the circumstances were when the event fired. I think this means I'll need to rewrite parts of the jTree to do this but I guess I'll see how it goes. Thanks.
Don't do it that way, override JTree.fireValueChanged instead.
Try something like this (untested):
class ChainedSelectionEvent extends TreeSelectionEvent {
ChainedSelectionEvent(TreeSelectionEvent e) {
super(e.newSource, e.paths, e.areNew, e.oldLeadSelectionPath, e.newLeadSelectionPath);
}
}
protected void fireValueChanged(TreeSelectionEvent e) {
if(chained) { // figure out separately
super.fireValueChanged(new ChainedSelectionEvent(e));
} else {
super.fireValueChanged(e);
}
}
Then check instanceof ChainedSelectionEvent in your listener
EDIT
Actually, I think the right way to do this is to implement your own TreeSelectionModel, and override fireValueChanged there instead. Assuming setSelectionPath(s) methods imply a new selection, and add/removeSelectionPath(s) imply chaining, you could distinguish between the two cleanly. I don't like listening to either keyboard or mouse events explicitly, because there's more than one way to change a selection (e.g. if someone is holding down SHIFT and hitting a down-arrow, you won't get a mouse event).
You may get the mouse event before or after the tree selection event. Best not to rely on such orders. The reason is that the tree selection event is caused in response to the mouse event. Is that mouse event listener called before or after your listener? Could be either.
This sort of thing is closely involved with the implementation of the PL&F.
the key here is to understand that a JTree is delivered with a BasicTreeUI.MouseHandler, see javax.swing.plaf.basic.BasicTreeUI.
to answer the central question, "what fires fireValueChanged", the answer is "this mouse handler"... which turns out to be the only mouse listener returned when you go tree.getMouseListeners().
So you have to replace this default mouse listener with your own version ... which is a little tricky. I use Jython, which everyone needs to discover. This code shouldn't be too difficult to translate into Java however:
from javax.swing.plaf.basic import BasicTreeUI
def makeMouseHandlerClass():
class MouseHandlerClass( BasicTreeUI.MouseHandler ):
def mousePressed( self, mouseEvent ):
genLog.info( "mouse handler MOUSE PRESSED!" )
nTFSelf.mousePressedStatus = True
BasicTreeUI.MouseHandler.mousePressed( self, mouseEvent )
nTFSelf.mousePressedStatus = False
return MouseHandlerClass
suppliedMouseHandler = nTFSelf.taskTree.mouseListeners[ 0 ]
nTFSelf.taskTree.removeMouseListener( suppliedMouseHandler )
nTFSelf.taskTree.addMouseListener( makeMouseHandlerClass()( nTFSelf.taskTree.getUI() ))
... basically the equivalent Java here would be to extend BasicTreeUI.MouseHandler as MyMouseHandler, and then in the last line replace with new MyMouseHandler( tree.getUI() )... "nTFSelf" here is merely a reference to the "this" object of the code where all this is being written...