Get the contents of selected textfield in JavaFX - javafx-2

I have a number of TextFields on my UI screen and on click of a button I want to get the contents of selected textfield.I am using JavaFX and isFocused() method is not working

The focus is moved to the Button before the EventHandler runs. This means the TextField is no longer focused at the time the EventHandler checks the property.
You could listen to the focusOwner property of the Scene though and save the last Node focused:
private static class FocusData {
private TextField textField = null;
public TextField getTextField() {
return textField;
}
public void setFocusedNode(Node node) {
this.textField = node instanceof TextField ? (TextField) node : null;
}
public boolean isTextField() {
return textField != null;
}
}
#Override
public void start(Stage primaryStage) {
final FocusData focusData = new FocusData();
Button btn = new Button("Print Text");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (focusData.isTextField()) {
System.out.println(focusData.getTextField().getText());
}
}
});
VBox root = new VBox();
for (int i = 0; i < 5; i++) {
root.getChildren().add(new TextField());
}
Scene scene = new Scene(root);
scene.focusOwnerProperty().addListener(new ChangeListener<Node>() {
#Override
public void changed(ObservableValue<? extends Node> observable, Node oldValue, Node newValue) {
focusData.setFocusedNode(oldValue);
}
});
root.getChildren().add(btn);
primaryStage.setScene(scene);
primaryStage.show();
}
If you're using a fxml you can get access to the scene by adding a listener to the scene property of some node in the initialize method and add/remove the listener in that listener.
root is some node in the following code snippet:
final ChangeListener<Node> listener = new ChangeListener<Node>() {
#Override
public void changed(ObservableValue<? extends Node> observable, Node oldValue, Node newValue) {
focusData.setFocusedNode(oldValue);
}
};
if (root.getScene() != null) {
root.getScene().focusOwnerProperty().addListener(listener);
}
root.sceneProperty().addListener(new ChangeListener<Scene>() {
public void changed(ObservableValue<? extends Scene> observable, Scene oldValue, Scene newValue) {
if (oldValue != null) {
oldValue.focusOwnerProperty().removeListener(listener);
}
if (newValue != null) {
newValue.focusOwnerProperty().addListener(listener);
}
listener.changed(null, null, null);
}
});

Related

behavior explanation: Using LiveData to update adapter with DiffUtil

