Roman
Roman

Reputation: 2079

Touch event handling in Blackberry

I try to implement simple touch event handling on Blackberry 9550 emulator, but it doesn't work. Actually, touchEvent never gets called, 'cos no text ever appears in the console. Also, I get an annoying "Full Menu" which appears on touching the screen. Here's the code:

package mypackage;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.EventInjector.TouchEvent;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.VirtualKeyboard;
import net.rim.device.api.ui.container.MainScreen;

public class MyScreen extends MainScreen
{   
public MyScreen()
{    
    super(NO_SYSTEM_MENU_ITEMS);
    getScreen().getVirtualKeyboard().setVisibility(VirtualKeyboard.HIDE_FORCE);      
    add(new HandleTouch());

}

class HandleTouch extends Field {

    protected void layout(int width, int height) {
        setExtent(width, height);
    }

    public void paint(Graphics graphics) {
        graphics.drawBitmap(0, 0, this.getWidth(), this.getHeight(), Bitmap.getBitmapResource("bg.png"), 0, 0);
    }

    public boolean isFocusable() { return true;}

    protected boolean touchEvent(TouchEvent message) {
        switch( message.getEvent() ) {
        case TouchEvent.CLICK:
            System.out.println("----------------------------->CLICK");
            return true;
        case TouchEvent.DOWN:
            System.out.println("----------------------------->DOWN");
            return true;    
        case TouchEvent.MOVE:
            System.out.println("----------------------------->MOVE");
            return true;    
        }
        System.out.println("PRINT ME SOMETHING IN ANY CASE");
        return false;
    }

    public HandleTouch() {

    }
}

}

Upvotes: 3

Views: 3399

Answers (2)

Richard Le Mesurier
Richard Le Mesurier

Reputation: 29713

I would like to add extra info to Arhimed's answer, since this seems to be a landing page for googling touch events...

My experiences are not to contradict him, but to add possible solutions for future readers. I am using BB OS 5.0. My experiences have been with the Storm simulator, and a Torch device. My app was originally written for OS 4.5, so it might be running in some sort of compatibility mode.

1) As explained in his point 4, a Touch Event gets passed along to a Navigation Click event, if touchEvent(TouchEvent) returns false. If navigationClick(int, int) returns false, this prompts the system to display a ContextMenu.

2) On my system, I could not find a method getContextMenu(int). So I could not test his point 3. I presume this gets added in BB6 or later.

3) I did find getContextMenu() - i.e. it takes no parameters. I tried to override that method to return null.

The strange thing is that this method only gets called after the initial context menu popup is shown! The initial context menu popup (?) gets shown, with a button on it for "Full Menu". When that button is pressed, this method gets called, and can be used to populate the MainMenu that appears. ... strange...

However, it means that overriding that method did not solve my problem.

4) I was unable to get a solution by returning true in touchEvent(TouchEvent). I agree that this would have been bad form (hack), but I have learnt to hack a lot on the BB platform. However, scrolling list fields need to have the touch event passed up, so that the scroll works.

5) Eventually I found something similar to the OP's problem with TouchEvent.UNCLICK. It has taken me 18 months to find the method navigationUnClick(int, int). Similar to my point 1 above, an unhandled UNCLICK becomes a navigationUnClick(int, int) call, which can also lead to the context menu being shown.

So by adding similar logic to both navigationClick(int, int) & navigationUnClick(int, int), I was able to get my lists & touches to interact nicely.


This is just supplemental info, that may add to the accepted anser.

Upvotes: 3

Vit Khudenko
Vit Khudenko

Reputation: 28418

1). First of all, with this code

protected void layout(int width, int height) {
    setExtent(width, height);
}

you are actually setting a VERY large size of the field. This because the BB UI framework passes max available/possible dimentions to layout(int width, int height) so the field should use some part within the passed values. In this specific case the width will be the width of the display (360 px) and the height is the max possible height of the VerticalFieldManager (the one your are adding screen fields to, it is implicitly present in the screen's internals) (1073741823 px). So, finally this may result in a very large Bitmap object that is required with the field in order to be painted and you can get an uncaught error "Bitmap is too large" (I did on Storm 9530).

So, the layout() should use some relatively small values, e.g.:

protected void layout(int width, int height) {
    setExtent(Math.min(width, 360), Math.min(height, 480));
}

2).

Actually, touchEvent never gets called

Well, actually it does get called. To see that you should simply touch (versus click). Left button of the mouse simulates clicks (a sequence of TouchEvent.DOWN > TouchEvent.CLICK > TouchEvent.UNCLICK > TouchEvent.UP), right button simulates touches (a sequence of TouchEvent.DOWN > TouchEvent.UP).

3).

Also, I get an annoying "Full Menu" which appears on touching the screen.

This is because your field does not consume TouchEvent.UNCLICK event. For instance, with this code your field will not show the popup:

protected boolean touchEvent(TouchEvent message) {
    return true;
}

But, that is a bad solution for the popup. It is better to understand what really causes the popup. If TouchEvent.UNCLICK event is not consumed then BB UI framework calls getContextMenu(int instance) and makeContextMenu(ContextMenu contextMenu, int instance) methods of the field. So in order to disable the popup (which is actually a ContextMenu created by the getContextMenu(int instance) you should override the getContextMenu(int instance) to be smth like this:

public ContextMenu getContextMenu(int instance) {
    // just in case check if a context menu is requested
    // in order not to disable other types of menu
    boolean isContextMenu = (Menu.INSTANCE_CONTEXT == instance);
    return isContextMenu ? null : super.getContextMenu(instance);
}

4). Finally I'd recommend to not change native/default behavior of touchEvent(TouchEvent message) method. You can just watch/log it, but don't change (always call its super version). This is because touch events handling is more complicated than it may look at first. It is very easy to get a tricky bug here. I do believe most programmers should not change the native behavior of touchEvent(TouchEvent message) unless they really want to create some custom UI component to work with touch gestures. Normally they just want to react on a click (to behave as a ButtonField), however for that you can simply override navigationClick(int status, int time) or navigationUnclick(int status, int time). The BB UI framework will call those methods when user clicks your field on a touch screen.

Upvotes: 6

Related Questions