How to switch views in Gluon mobile app using javafx? - java

I am trying to create a Gluon mobile application using javafx. I want to create a login page in which on a successful login i need to load another(Second View) view in a button click. I didn't get a proper example for this. If anyone knows this please help. I have two views Primary presenter and secondary presenter.(gluon application with FXML).Below is my primary view's controller.
public class PrimaryPresenter {
#FXML
private View primary;
private Label label;
#FXML
private TextField username;
#FXML
private Button loginBt;
private Alert alert;
#FXML
private PasswordField password;
public void initialize() {
primary.showingProperty().addListener((obs, oldValue, newValue) -> {
if (newValue) {
AppBar appBar = MobileApplication.getInstance().getAppBar();
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e
-> MobileApplication.getInstance().showLayer(ArjunsApp.MENU_LAYER)));
appBar.setTitleText("Primary");
appBar.getActionItems().add(MaterialDesignIcon.SEARCH.button(e
-> System.out.println("Search")));
}
});
}
#FXML
private void buttonClick(ActionEvent event) {
if(username.getText().equals("")){
alert = new Alert(AlertType.ERROR,"Enter username");
alert.showAndWait();
}else if(password.getText().equals("")){
alert = new Alert(AlertType.ERROR,"Enter password");
alert.showAndWait();
}else{
//Code to load my secondary view
}
}
}

Assuming you are using the Gluon plugin - Multi View project with FXML template, you can switch views easily with MobileApplication.getInstance().switchView(viewName).
In your case:
#FXML
private void buttonClick(ActionEvent event) {
...
MobileApplication.getInstance().switchView("SECONDARY_VIEW");
}
If you are using the Glisten-Afterburner template instead (it also uses FXML), you could use something like:
#FXML
private void buttonClick(ActionEvent event) {
...
AppViewManager.SECONDARY_VIEW.switchView();
}
You can find more about the Gluon Mobile API here.

Related

ListView is not updating properly with JavaFX FXML

In JavaFX I use ListView to display items added or removed to/from a Set. I have made an observableSet to use with the ListView to show the updates but the ListView is not updating properly when the Set changes. Here is my code with a work around. But why it's not working as expected?
public class FXMLDocumentController implements Initializable {
#FXML
private ListView listView;
ObservableSet<String> observableSet; //ObservableSet to prevent dublicates
Integer i = 3;
#Override
public void initialize(URL url, ResourceBundle rb) {
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
observableSet = FXCollections.observableSet();
observableSet.addAll(Arrays.asList("Item1", "Item2", "Item3"));
//Setting up ListView to the ObservableSet
listView.setItems(FXCollections.observableArrayList(observableSet));
}
#FXML
private void handleButtonAction(ActionEvent event) {
observableSet.add("Item" + i++);
//Setting up ListView to the ObservableSet otherwise it won't update
//My understanding that I don't have to do this with an observableSet
listView.setItems(FXCollections.observableArrayList(observableSet));
}
#FXML
private void handleRemoveAction(ActionEvent event) {
observableSet.removeAll(listView.getSelectionModel().getSelectedItems());
//Setting up ListView to the ObservableSet otherwise it won't update
listView.setItems(FXCollections.observableArrayList(observableSet));
}
}
The Issue:
I have to keep setting up the ListView as demonstrated above and below everytime the observableSet is updated. Otherwise the change won't show in the ListView.
listView.setItems(FXCollections.observableArrayList(observableSet));
Try calling
listview.refresh();
after adding and removing items from the list.
or you can add a change listener on the list and call refresh method from it.
but i prefer first method, because adding a listener sometimes will not update the list view.
This is the expected behavior. The method you are calling to create the observable list "Creates a new observable list and adds the contents of [the set] to it". So subsequent changes to the set will not change the list.
Another option is just to register a listener with the observable set, and update the list view's items by adding or removing an element appropriately:
public class FXMLDocumentController implements Initializable {
#FXML
private ListView listView;
private ObservableSet<String> observableSet; //ObservableSet to prevent dublicates
private int i = 3;
#Override
public void initialize(URL url, ResourceBundle rb) {
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
observableSet = FXCollections.observableSet();
observableSet.addListener((SetChangeListener.Change<? extends String> c) -> {
if (c.wasAdded()) {
listView.getItems().add(c.getElementAdded());
}
if (c.wasRemoved()) {
listView.getItems().remove(c.getElementRemoved());
}
});
observableSet.addAll(Arrays.asList("Item1", "Item2", "Item3"));
}
#FXML
private void handleButtonAction(ActionEvent event) {
observableSet.add("Item" + i++);
}
#FXML
private void handleRemoveAction(ActionEvent event) {
observableSet.removeAll(listView.getSelectionModel().getSelectedItems());
}
}