I am updating my recyclerview by using LiveData as below:
viewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);
viewModel.getPurchaseList().observe(getViewLifecycleOwner(), new Observer<List<ProductsObject>>() {
#Override
public void onChanged(#Nullable List<ProductsObject> productsObjects) {
adapter.submitList(productsObjects);
//adapter.notifyDataSetChanged();
}
});
And I am using a FloatActionButton to change the value of my MutableLiveData as below:
FloatingActionButton fab = view.findViewById(R.id.cart_fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewModel.setPurchasePrice(0, 101.2);
}
});
All the data gets changed and onChanged is called as expected, but it only updates my recyclerview when I enable the adapter.notifyDataSetChanged();
If I create a new ProductsObject inside the FAB and submit a new list, the recyclerview gets updated without calling adapter.notifyDataSetChanged(); as below:
FloatingActionButton fab = view.findViewById(R.id.cart_fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//viewModel.setPurchaseAmount(0, 101.2);
ProductsObject prod = new ProductsObject("6666", 5, 152.2, "new product");
List<ProductsObject> prodList = new ArrayList<>();
prodList.add(prod);
adapter.submitList(prodList);
}
});
I appreciate if anyone could explain why.
Here is my adapter:
public class CartFragAdapter extends RecyclerView.Adapter<CartFragAdapter.CartFragViewHolder> {
private static final String TAG = "debinf PurchaseAdap";
private static final DiffUtil.ItemCallback<ProductsObject> DIFF_CALLBACK = new DiffUtil.ItemCallback<ProductsObject>() {
#Override
public boolean areItemsTheSame(#NonNull ProductsObject oldProduct, #NonNull ProductsObject newProduct) {
Log.i(TAG, "areItemsTheSame: old is "+oldProduct.getCode()+" ; new is "+newProduct.getCode());
return oldProduct.getCode().equals(newProduct.getCode());
}
#Override
public boolean areContentsTheSame(#NonNull ProductsObject oldProduct, #NonNull ProductsObject newProduct) {
Log.i(TAG, "areContentsTheSame: old is "+oldProduct.getPrice()+" ; new is "+newProduct.getPrice());
return oldProduct.getPrice() == newProduct.getPrice();
}
};
private AsyncListDiffer<ProductsObject> differ = new AsyncListDiffer<ProductsObject>(this, DIFF_CALLBACK);
#NonNull
#Override
public CartFragViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_purchase, parent, false);
return new CartFragViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull CartFragViewHolder holder, int position) {
final ProductsObject purchaseList = differ.getCurrentList().get(position);
holder.mCode.setText(purchaseList.getCode());
holder.mPrice.setText(String.valueOf(purchaseList.getPrice()));
holder.mDescription.setText(purchaseList.getDescription());
}
#Override
public int getItemCount() {
Log.i(TAG, "getItemCount");
return differ.getCurrentList().size();
}
public void submitList(List<ProductsObject> products){
Log.i(TAG, "submitList: products.size is "+products.size());
differ.submitList(products);
}
public class CartFragViewHolder extends RecyclerView.ViewHolder {
public TextView mCode, mPrice, mDescription;
public CartFragViewHolder(#NonNull View itemView) {
super(itemView);
mCode = (TextView) itemView.findViewById(R.id.item_productCode);
mPrice = (TextView) itemView.findViewById(R.id.item_productPrice);
mDescription = (TextView) itemView.findViewById(R.id.item_productDescription);
}
}
}
And here is my ViewModel:
public class MyViewModel extends ViewModel {
MutableLiveData<List<ProductsObject>> purchaseList = new MutableLiveData<>();
public LiveData<List<ProductsObject>> getPurchaseList() {
return purchaseList;
}
public void setPurchasePrice(int position, double price) {
List<ProductsObject> itemList = purchaseList.getValue();
if (itemList != null && itemList.get(position) != null) {
Log.i("debinf ViewModel", "setPurchaseAmount: "+itemList.get(position).getPrice());
itemList.get(position).setPrice(price);
purchaseList.postValue(itemList);
}
}
}
AsyncListDiffer saves only the reference of the list. This means that if you submit a modified list instead of submitting a new list, AsncListDiffer won't be able to detect any difference because both the previous list and the new list are referencing the same list with the same items.
To fix this you need to create a new list and new item. Change MyViewModel#setPurchasePrice as below:
public void setPurchasePrice(int position, double price) {
List<ProductsObject> itemList = purchaseList.getValue();
if (itemList != null && itemList.get(position) != null) {
List<ProductsObject> newList = new ArrayList<>();
for (int i = 0; i < itemList.size(); i++) {
ProductsObject prevProd = itemList.get(i);
if (i != position) {
newList.add(prevProd);
} else {
ProductsObject newProd = new ProductsObject(..., price, ...);
newList.add(newProd);
}
}
purchaseList.postValue(newList);
}
}

how to Update ListView after deletion

Here I'm using Custom Adapter by implementing listAdapter to Support buttons in the list items. When i click the Delete button it deletes currect row. But i can't able to refresh this listView.
File Structure is MainActivity -> FragmentClass-> this Custom class for the listAdpater.
public class Category_ListView_Custom_Adapter extends BaseAdapter implements ListAdapter{
private Realm realm;
private ArrayList<String> list = new ArrayList<>();
private Context context;
public Category_ListView_Custom_Adapter(ArrayList<String> list, Context context){
this.list = list;
this.context = context;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int i) {
return list.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(final int i, View view, ViewGroup viewGroup) {
View view1 = view;
realm = Realm.getDefaultInstance();
if(view == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.category_listview_row, null);
}
TextView listItemText = (TextView) view.findViewById(R.id.item);
listItemText.setText(list.get(i));
ImageView edit = (ImageView) view.findViewById(R.id.image);
ImageView delete = (ImageView) view.findViewById(R.id.delete);
edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// list.remove(i);
/// Toast.makeText(view.getContext(), "hey "+list.get(i).toString(), Toast.LENGTH_SHORT).show();
// notifyDataSetChanged();
Intent intent = new Intent(context, AddCategory.class);
intent.putExtra("category","expense");
intent.putExtra("subcategory", list.get(i));
context.startActivity(intent);
}
});
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
RealmResults<Category> categorylist = realm.where(Category.class).equalTo("Id",i+1).and().equalTo("Subcategory",list.get(i)).findAll();
for (Category category : categorylist) {
realm.beginTransaction();
categorylist.deleteFirstFromRealm();
realm.commitTransaction();
try {
context.notifyAll();
}catch (Exception e){
Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show();
}
// Expense.call_resume
}
}
});
return view;
}
}
Please Help me. Thank you.
You are .removing from a wrong view. Try to make root List<> static and do Class.list.get(i).remove or something like that.
Also, try to hide a view inside your get view.

