How can i invoke paint multiple time in my app i tried invalidate but but it is not calling paint i think can anybody provide sample code for invoking paint multiple time.
package mypackage;
import com.rss.logger.Log;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
/**
* A class extending the MainScreen class, which provides default standard
* behavior for BlackBerry GUI applications.
*/
public final class MyScreen extends MainScreen
{
BitmapField objBitmapField;
boolean objBoolean;
int postion=0;
public MyScreen()
{
objBitmapField=new BitmapField(Bitmap.getBitmapResource("bb.png"));
// Set the displayed title of the screen
setTitle("MyTitle");
objBoolean=false;
new AnimationThread().start();
}
private class AnimationThread extends Thread{
public void run() {
super.run();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run()
{
objBoolean=true;
//Add a new LabelField to the screen.
//theScreen.add(new LabelField("Hello there.");
//Call the screen’s invalidate method to
//force the screen to redraw itself.
//Note that invalidate can be called
//at the screen, manager or field level,
//which means you can inform the
//BlackBerry to only redraw the area that
//has changed.
for (int i = 0; i < 20; i++) {
try {
sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.info("in run");
postion=postion+5;
MyScreen.this.invalidate();
}
}
});
}
}
protected void paint(Graphics graphics) {
super.paint(graphics);
Log.info("in paint");
if(objBoolean)
graphics.drawBitmap(20, postion, 50, 50, Bitmap.getBitmapResource("bb.png"), 30, 40);
}
}
Hi piyus find the working code. invalidate() need to call in the paint() method. And one thing is also important that should not create object in paint method.
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.container.MainScreen;
public final class MyScreen extends MainScreen
{
private boolean objBoolean=false;
private int postion=0;
private Bitmap bb=Bitmap.getBitmapResource("bb.png");
public MyScreen()
{
setTitle("MyTitle");
new AnimationThread().start();
}
private class AnimationThread extends Thread
{
public void run()
{
objBoolean=true;
for (int i = 0; i < 20; i++)
{
try
{
sleep(200);
}
catch (InterruptedException e)
{
}
postion=postion+5;
}
}
}
protected void paint(Graphics graphics)
{
super.paint(graphics);
if(objBoolean)
graphics.drawBitmap(20, postion, 50, 50, bb, 30, 40);
invalidate();
}
}
paint() method can be invoked either by using invalidate method or by creating an object of the class that you are using now.
I think there is Typo Error in the sample code you have mentioned here. One cannot have a class inside a class just by defining it. Coming to the issue you are facing
While, calling the invalidate method, as you are using it as MyScreen.this.invalidate which is not the right way to call it, one cannot call the paint method from another class, as in your case it is AnimationThread is not possible. The propreitary feature of Screen class and the paint method is, it gets called once the Object of the screen is created.
And as I understand one can call the invalidate method for a manager or a screen, inside the same class but not by creating an object of the screen in another class and by calling it.
It should be called simply without using any objects simply, invalidate(); , gets the screen repainted or invalidated.
One can also achieve it by creating an object of the same screen, may be if one wanted to display the screen in a different way, they can create an object by using different arguments, and handle it accordingly in the paint method.
Here, whenever the thread is run, you can create an object and handle it according to your choice.
As a sample :
public class theScreen extends MainScreen{
int dummy;
public theScreen(int firstArg){
// Handle the firstArgument here
dummy=0;
}
public theScreen(int secondArg,int dummy){
// Handle the second Argument here
this.dummy = dummy;
}
public void paint(Graphics graphcis)
{
if(dummy == 0)
{
//Handle what you would like to paint here
}
else{
//Handle with a different paint here
}
}}
Hope this resolves your problem
Happy Coding.
Cheers
You may try using Screen.doPaint().
Is your Bitmap big enough to be completely drawn starting from top/left (30, 40)? It may just be that it doesn't look like it's painting because you're outside of the bounds that make sense for it to be drawn.
Related
I have a Vaadin Navigator with multiple View elements. Each view has a different purpose however some also contain common traits that I have put inside custom components.
One of those custom components is the menu - it is positioned at the top and allows navigation between the different views. I create and add this component inside the constructor of each view (if you are interested in the menu's implementation see the end of this post). Here is a skeleton for each custom view:
class MyViewX implements View {
MenuViewComponent mvc;
public MyViewX() {
mvc = new MenuViewComponent();
addComponent(mvc);
}
#Override
public void enter(ViewChangeEvent event) {
}
}
So far, so good. In order to make things simple I will explain my problem using a simple label and not one of my other custom components but the dependency that I will describe here is the same for those components just like with the label.
Let's say I have a label which sole purpose is to display a greeting with the user's username. In order to do that I use VaadinSession where I store the attribute. This is done by my LoginController, which validates the user by looking into a database and if the user is present, the attribute is set and one of the views is opened automatically. The problem is that VaadinSession.getCurrent().getAttribute("username") returns null when called inside the constructor. This of course makes sense omho because a constructor should not be bound by a session-attribute.
So far I have managed to use the enter() method where there is no problem in retrieving session attributes:
class MyViewX implements View {
MenuViewComponent mvc;
public MyViewX() {
mvc = new MenuViewComponent();
addComponent(mvc);
}
#Override
public void enter(ViewChangeEvent event) {
String username = (String)VaadinSession.getCurrent().getAttribute("username");
Label greeting = new Label("Hello " + username);
addComponent(greeting);
}
}
The issue that comes from this is obvious - whenever I open the view where this label is present, a new label is added so if I re-visit the view 10 times, I will get 10 labels. Even if I move the label to be a class member variable the addComponent(...) is the one that screws things up. Some of my custom components really depend on the username attribute (in order to display user-specific content) hence I also have to place those in the enter(...) method. The addComponent(...) makes a mess out of it. I even tried the dirty way of removing a component and then re-adding it alas! in vain:
class MyViewX implements View {
MenuViewComponent mvc;
Label greeting;
public MyViewX() {
mvc = new MenuViewComponent();
addComponent(mvc);
}
#Override
public void enter(ViewChangeEvent event) {
String username = (String)VaadinSession.getCurrent().getAttribute("username");
greeting = new Label("Hello " + username);
// Remove if present
try { removeComponent(greeting); }
catch(Exception ex) { }
// Add again but with new content
addComponent(greeting);
}
}
but it's still not working. So my question is: what is the simplest way of updating a component that requires session-bound attributes?
The navigation via the menu custom component is omho not the issue here since all components of the menu are loaded in it's constructor. That's why it's also load that component in particular in a view's own constructor. Here is an example of a button in my menu that opens a view:
#SuppressWarnings("serial")
#PreserveOnRefresh
public class MenuViewComponent extends CustomComponent {
public MenuViewComponent(boolean adminMode) {
HorizontalLayout layout = new HorizontalLayout();
Label title = new Label("<h2><b>Vaadin Research Project</b></h2>");
title.setContentMode(ContentMode.HTML);
layout.addComponent(title);
layout.setComponentAlignment(title, Alignment.TOP_LEFT);
Button personalDashboardButton = new Button("Personal dashboard", new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
getUI().getNavigator().navigateTo(MainController.PERSONALDASHBOARDVIEW);
}
});
personalDashboardButton.setStyleName(BaseTheme.BUTTON_LINK);
layout.addComponent(personalDashboardButton);
layout.setComponentAlignment(personalDashboardButton, Alignment.TOP_CENTER);
// Add other buttons for other views
layout.setSizeUndefined();
layout.setSpacing(true);
setSizeUndefined();
setCompositionRoot(layout);
}
}
PERSONALDASHBOARDVIEW is just one of the many views I have.
It may be worth considering how long should your view instances "live", just as long they're displayed, until the session ends or a mix of the two. With this in mind and depending on what needs to happen when you enter/re-enter a view, you have at least the following 3 options:
1) Recreate the whole view (allowing for early view garbage-collection)
first register a ClassBasedViewProvider (instead of a StaticViewProvider) which does not hold references to the created views:
navigator = new Navigator(this, viewDisplay);
navigator.addProvider(new Navigator.ClassBasedViewProvider(MyView.NAME, MyView.class));
simple view implementation
public class MyView extends VerticalLayout implements View {
public static final String NAME = "myViewName";
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
// initialize tables, charts and all the other cool stuff
addComponent(new SweetComponentWithLotsOfStuff());
}
}
2) Keep some already created components and replace others
public class MyView extends VerticalLayout implements View {
private MySweetComponentWithLotsOfStuff mySweetComponentWithLotsOfStuff;
public MyView() {
// initialize only critical stuff here or things that don't change on enter
addComponent(new MyNavigationBar());
}
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
// oh, so the user does indeed want to see stuff. great, let's do some cleanup first
removeComponent(mySweetComponentWithLotsOfStuff);
// initialize tables, charts and all the other cool stuff
mySweetComponentWithLotsOfStuff = new SweetComponentWithLotsOfStuff();
// show it
addComponent(mySweetComponentWithLotsOfStuff);
}
}
3) Lazy creating and updating (or not) the content when entering
public class MyView extends VerticalLayout implements View {
private boolean isFirstDisplay = true;
private MySweetComponentWithLotsOfStuff mySweetComponentWithLotsOfStuff;
public MyView() {
// initialize only critical stuff here, as the user may not even see this view
}
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
// oh, so the user does indeed want to see stuff
if (isFirstDisplay) {
isFirstDisplay = false;
// lazily initialize tables, charts and all the other cool stuff
mySweetComponentWithLotsOfStuff = new SweetComponentWithLotsOfStuff();
addComponent(mySweetComponentWithLotsOfStuff);
} else {
// maybe trigger component updates, or simply don't do anything
mySweetComponentWithLotsOfStuff.updateWhateverIsRequired();
}
}
}
I'm sure (and curious) that there may be other options, but I've mainly used a variation of 1) using spring with prototype views and component tabs.
I want to make a tab bar that will display at the bottom of a couple of MainScreens, and I thought creating a single class would be the right way to go.
The problem, not surprisingly since I'm new, is that when I try to add a field in my class how does it place it in the MainScreen? Do I have to send some sort of reference to the screen I want to work with?
package mypackage;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.container.HorizontalFieldManager;
public class CustomTabBar {
private HorizontalFieldManager bar;
public CustomTabBar(){
}
public void buildBar(){
bar = new HorizontalFieldManager();
add(bar); //Where am I adding this?!
Bitmap eventIcon = Bitmap.getBitmapResource("eventsicon.png");
Bitmap eventIcon_hover = Bitmap.getBitmapResource("eventsicon-hover.png");
CustomMenuField eventIconField = new CustomMenuField(eventIcon_hover,eventIcon, "TheatreScreen");
}
}
If you want to add child objects directly to a MainScreen, then yes, you need to pass a reference to the MainScreen around, eg:
public class CustomTabBar {
private HorizontalFieldManager bar;
public void buildBar(MainScreen main) {
bar = new HorizontalFieldManager();
Bitmap eventIcon = Bitmap.getBitmapResource("eventsicon.png");
Bitmap eventIcon_hover = Bitmap.getBitmapResource("eventsicon-hover.png");
CustomMenuField eventIconField = new CustomMenuField(eventIcon_hover,eventIcon, "TheatreScreen");
bar.add(eventIconField);
main.add(bar);
}
}
.
public class MyMainScreen extends MainScreen {
private CustomTabBar tab;
public MyMainScreen() {
...
tab = new CustomTabBar();
tab.buildBar(this);
...
}
}
I think a better solution would be to change your class to extend from HorizontalFieldManager instead of encapsulating it, eg:
public class CustomTabBar extends HorizontalFieldManager {
public CustomTabBar(long style) {
super(style);
Bitmap eventIcon = Bitmap.getBitmapResource("eventsicon.png");
Bitmap eventIcon_hover = Bitmap.getBitmapResource("eventsicon-hover.png");
CustomMenuField eventIconField = new CustomMenuField(eventIcon_hover,eventIcon, "TheatreScreen");
add(eventIconField);
}
}
.
public class MyMainScreen extends MainScreen {
private CustomTabBar tab;
public MyMainScreen() {
...
tab = new CustomTabBar(...);
add(tab);
...
}
}
You need the MainScreen object, and you want to use setStatus(this) to put your tab bar at the bottom of the screen. The status section of the MainScreen stays visible, and is always at the bottom of the screen. The Banner is always at the top, and the Title is just below the banner. Everything else sits in a scrollable area between the title/banner and the status sections of the screen.
My app has has an option to show screen-B instead of screen-A (default main) at app start up.
First I tried pushScreen(screen-B) in screen-A's constructor which resulted in display stack has screen-A on top and then screen-B..
What I want to do is:
At start up if the option is on, show screen-B (stack has screen-B then screen-A so that Escape key would lead to screen-A)
What would be the right way to acheive this?
You might consider pushing B a little bit later in the process, in the onUiEngineAttached method:
class ScreenA extends Screen {
...
protected void onUiEngineAttached(boolean attached) {
if (attached) {
// check condition and push B as appropriate
}
}
}
When the application starts, in the UiApplication class make the following:
class UiApp extends UiApplication {
UiApp() {
if (yourCondition)
//start A
else
//start B
}
public static void main (String[] args) {
UiApp app = new UiApp();
app.enterEventDispatcher();
}
}
HI, I try to detect reterning to screen after closing another screen,
should work when returning from my application screens, but also returning from device camera
after shooting video. In overriden method onExposed() I'm able to detect this situation,
but it's called too many times, and also called when dialog was shown (alert).
Is there better way to detect return to screen?
protected void onExposed() {
// return to screen detected
MainApp.addLog("onExposed");
}
returning from device camera after
shooting video
Check the Application.activate()
The system invokes this method when it
brings this application to the
foreground. By default, this method
does nothing. Override this method to
perform additional processing when
being brought to the foreground.
If you override the Screen.onUiEngineAttached(boolean) method, you can be notified when the screen is attached or detached from the UI --- basically when it's pushed or popped from the screen stack.
I had to do a similar thing and found it's very confusing because onExposed() can be called multiple times in uncertain timing.
To detect returning from screen B in screen A (main screen), I used screen B's onUiEngineAttached(false) which is called when it is popped.
To use callback:
public interface Ievent {
public void backFromScreenBEvent();
}
Screen A:
public class ScreenA extends MainScreen implements Ievent
{
private ScreenB screenB;
// constructor
public ScreenA()
{
screenB = new ScreenB(this); // pass over Ievent
// ....
}
public void backFromScreenBEvent()
{
// screen B is returning, do something
}
Screen B:
public final class ScreenB extends MainScreen
{
private Ievent event;
// constructor
public ScreenB(final Ievent event)
{
this.event = event;
// ...
}
protected void onUiEngineAttached(boolean attached) {
super.onUiEngineAttached(attached);
if (!attached) {
event.backFromScreenBEvent(); // notify event
}
}
I'm working on adding a BitmapField to my Blackberry project.
I implemented my class with a FieldChangeListener and added the FieldChangeListener method to my class. I even added a setChangeListener to that particular Bitmap Field, but it's not responding to click events.
How do I fix this?
First, BitmapField is not focusable by default, so you'll need to subclass and override isFocusable to fix that. Then override navigationclick to fire a fieldChanged event. Code snippet for a minimum field:
import net.rim.device.api.ui.component.BitmapField;
public class ClickableBitmapField extends BitmapField {
public boolean isFocusable() {
return true;
}
protected boolean navigationClick(int status, int time) {
fieldChangeNotify(0);
return true;
}
}
In addition to this, you may want to provide some indication of when your field is in focus (unless you only care about touch-screen devices). The default implementation will just draw a highlight on any transparent areas of your bitmap. You can change this by overriding drawFocus, and maybe onFocus and onUnfocus to change the bitmap you display when the focus state changes.