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
}
}
Related
I am using Vaadin 8.5.1 with the Vaading Desiin combination with Spring Boot 2.0.4.
Currently I am trying to add a PopupView at the bottom of the page which opens on button click. In the Popup there is a vertical layout including two components: a HorizontalSplitPanel and a Button. The PopupView should have the width of the current BrowserWindow and one third of the height.
The HorizontalSplitPanel should use all the space in the popup, which is not needed for the button.
What I did:
#SpringComponent
#UIScope
public class View extends VerticalLayout implements Observer {
private final PopupContentView popupContentView;
private PopupView popup;
#Autowired
public View(PopupContentView popupContentView) {
this.popupContentView = popupContentView;
}
#PostConstruct
void init() {
button.addClickListener(clickEvent -> openPopup());
}
private void openPopup() {
if (popup == null) {
setSizeOfPopUp();
// popup will adjust automatically to size of content
popup = new PopupView(null, popupContentView);
popup.addPopupVisibilityListener(event -> {
if (event.isPopupVisible()) {
popupContentView.build(this::submitted);
}
});
popup.setHideOnMouseOut(false);
this.addComponent(popup);
}
popup.setPopupVisible(true);
}
private void setSizeOfPopUp() {
if (popupContentView != null) {
popupContentView.setWidth(Page.getCurrent().getBrowserWindowWidth(), Unit.PIXELS);
popupContentView.setHeight(((float) Page.getCurrent().getBrowserWindowHeight()) / 3, Unit.PIXELS);
}
}
private void submitted() {
// do some stuff
}
#Override
public void update(Observable observable, Object o) {
if (observable instanceof BrowserWindowResizeListenerObservable) {
setSizeOfPopUp();
}
}
}
#Service
public class BrowserWindowResizeListenerObservable extends Observable implements Page.BrowserWindowResizeListener {
#Override
public void browserWindowResized(Page.BrowserWindowResizeEvent browserWindowResizeEvent) {
this.setChanged();
this.notifyObservers();
}
}
#SpringComponent
#UIScope
public class PopupContentView extends VerticalLayout {
private SubmitCallback submitCallback;
private Button submitBtn;
#PostConstruct
void init() {
super.init();
}
void build(#NotNull SubmitCallback) {
removeAllComponents();
this.addComponent(horizontalSplitPanel);
this.addComponent(submitBtn);
this.setExpandRatio(horizontalSplitPanel, 1.0f);
this.submitCallback = callback;
}
private void submit() {
submitCallback.submit(someContent);
}
#FunctionalInterface
public interface SubmitCallback {
void submit(SomeContent someContent);
}
}
As you can see, I have a main view, a view for the content and a listener class.
What I want to happen is that the popup is visible on button click and contains the content view with the panel and the submit button. The panel takes the rest of the space, which is not needed for the button. and the popup is fully filled with content.
What actually happens is that the panel takes the full space of the popup and the button will be shown below the popup.
However, when I resize the window and the resizing event gets fired, everything is fine and the button is no longer below the popup.
It seems to be that the padding and the margin (which are the HTML implementation of the expand ratio in Vaadin) are calculated at an earlier stage and get triggered again when resizing the window. However, I have no clue when and what I need to do, to trigger it.
Does anyone have an idea, how can fix this?
EDIT:
When I have a Tree component or a DateField component in the PopupView and then expand a tree element or change the value of the DateField by selecting a value from the Date popup, the resizing is done correctly and everything is fine.
I think in your case the method of checking Browser window size and calculating target pixel size is too complex for your case. I would recommend just to set the width of the popup to be 100% and height to be 33%, like component.setHeight("33%"), yes you can use percentages for width and height instead of pixels. Then sizing is done by CSS, and it will react faster to browser window sizing without server round trip.
I have the following code:
public class FileLoader extends SwingWorker(Void, Void) {
#Override
private Void doInBackground() {
loadFiles();
}
}
public class LogInPage {
private FileLoader fileLoader = new FileLoader();
public LogInPage() {
fileLoader.execute();
}
loginButtonActionPerformed(ActionEvent evt) {
//wait for files to finish loading
//while displaying a waiting cursor
showMainForm();
}
}
My question would be:
After clicking the button, I would want all the files to be loaded first (while displaying an hourglass cursor and progress bar) before showing the main form.
I have done this before with Thread's join() but was not able to do the same with SwingWorker.
I have read about overriding done() and implementing listeners but I can't apply it here.
Any help?
Thanks.
From what you're saying and contrary to what you think, I think you can actually use SwingWorker's done() method. Before execute(), disable the button, start a busy animation, whatever, then in the done() method, do whatever it is you need to do to continue the program. That's what it's for :-)
You should also look at the SwingWorker.publish() and process() to send and receive the progress bar events.
See also: How do I wait for a SwingWorker's doInBackground() method?
In my Application, I want to show the screens according to the Orientation. I knew, Whenever the device is Oriented then sublayout() method of current screen is called. According that point of view I write like this:
Here StartUp is another className;
This is my LoadingScreen.java Class;
public class LoadingScreen extends MainScreen
{
public LoadingScreen()
{
createGUI();
}
protected void sublayout(int width, int height)
{
StartUp.screenOrientation();
if(StartUp.isLandscape)
{
deleteAll();
createGUI();
invalidate();
}
else
{
deleteAll();
orientGUI();
invalidate();
}
super.sublayout(width,height);
}
public void createGUI()
{
//For LANDSCAPE Display;
}
public void orientGUI()
{
//For PORTRAIT Display;
}
}
The screenOrientation() method is this:
public static void screenOrientation()
{
if(Display.getOrientation()==Display.ORIENTATION_LANDSCAPE)
{
isLandscape=true;
width=480;
height=360;
}
else
{
isLandscape=false;
width=360;
height=480;
}
}
I am getting the Screen in both Orientation Modes. My problem is, if I take one textboxField and enter something in LANDSCAPE Mode and Oriented to PORTRAIT Mode then the data is gone. Because I am calling createGUI(); or orientGUI(); methods in sublayout().
One more problem that I am getting in Touch screen is:
If I want to enter text in any textboxField It opens the "keypad". Its Not a problem. The main thing is whenever the keypad open/hide both times again calling the sublayout() of that class. So I am getting the refreshed screen.
So, is there any other method to get Orientation? If it is then help me.
To solve the first issue, you have two options.
Dont delete the fields, just redraw the screen for the different
orientation.
or
Save the value of textboxfield before you delete the field and
after orientation change, set the value of textboxfield with the
saved value. You will need to even get the cursor position and set
that as well.
To solve the second issue
After orientation change, set a new variable "currentWidth" as Display.getWidth() . Then when you get a call to sublayout() check the Display.getWidth() and see if its equal to currentWidth. If its equal that means the orientation hasn't changed. If not then the orientation has changed.
hope this helps
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();
}
}
In my BlackBerry application, I have a home screen. The user can then navigate to a settings screen. When the user goes back to the home screen, is there no method that is called on the home screen indicating that the screen has come to the foreground?
I have tried onFocus() with no avail.
Thanks!
Unfortunately, hooking on the onExposed is not enough. I found that in Blackberry dialogs are also screens and even context menus are screens too. They are pushed on top of your screen so you receive onExposed callback when they are dismissed.
Though it's OK in many cases, in other cases it poses a problem - e.g. if I must refresh the screen's content only when the user returns to it, but not after menus/dialogs, then how do I do that? My case is, unfortunately, one of those.
I found no documented way of detecting "covered"/"uncovered" events. Here is my approach. onCovered/onUncovered callbacks are called when the current screen is covered/uncovered by another screen of the app, but not by dialogs/menus/virtual keyboard:
public class MyAppScreen extends MainScreen {
private boolean isCovered;
protected void onExposed() {
Log.d("onExposed");
super.onExposed();
if (isCovered) {
onUncovered();
isCovered = false;
}
}
protected void onObscured() {
Log.d("onObscured");
super.onObscured();
final Screen above = getScreenAbove();
if (above != null) {
if (isMyAppScreen(above)) {
isCovered = true;
onCovered();
}
}
}
private boolean isMyAppScreen(final Screen above) {
return (above instanceof MyAppScreen);
}
protected void onUncovered() {
Log.d("onUncovered");
}
protected void onCovered() {
Log.d("onCovered");
}
protected void onUiEngineAttached(final boolean attached) {
if (attached) {
Log.d("UI Engine ATTACHED");
} else {
Log.d("UI Engine DETACHED");
}
super.onUiEngineAttached(attached);
}
protected void onFocusNotify(final boolean focus) {
if(focus){
Log.d("focus GAINED");
} else {
Log.d("focus LOST");
}
super.onFocusNotify(focus);
}
}
And a test. Try various combinations and see what events you receive in the log.
public class TestLifecycle extends MyAppScreen implements FieldChangeListener {
private final ABNTextEdit txt1;
private final ButtonField btn1;
private final ButtonField btn2;
public TestLifecycle() {
final Manager manager = getMainManager();
txt1 = new ABNTextEdit();
manager.add(txt1);
btn1 = new ButtonField("Dialog", ButtonField.CONSUME_CLICK);
btn1.setChangeListener(this);
manager.add(btn1);
btn2 = new ButtonField("Screen", ButtonField.CONSUME_CLICK);
btn2.setChangeListener(this);
manager.add(btn2);
}
public void fieldChanged(final Field field, final int context) {
if (field == btn1) {
Dialog.alert("Example alert");
} else if (field == btn2) {
UiApplication.getUiApplication().pushScreen(new TestLifecycle());
}
}
}
Update:
This method has a limitation: if a new screen is pushed when a dialog or the soft keyboard has focus your current screen will not receive onCovered/onUncovered notification.
Example A: if you have an input field of fixed size and you push a new screen when the user completes it, your current screen will not receive the notification if the user types very quickly. This happens because in the moment between you call push(newScreen) and it is actually pushed the user clicks on a letter on soft KB and it grabs the focus. So only onObscured is called, but not onCovered.
Solution: explicitly hide the soft keyboard before the push(newScreen).
Example B: if you have a customized dialog which pushes new screen and then dismisses itself, your current screen will not receive the notification. This happens because your customized dialog is not recognized as a screen, so only onObscured is called, but not onCovered.
Solution: dismiss the dialog in the first place returning a result value, and let your screen push the new screen based on that value. -OR- override isMyAppScreen() to return true also for your customized dialog.
You should be able to use protected void onExposed() to detect when it is displayed again.