I'm new to JavaFX, so this might be a trivial question. I have a ListView inside a dialog that shows when the user clicks a menu button. The problem is that when the dialog shows, the first item in the ListView is already selected. I have listView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<NewChoices>()) as the listener for when a user selects an item, but since the first item is already selected, when I click on the first item nothing happens. I need to find a way to make sure that no item is selected when the dialog shows. I tried using listView.getSelectionModel().clearSelection() before showing the dialog, but if the program loses then regains focus, the first item is selected again without being clicked on. How can I prevent the first item, or any item for that matter, being preselected?
Here is the code:
Pane rootPane = new Pane();
ObservableList<NewChoices> listChoices = FXCollections.observableArrayList(NewChoices.values());
ListView<NewChoices> listView = new ListView<NewChoices>();
listView.setItems(listChoices);
rootPane.getChildren().add(listView);
Stage newDialog = new Stage(StageStyle.UTILITY);
newDialog.initModality(Modality.APPLICATION_MODAL);
newDialog.setTitle("New");
Scene newDialogScene = new Scene(rootPane);
newDialog.setScene(newDialogScene);
newDialog.show();
Should be fixed in 8u40 - see https://javafx-jira.kenai.com/browse/RT-38517
Since you have only a list on your new scene, with no buttons, when the scene gains the focus, as the only focusable node is the list, its first item gets selected.
Adding some OK/Cancel buttons may help since they can gain the focus instead, but for that they need to gain first the focus.
Any of these two options will work:
Put first the button, so its the first focusable node:
listView.setItems(listChoices);
Button button = new Button("Ok");
VBox rootPane = new VBox(10, button, listView);
Stage newDialog = new Stage(StageStyle.UTILITY);
newDialog.initModality(Modality.APPLICATION_MODAL);
newDialog.setTitle("New");
Scene newDialogScene = new Scene(rootPane);
newDialog.setScene(newDialogScene);
newDialog.show();
Remove temporaly the focusable property of the list:
listView.setItems(listChoices);
listView.setFocusTraversable(false);
Button button = new Button("Ok");
VBox rootPane = new VBox(10, listView, button);
Stage newDialog = new Stage(StageStyle.UTILITY);
newDialog.initModality(Modality.APPLICATION_MODAL);
newDialog.setTitle("New");
Scene newDialogScene = new Scene(rootPane);
newDialog.setScene(newDialogScene);
newDialog.show();
listView.setFocusTraversable(true);
In any case, both require an extra node. Anyway you will need it to close the modal stage, right?
If you still want to go without buttons, you could use JDK 8u40 early versions where the problem has already been fixed, as #wzberger points out, or if this is not possible, use ControlsFX new Dialogs API (a fork of the API that will ship in JDK 8u40), and you won't have any problem.
listView.setItems(listChoices);
final Dialog dialog = new Dialog();
dialog.getDialogPane().setContent(listView);
Optional<ButtonType> result = dialog.showAndWait();
Related
The last column of my Table Viewer contains a check box only. The check box appears in the left side of the cell, and because the column name is pretty long it looks ugly as hell. How can I center the check box in the middle of the cell ? Is it possible without using images ? Here is how I create the column:
// third column - check box. temporary
TableColumn column = new TableColumn(viewer.getTable(), SWT.NONE);
column.setText("PrettyLongColumnName");
column.setWidth(100);
TableViewerColumn checkColumn = new TableViewerColumn(viewer, column);
checkColumn.setLabelProvider(new ColumnLabelProvider() {
// the checkboxes should be disposed and rebuilt when input changes
#Override
public void update(ViewerCell cell) {
MyObject system = (MyObject) cell.getElement();
TableItem item = (TableItem) cell.getItem();
Button button;
if (buttonsMap.containsKey(cell.getElement())) {
button = rightTableButtons.get(cell.getElement());
} else {
button = new Button((Composite) cell.getViewerRow().getControl(), SWT.CHECK);
button.setEnabled(true);
buttonsMap.put(cell.getElement(), button);
TableEditor editor = new TableEditor(item.getParent());
editor.grabHorizontal = true;
editor.grabVertical = true;
editor.setEditor(button, item, cell.getColumnIndex());
editor.layout();
}
}
}
});
TL;DR: Not available nativley, but can be implemented via epic hackery.
Checkboxes are actually an OS feature. As SWT is cross-platform, we rely on it being provided by OS.
AFIK the only thing provided by all OS's (Gtk/Win32/Cocoa) is a single checkbox on the first column.
Other
fancy functionality has to be implemented manually.
One way I've seen people do it is to draw custom icons and then update the icon when you click on it with event listeners.
One example on how to draw icons on the right is in this snippet. You'd have to add click listener to change the icon when clicked into checked/unchecked.
Note, this may cause your application to look inconsistent across platforms and themes (e.g dark theme).
To get around this, we have had some people that actually generate a native checkbox, then programatically take a screen shot, then draw it in the right side of a column. I think this is hackery at it's finest.
Let me know if you have questions.
I have a school project or something like that and I am trying to make a sign up panel for users. This panel opens when user clicks on sign up. It looks like this.
What I am trying to do is I want to disable that Create Button and It will be enabled only if there are 3 checks on the dialog.
I am using a GridPane on Dialog and I was thinking about returning those certain nodes (Checks which are ImageViews) at those cells and check whether the condition is true. However, I could not figure out how to return a node from GridPane. If you have any other approach for this problem it is fine too.
This is the code's relevant part.
public void SignUp(){
//Create the custom dialog.
Dialog signUpDialog = new Dialog();
//Dialog Title
signUpDialog.setTitle("Sign Up");
//Setting "OK" button type.
ButtonType buttonTypeCreate = new ButtonType("Create", ButtonBar.ButtonData.OK_DONE);
//Adding Button types.
signUpDialog.getDialogPane().getButtonTypes().addAll(buttonTypeCreate, ButtonType.CANCEL);
//Creating the GridPane.
GridPane gridPane = new GridPane();
gridPane.setHgap(10);
gridPane.setVgap(10);
gridPane.setPadding(new Insets(20, 150, 10, 10));
//Setting the Check Icon.
Image imageCheck = new Image("resources/check_icon.png");
//Setting 3 different ImageViews for Check Icon because can't add duplicates to GridPane.
ImageView imageViewCheck1 = new ImageView(imageCheck);
ImageView imageViewCheck2 = new ImageView(imageCheck);
ImageView imageViewCheck3 = new ImageView(imageCheck);
//Setting the X Icon.
Image imageX = new Image("resources/x_icon.png");
//Setting 3 different ImageViews for X Icon because can't add duplicates to GridPane.
ImageView imageViewX1 = new ImageView(imageX);
ImageView imageViewX2 = new ImageView(imageX);
ImageView imageViewX3 = new ImageView(imageX);
//TextField for User ID.
TextField textFieldDialogUserID = new TextField();
textFieldDialogUserID.setPromptText("User ID");
textFieldDialogUserID.setAlignment(Pos.CENTER_RIGHT);
//PasswordField for Password.
PasswordField passwordFieldDialogPassword = new PasswordField();
passwordFieldDialogPassword.setPromptText("Password");
passwordFieldDialogPassword.setAlignment(Pos.CENTER_RIGHT);
//PasswordField for Confirm Password.
PasswordField passwordFieldDialogConfirmPassword = new PasswordField();
passwordFieldDialogConfirmPassword.setPromptText("Confirm Password");
passwordFieldDialogConfirmPassword.setAlignment(Pos.CENTER_RIGHT);
gridPane.add(new Label("User ID"), 0, 0);
gridPane.add(textFieldDialogUserID, 1, 0);
gridPane.add(new Label("Password"), 0, 1);
gridPane.add(passwordFieldDialogPassword, 1, 1);
gridPane.add(new Label("Confirm Password"), 0, 2);
gridPane.add(passwordFieldDialogConfirmPassword, 1, 2);
gridPane.add(imageViewX1,2,0);
gridPane.add(imageViewX2,2,1);
gridPane.add(imageViewX3,2,2);
signUpDialog.getDialogPane().setContent(gridPane);
Stage signUpStage = (Stage) signUpDialog.getDialogPane().getScene().getWindow();
signUpStage.getIcons().add(new Image("resources/application_icon.png"));
Optional<Pair<String, String>> result = signUpDialog.showAndWait();
}
Create an appropriate BooleanBinding which expresses when the button should be disabled. You can use the Bindings utility class to create the expression, including comparison, ands and ors. To make the code more readable do a static import of the functions.
Get the create button from your panel and bind the boolean expression to the disable property of your button.
If any of the values change the JavaFX framework will automatically reevaluate the bindings and update the button's state accordingly.
import static javafx.beans.binding.Bindings.*;
BooleanBinding notComplete = or(
equal(textFieldDialogUserID.textProperty(), null),
equal(passwordFieldDialogPassword.textProperty(), null));
Node createButton = signUpDialog.getDialogPane().lookupButton(buttonTypeCreate);
createButton.disableProperty().bind(notComplete);
You can use the same mechanism to control the visibility of each checkmark. Create a 'incomplete' BooleanBinding for each textfield and bind it with a not binding to the visible property of the checkmark. Use all these BooleanBindings in a compound or to determine the button state. This way the button state and checkmarks will always be in sync.
I could not figure out how to return a node from GridPane.
gridPane.getChildren()
provides the list of nodes, but you already have your components textFieldDialogUserID, passwordFieldDialogPassword, passwordFieldDialogConfirmPassword.
=> Add an action listener for each of them, that checks the values when its value is changed. depending on the result, enable/disable the Create button (per default, it should be disabled).
you can have an example : http://docs.oracle.com/javafx/2/ui_controls/text-field.htm
I'm trying to stop the users from being able to move an alert that pops up. I have found one option is to set the style to UNDECORATED to remove the border which they would click on to move the alert, but I personally think this looks very ugly.
Are there any other options?
I suggest going with StageStyle.UNDECORATED and adding any decoration you want inside.
Not having system decoration, in this case, is a benefit. Because people are used to standard controls (close button, moving by dragging title, etc) and by removing them you give a clear sign that you don't want this windows to be movable.
Small example:
Stage alert = new Stage(StageStyle.UNDECORATED);
alert.initModality(Modality.APPLICATION_MODAL);
VBox root = new VBox(30);
root.setStyle("-fx-background-color: antiquewhite");
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(25));
root.setBorder(new Border(new BorderStroke(Color.BLACK,
BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderWidths.DEFAULT)));
Button btn = new Button("Got it!");
btn.setOnAction((e)-> {alert.close();});
Label label = new Label("Alert!");
label.setFont(Font.font("Verdana", 20));
root.getChildren().addAll(label, btn);
alert.setScene(new Scene(root, 200, 150));
which gives you next window:
I have a map with data of a "benchmark" for my little algorithm.
Keys represent the name of the benchmark, values the time needed.
I want to create a Dialog with lists those results in an easy to read way.
This is what I got so far:
Platform.runLater(() -> {
Dialog<Object> dialog = new Dialog<>();
dialog.setTitle("Result");
DialogPane pane = dialog.getDialogPane();
VBox list = new VBox();
for (Entry<String, Long> entry : resultMap.entrySet()) {
BorderPane box = new BorderPane();
box.setLeft(new Text(entry.getKey() + ": "));
box.setRight(new Text(entry.getValue().toString() + "ms"));
list.getChildren().add(box);
}
list.getChildren().add(new Text("Check: " + (logic.getResult() ? "PASSED" : "FAILED")));
pane.getChildren().add(list);
//pane.setPrefSize(pane.getPrefWidth(), 200); needed otherwhise the dialog is cut off
dialog.show();
});
There are multiple problems with this.
This Dialog isn't closeable for whatever reason.
The "Time" result is
aligned left instead of right.
It works for me inside scene builder, but since I need to generate those dynamically that's no possible choice.
Any help is appreciated!
Rules about closing a dialog are described in the Dialog documentation under "Dialog Closing Rules". In short, you need to add a button of some kind, which you can do with
pane.getButtonTypes().add(ButtonType.OK);
The reason the layout of list is not working correctly is that you use
pane.getChildren().add(list);
The dialog pane has a specific structure (again, see the documentation), and if you "blindly" add a node to the list of children, the dialog pane doesn't know how to manage it. Use setContent(...) instead:
// pane.getChildren().add(list);
pane.setContent(list);
This will also avoid the need to set the preferred size of the dialog pane.
I am trying to set a SWT Button into a "pressed" state programmatically.
Is that possible somehow?
Update:
What I am trying to achieve - is render draw a Button in it's selected state onto an Image.
Image buttonimg_mouseover = new Image(getDisplay(), 100, 100);
Button button = new Button(parent.parent, SWT.PUSH);
button.setAlignment(SWT.CENTER);
button.setImage(arrowimg);
button.setSize(100, 100);
button.setSelection(true); // doesn't work
GC gcbutton = new GC(buttonimg_mouseover); //draw an image of the button
button.print(gcbutton);
You can do it with the following snippet
Button myButton = new Button(parent, SWT.TOGGLE);
myButton.setSelection(true);
However, this will only work with the types CHECK, RADIO or TOGGLE.
See Javadoc of Button#setSelection(boolean).