JavaFX disableProperty with two conditions not working [duplicate] - binding

This question already has answers here:
Enabling/Disabling buttons in JavaFX [duplicate]
(2 answers)
How to disable Button when TextField is empty?
(3 answers)
Closed 7 years ago.
I have a problem with
public class LoginController implements Initializable {
#FXML protected Button loginButton;
#FXML protected TextField email;
#FXML protected PasswordField password;
#Override
public void initialize(URL location, ResourceBundle resources) {
loginButton.disableProperty().bind(Bindings.and(email.textProperty().isEmpty(), password.textProperty().isEmpty()));
}
}
The LoginButton shall be disabled until both fields, email and password, are not empty...
At the moment, the LoginButton is enabled, when I enter one character in either field, leaving the other field alone...
Any ideas, where I got my mistake?
Regards

Use OR:
loginButton.disableProperty().bind(Bindings.or(email.textProperty().isEmpty(), password.textProperty().isEmpty()));

Related

Forcing a Vaadin Tabsheet to use the CloseHandler

I have a Vaadin Tabsheet. All tabs are closable. I have defined a custom CloseHandler. When a Tab is closed via the small x button, the the CloseHadler executes; however, if I close the tab programmatically
TabSheet parent = (TabSheet) this.getParent();
parent.removeTab(parent.getTab(this));
The close handler does not execute. Is there a way to force the CloseHandler to execute before the Tab is removed.
Thanks,
Oliver
A solution would be to extend the TabSheet class and override removeTab() to force it to execute the closeHandler. As the TabSheet.closeHandler is private you'll need to override this field and its setter too. Vaadin could make things simpler (changing the closeHandler to protected or providing a getter) but I don't see it as a "dirty" solution.
public class MyTabSheet extends TabSheet {
private static final long serialVersionUID = 1L;
private CloseHandler closeHandler;
#Override
public void removeTab(Tab tab) {
if (closeHandler != null) {
closeHandler.onTabClose(this, tab.getComponent());
}
super.removeTab(tab);
}
#Override
public void setCloseHandler(CloseHandler handler) {
closeHandler = handler;
// needed for TabSheet.TabsheetServerRpcImpl
super.setCloseHandler(handler);
}
}
If you want you could create a feature request at Vaadin (vaadin.com/bug), maybe the closeHandler should be called by default. There's already the #10555 but it's 3 years old...

VaadinSession attribute and updating session-bound components

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.

JavaFX: Tooltip - Can't get tooltip's to show at all

I'm in the middle of a project where i'm supposed to write a login system using JavaFX 2.0.
And right now i'm trying to write a tooltip with a connection to the password field, but the tooltip NEVER shows at all.. I'm using the FXML-LoginDemo project from the 'javafx-samples-2.0.3'. And then I tried to use: http://docs.oracle.com/javafx/2.0/ui_controls/tooltip.htm#BABHCHGG example 19.1.
If you need more code to see this problem please say so.. because I don't really know where the problem is..
Here's my code so far:
package demo;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
/**
* Login Controller.
*/
public class LoginController {
#FXML private TextField userId;
#FXML private PasswordField password;
#FXML private Label errorMessage;
#FXML final Tooltip tooltip = new Tooltip();
#FXML protected void processLogin(ActionEvent event) {
tooltip.setText("\nYour password must be\n at least 8 characters in length\n");
password.setTooltip(tooltip);
if(!App.getInstance().userLogging(userId.getText(), password.getText())){
errorMessage.setText("Invalid username or password: " + userId.getText());
}
//Replaces inputed password with an empty String.
password.setText("");
}
}
Define an initialize method on the controller and, in that method, set the tooltip text and associate the tooltip with the password field. If you wait until the processLogin action is called to set the Tooltip, the scene has already been displayed and the user has already tried to login.
Also, you don't need to place the #FXML annotation in front of the Tooltip unless you are defining Tooltip properties in FXML, which is probably not necessary in this case.

Vaadin addStyleName problem

I created a TextField with TextChangeListener. When user types in certain values (in this case 'admin') then addStyleName is invoked on that field and font color becomes red. But afterwards, the value is blank and each entered character is being cleared.
Here is the code of the application. Why after adding new style to TextField its value changes?
public class VaadintestApplication extends Application {
#Override
public void init() {
Window mainWindow = new Window("Vaadintest Application");
setTheme("test");
TextField textField = new TextField("username");
textField.setEnabled(true);
textField.setTextChangeEventMode(TextChangeEventMode.EAGER);
textField.addListener(new TextChangeListener() {
public void textChange(TextChangeEvent event) {
if ("admin".equals(event.getText())) {
((TextField) event.getComponent()).addStyleName("text-error");
} else {
((TextField) event.getComponent()).removeStyleName("text-error");
}
}
});
mainWindow.addComponent(textField);
setMainWindow(mainWindow);
}
}
I would guess that the following happens:
The style name change triggers a repaint on the server, causing the TextField component to be serialized again to the client
The client receives the serialization (the whole bloody thing, not just the changed parts, because that's how things work with Vaadin), and hence it changes the contents of the textfield, while ignoring any changes that are pending from the text change listener
Solutions:
Update the value of the TextField at the same time you add/remove the style name: ((TextField) event.getComponent()).setValue(event.getText())
Create a custom client side widget which extends VTextField and add the functionality there

Blackberry PopupScreen size limited by virtual keyboard

I am trying to display a Custom PopupScreen and when the virtual keyboard is being displayed it reduces the size of the popup. I know when you for example, select new message you get a PopupScreen that allows you to select message type (sms, email, etc) and it shows on top of the virtual keyboard. Here is my code am I missing something? I can't find a z-index or something similar...
public class InsertApplicationMenuItem extends ApplicationMenuItem {
public Object run(Object context) {
InsertWhatScreen screen = new InsertWhatScreen();
UiApplication.getUiApplication().pushModalScreen(screen);
return context;
}
}
public class InsertWhatScreen extends PopupScreen {
public InsertWhatScreen() {
super(new VerticalFieldManager(), FOCUSABLE);
}
}
alt text http://dl.dropbox.com/u/2645315/2010-01-20%2015%2017%2023.png
Thanks for the help.
There's no way to put anything on top of the virtual keyboard from a third-party app. If you read the display height while the virtual keyboard is showing, you'll see that the device actually shrinks the "screen size" given to your app while the keyboard is showing.

Resources