How to scroll JavaFX TextArea after setText - scroll

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.

Related

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.

JavaFX Toggle Group Change

i have a lot of Toggle Buttons! They are all in one toggle group, now i want to add a change listener! If there is one event one a toggle button in this group i want to have a event on the other buttons too!
How can i check that?
I made something like this, but it doesn't work very well:
triangleGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>()
{
#Override
public void changed(ObservableValue<? extends Toggle> arg0, Toggle arg1, Toggle arg2)
{
if (btnTriangle.getRotate() != iRotateCoord1)
{
closeTriangle();
}
}
});
So the triangleGroup represents my ToggleGroup! There i add a ChangeListener.... If there ia a Event, the current btnTriangle ( ToggleButton ) will close if it has not the rotate value like iRotate...
How can I get the Event when ever there is a Event on this Button Group or when ever there is a change...
Or is there a possibility to get all of the buttons that are in the Group?

onPrepareOptionsMenu acts weird if API is called from inside

I have a need to enable and disable menu items based on the API call response and it has to be called everytime the menu shows up.
I need asynctask because I have to show progressbar
#Override
public boolean onPrepareOptionsMenu (Menu menu) {
handleMenuItems(menu)
}
private void handleMenuItems(menu)
{
new AsyncTask<Void, Void, Void>(){
#Override
protected Void doInBackground(Void... params) {
//API call
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (progressDialog != null)
progressDialog.hide();
//necessary menu items are enabled and disabled
super.onPrepareOptionsMenu(menu);
}
#Override
protected void onPreExecute() {
if (progressDialog != null){
progressDialog.setMessage("Checking");
progressDialog.show();
}
super.onPreExecute();
}
}.execute();
}
Whenever I touch the options menu the onPrepareOptionsMenu gets called and the options menu doesn't appear then when I press it again the onPrepareOptionsMenu doesn't get called and the options menu appears.
I want the api to get called every time and menu to be shown whenever I touch for options menu.
You shouldn't show and hide progress dialog in OnPrepareOptionsMenu
Comment out the progress dialog codings and rest of the codes are ok and works as you expected
Note:
You have called super.OnPrepareOptionsMenu in OnPostExecute(UI
Thread)
As the progress bar is not needed don't remove the AsyncTask
otherwise app my crash
I don't think this code does what you expect it to do. When onPrepareOptionsMenu is called the first time, it only schedules the AsyncTask to run at a future time and not right away. Next it executes the super.onPrepareOptionsMenu line which should show whatever the option menu is set to be at that time. I think (have to check on that) the UI will then wait for the user input as it is showing some sort of a menu (maybe not what you had expected). When the menu is touched for the second time, I think it will dismiss the menu and that might be the time that the AsyncTask is executed which results in the first menu that you had expected in the first place. The second instance of the AsyncTask will not run until the first one finishes (unless executeOnExecutor is called instead of execute, but that is not the case here nor I believe it to help the expected outcome.)
You might want to have a "dummy" menu prepared (maybe something that shows "waiting...") and start a background thread where it builds up the right menu and then when it is ready update and display a new menu (programmatically).
I personally would advise in finding a way to build and show the menu on the UI thread (maybe prep the menu as the changes are made, ahead of time, and just show it when needed.
Kaamel

JavaFX: Focusing textfield programmatically

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();
}

How to handle OnBackKeyPress correctly?

To make it simple, I create a new app, which contains MainPage, and Page2.
MainPage has a button, which navigates to Page2. Also override MainPage.OnBackKeyPress:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
if (MessageBox.Show("Quit?", "Confirm", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
e.Cancel = true;
else
base.OnBackKeyPress(e);
}
Page2 is empty, except override OnNavigateFrom, to simulate a long time operation when back from Page2 to MainPage:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
System.Threading.Thread.Sleep(1000);
base.OnNavigatedFrom(e);
}
Everything is ok, but when I am at Page2, and press Back key 3-4 times very quickly, then I see the message box popup twice.
I expect the message box not shown, or at least show and hide. Is there anything wrong in my code? Thanks.
It depends on what you mean by very quickly...
The code looks OK (apart from the Thread.Sleep which is presumably to simulate a long operation on the UI thread).
I expect this is because while the UI thread is busy (or "sleeping") the back key presses are still registering and being sent to the app, and when the UI thread is available again it will process them one after the other.
This is a good example of why you should avoid blocking the UI thread.

Resources