JavaFX: Focusing textfield programmatically - events

I wrote an application with JavaFX which will only be usable with keyboard's arrows.
So I prevented MouseEvent on Scene's stage, and I "listen" to KeyEvents.
I also switched off focusability of all nodes :
for(Node n : children) {
n.setFocusTraversable(false);
Now I have some textfields, checkboxes, and buttons.
I would like to change the state of my input controls (textfield, checkbox,..) programatically: for example I would like to enter the textfield to edit the content programatically.
So my question is: how to enter in a non-focus-traversable textfield?
Because textfield.requestFocus(); doesn't work anymore since I set false to focustraversable property of my textfield.
Thanks

By
n.setFocusTraversable(false);
the node is made non-focus-traversable instead of non-focusable. It can still be focused for example by mouse or programmatically. Since you prevented mouse events, here the other option:
Platform.runLater(new Runnable() {
#Override
public void run() {
textfield.requestFocus();
}
});
Scene scene = new Scene(root);
EDIT: as per comment,
The javadoc of requestFocus states:
... To be eligible to receive the focus, the node must be part of a scene,
it and all of its ancestors must be visible, and it must not be
disabled. ...
So this method should be called after construction of scene graph as follow:
Scene scene = new Scene(root);
textfield.requestFocus();
However, Platform.runLater in the above will run at the end, after the main method start(), which ensures the call of requestFocus will be after scene graph cosntruction.
There maybe other reasons depending on the requestFocus implementation code.

set the .requestFocus(); on initialize method to fire on .fxml file loading controller
#Override
public void initialize(URL url, ResourceBundle rb) {
/* the field defined on .fxml document
#FXML
private TextField txtYear;
*/
txtYear.requestFocus();
}

Related

How do I add a controller (MVC) to my JavaFX application which I wrote in Java?

So I created an app containing the following classes: Main.java (where launch is along with window, scenes, buttons, etc.), Students.java (students), Connection.java (JDBC connects to MySQL database). There's also a class for login (with its own window, scenes, buttons), a class for charts (opens up a Pie Chart) as well as a confirmbox and alertbox (again with windows, scenes and buttons)...
I then read that good practice is to use MVC by looking through different tutorials plus previous answers here. Additionally the best tutorial was this: http://code.makery.ch/library/javafx-8-tutorial/part1/
The problem with this tutorial however was that it uses scene builder... I wish to create my application by writing code instead. And with my existing code (I can run the app on my IDE and buttons etc. work perfectly, fetches data from database too...) but what do I do with connector?
Do I create a new one?
(NOTE: all my classes are in .src)
A javafx controller is used to control UI elements. One way to attach controller is by adding fx:controller="controllerClassLocation" in your fxml file.
Another way would be to add controller in your code but this also involves fxml file as shown below.
String fxmlPath="MainLayout.fxml";
private Scene getScene(String fxmlPath, ControllerClass controller) {
FXMLLoader loader;
Parent parent;
Scene scene;
try {
//not FXMLLoader.load(getClass().getResource(fxmlPath)
loader = new FXMLLoader(getClass().getResource(fxmlPath));
loader.setController(controller);
parent = loader.load();
} catch (Exception e) {
e.printStackTrace();
return null;
}
scene = new Scene(parent);
return scene;
}
You use a controller if you want to bind your javafx UI elements.
If you do not want to use fxml file then you will have to code all the UI elements and bind to their respective functions and events for controlling them. For eg: In the below example a button btn is created and an event is handled when the button is clicked. The Button btn is binded to the function setOnAction(new EventHandler()) .
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 500, 250);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
You can create a controller class just like you would using FXML. Create an instance of the controller and pass on all references of your controls that you created in the code where you create all the controls.
Doing this way, you cannot leverage the benefits of FXML binding, such as fx:id, fx:controller and event bindings.

Why RecyclerView is not working setBackground function?

I tried many Times for setting backgroundColor on RecyclerView. but i try to scroll then background was removed.So I can fix backgroundColor in RecyclerView. Help me please.
Or I Want to change ForegroundColor.
My Issue Video
https://www.youtube.com/watch?v=C29qhPb44FE
I don't know the reason...
You need to first understand how RecyclerView works.
As you scroll through the cells, the views that gets out of the screen will be RECYCLED, and they will subsequently be reused to display the incoming views. Hence the name RecyclerView. This way, views will always be recycled and reused, thus saving memory.
What you need to do is something like this:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
//mList and mSelectedObjects are array lists
View yourView = holder.itemView.findViewById(R.id.your_view);
Object object = mList.get(position);
yourView.setTag(object);
yourView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Object object = (Object) v.getTag();
if (mSelectedObjects.contains(object)) {
mSelectedObjects.remove(object);
v.setBackground(null);
} else {
mSelectedObjects.add(object);
v.setBackgroundColor(Color.GRAY);
}
}
});
}
If you set programmatically the background color. You have to set every time the normal color and the selected color.
RecyclerViews are reusing their views. When an item leaves the screen it will be reused to increase the performance of the recycler view.
In this case when one set programmatically a background color and the item leaves the screen. It will be reused in the new item and the background color is still the same as when the item has left the screen.

