How to make a SWT window/shell and all the components on it adjustable? - user-interface

So I have created windows/shells with buttons in an application but I want everything to resize when expanded and not to stay in one corner. I have used SWT and window builder to achieve this I used Absolute layout and now when I press full screen it is all in one corner how could I make this aesthetically pleasing so all the buttons and labels expand as well?

Please take a look at Standard layouts in SWT. Refer How to position your widgets and Understanding Layouts.
For Example below is a sample code where I have created 2 labels and 2 text in a Grid Layout which will FILL horizontally when you resize. You can change it according to your needs.
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class SampleApplication
{
protected Shell shell;
private Text text;
private Text text_1;
/**
* Launch the application.
* #param args
*/
public static void main(final String[] args)
{
try
{
SampleApplication window = new SampleApplication();
window.open();
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open()
{
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
}
/**
* Create contents of the window.
*/
protected void createContents()
{
shell = new Shell();
shell.setSize(450, 224);
shell.setText("SWT Application");
shell.setLayout(new GridLayout(2, false));
Label lblNewLabel = new Label(shell, SWT.NONE);
lblNewLabel.setText("Name");
lblNewLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
text = new Text(shell, SWT.BORDER);
text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
Label lblNewLabel_1 = new Label(shell, SWT.NONE);
lblNewLabel_1.setText("ID");
lblNewLabel_1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
text_1 = new Text(shell, SWT.BORDER);
text_1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
}
}

Related

Is it possible to consume the event from a JavaFX FileChooser window?

I have a JavaFX Button that triggers when the user presses enter. This causes a FileChooser to open up. Some people (like myself) may hit enter inside the FileChooser to save the file. However, this causes the save button to trigger itself again and open the FileChooser again to save a new file. Clicking the button (in the FileChooser) with the mouse does not have this issue.
I thought consuming the event from the button would do something about this issue, but it only consumes the button on the GUI's event, rather than the FileChooser button. I've tried looking for ways to modify the FileChooser's EventHandler to consume an enter keypress, but with no success.
I've also tried taking the focus off the button and moving it to the parent (a Pane) so it can't be clicked again. However, there are buttons that benefit being clicked multiple times without having to regain focus on them again.
A example of my code looks like this (obviously this would be part of a bigger class that extends Application):
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
Button b1 = new Button("Save");
b1.setOnKeyReleased(enter);
/* Called by .fire method */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/*
* ... do stuff with file ...
*/
});
Note: This example isn't my exact code. Instead the key released event is a variable used for multiple buttons, rather than just the save button (i.e. b2.setOnKeyReleased(enter);
b2.setOnAction(event -> {/* Do something */});).
How could I go about preventing the button from triggering when the user presses enter in the FileChooser? I don't want the user to be stuck in a loop if they don't have a mouse. I'm aware that pressing Alt+S also saves it, but I can't expect all users to be aware of that.
EDIT: As requested in a comment which appears to be deleted now, here's a runnable version of the code:
import java.io.File;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class ButtonTest extends Application {
#Override
public void start(Stage stage) throws Exception {
/* EventHandler to be used with multiple buttons */
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
/* Create a new button */
Button b1 = new Button("Save");
Button b2 = new Button("Print");
/* Add event handlers */
b1.setOnKeyReleased(enter);
b2.setOnKeyReleased(enter);
/* Called by .fire method of save button */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/* ... do stuff with file ... */
});
/* Called by .fire method of print button */
b2.setOnAction(event -> System.out.println("Pressed"));
Scene scene = new Scene(new HBox(b1, b2));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
The problem is firing the Button from the onKeyReleased handler. By the time you release the ENTER key the FileChooser has been hidden and the Stage has regained focus, meaning the key-release event is given to your Stage/Button. Obviously this will cause a cycle.
One possible solution is to fire the Button from inside a onKeyPressed handler. This will give slightly different behavior relative to other applications, however, which your users might not expect/appreciate.
Another possible solution is to track if the FileChooser had been open before firing the Button, like what Matt does in his answer.
What you seem to be trying to do is allow users to use the ENTER key to fire the Button; this should be default behavior on platforms like Windows.
Not for me. Space is the only key that triggers a button. I think the reason for that is because enter is used to trigger the default button which is set using btn.setDefaultButton(true);
For me, pressing ENTER while the Button has focus fires the action event when using JavaFX 11.0.2 but not JavaFX 8u202, both on Windows 10. It appears the behavior of Button changed since JavaFX 8. Below is the different implementations of com.sun.javafx.scene.control.behavior.ButtonBehavior showing the registered key bindings.
JavaFX 8u202
protected static final List<KeyBinding> BUTTON_BINDINGS = new ArrayList<KeyBinding>();
static {
BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_PRESSED, PRESS_ACTION));
BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_RELEASED, RELEASE_ACTION));
}
JavaFX 11.0.2
public ButtonBehavior(C control) {
super(control);
/* SOME CODE OMITTED FOR BREVITY */
// then button-specific mappings for key and mouse input
addDefaultMapping(buttonInputMap,
new KeyMapping(SPACE, KeyEvent.KEY_PRESSED, this::keyPressed),
new KeyMapping(SPACE, KeyEvent.KEY_RELEASED, this::keyReleased),
new MouseMapping(MouseEvent.MOUSE_PRESSED, this::mousePressed),
new MouseMapping(MouseEvent.MOUSE_RELEASED, this::mouseReleased),
new MouseMapping(MouseEvent.MOUSE_ENTERED, this::mouseEntered),
new MouseMapping(MouseEvent.MOUSE_EXITED, this::mouseExited),
// on non-Mac OS platforms, we support pressing the ENTER key to activate the button
new KeyMapping(new KeyBinding(ENTER, KeyEvent.KEY_PRESSED), this::keyPressed, event -> PlatformUtil.isMac()),
new KeyMapping(new KeyBinding(ENTER, KeyEvent.KEY_RELEASED), this::keyReleased, event -> PlatformUtil.isMac())
);
/* SOME CODE OMITTED FOR BREVITY */
}
As you can see, both register SPACE to fire the Button when it has focus. However, the JavaFX 11.0.2 implementation also registers ENTER for the same—but only for non-Mac OS platforms. I couldn't find any documentation about this change in behavior.
If you want the same behavior in JavaFX 8, and you don't mind hacking into the internals of JavaFX, then you can use reflection to alter the behavior of all button-like controls in your application. Here's a utility method example:
import com.sun.javafx.PlatformUtil;
import com.sun.javafx.scene.control.behavior.ButtonBehavior;
import com.sun.javafx.scene.control.behavior.KeyBinding;
import java.lang.reflect.Field;
import java.util.List;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
public final class ButtonUtils {
public static void installEnterFiresButtonFix() throws ReflectiveOperationException {
if (PlatformUtil.isMac()) {
return;
}
Field bindingsField = ButtonBehavior.class.getDeclaredField("BUTTON_BINDINGS");
Field pressedActionField = ButtonBehavior.class.getDeclaredField("PRESS_ACTION");
Field releasedActionField = ButtonBehavior.class.getDeclaredField("RELEASE_ACTION");
bindingsField.setAccessible(true);
pressedActionField.setAccessible(true);
releasedActionField.setAccessible(true);
#SuppressWarnings("unchecked")
List<KeyBinding> bindings = (List<KeyBinding>) bindingsField.get(null);
String pressedAction = (String) pressedActionField.get(null);
String releasedAction = (String) releasedActionField.get(null);
bindings.add(new KeyBinding(KeyCode.ENTER, KeyEvent.KEY_PRESSED, pressedAction));
bindings.add(new KeyBinding(KeyCode.ENTER, KeyEvent.KEY_RELEASED, releasedAction));
}
private ButtonUtils() {}
}
You would call this utility method early in the startup of your application, before any Buttons are created. Here's an example using it:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
ButtonUtils.installEnterFiresButtonFix();
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
Button button = new Button("Save");
button.setOnAction(event -> {
event.consume();
System.out.println(new FileChooser().showSaveDialog(primaryStage));
});
Scene scene = new Scene(new StackPane(button), 300, 150);
primaryStage.setScene(scene);
primaryStage.setTitle("Workshop");
primaryStage.show();
}
}
Reminder: This fix is implementation dependent.
I added a boolean for the fileChooser being open and it seems to be working for me but I had to split the events up otherwise it will only fire the print button every other
public class Main extends Application {
private boolean fileChooserOpen = false;
#Override
public void start(Stage stage) throws Exception{
/* EventHandler to be used with multiple buttons */
EventHandler<KeyEvent> enterWithFileChooser = event -> {
if (!fileChooserOpen && event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
fileChooserOpen = true;
}else {
fileChooserOpen = false;
}
event.consume();
};
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
/* Create a new button */
Button b1 = new Button("Save");
Button b2 = new Button("Print");
/* Add event handlers */
b1.setOnKeyReleased(enterWithFileChooser);
b2.setOnKeyReleased(enter);
/* Called by .fire method of save button */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/* ... do stuff with file ... */
});
/* Called by .fire method of print button */
b2.setOnAction(event -> System.out.println("Pressed"));
Scene scene = new Scene(new HBox(b1, b2));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}

