How to handle ButtonField & BitmapField Click (Touch) events in Blackberry Storm? - user-interface

I have created a ButtonField & a BitmapField like..
public class MyCanvas extends MainScreen implements FieldChangeListener
{
HorizontalFieldManager hfm;
private Bitmap startBitmap;
private BitmapField startBitmapField;
private ButtonField okButton;
MyCanvas()
{
hfm = new HorizontalFIeldManager();
startBitmap = Bitmap.getBitmapResource("start.png");
startBitmapField = new BitmapField(startBitmap);
startBitmapField.setChangeListener(this);
hfm.add(startBitmapField);
okButton = new ButtonField("Ok", ButtonField.CONSUME_CLICK | ButtonField.NEVER_DIRTY);
okButton.setChangeListener(this);
hfm.add(okButton);
}
public void fieldChanged(Field field, int context)
{
if(field == startBitmapField)
{
System.out.println("Touched START...");
}
else if(field == okButton)
{
System.out.println("Touched Ok...");
}
}
}
But the ButtonField or BitmapField click is not happening in Blackberry 4.7 simulator.
I want to build it for Blackberry Storm so I m using Blackberry 4.7
How to handle click/touch events for ButtonField & BitmapField for Blackberry Storm?
I m creating the ButtonField & BitmapFields as
okButtonField = new ButtonField("Ok", BitmapField.HIGHLIGHT_SELECT | BitmapField.FOCUSABLE);
startBitmapField = new BitmapField(startBitmap, BitmapField.HIGHLIGHT_SELECT | BitmapField.FOCUSABLE);
Its working with..
protected boolean touchEvent(TouchEvent event)
{
switch( event.getEvent() )
{
case TouchEvent.DOWN: ........
return true;
case TouchEvent.MOVE: .......
return true;
case TouchEvent.UP: ........
return true;
case TouchEvent.CLICK:
if(deleteButton.isFocus())
{
System.out.println("Touched DEL ..........");
}
else if(okButton.isFocus())
{
System.out.println("Touched OK ..........");
}
else if(startBitmapField.isFocus())
{
System.out.println("Touched START ..........");
}
return true;
}
return false;
}
but everytime the same button is invoked which is having focus.
Means if "Ok" button is having focus then even though u clicked on "Delete" button "Ok" button is called.
So how to change the focus on Button Click? means whichever ButtonField or BitmapField is clicked, should get the focus?
is there any method to check "button.isClicked() like button.isFocus() " ?

First of all, don't forget to add hfm to screen ;)
Actually button click works fine.
Now, to make bitmap click works as well, implement protected boolean touchEvent(TouchEvent message) for your BitmapField. It will be better to create extended class:
class MyCanvas extends MainScreen implements FieldChangeListener {
HorizontalFieldManager hfm;
private Bitmap startBitmap;
private BitmapField startBitmapField;
private ButtonField okButton;
private ButtonField cancelButton;
MyCanvas() {
hfm = new HorizontalFieldManager();
add(hfm);
startBitmap = Bitmap.getBitmapResource("start.png");
startBitmapField = new TouchBitmapField(startBitmap);
startBitmapField.setChangeListener(this);
hfm.add(startBitmapField);
okButton = new ButtonField("Ok", ButtonField.CONSUME_CLICK
| ButtonField.NEVER_DIRTY);
okButton.setChangeListener(this);
hfm.add(okButton);
cancelButton = new ButtonField("Cancel", ButtonField.CONSUME_CLICK
| ButtonField.NEVER_DIRTY);
cancelButton.setChangeListener(this);
hfm.add(cancelButton);
}
public void fieldChanged(Field field, int context) {
if (field == startBitmapField) {
System.out.println("Touched START...");
} else if (field == okButton) {
System.out.println("Touched Ok...");
} else if (field == cancelButton) {
System.out.println("Touched Cancel...");
}
}
}
class TouchBitmapField extends BitmapField {
public TouchBitmapField(Bitmap startBitmap) {
super(startBitmap);
}
protected boolean touchEvent(TouchEvent message) {
if (TouchEvent.CLICK == message.getEvent()) {
FieldChangeListener listener = getChangeListener();
if (null != listener)
listener.fieldChanged(this, 1);
}
return super.touchEvent(message);
}
}