Create a Sizeable Draggable Pane in JavaFX 8

I am attempting to create a "workspace" where users can open several containers to display distinct information. These need to be moveable and sizeable (ScrollPane for example).
I have successfully created the majority of the functionality - however one thing is really causing me issues and I am not able to figure out the issue.
I created the following class:
public class WorkspaceMoveableSizeablePane extends Pane
public WorkspaceMoveableSizeablePane(Node view) {
getChildren().add(view);
init();
}
private void init() {
...set up the event handlers....
I attempt to use this pane by wrapping an existing pane like so in my WorkspaceController:
#FXML private openSampleWorkspaceNode() {
FXMLLoader loader = new FXMLLoader();
Parent node = loader.load(
this.getClass().getResource("MyView.fxml").openStream());
WorkspaceMoveableSizeablePane dn = new WorkspaceMoveableSizeablePane(node);
pane.getChildren().add(dn);
}
When I open it this way - I can size my Pane and drag it, however the children on the "node" which is an anchor pane stay in their current positions rather than get hidden.
To correct this issue, I wrapped the AnchorPane in a ScrollPane in the FXML file. This allowed the resize to happen - and as expected the portions out of bounds were not visible and the scrollbars appeared, however the drag stopped. When I attempted to track the mouse dragged event, it actually didn't fire unless I was resizing the WorkspaceMoveableSizeablePane.
//Event Listener for MouseDragged
onMouseDraggedProperty().set(event -> {
System.out.println("You are in the Mouse Dragged Event");
if(isTopSelected){
dragPaneToNewLocation(event);
}else if(isResizingHeight) {
handleResizeHeight(event);
}else if(isResizingWidth) {
handleResizeWidth(event);
}
});
I reverted my FXML to AnchorPane and changed the WorkspaceMoveableSizeablePane as follows to see if that would help:
public class WorkspaceMoveableSizeablePane extends ScrollPane
public WorkspaceMoveableSizeablePane(Node view) {
setContent(view);
init();
}
private void init() {
...set up the event handlers....
As before the resize worked, but the drag didn't. The mouse dragged event never fired. Additionally, my scroll pane was blank with nothing in it.
So I am at a loss on how to proceed with this attempt.
Is there a limitation on the event handlers of the ScrollPane? Is there a different event I should be listening for? Thanks!!
The issue was that the ScrollPane was trapping the MouseDragged event.
Added an Event Filter and all is good...
addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
if(isTopSelected){
dragPaneToNewLocation(event);
}else if(isResizingHeight) {
handleResizeHeight(event);
}else if(isResizingWidth) {
handleResizeWidth(event);
}
});

JavaFX title bar RTL not supported?

I cant seem to find a way of making the title bar of my window be RTL.
I can make the inner nodes RTL by changing the node orientation property, but not the title bar.
So I get a really weird looking app where everything is RTL except the title bar.
How can I fix this?
You need to invoke setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT) on the scene before showing the stage primaryStage.show():
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
Scene scene = new Scene(root, 300, 275);
primaryStage.setScene(scene);
scene.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
See Node Orientation in JavaFX:
Because the orientation of children might be different for each child, the orientation of a child node when explicitly set can override the parent. For example, the top level window might be right-to-left, with the title and close box appearing on the left.
Just like what #Eng.Fouad said for scene object can be done for menubar.
Invoking
setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT)
for the menubar object makes it rtl:
MenuBar menuBar = new MenuBar();
menuBar.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
except that the arg for this method can be
NodeOrientation.LEFT_TORIGHT
which makes it left to right and
NodeOrientation.INHERIT
that gets its value from the parent container.

How to scroll JavaFX TextArea after setText

I am using JavaFX and I want to scroll a textarea to a certain position from the top after I have set the text of the textarea first.
I have tried to first set a listener on my textarea and inside it I use setText:
textArea.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(final ObservableValue<? extends String> observable, final String oldValue, final String newValue) {
textArea.setScrollTop(<Here I use the scroll position that I want>);
}
});
Then I try to set the text of the textarea by setText. But this does not scroll my textarea. I should add that I am loading in book long strings, but they load rather quickly. I have also tried to use a delay of 1 second inside the listener after I set the text and then scroll the textarea, and this turns out to work for me which might suggest that I use the wrong listener. I really want to be able to use a listener for this and not a delay.
All help is welcome!
What will happen if you use this code ?
textarea.addEventHandler(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
//textArea.setScrollTop(<Here I use the scroll position that I want>);
}
}
You should put the code of the listener in a separate Thread to make the sleep and then call the textArea.setScrollTop using Platform.runLater, in this way the sleep doesn't block the Platform Thread. If you don't the Platform Thread is blocked by the sleep and any pending operation on the TextArea will be blocked as well, if any of the pending operation is preventing the scrolling it will not finish and your call will be voided.

Resources