JavaFx - Cancel a MouseEvent - javafx

I am trying to get my TitledPane to NOT open when it is in the process of expanding. I created a boolean variable isExpanding to set to true when it's expanding, and false after it's done expanding.
My issue is that, while using the SceneBuilder GUI, I have a TitledPane that when clicked it expands by default and I don't think I can change that. What I need is for when my var isExpanding == true then clicking on the TitledPane event is consumed, and it does nothing.
Here is my MouseEvent for when you click on the TitledPane. After the animation is completed in a different function the isExpanding is set to false.
#FXML
private void handleTitledPaneMouseClickDNSAction(MouseEvent event) {
if( dnsTitledPane.expandedProperty() == null || dnsTitledPane.isExpanded() == false ) {
animateCollapse( dnsPane, dnsTitledPane );
isExpanding = false;
} else {
expanTimeline = new Timeline(new KeyFrame(
Duration.millis( 15 ),
ae -> animateExpanstion( dnsPane, dnsTitledPane )));
expanTimeline.setCycleCount( Timeline.INDEFINITE );
expanTimeline.play();
isExpanding = true;
}
}

Its just a workaround. You can explicitly set titledPane Expansion as false in its mouse click handler.
Here's the code:
titlePane.setOnMouseClicked((evt) -> {
if(isExpanding)
titlePane.setExpanded(false);
else
titlePane.setExpanded(true);
});

Related

Qt hover event with pressed mouse on QQuickItem

I am using several instances of QQuickPaintedItem class that listen to hoverEnterEvent and hoverLeaveEvent, as well as mousePressEvent and mouseReleaseEvent. I have a need to select or deselect items when the cursor passes over them with the mouse button held down. However, the "hover" events are no longer handled when the button is held down. How can I fix it?
In this case, the sequence of actions is as follows:
mouse button is clicked over first element.
the cursor is dragged over the second element
when the cursor leaves the second element, it is highlighted
the same with the next element, until the mouse button is released.
'Item::Item( QQuickItem* parent )
: QQuickPaintedItem( parent )
{
setAcceptedMouseButtons( Qt::LeftButton );
setAcceptHoverEvents( true );
}
void Item::mousePressEvent( QMouseEvent* e )
{
myStateHandler->mousePressed = true;
}
void Item::mouseReleaseEvent( QMouseEvent* e )
{
myStateHandler->mousePressed = false;
}
void Item::hoverLeaveEvent( QHoverEvent* e )
{
QQuickItem::hoverEnterEvent( e );
if( myStateHandler->mousePressed )
{
isSelected = !isSelected;
update();
}
}
void Item::paint( QPainter* p )
{
if(isSelected )
{
p->setPen( Qt::NoPen );
p->setBrush( QColor( 205, 205, 0 ) );
p->drawRect( boundingRect() );
}
}'
Thank you in advance.

How to activate the OK button by pressing enter on TextField?