populate listView from another listView

i want to populate a listView from the first listView that show all applications installed on the device, the second listView is on the second activity called "Blocked app" , my point is when i click on first listView items , the item should going to the second listView "Blocked App" for making an password interface thank uu and sorry for my english:
here is my MainActivity.Java code:
public class MainActivity extends AppCompatActivity {
private PackageManager packageManager=null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ListView userInstalledApps=(ListView)findViewById(R.id.installed_apps_list);
packageManager=getPackageManager();
final List<AppList>installedApp=getInstalledApps();
final AppAdapter installedAppAdapter=new AppAdapter(MainActivity.this,installedApp);
userInstalledApps.setAdapter(installedAppAdapter);
userInstalledApps.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
((ImageView)view.findViewById(R.id.ivlock)).setImageResource(R.drawable.unlocked);
// i shouuld write something here
}
});
}
private List<AppList> getInstalledApps()
{
List<AppList> resList=new ArrayList<AppList>();
List<PackageInfo> packs=getPackageManager().getInstalledPackages(0);
for(int i = 0; i < packs.size() ; i++)
{
PackageInfo pi= packs.get(i);
if ((isSystemPackage(pi)== false))
{
String appName=pi.applicationInfo.loadLabel(getPackageManager()).toString();
Drawable dIcon=pi.applicationInfo.loadIcon(getPackageManager());
resList.add(new AppList(appName,dIcon));
}
}
return resList;
}
private boolean isSystemPackage(PackageInfo pkgInfo)
{
return ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) !=0) ? true : false;
}
public class AppAdapter extends BaseAdapter
{
private LayoutInflater layoutInflater;
private List<AppList> listExtStorage;
public AppAdapter(Context context,List<AppList> customListView)
{
layoutInflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
listExtStorage=customListView;
}
#Override
public int getCount() {
return listExtStorage.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder listViewHolder;
if(convertView==null)
{
listViewHolder=new ViewHolder();
convertView=layoutInflater.inflate(R.layout.installed_app_list,parent, false);
listViewHolder.AppNameInList=(TextView)convertView.findViewById(R.id.app_name_in_list);
listViewHolder.AppIconInList=(ImageView)convertView.findViewById(R.id.apps_icon);
convertView.setTag(listViewHolder);
}
else
{
listViewHolder=(ViewHolder)convertView.getTag();
}
listViewHolder.AppNameInList.setText(listExtStorage.get(position).getName());
listViewHolder.AppIconInList.setImageDrawable(listExtStorage.get(position).getIcon());
return convertView;
}
}
static class ViewHolder
{
TextView AppNameInList;
ImageView AppIconInList;
}
public class AppList
{
private String name;
Drawable icon;
public AppList(String name, Drawable icon)
{
this.name=name;
this.icon=icon;
}
public String getName()
{
return name;
}
public Drawable getIcon()
{
return icon;
}
}
}

messed up dynamic radio buttons in ArrayAdapter

