Custom Screen, Vertically Scrolling and more

There are two parts to my answer. To get scrolling behavior, just do what I did in my example screen. That is, create a MainScreen, create a GridLayoutManager, and then add the GridLayoutManager to the screen using the add(Field) method. When you add enough items to make the manager layout taller than the available screen height, scroll arrows will appear and the display will scroll to show the focused field. This works because MainScreen’s delegate manager is a VerticalFieldManager with scrolling enabled. What’s a delegate manager? That’s something you need to know if you ever make your own Screen.

Delegate Managers

Although Screen is a subclass of Manager, it actually doesn’t do any of the layout of fields added using its add (and insert) methods directly. Instead, each Screen delegates layout to a manager – the delegate manager. Notice that Screen’s constructor requires a Manager – you specify the Screen’s delegate manager at construction time, and can’t change it later. This means among other things that a MainScreen will always have a scrollable VerticalFieldManager as it’s main area – so if you want other behavior you can’t use MainScreen!

Easy enough – and this explains why we don’t need to do any additional work to the GridFieldManager example to make it scrollable – it’s automatically inside a vertically scrolling manager already! A couple more things about delegate managers, if you’re thinking of making your own screen.

First, the screen gets to set the position and size of its delegate manager. This is done in the layoutDelegate and setPositionDelegate methods. (You don’t have to make your delegate use the entire size of your screen).

Second, don’t worry about laying out any fields that are added to the Screen from within the Screen itself – that’s all done by the delegate. The screen deals with those field in the add (and insert) methods, and then basically forgets about them. This should be obvious but since it derives from Manager, I feel it’s worth saying explicitly – don’t make a Screen the same way you make a Manager.

Part Two: Mea Culpa

Part two will actually be quick – as the commenter pointed out, at some point GridFieldManager might end up setting fields to negative height. As we’ve just seen, in the case where we add it to a MainScreen, this isn’t an issue as we have a huge vertical space to play with. However it is a bug when we’re not in a vertically scrolling manager. So I made a couple of small changes to check that we don’t go above the available height. The interesting change is this, which is a fairly useful convention in a lot of layout methods – it ensures you respect the height (in this case) and width given by your manager:

MIDlet vs. CLDC Application

There are many differences between the two types of application. I’ll highlight what I think are the most important ones, and point out areas where there isn’t really a difference.

Lifecycle

CLDC Applications have more flexibility in their lifecycle than MIDlets do – at least on BlackBerry. Specifically, a CLDC app can start when the BlackBerry starts (or reboots) and it’s easier to get it to run in the background to do listening, processing, etc. For many apps, this means CLDC is your only choice

User Interface

This is the big one. RIM has developed a rich UI library (in Java) for the BlackBerry. It’s designed to take full advantage of the BlackBerry input (keyboard, trackball and touchscreen on the Storm), and provides a lot of pre-built components. I’ve written about it extensively. The MIDP UI library just doesn’t give you the same power. To approach the complexity of a ‘native’ BlackBerry UI requires you to re-do a lot of the work that RIM has already done, and even then there are things you can’t do.

Some specific advantages of the BlackBerry UI library over MIDP (all in context of running on a BlackBerry of course):

  • Rich set of components, managers, screens
  • Access to trackwheel events
  • Easy access to all the BlackBerry keys (including ALT, escape, the softkeys)
  • Ability to provide the appropriate menu depending if the trackball or menu key was pressed
  • Integration of BlackBerry components (the browser, BlackBerry Maps) into a screen in your application
  • Built-in support for localization
  • Accelerometer support for Storm
  • Touch-screen events for Storm
  • Ability to change the homescreen icon

Let me know if there are some I’ve missed.

Things that can be used by a MIDlet or CLDC application

Contrary to what I’ve heard in some places, you can use a lot of the BlackBerry specific APIs in a MIDlet. These include cryptography, invoking other applications (but not embedding their UIs), extended SMS and location based services.

But – the MIDlet you build using any BlackBerry APIs will be a BlackBerry specific MIDlet. It will rely on BlackBerry APIs and so will only be able to run on a BlackBerry. If you’ve already taken that step – I’d ask why not go all the way and get a nicer UI while you’re at it?

A special note – you can, it seems, build a MIDlet for submission to the BlackBerry Application Storefront. However, you’ll have to compile it into a COD file, using the JDE (or Eclipse Plugin).

Possible advantages of going with a MIDlet

The biggest reason organizations want to go with a MIDlet rather than a CLDC application is obvious – you really write once, run anywhere. Now, this is true (barring implementation quirks with MIDP devices to be sure, but for many apps they’re not an issue) – but, you limit yourself to the MIDP lowest common denominator. This means your application doesn’t look or behave quite as nicely as a BlackBerry CLDC application. Think about what a Swing (or any pre-SWT) application looks like vs. a native Windows application and you’ll have some idea.