JavaFX button background image

I have problem with setting backgroundImage on button in JavaFX.
Image newGame = new Image("File:/CSS/nova_hra.png");
BackgroundImage newGameBgr = new BackgroundImage(newGame, null, null, null, null);
Button buttonNewGame = new Button("Nová Hra");
Button buttonLoadGame = new Button("Načíst Hru");
Button buttonStatistics = new Button("Statistiky");
Button buttonExit = new Button("Konec");
buttonNewGame.setGraphic(new ImageView(newGame));
//buttonNewGame.setBackground(new Background(newGameBgr));
buttonExit.setMinHeight(40);
buttonLoadGame.setMinHeight(40);
buttonNewGame.setMinHeight(40);
buttonStatistics.setMinHeight(40);
buttonExit.setMinWidth(120);
buttonLoadGame.setMinWidth(120);
buttonNewGame.setMinWidth(120);
buttonStatistics.setMinWidth(120);
This does nothing with the buttonNewGame. Every time I tryed to load image with this
Image image = new Image(getClass().getResourceAsStream("a.png"));
I got runTime exception. When I used
Image image = new Image(getClass().getResourceAsStream("a.png"));
the whole image disapeard.
You can do it via css. If your background.jpg is in a package testing, simply do this:
package testing;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Button button = new Button( "Click me!");
button.setStyle("-fx-background-image: url('/testing/background.jpg')");
root.getChildren().add(button);
Scene scene = new Scene(root, 800, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
If you don't want to use css, you could do it like this:
BackgroundImage backgroundImage = new BackgroundImage( new Image( getClass().getResource("/testing/background.jpg").toExternalForm()), BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT, BackgroundSize.DEFAULT);
Background background = new Background(backgroundImage);
Button button = new Button( "Click me!");
button.setBackground(background);

Can't paint an image after choosing it from JFileChooser

Good evening. I have read a lot of topics here on stackoverflow or even internet but I can't find the solution to my problem.
I have an interface like this:
When I click on "Load Image A", I can choose the image that I want. Next I want to paint this image under the JLabel "Image A". But it doesn't want to show up.
Here is the code I wrote:
package projet;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class MonPanelImage extends JPanel{
private static final long serialVersionUID = -8267224342030244581L;
private BufferedImage image;
public MonPanelImage(File adresse)
{
try{
image = ImageIO.read(adresse);
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
System.out.println("paint");
if(image != null){
g.drawImage(image, 20, 20, this);
}
}
}
and here is where I call it:
//panel image. This is my second panel which will be for the images
final JPanel second = new JPanel(new BorderLayout());
//panel button. This is the third panel for the buttons
rows = 0;
cols = 3;
hgap = 5;
vgap = 0;
JPanel third = new JPanel(new GridLayout(rows,cols,hgap,vgap));
//buttons
JButton boutonLoad1 = new JButton("Load image A");
boutonLoad1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int retour = fc.showDialog(frame, "Charger l'image");
if(retour == JFileChooser.APPROVE_OPTION){
String pathImage1 = fc.getSelectedFile().getAbsolutePath();
path1 = pathImage1;
File file = fc.getSelectedFile();
MonPanelImage panelImage1 = new MonPanelImage(file);
second.add(panelImage1, BorderLayout.WEST);
second.revalidate();
second.repaint();
}
}
});
At the very end, i add the 3 panels to my frame and set the frame to visible.
But I can't paint an image. Maybe I'm not doing it properly. Can someone help me please?
Thanks
super.paintComponents(g);
First of all it should be super.paintComponent(g), without the "s".
second.add(panelImage1, BorderLayout.WEST);
You are adding your image to a component using a BorderLayout. The BorderLayout will respect the width of your component, which is 0, so there is nothing to paint.
Whenever, you do custom painting you need to override the getPreferredSize() method to return the size of your component so the layout manager can do its job.
However, an easier solution is to just use a JLabel with an Icon. There is no need to do custom painting when you are painting the image at its real size.