Related

How to use a modal pop up to update data in a grid with a custom cell

I would like to be able to use a modal window to present the contents of a column to the user for editing. I am not able to make this work, and I am not sure where I am going wrong.
I have provided a button in the table which will indicate if there are additional details (in this case comments). When the user selects the button, I want to open a modal dialog to enter the data and when it closes, update the field.
I have gotten the majority of this wired up, but the data is not making it back to my model. I have tried several things, and all without results. It appears that the commit edit call I am making is not seeing the field as in "edit mode" and just skips.
This is my code for my custom table cell:
public class CommentTableCell<T> extends TableCell<T, String> {
private Button actionBtn;
private TextArea textArea;
public CommentTableCell(TableColumn<T, String> column) {
super();
actionBtn = new Button("my action");
actionBtn.setTooltip(new Tooltip("Select to add/edit comments..."));
actionBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
startEdit();
System.out.println("Action: "+getItem());
Stage commentStage = new Stage();
AnchorPane ap = new AnchorPane();
textArea = new TextArea();
AnchorPane.setTopAnchor(textArea, 5.0);
AnchorPane.setBottomAnchor(textArea, 5.0);
AnchorPane.setLeftAnchor(textArea, 5.0);
AnchorPane.setRightAnchor(textArea, 5.0);
ap.getChildren().add(textArea);
Scene commentScene = new Scene (ap, 200, 200);
commentStage.setScene(commentScene);
commentStage.show();
commentStage.setOnCloseRequest(a -> {
commitEdit(textArea.getText());
});
// I have tried with an column.setOnEditCommit() as well as what is noted below which I found here, passing in the column.
final TableView<T> tableView = getTableView();
tableView.getSelectionModel().select(getTableRow().getIndex());
tableView.edit(tableView.getSelectionModel().getSelectedIndex(), column);
}
});
setText(null);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
actionBtn.getStyleClass().clear();
setEditable(false);
if (item != null && item.length() > 0) {
actionBtn.getStyleClass().add(CSSConstants.GRID_BUTTON_EDIT_COMMNET);
setGraphic(actionBtn);
} else if (!empty) {
actionBtn.getStyleClass().add(CSSConstants.GRID_BUTTON_ADD_COMMNET);
setGraphic(actionBtn);
} else {
setGraphic(null);
}
}
}
During the execution it hits the commitEdit() call and the following has isEditing in the TableCell as null:
#Override public void commitEdit(T newValue) {
if (! isEditing()) return;
My table looks basically like this:
TableView<SomeDTO> addressTableView = new TableView()
addressTableView.setItems(sortedItems);
addressTableView.setEditable(true);
commentsColumn.setCellValueFactory(cellValue -> cellValue.getValue().commentsProperty());
commentsColumn.setCellFactory(tc -> new CommentTableCell<SomeDTO>(commentsColumn));
I have found a solution to my issue - though I am not sure it is the best way or not.
I have changed my CommentTableCell as follows and it seems to work like a charm..
public class CommentTableCell<T> extends TableCell<T, String> {
private Button actionBtn;
public CommentTableCell() {
super();
actionBtn = new Button("my action");
actionBtn.setTooltip(new Tooltip("Select to add/edit comments..."));
actionBtn.setOnAction(event ->
{
Stage commentStage = new Stage();
AnchorPane ap = new AnchorPane();
TextArea textArea = new TextArea();
AnchorPane.setTopAnchor(textArea, 5.0);
AnchorPane.setBottomAnchor(textArea, 5.0);
AnchorPane.setLeftAnchor(textArea, 5.0);
AnchorPane.setRightAnchor(textArea, 5.0);
ap.getChildren().add(textArea);
Scene commentScene = new Scene (ap, 200, 200);
commentStage.setScene(commentScene);
if(getItem() != null) {
String myValue = getItem();
textArea.setText(myValue);
textArea.selectAll();
}
commentStage.show();
commentStage.setOnCloseRequest(a -> {
commitEdit(textArea.getText());
});
});
}
#Override
#SuppressWarnings({"unchecked", "rawtypes"})
public void commitEdit(String item) {
if (isEditing()) {
super.commitEdit(item);
} else {
final TableView table = getTableView();
if (table != null) {
TablePosition position = new TablePosition(getTableView(),
getTableRow().getIndex(), getTableColumn());
CellEditEvent editEvent = new CellEditEvent(table, position,
TableColumn.editCommitEvent(), item);
Event.fireEvent(getTableColumn(), editEvent);
}
updateItem(item, false);
if (table != null) {
table.edit(-1, null);
}
}
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
actionBtn.getStyleClass().clear();
setEditable(false);
if (item != null && item.length() > 0) {
actionBtn.getStyleClass().add(CSSConstants.GRID_BUTTON_EDIT_COMMNET);
setGraphic(actionBtn);
} else if (!empty) {
actionBtn.getStyleClass().add(CSSConstants.GRID_BUTTON_ADD_COMMNET);
setGraphic(actionBtn);
} else {
setGraphic(null);
}
}
}