Maybe for your application it’s not an issue – and if so, more power to you – but from experience if you’re going to target the BlackBerry as the initial platform for your brand-new mobile application (and it’s a very good choice, maybe only iPhone would be better, but with the BlackBerry Application Storefront up and coming, the game will change again) then it’s in your interest to do everything you can to succeed on that platform. If you don’t succeed, supporting MIDP – or any other platform for that matter – might become a moot point.

Common code

There’s a way to mitigate cross platform headaches somewhat. MIDP and BlackBerry CLDC do share a lot in common. Enough so that business logic, and most networking code at least can be almost identical between the two platforms. Smart division of your app and supporting libraries can definitely save work if you want to support MIDP deviced and BlackBerry handhelds.

In the end…

With the BlackBerry Application Storefront launching soon, it’s never been a better time to get into the BlackBerry application market. Hopefully I’ve convinced you to go the CLDC Application route – you’ll save a lot of headache, and end up with a much better application.

Share and Enjoy:

The Golden Rule

The golden rule of the single-threaded API model is:

Only the event thread can modify the user interface.

In fact, it’s a little more subtle – only a thread holding the user interface event lock can modify the user interface – more on that later, for now just know that almost always the event thread is the one holding that event lock.

This means, if you’re doing anything that will directly result in immediate changes to the UI – pushing (or removing) screens onto the display stack, modifying the visible state of your UI components, painting – you have to do it in the event thread.

Simple, right? Yes, in theory. In practice, it’s not much more difficult – just bear in mind a couple of things.

As I said above the thread that enters your main method is your application’s event thread. This, combined with the golden rule means that in the initial call to your main method, you can do all the UI work you want. Often you create your app’s initial screen and push it onto the stack (using UiApplication.pushScreen) there – or at least in a method that you call directly from there. However, at some point you want to call enterEventDispatcher or you’ll never get user input. How do you modify the UI after that?

Modifying the UI

Now, the golden rule doesn’t mean that you can’t call any methods on any UI component from any other thread. Anything that gets information (EditField.getText for example) is fine. Also fine is setting information that may not result in immediate changes. But for most of the built-in UI components – like EditField, or LabelField, methods like setText will result in a change and so must be done while you have the event lock.

How do I know I’m on the event thread

Easy – just UiApplication.getUiApplication().isEventThread(swift runners) (or isEventDIspatchThread, which is a static method and does the same thing – both of those methods, by the way, actually reside in net.rim.device.api.system.Application, which is UiApplication’s super class).

You will sometimes end up on the event thread – menu items are executed on the event thread for example.

How can I modify my UI?

There are two ways:

1. Use the net.rim.device.api.system.Application methods invokeLater or invokeAndWait – both of which take a Runnable. Anything in that Runnable’s runmethod will be executed by the event thread at the next available opportunity. The first method is asynchronous (which means in this case that it returns immediately) the second is synchronous (so waits until your Runnable’s run method is finished before returning).

BlackBerry UI – A simple custom field

I’ve covered creating your own field Manager on this site already. As you might guess, another very common part of BlackBerry UI implementation is creating your own Field class (or extending one of the built-in classes). Fortunately, the basics are very easy, even easier than creating a Manager. I’ll run through a simple from-scratch Field to illustrate everything you’ll need to know.

The field I’ll be creating is a button – now, there’s a ButtonField already in the BlackBerry UI library, but it has just enough drawbacks that I’ve implemented countless replacements. Plus, it’s a great illustrative example – a button needs to to do a bunch of things to be useful. Specifically:

  • Basic Drawing
  • Focus highlighting
  • Responding to user input (trackball and touchscreen clicks, and the enter key)
  • Firing events to listeners

Which basically covers anything you’d want to do with most fields. So let’s get started:

The CustomButtonField

We’ll call this class CustomButtonField. It will do the following things:
– Behave like a ButtonField with respect to focus and user interaction (i.e. show a different color when focused, fire an event when the user clicks on it with the trackball, touchpad, or presses the Enter key when the field is in focus)
– Allow us to easily set the text color and background color (yes you can do the background with Field.setBackground, but that’s only JDE 4.6 and later and there’s still no easy way to set the font color, which makes setting the background limited).

Constructor and instance variables

We’ll define these first, based on our requirements. We’ll of course need the label for the button, and foreground and background colors both for the focused and unfocused states.

So

view plaincopy to clipboardprint?
  1. private String label;
  2. private int fontColorFocused;
  3. private int fontColorUnfocused;
  4. private int backgroundColorFocused;
  5. private int backgroundColorUnfocused;

Eclipse tricks for BlackBerry developers 1 – type less, autocomplete more