How to create Bottom Navigation

I am new to mobile development, I started using Gluon mobile for Netbeans and I'm trying to add a Bottom navigation bar to the default Gluon Mobile App. They describe the class in the JavaDoc http://docs.gluonhq.com/charm/javadoc/4.1.0/com/gluonhq/charm/glisten/control/BottomNavigation.html but I can't seem to make it work.
Would someone be able to post a snippet on how and where to do this?
Here is a simple example:
public class GluonApplication extends MobileApplication {
#Override
public void init() {
addViewFactory(HOME_VIEW, () ->
{
StackPane root = new StackPane();
root.getChildren().add(new Label("test"));
View view = new View(root) {
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setTitleText("Home");
}
};
view.setBottom(createBottomNavigation());
return view;
});
}
private BottomNavigation createBottomNavigation() {
BottomNavigation bottomNavigation = new BottomNavigation();
ToggleButton btn1 = bottomNavigation.createButton("View1", MaterialDesignIcon.DASHBOARD.graphic(), e -> showView("view1"));
ToggleButton btn2 = bottomNavigation.createButton("View2", MaterialDesignIcon.AC_UNIT.graphic(), e -> showView("view2"));
ToggleButton btn3 = bottomNavigation.createButton("View3", MaterialDesignIcon.MAP.graphic(), e -> showView("view3"));
bottomNavigation.getActionItems().addAll(btn1, btn2, btn3);
return bottomNavigation;
}
private void showView(String viewName) {
MobileApplication.getInstance().switchView(viewName);
}
}

Error in OK button selection listener in a SWT/JFace Dialog

I am receiving the below exception while trying to access the field value from a text field within a SWT Dialog, from the selection listener of the 'OK' button.
org.eclipse.swt.SWTException: Widget is disposed
I can understand the error is because the Dialog is already disposed when I am trying to access it. But i haven't made any explicit call to dispose the shell.
Is the Dialog disposed automatically on clicking the 'OK' button? Is there any way it can be overridden? Or Am i doing something wrong here?
Appreciate any help or pointers. Relevant code snippet below:
public class MyDialog extends Dialog {
/** The file Name Text field. */
private Text fileNameText;
/** The constructor. **/
protected MyDialog(Shell parentShell) {
super(parentShell);
}
/** Create Dialog View. **/
protected Control createDialogArea(Composite parent) {
Composite mainComposite = (Composite) super.createDialogArea(parent);
fileNameText = new Text(mainComposite, SWT.BORDER);
fileNameText.setText("");
fileNameText.setBounds(0, 20, 428, 20);
return mainComposite;
}
/** Override method to set name and listener for 'OK' button. **/
protected void createButtonsForButtonBar(Composite parent) {
super.createButtonsForButtonBar(parent);
Button submitButton = getButton(IDialogConstants.OK_ID);
submitButton.setText("Review");
setButtonLayoutData(submitButton);
// Perform Selected CleanUp activity on Submit Click.
submitButton.addSelectionListener(new SelectionListener() {
#Override
public void widgetSelected(SelectionEvent e) {
// do something.
if (fileNameText.getText().isEmpty()) {
return;
}
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
}
Yes the dialog is automatically disposed when the OK button is clicked and No you should not stop this.
What you must do is override okPressed and save the text value before the dialog is disposed:
private String fileNameValue;
....
#Override
protected void okPressed()
{
fileNameValue = fileNameText.getText();
super.okPressed();
}

JavaFX: Is there a simple way to change the method of the onAction Handler in the code?

I have a Login Button who looks like this:
<Button fx:id="loginButton" mnemonicParsing="false" onAction="#doLogin" prefHeight="29.0" prefWidth="127.46630859375" text="Login" />
When the button is clicked I want to set the onAction to "#doLogout"in the code
I know there is a button.setOnAction method, but it has ActionEvent parameter and I have the problem that in the inner class, which I would have to make when I use this option, I do not have access to the variables in the outher class, which I need.
Is there any other solution to this problem?
Try something like this:
//In the Controller class
#FXML
private Button loginButton = new Button();
//...
//... on The public void initialize method of the Controller
//...
loginButton.setId("loginButton");
loginButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
Object source = e.getSource();
if (source instanceof Button) { //always true
//Do whatever you want when the event occurs
Button temp = (Button) source;
DoSomething(temp.getId());
}
}
});
Then after the login:
loginButton.setId("logoutButton");
or create a flag:
public boolean userLogged = false;
and check it to define what the button should do as here:
loginButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
if(userLogged)
doLogout();
else
doLogin();
}
});