How to get position of an item in ListView in JavaFX?

If I create a ListView in JavaFX like this:
ObservableList<String> elements = FXCollections.observableArrayList("John", "Doe");
ListView<String> lView = new ListView<String>(elements);
What I want to do is draw a line starting from the end of a row in the ListView, say from "John"
To do this, I need the location(x,y) of the row "John". Is it possible to get the location?
Update
This is a sample interface that I got using Swing and Piccolo2D. However, using that library is painful. I am wondering if I can do the same in JavaFX
It is possible, but it may not be as straight forward as you hoped. In order to determine the layout coordinates for a particular Cell within a ListView (or TableView/TreeView) you need to have access to that particular Cell object. The best way (and maybe only way in JavaFX 2.2) is to provide the container with a custom Cell and CellFactory that exposes each Cell. How you expose the Cell depends on what your triggers are for drawing the line.
Bases on your illustration, you'll need access to each cell once the ListViews are populated. You can do this with a List<ListCell<String>> field in the CellFactory. I'll mention one caveat here about ListCells. The ListViewSkin will reuse Cells whenever possible. That means that if you are going to try to populate and connect a list that ends up scrolling, then keeping your lines in the right place will be much more difficult. I'd recommend trying to ensure that all your list items fit on screen.
Below is an example with some notes in the comments. Take note that getting the correct coordinates for drawing your Line will probably require calculating the offset of your SceneGraph which I didn't do in this example.
package listviewcellposition;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Callback;
public class ListViewCellPosition extends Application {
// CustomCellFactory for creating CustomCells
public class CustomCellFactory implements
Callback<ListView<String>, ListCell<String>> {
List<ListCell<String>> allCells = new ArrayList<>();
#Override
public ListCell<String> call(final ListView<String> p) {
final CustomCell cell = new CustomCell();
allCells.add(cell);
return cell;
}
public List<ListCell<String>> getAllCells() {
return allCells;
}
}
// CustomCell is where the exposure occurs. Here, it's based on the
// Cell being selected in the ListView. You could choose a different
// trigger here but you'll need to explore.
public class CustomCell extends ListCell<String> {
// General display stuff
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
setText(item == null ? "" : item);
setGraphic(null);
}
}
}
#Override
public void start(Stage primaryStage) {
// This pane will contain the lines after they are created.
// I set it into an AnchorPane to avoid having to deal with
// resizing.
Pane linePane = new Pane();
AnchorPane pane = new AnchorPane();
pane.setPrefSize(100, 250);
AnchorPane.setBottomAnchor(linePane, 0.0);
AnchorPane.setLeftAnchor(linePane, 0.0);
AnchorPane.setRightAnchor(linePane, 0.0);
AnchorPane.setTopAnchor(linePane, 0.0);
pane.getChildren().add(linePane);
ListView<String> lView = new ListView<>();
lView.setPrefSize(100, 250);
CustomCellFactory lCellFactory = new CustomCellFactory();
lView.setCellFactory(lCellFactory);
ListView<String> rView = new ListView<>();
rView.setPrefSize(100, 250);
CustomCellFactory rCellFactory = new CustomCellFactory();
rView.setCellFactory(rCellFactory);
lView.getItems().addAll("Bill", "Doctor", "Steve", "Joanne");
rView.getItems().addAll("Seuss", "Rowling", "King", "Shakespeare");
HBox root = new HBox();
root.getChildren().addAll(lView, pane, rView);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
connectCells(lCellFactory, "Bill", rCellFactory, "Shakespeare", linePane);
connectCells(lCellFactory, "Doctor", rCellFactory, "Seuss", linePane);
connectCells(lCellFactory, "Steve", rCellFactory, "King", linePane);
connectCells(lCellFactory, "Joanne", rCellFactory, "Rowling", linePane);
}
// Looks up the ListCell<> for each String and creates a Line
// with the coordinates from each Cell. The calculation is very
// contrived because I know that all the components have the same
// x-coordinate. You'll need more complicated calculations if your
// containers are not aligned this way.
private void connectCells(CustomCellFactory lCellFactory, String lVal,
CustomCellFactory rCellFactory, String rVal, Pane linePane) {
List<ListCell<String>> lList = lCellFactory.getAllCells();
ListCell<String> lCell = null;
for (ListCell<String> lc : lList) {
if (lc.getItem() != null && lc.getItem().equals(lVal)) {
lCell = lc;
break;
}
}
List<ListCell<String>> rList = rCellFactory.getAllCells();
ListCell<String> rCell = null;
for (ListCell<String> rc : rList) {
if (rc.getItem() != null && rc.getItem().equals(rVal)) {
rCell = rc;
break;
}
}
if (lCell != null && rCell != null) {
double startY = lCell.getLayoutY() +
(lCell.getBoundsInLocal().getHeight() / 2);
double endY = rCell.getLayoutY() +
(rCell.getBoundsInLocal().getHeight() / 2);
Line line = new Line(0, startY,
linePane.getBoundsInParent().getWidth(), endY);
line.setStrokeWidth(2);
line.setStroke(Color.BLACK);
linePane.getChildren().add(line);
}
}
public static void main(String[] args) {
launch(args);
}
}