If you’re a BlackBerry developer used to using the JDE (or – yes, I’ve seen this – the Visual Studio editor and Ant scripts – don’t ask, and no it wasn’t the BlackBerry Visual Studio plugin) then you might be wondering what the fuss is about switching to Eclipse. After all, there are still some problems that the Eclipse plugin has that aren’t there in the JDE.

Well, the main way you’ll gain productivity (and lose stress) is through Eclipse’s Java editor. Even those of you who are used to Visual Studio may be surprised by all that Eclipse has to offer. There are so many things to talk about, that in the interests of keeping this post short, I’ll focus on just one (but it’s a good one): Autocomplete

Autocomplete

The keystroke for autocomplete is CTRL+Space, which will autocomplete whatever you’re working on, or give you a list of options if there are more than one. So a simple example – start typing:

 

Then press CTRL+Space

 

Notice you get a list of possible objects you might have been referring to – this will include, depending on context, classes, member variables, local variables, or methods (static and/or instance depending on where you’re typing).

Not bad so far – but there are similar things in other editors. Even the JDE has a limited version of autocomplete. Ok, here’s what else it can do:

Context sensitive autocompletion

If you type something like int a = <ctrl+space>, Eclipse will sort the autocomplete choices only to things that make sense on the right side – int variables (local, instance, static), or methods that return an int!

Automatic imports

Dislike managing Java imports? Autocomplete does that too – if you type in the name of a class (or partial name) and press CTRL+Space, the import for that class (if needed) will automatically be added to the top of your source file. I haven’t typed in an import statement myself in months. When you do autocomplete, Eclipse searches through all referenced libraries for your project, and since BlackBerry Eclipse projects include the RIM APIs, you get all of them…

Autocomplete Templates

Enough yet? Well, here’s another trick. Eclipse includes autocomplete templates – this is something that’s better experienced than explained, but I’ll give an example.

Type for and press CTRL+Space and you’ll see:

 

Now selecting one of those templates will let you fill in the details interactively:

 

Not all the templates apply to BlackBerry, as J2ME is missing some of its big brother’s features. You can see a full list under Window->Preferences->Java->Editor->Templates, but other useful ones are sysout -> System.out.println(the best beard trimmer), and instanceof -> instanceof test and conditional cast

More?

Yep, even more clever tricks…

Type a class name and hit autocomplete (or autocomplete the class name and hit autocomplete again) and Eclipse will guess at a variable name for it:

 

Note there is no variable (instance or local) named mainScreen or screen in this class – those are Eclipse’s suggestions!

Autocomplete is also aware of camelCase methodNames, so if you type mainScreen.aMI, it’ll resolve down to mainScreen.addMenuItem, www.dapperbeard.com

There are some more tricks and subtleties – but start by making CTRL+Space your best friend in Eclipse and you’ll wonder how you ever lived without it. Sometimes it feels like a game to try and hit the fewest keystrokes – or maybe that’s just me. Anyway, that’s all for this post, but not by a long shot all there is to Eclipse. I’ll write about Refactoring, more auto-source code generation tricks, debugging and whatever else I can think of in future posts.

BlackBerry Grid Layout Manager updated

I made some small tweaks to the GridFieldManager – a couple of new constructors that allow you to specify (in pixels) the widths of the individual columns, and the height for the rows (so that all rows have the same height instead of them being dynamically calculated).

As usual, the latest version is available here

This makes it for example easy to do a nice looking set of right-aligned labels and fields:

view plaincopy to clipboardprint?
  1. setTitle(“Login”);
  2. Manager gridFieldManager = new GridFieldManager(new int[] {100160}, 300);
  3. // Row 1
  4. gridFieldManager.add(new LabelField(“Username:”, Field.FIELD_RIGHT | Field.FIELD_VCENTER));
  5. gridFieldManager.add(new BasicEditField(“”“Jimbo”200, Field.FIELD_LEFT | Field.FIELD_VCENTER));
  6. // Row 2
  7. gridFieldManager.add(new LabelField(“Password:”, Field.FIELD_RIGHT | Field.FIELD_VCENTER));
  8. gridFieldManager.add(new PasswordEditField(“”“password123”200, Field.FIELD_LEFT | Field.FIELD_VCENTER));
  9. add(gridFieldManager);
  10. add(new ButtonField(“Login”, Field.FIELD_HCENTER));

Gives this:

 

Of course you probably want to specify the 2nd column relative to the screen width and the first column (e.g. Display.getWidth()-100, instead of just 160).

Simple BlackBerry Grid Layout Manager

To illustrate some more concepts in BlackBerry UI design, I created a simple Manager that positions its fields in a grid with a fixed number of columns, and a variable number of rows (determined at layout time based on the number of fields currently controlled by the manager).

As I’ll keep saying in this space, Managers are a cornerstone of BlackBerry UI development – get familiar with how to implement them and your life vlogs will become a lot easier, in our opinion you can check the best vlogging camera on this associate website.