when i run my app, i get much more radiobuttons than i need. It seems the radiobuttons repeat themselves in the same group. I don't really understand what is is going on. Here is my custom ArrayAdapter. I would like to know the problem here
public class QuestionsListAdapter extends ArrayAdapter<QuestionProperties> {
List<QuestionProperties> list;
Context test;
public QuestionsListAdapter(Context context, int resource, List<QuestionProperties> list2) {
super(context,resource,list2);
test = context;
list =list2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
final RadioButton[] rB;
RadioHolder holder = new RadioHolder();
view= convertView;
LinearLayout.LayoutParams layoutParams = new RadioGroup.LayoutParams(
RadioGroup.LayoutParams.WRAP_CONTENT,
RadioGroup.LayoutParams.WRAP_CONTENT);
if(view == null)
{
LayoutInflater inflator = ((Activity) test).getLayoutInflater();
view = inflator.inflate(R.layout.question_list_row, null);
holder.questionTV = (TextView) view.findViewById(R.id.qTextView);
holder.radiogroup = (RadioGroup) view.findViewById(R.id.radio_group);
view.setTag(holder);
}
else{
//view = convertView;
holder = (RadioHolder) view.getTag();
}
holder.questionTV.setText(String.valueOf(list.get(position).getQuestionNo())+"."+" " + list.get(position).getQuestion());
rB=new RadioButton[list.get(position).possibleAns.length];
for(int count = 0; count<(list.get(position).possibleAns.length);count++)
{
rB[count]= new RadioButton(test);
rB[count].setId(count);
rB[count].setText(list.get(position).possibleAns[count]);
layoutParams.weight=1.0f;
layoutParams.setMargins(15, 0, 5, 10);
rB[count].setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
String a = String.valueOf(v.getId());
Toast.makeText(QActivity.context, "Radio Button "+ a,Toast.LENGTH_SHORT).show();
}
});
holder.radiogroup.addView(rB[count],layoutParams);
}
return view;
}
static class RadioHolder {
protected TextView questionTV;
protected RadioGroup radiogroup;
}
Finally after some hacks i solved it! i removed all the radio buttons in the else clause.
The solution..
public class QuestionsListAdapter extends ArrayAdapter<QuestionProperties> {
List<QuestionProperties> list;
RadioButton rB;
Context test;
RadioHolder holder;
String chkBtn;
LinearLayout.LayoutParams layoutParams = new RadioGroup.LayoutParams(
RadioGroup.LayoutParams.WRAP_CONTENT,
RadioGroup.LayoutParams.WRAP_CONTENT);
public QuestionsListAdapter(Context context, int resource, List<QuestionProperties> list2) {
super(context,resource,list2);
test = context;
list =list2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
holder = new RadioHolder();
view= convertView;
Log.v("ConvertView", String.valueOf(position));
if(view == null)
{
LayoutInflater inflator = ((Activity) test).getLayoutInflater();
view = inflator.inflate(R.layout.question_list_row, parent,false);
holder.questionTV = (TextView) view.findViewById(R.id.qTextView);
holder.radiogroup = (RadioGroup) view.findViewById(R.id.radio_group);
//holder.radiogroup.check(list.get(position).getSelectedAns());
view.setTag(holder);
//((RadioHolder) view.getTag()).radiogroup.setTag(list.get(position));
Log.v("holder setTag", String.valueOf(position));
}
else{
view = convertView;
holder = (RadioHolder)view.getTag();
//((RadioHolder)view.getTag()).radiogroup.getTag();
holder.radiogroup.removeAllViews();
}
holder.questionTV.setText(String.valueOf(list.get(position).getQuestionNo())+"."+" " + list.get(position).getQuestion());
configureRadioButtons(position);
chkBtn = String.valueOf(list.get(position).getSelectedAns());
holder.radiogroup.check(Integer.valueOf(chkBtn));
return view;
}
static class RadioHolder {
protected TextView questionTV;
protected RadioGroup radiogroup;
}
public void configureRadioButtons(int pos){
final int position = pos;
//rB=new RadioButton(test);
for(int count = 0; count<(list.get(position).possibleAns.length);count++)
{
rB= new RadioButton(test);
rB.setId(count);
rB.setText(list.get(position).possibleAns[count]);
layoutParams.weight=1.0f;
layoutParams.setMargins(15, 0, 5, 10);
holder.radiogroup.addView(rB,layoutParams);
rB.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
String a = String.valueOf(v.getId());
list.get(position).setSelectedAns(v.getId());
chkBtn = String.valueOf(list.get(position).getSelectedAns());
Toast.makeText(QActivity.context, "Radio Button "+ a,Toast.LENGTH_SHORT).show();
}
});
rB.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
}
});
holder.radiogroup.clearCheck();
Log.v("rB added to radiogroup", String.valueOf(position));
}
}

JavaFX: Custom traversing with key combinations

