Pressing on the Enter button is similar to mouse left click on focused node and pressing on Tab changes focused node. How can I disable it? I just want that these pressings do nothing.
Just try to installEventHandler create under public void initFX(JFXPanel fxPanel), it will work for you
public void initFX(JFXPanel fxPanel) {
//.............
//............. your code
installEventHandler(scene);
}
then into installEventHandler(final Scene keyNode) method
final EventHandler<javafx.scene.input.KeyEvent> keyEventHandler = new EventHandler<javafx.scene.input.KeyEvent>() {
public void handle(final javafx.scene.input.KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
//do nothing
}
if (keyEvent.getCode() == KeyCode.TAB) {
//Do nothing
}
}
Related
I know how to deal with left or right click separately, dragging, double-clicking, but I can't figure out how to do something if the user clicks left and right mouse buttons at the same time without interfering/causing other events to fire.
#Override
public void handle(Event event) {
if (event.getSource() instanceof Tile) {
Tile tile = (Tile) event.getSource();
if (event.getEventType().equals(MouseEvent.MOUSE_CLICKED)) {
if (((MouseEvent) event).getButton().equals(MouseButton.SECONDARY))
tile.toggleFlag();
else if (((MouseEvent) event).getClickCount() == 2)
mineField.massClick(tile);
}
if (event.getEventType().equals(MouseEvent.DRAG_DETECTED))
if (!((MouseEvent) event).getButton().equals(MouseButton.SECONDARY))
tile.startFullDrag();
if (event.getEventType().equals(MouseDragEvent.MOUSE_DRAG_ENTERED))
tile.arm();
if (event.getEventType().equals(MouseDragEvent.MOUSE_DRAG_EXITED))
tile.disarm();
if (event.getEventType().equals(MouseDragEvent.MOUSE_DRAG_RELEASED))
mineField.clickedTile(tile);
if (event.getEventType().equals(ActionEvent.ANY))
mineField.clickedTile(tile);
}
}
Also, if you see a problem with my code feel free to point it out, always looking to improve.
The simple version is this:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
StackPane root = new StackPane();
root.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
if( e.isPrimaryButtonDown() && e.isSecondaryButtonDown()) {
System.out.println( "Both down");
} else if( e.isPrimaryButtonDown()) {
System.out.println( "Primary down");
} else if( e.isSecondaryButtonDown()) {
System.out.println( "Secondary down");
}
});
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
If you prefer your own event happening when both buttons are pressed, you could try it this way:
public class Main extends Application {
BooleanProperty primaryMouseButtonDown = new SimpleBooleanProperty();
BooleanProperty secondaryMouseButtonDown = new SimpleBooleanProperty();
#Override
public void start(Stage primaryStage) {
try {
StackPane root = new StackPane();
root.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
primaryMouseButtonDown.setValue( e.isPrimaryButtonDown());
secondaryMouseButtonDown.setValue( e.isSecondaryButtonDown());
});
root.addEventFilter(MouseEvent.MOUSE_RELEASED, e -> {
primaryMouseButtonDown.setValue( e.isPrimaryButtonDown());
secondaryMouseButtonDown.setValue( e.isSecondaryButtonDown());
});
BooleanBinding binding = Bindings.and(primaryMouseButtonDown, secondaryMouseButtonDown);
binding.addListener( new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println( "Mouse Button Event: " + oldValue + " -> " + newValue);
}
});
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
There are 2 boolean properties, one for the primary button down and one for the secondary button down. Both properties are connected via a BooleanBinding. Whenever one of the properties change via the mouse event, an event is fired. So what's left to do is for you to check if newValue is true and fire your handling code.
Do something more along the lines of, watch for mouse presses, and set a boolean to true when a mousePressed event is called for left/right mouse button. Then later in the event look to see if both booleans for left and right are true. If they are, act on it as if both were pressed at the same time.
boolean mouse_1, mouse_2 = false;
public void mousePressed(MouseEvent e){
//The numbers are just made up I don't remember the actual codes for the buttons but it's simple enough to figure out.
if(e.getButton()==1){
mouse_1 = true;
}
if(e.getButton()==2){
mouse_2 = true;
}
if(mouse_1&&mouse_2){
//Your code here
}
}
public void mouseReleased(MouseEvent e){
if(e.getButton() == 1){
mouse_1 = false;
}
if(e.getButton() == 2){
mouse_2 = false;
}
}
Assume this is some sort of handler class... But this is the short for how to implement it.
I'm probably late to answer this question, but I'm going to post my solution in order to demonstrate how to handle single-button clicks separately from both buttons being clicked at the same time
Existing answers already explained how to detect both mouse buttons being clicked at the same time. But mouse events (click, press, and release) are still triggered by individual buttons and previous posters didn't address how to avoid these events from interfering with each other.
My solution is to track both buttons being pressed on mouse press and detect mouse clicks of any kind on mouse release:
//flag to track both buttons being pressed
private boolean wereBothButtonsPressed = false;
private void onMousePressed(MouseEvent e) {
//single button press sets flag to false
wereBothButtonsPressed = e.isPrimaryButtonDown() && e.isSecondaryButtonDown();
}
private void onMouseReleased(MouseEvent e) {
if (e.isPrimaryButtonDown() || e.isSecondaryButtonDown()) {
//do nothing if user is still holding the button
return;
}
if (wereBothButtonsPressed) {
System.out.prinln("Both buttons");
} else if (e.getButton() == MouseButton.PRIMARY) {
System.out.prinln("Only primary");
} else if (e.getButton() == MouseButton.SECONDARY) {
System.out.prinln("Only secondary");
}
}
You can set these handlers for specific events on specific controls or fit them into your method:
private boolean wereBothButtonsPressed = false;
#Override
public void handle(Event event) {
...
if (event.getEventType().equals(MouseEvent.MOUSE_PRESSED)) {
MouseEvent me = (MouseEvent) event;
wereBothButtonsPressed = me.isPrimaryButtonDown() && me.isSecondaryButtonDown();
} else if (event.getEventType().equals(MouseEvent.MOUSE_RELEASED)) {
MouseEvent me = (MouseEvent) event;
if (!me.isPrimaryButtonDown() && !me.isSecondaryButtonDown()) {
if(wereBothButtonsPressed) {
mineField.massClick(tile);
} else if(me.getButton() == MouseButton.PRIMARY) {
mineField.clickedTile(tile);
} else if(me.getButton() == MouseButton.SECONDARY) {
tile.toggleFlag();
}
}
...
I have a MenuItem that has a ScheduledCommand attached. When the user clicks on the menu, a new PopupPanel appears that has autoHide enabled. Now when the user clicks on the MenuItem while the popup is open, the panel gets closed, but immediately opens again as the PopupPanel's close event fires as a click event on the menu item. Can somebody tell me how can I prevent the PopupPanel from opening in this case?
My code is something like this:
#UiField
protected MenuItem menuItem;
....
menuItem.setScheduledCommand(new ScheduledCommand() {
#Override
public void execute() {
PopupPanel window = new PopupPanel();
window.init();
window.addCloseHandler(new CloseHandler<PopupPanel>() {
#Override
public void onClose(final CloseEvent<PopupPanel> event) {
// TODO Maybe something here?
}
});
window.show();
}
});
Create a single instance for the popup and use PopupPanel#isShowing method to hide or show the popup.
public class MyMenuClass{
private PopupPanel window;
....
....
menuItem.setScheduledCommand(new ScheduledCommand() {
#Override
public void execute() {
if(window==null){
window = new PopupPanel(true);
window.add(new Label("Hello close me!!!"));
}
if(window.isShowing()){
window.hide();
}else{
window.show();
}
}
}
OK, I managed to do this by checking whether the last hovered element on the Menubar was the menuItem that opens the window. To do this, I had to subclass the default MenuBar class and exposing the getSelectedItem() method (it was protected by default, why?)
#UiField
MyMenuBar myMenuBar;
....
menuItem.setScheduledCommand(new ScheduledCommand() {
#Override
public void execute() {
if (!wasHoveredWhenClosed) {
window.init();
window.addCloseHandler(new CloseHandler<PopupPanel>() {
#Override
public void onClose(final CloseEvent<PopupPanel> event) {
wasHoveredWhenClosed = myMenuBar.getSelectedItem() != menuItem;
}
});
window.show();
} else {
wasHoveredWhenClosed = false;
}
}
});
Sorry if this seems a little too easy, I'm brand new to JavaFX, this is my first little app built with it.
I am trying to make a bare bones chat client. I am using the JavaFX Scene builder to make the client UI, and a controller class connected to the FXML.
How can I make is so that the current text of in the text area is submitted to the server and the text area is cleared upon the enter key press, instead of using some kind of "send" button?
EDIT: Here is the code that is not working:
//...
public class FXMLDocumentController
{
//...
#FXML private TextArea messageBox;
//...
messageBox.setOnKeyPressed(new EventHandler<KeyEvent>()
{
#Override
public void handle(KeyEvent keyEvent)
{
if(keyEvent.getCode() == KeyCode.ENTER)
{
//sendMessage();
}
}
});
//...
This should get you what you want:
TextArea area;
//... (initialize all your JavaFX objects here...)
// wherever you assign event handlers...
area.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
String text = area.getText();
// do your thing...
// clear text
area.setText("");
}
}
});
I might add, that if you are so inclined to provide both a button and an enter key event, you could tie the event handler functions of both controls to a single common function in a way such as this:
Button sendButton;
TextArea area;
// init...
// set handlers
sendButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
sendFunction();
}
});
area.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
sendFunction();
}
}
});
// define send function
public void sendFunction() {
String text = this.area.getText();
// do the send stuff
// clear text (you may or may not want to do this here)
this.area.setText("");
}
Either way works, good luck.
You can use lambda expressions also ... I think it is more elegant and simply
textArea.setOnKeyPressed(event -> {
if(event.getCode() == KeyCode.ENTER){
//type here what you want
}
});
In addition to the other answers, I think it might be useful in some applications to not actually invoke the send function if the user pressed SHIFT+ENTER. In that case he/she maybe actually wanted a new line.
textArea.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
event.consume(); // otherwise a new line will be added to the textArea after the sendFunction() call
if (event.isShiftDown()) {
textArea.appendText(System.getProperty("line.separator"));
} else {
sendFunction();
}
}
});
If you don't want to send empty messages you can do something like this:
textArea.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
event.consume();
if (event.isShiftDown()) {
textArea.appendText(System.getProperty("line.separator"));
} else {
if(!textArea.getText().isEmpty()){
sendFunction();
}
}
}
});
Inspired by the JavaFX tutorial on http://docs.oracle.com/javafx/2/ui_controls/tree-view.htm I am wondering how could I change the behaviour to enter a cell in edit mode. The behaviour I would like to get is
on one left mouse-click: just select the cell
on two left mouse-clicks: select cell and invoke some action
on right-mouse-click: enter cell in edit mode
I tried to install a mouse event handler on the TreeView/TreeCell but it seems that the event is already consumed by TreeCellBehavior.
In class TreeCellBehvior there is the following method:
private void simpleSelect(MouseEvent e) {
TreeView tv = getControl().getTreeView();
TreeItem treeItem = getControl().getTreeItem();
int index = getControl().getIndex();
MultipleSelectionModel sm = tv.getSelectionModel();
boolean isAlreadySelected = sm.isSelected(index);
tv.getSelectionModel().clearAndSelect(index);
// handle editing, which only occurs with the primary mouse button
if (e.getButton() == MouseButton.PRIMARY) {
if (e.getClickCount() == 1 && isAlreadySelected) {
tv.edit(treeItem);
} else if (e.getClickCount() == 1) {
// cancel editing
tv.edit(null);
} else if (e.getClickCount() == 2/* && ! getControl().isEditable()*/) {
if (treeItem.isLeaf()) {
// attempt to edit
tv.edit(treeItem);
} else {
// try to expand/collapse branch tree item
treeItem.setExpanded(! treeItem.isExpanded());
}
}
}
}
I am not sure if can replace the TreeCellBehavior with my own implementation. Though this method is private I am not sure if this would be the right way to go. Any idea?
I worked it out by myself. I disable the editable of TreeView by default. For each TreeItem there is a context menu allowing to change the items name. If context menu action is invoked the TreeView is set to editable and TreeView.edit() with the current TreeItem is invoked. Now startEdit() is called behind the scenes and edit mode is active.
However I have got some strange behavior after enter is pressed and commitEdit() is called. This method checks if the cell is still in edit mode (which it is and therefore returns true) causing an internal invocation of cancelEdit()?!?! As a workaround I introduced a commitModeProperty and check in cancelEdit() if it is set.. otherwise the new text value would never be set.
Here is my code:
public class FolderTreeCell extends TreeCell<FolderCellType> {
// workaround for a strange behaviour in commitEdit.. see initTextFieldListener()
private BooleanProperty commitModeProperty = new SimpleBooleanProperty(false);
public FolderTreeCell() {
assert Platform.isFxApplicationThread();
}
private ContextMenu createContextMenu() {
MenuItem menuItem = new MenuItem("Change folder name");
menuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent evt) {
getTreeView().setEditable(true);
getTreeView().edit(getTreeItem());
}
});
return new ContextMenu(menuItem);
}
private void initTextFieldListener() {
getItem().textFieldProperty().get().setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent evt) {
if (evt.getCode() == KeyCode.ENTER) {
commitEdit(getItem()); // TODO calls updateItem() when isEditing() is true causing invocation of cancelEdit() ?!?!
}
}
});
}
#Override
public void commitEdit(FolderCellType newFolderCellType) {
commitModeProperty.set(true);
super.commitEdit(newFolderCellType);
commitModeProperty.set(false);
}
#Override
public void startEdit() {
super.startEdit();
setGraphic(getItem().getEditBox());
if (getItem().textFieldProperty().get().getOnKeyReleased() == null) {
initTextFieldListener();
}
getItem().textFieldProperty().get().selectAll();
getItem().textFieldProperty().get().requestFocus();
}
#Override
public void cancelEdit() {
super.cancelEdit();
getTreeView().setEditable(false);
if (!commitModeProperty.getValue()) {
getItem().resetCurrentEntry();
}
setGraphic(getItem().getViewBox());
}
#Override
public void updateItem(FolderCellType item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
setGraphic(item.getEditBox());
} else {
setGraphic(item.getViewBox());
if (getContextMenu() == null) {
setContextMenu(createContextMenu());
}
}
}
getTreeView().setEditable(false);
}
}
I've one Label in my custom FlowPanel which implements HasDoubleClickHandlers.
final Label label = new Label("Click here to write");
label.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
clicked();
}
});
final CustomFlowPanel customFlowPanel=new CustomFlowPanel();
customFlowPanel.addDoubleClickHandler(new DoubleClickHandler() {
#Override
public void onDoubleClick(DoubleClickEvent event) {
if (event.getSource() instanceof FlowPanel) {
doubleClicked();
}
}
});
custoFlowPanel.add(label);
The problem is when i double click to the label doubleClicked() should not execute.
How to prevent executing doubleClicked() when label is double clicked?
Thanks in advance!!!
You could just check the DoubleClickEvent if the label was clicked and if not you call doubleClicked().
customFlowPanel.addDoubleClickHandler(new DoubleClickHandler() {
#Override
public void onDoubleClick(DoubleClickEvent event) {
Element clicked = event.getNativeEvent();
if (!clicked.Equals(label.getElement())
{
doubleClicked();
}
}
});
I haven't tried it yet, but try adding a double click handler on the label and use Event.stopPropagation() on it. This prevents the event from being propagated to the parent.