Blackberry - How to use notification icon in statusbar

In RIM Blackberry OS 4.6+ there is a new feature - ability to show notification icon in statusbar. Integrated application use it to give quick and informative information for user: Dealler - missed calls, Messages - unread messages etc.
removed dead ImageShack link
Possible use of notification icon:
missed events
RSS updates
object status (ex. weather/app activity/gps signal strength)
other
I would like to post a howto guide for this feature.
ApplicationIndicator class
To add/modify/remove notification icon we can use ApplicationIndicator class:
Represents an application indicator that consists of an icon and optional numeric value.
The icon is placed in indicators area along with others such as new mail counter, calendar reminders, missed calls counter, security status and others.
Application can register only one indicator and has to register it every time the phone starts.
All indicators are cleared upon phone restart.
Indicators may be not visible if there will be no space on statusbar
Indicator dimensions depend on current theme and phone screen size.
The icon size varies from 10x10 up to 24x24.
If indicator is initialized with a big icon then an exception is thrown.
Indicator can have optional numeric value that usually serves as a counter.
The value can be negative, 0 or positive.
If indicator is used as a counter it's better to hide it when its value is equal to 0.
If indicator value is too big, it will display '99+' or '999+'
Add notification icon
For this we should create instance of ApplicationIcon:
Application icon class is used in conjunction with application indicator and application messages.
It incapsulates image and its painting properties.
EncodedImage mImage = EncodedImage.getEncodedImageResource("indicator_icon.png");
ApplicationIcon mIcon = new ApplicationIcon(mImage);
Then we should register ApplicationIndicator with ApplicationIndicatorRegistry:
ApplicationIndicatorRegistry.register(icon, iconOnly, visible)
icon - an icon to be displayed in the indicators area
iconOnly - specifies if indicator should have icon representation only and no value
visible - specifies whether indicator has to be visible initially
ApplicationIndicatorRegistry reg = ApplicationIndicatorRegistry.getInstance();
ApplicationIndicator indicator = reg.register(mIcon, false, true);
Modify indicator icon and value
To modify icon, use ApplicationIndicator.setIcon method:
ApplicationIndicatorRegistry reg = ApplicationIndicatorRegistry.getInstance();
ApplicationIndicator appIndicator = reg.getApplicationIndicator();
appIndicator.setIcon(icon);
To modify number value, use ApplicationIndicator.setValue method:
ApplicationIndicatorRegistry reg = ApplicationIndicatorRegistry.getInstance();
ApplicationIndicator appIndicator = reg.getApplicationIndicator();
appIndicator.setValue(value);
If very big value is provided then indicator will display '99+' or '999+'.
To hide or show indicator, use ApplicationIndicator.setVisible
Unregister ApplicationIndicator
Most likely you don't want your app indicator to stay in statusbar, it's better to ApplicationIndicatorRegistry.unregister() it on app close.
Sample application
Icons:
removed dead ImageShack links
Screenshots:
removed dead ImageShack links
Code:
import net.rim.blackberry.api.messagelist.ApplicationIcon;
import net.rim.blackberry.api.messagelist.ApplicationIndicator;
import net.rim.blackberry.api.messagelist.ApplicationIndicatorRegistry;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.container.MainScreen;
class Scr extends MainScreen {
EncodedImage mImageGreen = EncodedImage
.getEncodedImageResource("bb_icon_green.png");
ApplicationIcon mIconGreen = new ApplicationIcon(mImageGreen);
EncodedImage mImageRed = EncodedImage
.getEncodedImageResource("bb_icon_red.png");
ApplicationIcon mIconRed = new ApplicationIcon(mImageRed);
ApplicationIcon mIcon = mIconGreen;
public Scr() {
add(new LabelField("Use menu to:"));
add(new LabelField("Register indicator"));
add(new LabelField("Increment value"));
add(new LabelField("Decrement value"));
add(new LabelField("Switch icon"));
add(new LabelField("Unregister indicator"));
}
MenuItem menuRegister = new MenuItem("register", 0, 0) {
public void run() {
registerIndicator();
};
};
protected int mValue = 0;
MenuItem menuIncrement = new MenuItem("increment", 0, 0) {
public void run() {
mValue++;
updateValue(mValue);
};
};
MenuItem menuDecrement = new MenuItem("decrement", 0, 0) {
public void run() {
mValue--;
updateValue(mValue);
};
};
MenuItem menuSwitchIcon = new MenuItem("icon", 0, 0) {
public void run() {
mIcon = (mIcon == mIconGreen) ? mIconRed : mIconGreen;
updateIcon(mIcon);
};
};
MenuItem menuUnregister = new MenuItem("unregister", 0, 0) {
public void run() {
unregisterIndicator();
};
};
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
menu.add(menuRegister);
menu.add(menuIncrement);
menu.add(menuDecrement);
menu.add(menuSwitchIcon);
menu.add(menuUnregister);
}
private void registerIndicator() {
try {
ApplicationIndicatorRegistry reg = ApplicationIndicatorRegistry
.getInstance();
ApplicationIndicator indicator =
reg.register(mIcon, false, true);
} catch (Exception e) {
}
}
private void unregisterIndicator() {
try {
ApplicationIndicatorRegistry reg = ApplicationIndicatorRegistry
.getInstance();
reg.unregister();
} catch (Exception e) {
}
}
void updateValue(int value) {
try {
ApplicationIndicatorRegistry reg = ApplicationIndicatorRegistry
.getInstance();
ApplicationIndicator appIndicator =
reg.getApplicationIndicator();
appIndicator.setValue(value);
} catch (Exception e) {
}
}
void updateIcon(ApplicationIcon icon) {
try {
ApplicationIndicatorRegistry reg = ApplicationIndicatorRegistry
.getInstance();
ApplicationIndicator appIndicator =
reg.getApplicationIndicator();
appIndicator.setIcon(icon);
} catch (Exception e) {
}
}
}

Resources