I have a table with one editing combobox and three editable text fields,
editable fields create like this:
public class EditingCell extends TableCell<Person, String> {
private TextField textField;
public EditingCell() {
}
#Override
public void startEdit() {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.requestFocus();
textField.selectAll();
}
});
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(textField.getText());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.TAB) {
commitEdit(textField.getText());
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
if (nextColumn != null) {
getTableView().edit(getTableRow().getIndex(), nextColumn);
}
}
}
});
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (!newValue && textField != null) {
commitEdit(textField.getText());
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
/**
*
* #param forward true gets the column to the right, false the column to the left of the current column
* #return
*/
private TableColumn<Person, ?> getNextColumn(boolean forward) {
List<TableColumn<Person, ?>> columns = new ArrayList<>();
for (TableColumn<Person, ?> column : getTableView().getColumns()) {
columns.addAll(getLeaves(column));
}
//There is no other column that supports editing.
if (columns.size() < 2) {
return null;
}
int currentIndex = columns.indexOf(getTableColumn());
int nextIndex = currentIndex;
if (forward) {
nextIndex++;
if (nextIndex > columns.size() - 1) {
nextIndex = 0;
}
} else {
nextIndex--;
if (nextIndex < 0) {
nextIndex = columns.size() - 1;
}
}
return columns.get(nextIndex);
}
private List<TableColumn<Person, ?>> getLeaves(TableColumn<Person, ?> root) {
List<TableColumn<Person, ?>> columns = new ArrayList<>();
if (root.getColumns().isEmpty()) {
//We only want the leaves that are editable.
if (root.isEditable()) {
columns.add(root);
}
return columns;
} else {
for (TableColumn<Person, ?> column : root.getColumns()) {
columns.addAll(getLeaves(column));
}
return columns;
}
}
}
And editable combo column create like this:
public static void createEditingComboColumn(final TableColumn<DUMMY_PurchaseOrderLine, String> Column, final ObservableList<String>comboData, final ObservableList<DUMMY_PurchaseOrderLine> Pdata) {
Column.setCellFactory(new Callback<TableColumn<DUMMY_PurchaseOrderLine,String>,TableCell<DUMMY_PurchaseOrderLine,String>>(){
#Override
public TableCell<DUMMY_PurchaseOrderLine, String> call(TableColumn<DUMMY_PurchaseOrderLine, String> p) {
final TableCell<DUMMY_PurchaseOrderLine, String> cell = new TableCell<DUMMY_PurchaseOrderLine, String>(){
#Override
public void updateItem(String item, boolean empty) {
if(item!=null){
final ComboBox editableComboBox = new ComboBox(comboData);
editableComboBox.setEditable(true);
editableComboBox.setMaxWidth(Double.MAX_VALUE);
Platform.runLater(new Runnable() {
#Override
public void run() {
editableComboBox.requestFocus();
}
});
setGraphic(editableComboBox);
}
}
};
cell.addEventFilter(KeyEvent.KEY_PRESSED,new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent t) {
activeRow = cell.getIndex();
if(t.getCode() == KeyCode.TAB||t.getCode() ==KeyCode.RIGHT){
cell.getTableView().edit(cell.getTableRow().getIndex(),cell.getTableView().getColumns().get(1) );
}
}
});
return cell;
}
});
}
Problem: when I press TAB/Right arrow key from any column work properly ,but when I press SHIFT+Tab /left arrow from second column focus goes out. How I focus first column (editing combo) from second column using keyboard?
Thanks....
The condition below in key event handler
if (t.getCode() == KeyCode.TAB)
will handle "TAB" + Any modifier, which means it will handle "Ctrl+TAB", "Alt+TAB", "Shift+Alt+TAB" etc. The same is true for "Right" key. So to handle the "TAB" alone only, the preferred way is to define KeyCodeCombination.
Your posted code is partial, not executable ie. not SSCCE. As I understand your problem lays in key event handling. Because of this I wrote a completely different code but demonstrates the explanation mentioned above. See example, and try to traverse forward with key combination different from "TAB" or "RIGHT". Try with "Ctrl+TAB" or "Alt+RIGHT". It will not work for them, as expected.
public class TraverseDemo extends Application {
#Override
public void start(Stage primaryStage) {
final TextField textField1 = new TextField();
final TextField textField2 = new TextField();
final TextField textField3 = new TextField();
// Diasble all traversals since we will manage them manually, for only textField2.
textField1.setFocusTraversable(false);
textField2.setFocusTraversable(false);
textField3.setFocusTraversable(false);
// Define key combinations for traversals.
final KeyCombination kcTab = KeyCodeCombination.valueOf("TAB");
final KeyCombination kcShiftTab = KeyCodeCombination.valueOf("Shift+TAB");
final KeyCombination kcRight = KeyCodeCombination.valueOf("RIGHT");
final KeyCombination kcLeft = KeyCodeCombination.valueOf("LEFT");
// Default initial focused textfield
requestFocus(textField2);
textField2.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (kcTab.match(t) || kcRight.match(t)) {
System.out.println("traverse forward");
requestFocus(textField3);
} else if (kcShiftTab.match(t) || kcLeft.match(t)) {
System.out.println("traverse backward");
requestFocus(textField1);
}
}
});
StackPane root = new StackPane();
root.getChildren().add(HBoxBuilder.create().spacing(10).children(textField1, textField2, textField3).build());
Scene scene = new Scene(root, 300, 150);
primaryStage.setScene(scene);
primaryStage.show();
}
private void requestFocus(final Node node) {
Platform.runLater(new Runnable() {
#Override
public void run() {
node.requestFocus();
}
});
}
public static void main(String[] args) {
launch(args);
}
}

Resources