I have this class that generates a Alert Dialog with a field to enter a password, and want to activate the OK button when pressing Enter on the password field.
public class PasswordDialog extends Dialog<String> {
private PasswordField passwordField;
public PasswordDialog(boolean usuario) {
setTitle("Senha");
if (usuario == true){
setHeaderText("Por favor insira a senha do usuário.");
}else{
setHeaderText("Por favor insira a senha do administrador.");
}
ButtonType passwordButtonType = new ButtonType("OK", ButtonData.OK_DONE);
getDialogPane().getButtonTypes().addAll(passwordButtonType, ButtonType.CANCEL);
passwordField = new PasswordField();
passwordField.setPromptText("Password");
HBox hBox = new HBox();
hBox.getChildren().add(passwordField);
hBox.setPadding(new Insets(20));
HBox.setHgrow(passwordField, Priority.ALWAYS);
getDialogPane().setContent(hBox);
Platform.runLater(() -> passwordField.requestFocus());
setResultConverter(dialogButton -> {
if (dialogButton == passwordButtonType) {
return passwordField.getText();
}
return null;
});
}
public PasswordField getPasswordField() {
return passwordField;
}
}
Actually this should happen by default (at least that's the behaviour on JavaFX 11/Win 10), but you can also close the Dialog yourself by calling setResult and close.
Example closing on arrow keys:
// in constructor
passwordField.setOnKeyPressed(evt -> {
if (evt.getCode().isArrowKey()) {
setResult(passwordField.getText());
close();
}
});
For closing on pressing enter, use the onAction event of the PasswordField:
// in constructor
passwordField.setOnAction(evt -> {
setResult(passwordField.getText());
close();
});
For more complicated behaviour of the resultConverter, you could also use it for setting the result to avoid duplicate code:
setResult(getResultConverter().call(passwordButtonType));

How to handle wrong drop location in JavaFx?

In my GUI I create some dices (ImageView) and I can drag and drop them in one specific GridPane. When I drop a dice into the specific GridPane, the dice disappears from the initial location and it moves to the right position. This works fine only if I choose the right drop location.
The problem is how can I manage the wrong drop location?
Actually if I drop a dice in a wrong location (like outside the Gridpane) the dice disappears like it was moved to the right position.
I want to restore the dice to the original location if the dice isn't placed to the GridPane.
Is there a method can help me to check if I drop into the right location? Or something can prevent to drop into the wrong location?
You can check the transferMode property of the DragEvent passed to the onDragDone event:
dragSource.setOnDragDone(evt -> {
if (evt.getTransferMode() == null) {
System.out.println("drag aborted");
} else {
System.out.println("drag successfully completed");
}
});
Note: this requires you to mark the drag gesture as completed in the onDragDropped event handler using setDropCompleted. Example:
#Override
public void start(Stage primaryStage) {
Button source = new Button("Not dragged yet");
Button target = new Button("target");
HBox root = new HBox(20, source, target);
source.setOnDragDetected(evt -> {
Dragboard db = source.startDragAndDrop(TransferMode.COPY);
ClipboardContent content = new ClipboardContent();
content.putString(source.getText());
db.setContent(content);
});
source.setOnDragDone(evt -> {
source.setText(evt.getTransferMode() == null ? "failure" : "success");
});
target.setOnDragOver(evt -> {
if (evt.getDragboard().hasString()) {
evt.acceptTransferModes(TransferMode.COPY);
evt.consume();
}
});
target.setOnDragDropped(evt -> {
String value = evt.getDragboard().getString();
target.setText(value);
evt.setDropCompleted(true);
evt.consume();
});
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

How to add error popup for empty TextField input in Scenebuilder

I am making an application using Scenebuilder with JavaFX.
I have three inputs for a TableView:
Two TextField input1, input2.
One DatePicker.
When one or more of the input fields is empty and i click on the addButton, the object is added to the TableView.
How do I show an error popup which appears whenever i click on addButton and at least one field (input1, input2) is empty ?
addButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
if ((input1.getText() != null && !input1.getText().isEmpty()) &&
(input2.getText() != null && !input2.getText().isEmpty())){
//ADD CODE TO ADD THE ITEM HERE!
} else {
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Input fields empty");
alert.setContentText("Please fill all input fields");
alert.showAndWait();
}
}
});
PS : Here you can find different Alert Types depending on your needs.

How to get a JavaFX MenuItem to respond to a TAB KeyPress?