Fragment with update of detail layout

I have programmed an Android App with fragments. A ListView fragment and a detail fragment.
What I wanna do is, if someone clicks inside the detail activity, a layout which is "View.Gone" should be "View.Visible". The code works without errors but nothing changed on the screen.
You can see it in Detail fragment code where a clik event on the ImageButton btn is.
What do i wrong?
What is the best way to update the detail screen? If someone has a small example or could write me where in my code I have to change what, it makes me happy :-)
Thanks a lot
Tom
The FragmentActivity:
public class CacheFragment extends SherlockFragmentActivity {
CacheListFragment f;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_cachelist);
f = new CacheListFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
f.setArguments(args);
}
Here's the Detail Fragment, where you can see whatt should happen if someone clicks on the Imagebutton:
public class CacheDetailsFragment extends SherlockFragment implements OnClickListener {
private CacheDetailsLoading cdLoad= new CacheDetailsLoading();
private static GeocacheDetails _cacheDetails = new GeocacheDetails();
private static GCRatingTyp _cacheVote = new GCRatingTyp();
private CacheDetailsUsing cdUsing = new CacheDetailsUsing();
private Activity _context;
private static CacheDetailsFragment f;
private View view;
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static CacheDetailsFragment newInstance(int index ) {
f = new CacheDetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
public void setCacheDetail(GeocacheDetails cacheDetails)
{
_cacheDetails = cacheDetails;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
return null;
}
Bundle bundle=getArguments();
_cacheVote= bundle.getParcelable("cacheVote");
int index = bundle.getInt("index");
_cacheDetails=StaticCacheListByGroup.getCacheList().get(index);
_context = getActivity();
_context.setTheme(R.style.Theme_Sherlock_Light_DarkActionBar);
view = inflater.inflate(R.layout.list_cachedetails, container,false);
((RelativeLayout) view.findViewById(R.id.relativeLoggingInfo)).setVisibility(View.GONE);
((RelativeLayout) view.findViewById(R.id.relativeKategorienInfo)).setVisibility(View.GONE);
ImageButton btn = (ImageButton) view.findViewById(R.id.description_expand);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
if(((RelativeLayout) getActivity().findViewById(R.id.relativeDescriptionInfo)).getVisibility() == View.GONE)
{
((ImageButton) getActivity().findViewById(R.id.description_expand)).setBackgroundResource(R.drawable.navigation_collapse_dark);
((RelativeLayout) getActivity().findViewById(R.id.relativeDescriptionInfo)).setVisibility(View.VISIBLE);
}
else
{
((ImageButton) getActivity().findViewById(R.id.description_expand)).setBackgroundResource(R.drawable.navigation_expand_dark);
((RelativeLayout) getActivity().findViewById(R.id.relativeDescriptionInfo)).setVisibility(View.GONE);
}
});
return view;
}
}
Now the Listfragment:
public class CacheListFragment extends SherlockListFragment {
boolean isDualPane;
int mCurCheckPosition = 0;
private CacheListArrayAdapter _adapter;
private SharedPrefs _sp= new SharedPrefs();
private double latitude=0;
private double longitude=0;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
latitude =Double.parseDouble(_sp.getSharedPrefs(getActivity(), LibraryDefaults.PROGRAMMNAME, "Latitude", "0"));
longitude =Double.parseDouble(_sp.getSharedPrefs(getActivity(), LibraryDefaults.PROGRAMMNAME, "Longitude", "0"));
// Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
isDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
if(!isDualPane)
{
Bundle bundle = getActivity().getIntent().getExtras();
if(bundle != null && bundle.containsKey("Titel"))
((TextView) getActivity().findViewById(R.id.listtitle)).setText(bundle.getString("Titel"));
else
((TextView) getActivity().findViewById(R.id.listtitle)).setText(this.getResources().getString(R.string.caches_listtitle));
}
if (StaticCacheListByGroup.getCacheList() != null)
{
GeocachingCompass gc = new GeocachingCompass(getActivity());
_adapter = new CacheListArrayAdapter(getActivity(), StaticCacheListByGroup.getCacheList(), longitude,latitude);
_adapter.setActualCoordinates(new LatLng(latitude,longitude));
_adapter.setActualHeading(gc.getBearing(latitude,longitude));
if (_adapter != null)
setListAdapter(_adapter);
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
getListView().setSoundEffectsEnabled(true);
getListView().setSmoothScrollbarEnabled(true);
getListView().setDrawSelectorOnTop(false);
getListView().setCacheColorHint(R.color.transparentBlack);
getListView().setDivider(getResources().getDrawable( R.color.divider));
getListView().setDividerHeight(5);
if (isDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
showDetails(mCurCheckPosition);
}
}
}
#Override
public void onResume() {
super.onResume();
GeocachingCompass gc = new GeocachingCompass(getActivity());
_adapter = new CacheListArrayAdapter(getActivity(), StaticCacheListByGroup.getCacheList(), longitude,latitude);
_adapter.setActualCoordinates(new LatLng(latitude,longitude));
_adapter.setActualHeading(gc.getBearing(latitude,longitude));
if (_adapter != null)
setListAdapter(_adapter);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
/**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index;
ReadGCVote getVote = new ReadGCVote();
GeocacheDetails cacheDetails = new GeocacheDetails();
cacheDetails=StaticCacheListByGroup.getCacheList().get(index);
if (isDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true);
// Check what fragment is currently shown, replace if needed.
CacheDetailsFragment details = (CacheDetailsFragment)
getActivity().getSupportFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = CacheDetailsFragment.newInstance(index);
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
Intent intent = new Intent();
intent.setClass(getActivity(), CacheDetailsActivity.class);
intent.putExtra("index", index);
intent.putExtra("cacheDetails",cacheDetails);
intent.putExtra("cacheVote",getVote.getGCVoteByCacheGuid( StaticGCVoteList.getCacheList(), cacheDetails.GetGUID()));
startActivity(intent);
}
}
}
I found the bug :-)
In the code snippet of the Detail Fragment ...
public void onClick(View v)
{
if(((RelativeLayout) getActivity().findViewById(R.id.relativeDescriptionInfo)).getVisibility() == View.GONE)
}
...you shouldn't use "getActivity()" use "view" from "view = inflater.inflate(R.layout.list_cachedetails, container,false);"
Then it will work

How do I trap an event when a scroll bar appears?

I have a GWT ScrollPanel whose overflow-y is set to auto. Is there an event that is fired when the panel's scroll bar appears or disappears?
Unfortunately there is no event fired when scroll bars are added to or removed from an element. It's not hard, however, to roll your own:
public class MyScrollPanel extends ScrollPanel {
boolean horizontal = false;
boolean vertical = false;
public native int getScrollHeight() /*-{
return this.#com.mypackage.MyScrollPanel::getElement()().scrollHeight;
}-*/;
public native int getScrollWidth() /*-{
return this.#com.mypackage.MyScrollPanel::getElement()().scrollWidth;
}-*/;
private boolean hasHorizontalScrollbar() {
return getElement().getClientWidth() < getScrollWidth();
}
private boolean hasVerticalScrollbar() {
return getElement().getClientHeight() < getScrollHeight();
}
public void onLoad() {
new Timer() {
#Override
public void run() {
boolean scrollersChanged = false;
if (hasHorizontalScrollbar() != horizontal) {
horizontal = !horizontal;
scrollersChanged = true;
}
if (hasVerticalScrollbar() != vertical) {
vertical = !vertical;
scrollersChanged = true;
}
if (scrollersChanged) {
// Fire event or call onResize()
}
}
}.scheduleRepeating(500);
}
}