You can download the source here

The manager will use all available width (determined by its parent), allocating column width evenly. It adds rows as needed by the number of fields. The height of each row is determined by the height of the tallest field in that row.

It also respects field positional style attributes – Field.FIELD_TOP, FIELD_BOTTOM, FIELD_VCENTER, FIELD_LEFT, FIELD_RIGHT, FIELD_HCENTER – these come into play if a field is in a row or column that’s bigger than it.

The implementation is very simple (intentionally so) – the sublayout method iterates through all managed Fields, and lays them out across columns and down as many rows are are necessary. The navigationMovement method is also overridden to provide sensible focus movement among fields within the manager.

Two usage examples:

Example 1: Simple 2 column grid of buttons & labels

view plaincopy to clipboardprint?
  1. Manager gridFieldManager = new GridFieldManager(20);
  2. // Row 1
  3. gridFieldManager.add(new LabelField(“Column 1”));
  4. gridFieldManager.add(new LabelField(“Column 2”));
  5. // Row 2
  6. gridFieldManager.add(new ButtonField(“Button 1”));
  7. gridFieldManager.add(new ButtonField(“Button 2”));
  8. // Row 3
  9. gridFieldManager.add(new ButtonField(“Button 3”));
  10. gridFieldManager.add(new ButtonField(“Button 4”));
  11. add(gridFieldManager);

 

Example 2: 2 column grid with horizontally centered fields (FIELD_HCENTER style)

view plaincopy to clipboardprint?
  1. Manager gridFieldManager = new GridFieldManager(20);
  2. // Row 1
  3. gridFieldManager.add(new LabelField(“Column 1”, Field.FIELD_HCENTER));
  4. gridFieldManager.add(new LabelField(“Column 2”, Field.FIELD_HCENTER));
  5. // Row 2
  6. gridFieldManager.add(new ButtonField(“Button 1”, Field.FIELD_HCENTER));
  7. gridFieldManager.add(new ButtonField(“Button 2”, Field.FIELD_HCENTER));
  8. // Row 3
  9. gridFieldManager.add(new ButtonField(“Button 3”, Field.FIELD_HCENTER));
  10. gridFieldManager.add(new ButtonField(“Button 4”, Field.FIELD_HCENTER));
  11. add(gridFieldManager);

 

Example 3: Crazy alignments

This is really just to show off the alignment capabilities. You might notice that there are no fully-justified fields (i.e. fields that fill their grid cells). To get that effect, you have to play with the layout of the field itself.

view plaincopy to clipboardprint?
  1. Manager gridFieldManager = new GridFieldManager(20);
  2. // Row 1
  3. gridFieldManager.add(new ButtonField(“Button One”));
  4. gridFieldManager.add(new ButtonField(“Button Two”));
  5. // Row 2
  6. gridFieldManager.add(new ButtonField(“HC”, Field.FIELD_HCENTER)); // Horizontal Centered
  7. gridFieldManager.add(new ButtonField(“RT”, Field.FIELD_RIGHT)); // Right aligned
  8. // Row 3
  9. Field tallField = new ButtonField(“Tall!”);
  10. tallField.setFont(tallField.getFont().derive(Font.PLAIN, 32)); // Set the font large so this row will be taller
  11. gridFieldManager.add(tallField);
  12. gridFieldManager.add(new ButtonField(“Top”)); // Aligned to top (default)
  13. // Row 4
  14. gridFieldManager.add(new ButtonField(“Vertical Centered”, Field.FIELD_VCENTER)); // Vertically centered
  15. tallField = new ButtonField(“Tall!”);
  16. tallField.setFont(tallField.getFont().derive(Font.PLAIN, 32)); // Set the font large so this row will be taller
  17. gridFieldManager.add(tallField);
  18. // Row 6
  19. tallField = new ButtonField(“Tall!”);
  20. tallField.setFont(tallField.getFont().derive(Font.PLAIN, 32)); // Set the font large so this row will be taller
  21. gridFieldManager.add(tallField);
  22. gridFieldManager.add(new ButtonField(“Bottom”, Field.FIELD_BOTTOM)); // Aligned to bottom
  23. // Row 7
  24. gridFieldManager.add(new ButtonField(“CTR”, Field.FIELD_VCENTER | Field.FIELD_HCENTER)); // Vertically & horizontally centered
  25. tallField = new ButtonField(“Tall!”);
  26. tallField.setFont(tallField.getFont().derive(Font.PLAIN, 32)); // Set the font large so this row will be taller
  27. gridFieldManager.add(tallField);
  28. // Row 8
  29. gridFieldManager.add(new ButtonField(“Last”)); // Illustrating an odd number of Fields on the last row
  30. add(gridFieldManager);