Modify context menu in JavaFX WebView

I'm trying to add some options to the context menu in a JavaFX WebView when the user right clicks a link, however I can't figure out how to do it.
I found I could add my own context menu using:
final ContextMenu contextMenu = new ContextMenu();
view.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
System.out.println(mouseEvent.getEventType());
if(mouseEvent.isSecondaryButtonDown()) {
System.out.println("Secondary");
contextMenu.show(view, mouseEvent.getSceneX(), mouseEvent.getSceneY());
} else if (mouseEvent.isPrimaryButtonDown()) {
System.out.println("Primary");
} else if (mouseEvent.isMiddleButtonDown()) {
System.out.println("Middle");
}
}
});
javafx.scene.control.MenuItem menuItem1 = new javafx.scene.control.MenuItem("View Source");
menuItem1.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent actionEvent) {
System.out.println("Link: " + rightClickURL);
System.out.println("You clicked view source");
}
});
contextMenu.getItems().add(menuItem1);
Unfortunately, when I do that both menus appear:
If I use view.setContextMenuEnabled(false); then the default menu disappears. Unfortunately doing that also prevents me from detecting which link was right clicked. Here is the code I'm using for that:
engine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
#Override
public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
if (newState == Worker.State.SUCCEEDED) {
EventListener listener = new EventListener() {
#Override
public void handleEvent(org.w3c.dom.events.Event evt) {
String domEventType = evt.getType();
if (domEventType.equals(EVENT_TYPE_CLICK)) {
String href = ((Element)evt.getTarget()).getAttribute("href");
} else if (domEventType.equals(EVENT_TYPE_RIGHT_CLICK)) {
String href = ((Element)evt.getTarget()).getAttribute("href");
rightClickURL = href;
System.out.println(href);
}
}
};
Document doc = engine.getDocument();
NodeList nodeList = doc.getElementsByTagName("a");
for (int i = 0; i < nodeList.getLength(); i++) {
((EventTarget) nodeList.item(i)).addEventListener(EVENT_TYPE_CLICK, listener, false);
((EventTarget) nodeList.item(i)).addEventListener(EVENT_TYPE_RIGHT_CLICK, listener, false);
}
}
}
});
So my question is this: how can I access the default ContextMenu so I can customize it? I've scoured the docs but cannot find any method that allows you to access the default ContextMenu. It seems like there must be a way to do this but I'm stumped as to how.
If customizing the default ContextMenu is not possible, does anyone know how I can show a custom context menu when right clicking a link and also capture which link was clicked? I've been trying to achieve this for days with absolutely no luck...
Currently that's not possible. There is an open issue on JavaFX for that:
https://javafx-jira.kenai.com/browse/RT-20306
If you just want to add a different context menu, then you could do that
webView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouse) {
if (mouse.getButton() == MouseButton.SECONDARY) {
menu = new ContextMenu();
//add some menu items here
menu.show(this, mouse.getScreenX(), mouse.getScreenY());
} else {
if (menu != null) {
menu.hide();
}
}
}
});

Categories