BlackBerry - Consuming Click Event from ButtonField

I've developed UI application in blackberry.
On Button Click event I want to display result of adding two number.
How to handle this event in java app of Blackberry?
Best option to consume click event in ButtonField is to use FieldChangeListener. Just implement FieldChangeListener interface and apply ButtonField.setChangeListener():
class MenuScreen extends MainScreen implements FieldChangeListener {
EditField mNumberAEditField;
EditField mNumberBEditField;
ButtonField mAddButtonField;
public MenuScreen() {
super(DEFAULT_CLOSE);
mNumberAEditField = new EditField("A:", "2", 10,
EditField.FILTER_INTEGER);
add(mNumberAEditField);
mNumberBEditField = new EditField("B:", "2", 10,
EditField.FILTER_INTEGER);
add(mNumberBEditField);
mAddButtonField = new ButtonField("A + B",
ButtonField.CONSUME_CLICK);
add(mAddButtonField);
mAddButtonField.setChangeListener(this);
}
public void fieldChanged(Field field, int context) {
if(field == mAddButtonField)
{
showAddResult();
}
}
private void showAddResult() {
String message = "";
String aStr = mNumberAEditField.getText();
String bStr = mNumberBEditField.getText();
if(aStr == "")
message = "Enter A value!";
else if(bStr == "")
message = "Enter B value!";
else
{
int res = Integer.parseInt(aStr)+Integer.parseInt(bStr);
message = aStr+" + "+bStr+" = "+String.valueOf(res);
}
Dialog.inform(message);
}
}
Other option with FieldChangeListener is to declare and implement it inline. than you will not have to check from which field event is coming:
mAddButtonField.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
showAddResult();
}
});
or..
add(new ButtonField("Click Me")) {
protected boolean navigationClick(int status, int time) {
showAddResult();
return true;
}
});