A JavaFX MenuItem can respond to most KeyPress events by setting an ActionEvent EventHandler. However, while the event handler does catch a KeyPress of KeyCode.ENTER, it does not catch a KeyCode.TAB KeyPress event. Apparently, some key events like TAB are handled at a deeper level. For example, the arrow keys enable traversal of the menu.
My ContextMenu is a list of completions of an email address string the user has started typing in a TextField. The users want to press the arrow keys to select the desired item, and the TAB key to execute the completion.
I can attach an event handler to the ContextMenu itself and catch the TAB keypress. But the event's Source is then the ContextMenu, and I can find no variables in the ContextMenu indicating which MenuItem was highlighted when the TAB key was pressed. MenuItem allows css style to control appearance of the menu item in focus, but it does not have any properties telling whether it is in focus or not.
I have tried futzing with the EventDispatchChain via MenuItem buildEventDispatchChain() to no avail. There seems to be no way to intercept the TAB KeyPress or otherwise determine which menu item was in focus when the TAB key was pressed.
Any suggestions?
If I get this right, you want to override the default keypressed listener to add your own response, so for that we have to find where it's applied.
To get this working, we've got to get our hands dirty with private API...
ContextMenu skin (ContextMenuSkin) uses a ContextMenuContent object, as a container with all the items. Each of these items are also in a ContextMenuContent.MenuItemContainer container.
We can override the keypressed listener on the parent container, while we can add a focusedProperty listener to the items on the items container.
Using this private API
import com.sun.javafx.scene.control.skin.ContextMenuContent;
this is working for me:
private ContextMenuContent.MenuItemContainer itemSelected=null;
#Override
public void start(Stage primaryStage) {
MenuItem cmItem1 = new MenuItem("Item 1");
cmItem1.setOnAction(e->System.out.println("Item 1"));
MenuItem cmItem2 = new MenuItem("Item 2");
cmItem2.setOnAction(e->System.out.println("Item 2"));
final ContextMenu cm = new ContextMenu(cmItem1,cmItem2);
Scene scene = new Scene(new StackPane(), 300, 250);
scene.setOnMouseClicked(t -> {
if(t.getButton()==MouseButton.SECONDARY || t.isControlDown()){
cm.show(scene.getWindow(),t.getScreenX(),t.getScreenY());
ContextMenuContent cmc= (ContextMenuContent)cm.getSkin().getNode();
cmc.setOnKeyPressed(ke->{
switch (ke.getCode()) {
case UP: break;
case DOWN: break;
case TAB: ke.consume();
if(itemSelected!=null){
itemSelected.getItem().fire();
}
cm.hide();
break;
default: break;
}
});
VBox itemsContainer = cmc.getItemsContainer();
itemsContainer.getChildren().forEach(n->{
ContextMenuContent.MenuItemContainer item=(ContextMenuContent.MenuItemContainer)n;
item.focusedProperty().addListener((obs,b,b1)->{
if(b1){
itemSelected=item;
}
});
});
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
Excellent! Thank you #jose! I ended up writing somewhat different code but
the key is using com.sun.javafx.scene.control.skin.ContextMenuContent, which provides
access to the ContextMenuContent.MenuItemContainer objects that hold the MenuItems.
In order to not break the existing UP/DOWN key behavior, I added a new handler
to the ContextMenuContent object; this handler only consumes the TAB KeyPress and
everthing else passes through to their normal handlers.
Looking at the ContextMenuContent class, I borrowed their existing method for
finding the focused item, so didn't have to add focusedProperty listeners.
Also, I'm on Java 1.7 and don't have lambdas and I use a very basic programming style.
public class MenuItemHandler_CMC <T extends Event> implements EventHandler {
public ContextMenuContent m_cmc;
public AddressCompletionMenuItemHandler_CMC(ContextMenuContent cmc){
m_cmc = cmc;
}
#Override
public void handle(Event event){
KeyEvent ke = (KeyEvent)event;
switch(ke.getCode()){
case TAB:
ke.consume();
MenuItem focused_menu_item = findFocusedMenuItem();
if(focused_menu_item != null){
focused_menu_item.fire();
}
break;
default: break;
}
}
public MenuItem findFocusedMenuItem() {
VBox items_container = m_cmc.getItemsContainer();
for (int i = 0; i < items_container.getChildren().size(); i++) {
Node n = items_container.getChildren().get(i);
if (n.isFocused()) {
ContextMenuContent.MenuItemContainer menu_item_container = (ContextMenuContent.MenuItemContainer)n;
MenuItem menu_item = menu_item_container.getItem();
return menu_item;
}
}
return null;
}
}
...Attach the additional handler
if(m_context_menu.getSkin() != null){
ContextMenuContent cmc = (ContextMenuContent)m_context_menu.getSkin().getNode();
MenuItemHandler_CMC menu_item_handler_cmc = new MenuItemHandler_CMC(cmc);
cmc.addEventHandler(KeyEvent.KEY_PRESSED, menu_item_handler_cmc);
}

Resources