Blackberry - Loading/Wait screen with animation

Is there a way to show "Loading" screen with animation in blackberry?
Options:
PME animation content
multithreading + set of images + timer/counter
standard rim api
some other way
Any of this?
Thanks!
Fermin, Anthony +1. Thanks to all, you gave me the part of answer.
My final solution:
1.Create or generate (free Ajax loading gif generator) animation and add it to project.
2.Create ResponseCallback interface (see Coderholic - Blackberry WebBitmapField) to receive thread execution result:
public interface ResponseCallback {
public void callback(String data);
}
3.Create a class to handle your background thread job. In my case it was http request:
public class HttpConnector
{
static public void HttpGetStream(final String fileToGet,
final ResponseCallback msgs) {
Thread t = new Thread(new Runnable() {
public void run() {
HttpConnection hc = null;
DataInputStream din = null;
try {
hc = (HttpConnection) Connector.open("http://" + fileToGet);
hc.setRequestMethod(HttpsConnection.GET);
din = hc.openDataInputStream();
ByteVector bv = new ByteVector();
int i = din.read();
while (-1 != i) {
bv.addElement((byte) i);
i = din.read();
}
final String response = new String(bv.toArray(), "UTF-8");
UiApplication.getUiApplication().invokeLater(
new Runnable() {
public void run() {
msgs.callback(response);
}
});
}
catch (final Exception e) {
UiApplication.getUiApplication().invokeLater(
new Runnable() {
public void run() {
msgs.callback("Exception (" + e.getClass() + "): "
+ e.getMessage());
}
});
}
finally {
try {
din.close();
din = null;
hc.close();
hc = null;
}
catch (Exception e) {
}
}
}
});
t.start();
}
}
4.Create WaitScreen (a hybrid of FullScreen and AnimatedGIFField with ResponseCallback interface):
public class WaitScreen extends FullScreen implements ResponseCallback
{
StartScreen startScreen;
private GIFEncodedImage _image;
private int _currentFrame;
private int _width, _height, _xPos, _yPos;
private AnimatorThread _animatorThread;
public WaitScreen(StartScreen startScreen) {
super(new VerticalFieldManager(), Field.NON_FOCUSABLE);
setBackground(
BackgroundFactory.createSolidTransparentBackground(
Color.WHITE, 100));
this.startScreen = startScreen;
EncodedImage encImg =
GIFEncodedImage.getEncodedImageResource("ajax-loader.gif");
GIFEncodedImage img = (GIFEncodedImage) encImg;
// Store the image and it's dimensions.
_image = img;
_width = img.getWidth();
_height = img.getHeight();
_xPos = (Display.getWidth() - _width) >> 1;
_yPos = (Display.getHeight() - _height) >> 1;
// Start the animation thread.
_animatorThread = new AnimatorThread(this);
_animatorThread.start();
UiApplication.getUiApplication().pushScreen(this);
}
protected void paint(Graphics graphics) {
super.paint(graphics);
// Draw the animation frame.
graphics
.drawImage(_xPos, _yPos, _image
.getFrameWidth(_currentFrame), _image
.getFrameHeight(_currentFrame), _image,
_currentFrame, 0, 0);
}
protected void onUndisplay() {
_animatorThread.stop();
}
private class AnimatorThread extends Thread {
private WaitScreen _theField;
private boolean _keepGoing = true;
private int _totalFrames, _loopCount, _totalLoops;
public AnimatorThread(WaitScreen _theScreen) {
_theField = _theScreen;
_totalFrames = _image.getFrameCount();
_totalLoops = _image.getIterations();
}
public synchronized void stop() {
_keepGoing = false;
}
public void run() {
while (_keepGoing) {
// Invalidate the field so that it is redrawn.
UiApplication.getUiApplication().invokeAndWait(
new Runnable() {
public void run() {
_theField.invalidate();
}
});
try {
// Sleep for the current frame delay before
// the next frame is drawn.
sleep(_image.getFrameDelay(_currentFrame) * 10);
} catch (InterruptedException iex) {
} // Couldn't sleep.
// Increment the frame.
++_currentFrame;
if (_currentFrame == _totalFrames) {
// Reset back to frame 0
// if we have reached the end.
_currentFrame = 0;
++_loopCount;
// Check if the animation should continue.
if (_loopCount == _totalLoops) {
_keepGoing = false;
}
}
}
}
}
public void callback(String data) {
startScreen.updateScreen(data);
UiApplication.getUiApplication().popScreen(this);
}
}
5.In the end, create Start screen to call HttpConnector.HttpGetStream and to show WaitScreen:
public class StartScreen extends MainScreen
{
public RichTextField text;
WaitScreen msgs;
public StartScreen() {
text = new RichTextField();
this.add(text);
}
protected void makeMenu(Menu menu, int instance) {
menu.add(runWait);
super.makeMenu(menu, instance);
}
MenuItem runWait = new MenuItem("wait", 1, 1) {
public void run() {
UiApplication.getUiApplication().invokeLater(
new Runnable() {
public void run() {
getFile();
}
});
}
};
public void getFile() {
msgs = new WaitScreen(this);
HttpConnector.HttpGetStream(
"stackoverflow.com/faq", msgs);
}
//you should implement this method to use callback data on the screen.
public void updateScreen(String data)
{
text.setText(data);
}
}
UPDATE: another solution naviina.eu: A Web2.0/Ajax-style loading popup in a native BlackBerry application
The basic pattern for this kind of thing is:
Have a thread running a loop that updates a variable (such as the frame index of the animated image) and then calls invalidate on a Field which draws the image (and then sleeps for a period of time). The invalidate will queue a repaint of the field.
In the field's paint method, read the variable and draw the appropriate frame of the image.
Pseudo code (not totally complete, but to give you the idea):
public class AnimatedImageField extends Field implements Runnable {
private int currentFrame;
private Bitmap[] animationFrames;
public void run() {
while(true) {
currentFrame = (currentFrame + 1) % animationFrames.length;
invalidate();
Thread.sleep(100);
}
}
protected void paint(Graphics g) {
g.drawBitmap(0, 0, imageWidth, imageHeight, animationFrames[currentFrame], 0, 0);
}
}
Note also here I used an array of Bitmaps, but EncodedImage lets you treat an animated gif as one object, and includes methods to get specific frames.
EDIT: For completeness: Add this to a PopupScreen (as in Fermin's answer) or create your own dialog by overriding Screen directly. The separate thread is necessary because the RIM API is not thread-safe: you need to do everything UI related on the event thread (or while holding the event lock, see BlackBerry UI Threading - The Very Basics
This is simple code for loading screen ....
HorizontalFieldManager popHF = new HorizontalFieldManager();
popHF.add(new CustomLabelField("Pls wait..."));
final PopupScreen waitScreen = new PopupScreen(popHF);
new Thread()
{
public void run()
{
synchronized (UiApplication.getEventLock())
{
UiApplication.getUiApplication().pushScreen(waitScreen);
}
//Here Some Network Call
synchronized (UiApplication.getEventLock())
{
UiApplication.getUiApplication().popScreen(waitScreen);
}
}
}.start();
If it's just an animation could you show an animated gif on a popup and close it when loading operation is complete?
Easiest way is probably to use the standard GaugeField, setting style GaugeField.PERCENT. This will give you a progress bar. Add this to a PopupScreen and it will sit on top of your content. Something like..
private GaugeField _gaugeField;
private PopupScreen _popup;
public ProgressBar() {
DialogFieldManager manager = new DialogFieldManager();
_popup = new PopupScreen(manager);
_gaugeField = new GaugeField(null, 0, 100, 0, GaugeField.PERCENT);
manager.addCustomField(_gaugeField);
}
Then have an update method which will use _gaugeField.setValue(newValue); to update the progress bar.
I normally have this called from whichever thread is doing the work (loading in your case, everytime an operation is complete the progress bar is updated.
I would suggest to take a look at this simple implementation. I liked this but never used it. May be helpful to you.
link text
ActivityIndicator is a good option if you are working with at least BB OS 6.0.
http://www.brighthub.com/mobile/blackberry-platform/articles/94258.aspx
http://docs.blackberry.com/en/developers/deliverables/17966/Screen_APIs_1245069_11.jsp

Resources