Trouble with logic flow for filtering search method on CS50 Pokedex - cs50

The app compiles fine but initially it shows nothing in the list. When I use the search bar, it doesn't display my filtered information and when I get rid of search, the entire list is finally display. Any help would be really appreciated, this is my first time ever coding in Java.
Here is my adapter code.
public class PokedexAdapter extends RecyclerView.Adapter<PokedexAdapter.PokedexViewHolder> implements Filterable {
public static class PokedexViewHolder extends RecyclerView.ViewHolder {
public LinearLayout containerView;
public TextView textView;
PokedexViewHolder(View view) {
super(view);
containerView = view.findViewById(R.id.pokedex_row);
textView = view.findViewById(R.id.pokedex_row_text_view);
containerView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Pokemon current = (Pokemon) containerView.getTag();
Intent intent = new Intent(v.getContext(), PokemonActivity.class);
intent.putExtra("name", current.getName());
intent.putExtra("url", current.getUrl());
v.getContext().startActivity(intent);
}
});
}
}
private List<Pokemon> pokemon = new ArrayList<>();
private RequestQueue requestQueue;
private List<Pokemon> filteredPokemon = new ArrayList<>();
PokedexAdapter(Context context) {
requestQueue = Volley.newRequestQueue(context);
loadPokemon();
}
public void loadPokemon() {
String url = "https://pokeapi.co/api/v2/pokemon?limit=365";
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray results = response.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
String name = result.getString("name");
pokemon.add(new Pokemon(
name.substring(0, 1).toUpperCase() + name.substring(1),
result.getString("url")
));
}
notifyDataSetChanged();
} catch (JSONException e) {
Log.e("cs50", "Json error", e);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("cs50", "Pokemon list error");
}
});
requestQueue.add(request);
}
#NonNull
#Override
public PokedexViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.pokedex_row, parent, false);
return new PokedexViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull PokedexViewHolder viewholder, int position){
Pokemon results = pokemon.get(position);
viewholder.textView.setText(results.getName());
viewholder.containerView.setTag(results);
}
#Override
public int getItemCount() {
return filteredPokemon.size();
}
#Override
public Filter getFilter() {
return new PokemonFilter();
}
private class PokemonFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
// implement your search here
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0) {
//No filter implemented return whole list
results.values = pokemon;
results.count = pokemon.size();
}
else {
List<Pokemon> filtered = new ArrayList<>();
for (Pokemon pokemon : filtered) {
if (pokemon.getName().toUpperCase().startsWith(constraint.toString())) {
filtered.add(pokemon);
}
}
results.values = filtered;
results.count = filtered.size();
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredPokemon = (List<Pokemon>) results.values;
notifyDataSetChanged();
}
}
}
I really am not sure what is going on and given my knowledge of the subject, you could really help with understanding the logic better. Please let me know if there is any other information you would like from me about the code.

You might have already solved it and finished the Android tracks but this was the only thing I changed and it seemed to work after that.
for (Pokemon pokemon : pokemon) {
if (pokemon.getName().toUpperCase().startsWith(constraint.toString().toUpperCase()) {
filtered.add(pokemon);
}
}

Related

I want to know how to randomly display images in gridview through SwipeRefreshLayout

SwipeRefreshLayout refreshLayout = findViewById(R.id.refresh_grid);
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
getImages();
refreshLayout.setRefreshing(false);
}
});
getImages();
}
I want to know how to randomly display images in gridview through SwipeRefreshLayout
I want a UI like the site https://www.pinterest.com
I want to show random images on refresh to show a lot of images, can you tell me how?
thank you in advance
Below is the full code.
public class MainActivity extends AppCompatActivity {
private List<String> mImagesLinks = new ArrayList<>();
private GridView mGridView;
FloatingActionButton option_01;
FloatingActionButton option_02;
FloatingActionButton option_03;
FloatingActionButton option_04;
static final int PERMISSIONS_REQUEST = 0x0000001;
//종료팝업 전면광고 추가
private static final String TAG = "ted";
TedAdmobDialog nativeTedAdmobDialog;
int nCurrentPermission = 0;
private AdView mAdView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MobileAds.initialize(this, getString(R.string.admob_app_id));
mAdView = findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder().build();
mAdView.loadAd(adRequest);
checkPermission();
mGridView = findViewById(R.id.grid_view);
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
startActivity(new Intent(MainActivity.this, ImageActivity.class)
.putExtra("Link", mImagesLinks.get(i)));
}
});
option_01 = findViewById(R.id.option_01);
option_01.setOnClickListener(v -> {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName()));
startActivity(intent);
});
option_02 = findViewById(R.id.option_02);
option_02.setOnClickListener(v -> {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/developer?id=Project+J+Lab"));
startActivity(intent);
});
option_03 = findViewById(R.id.option_03);
option_03.setOnClickListener(v -> {
Intent myintent = new Intent(Intent.ACTION_SEND);
myintent.setType("text/plan");
String shereBoday = "Your Boday Here";
String shereSub = "\"http://play.google.com/store/apps/details?id=" + getPackageName();
myintent.putExtra(Intent.EXTRA_SUBJECT, shereBoday);
myintent.putExtra(Intent.EXTRA_TEXT, shereSub);
startActivity(Intent.createChooser(myintent, "shere Using"));
});
option_04 = findViewById(R.id.option_04);
option_04.setOnClickListener(v -> {
Intent email = new Intent(Intent.ACTION_SEND);
email.setType("plain/text");
String[] address = {"dhsthdwjd1#gmail.com"};
email.putExtra(Intent.EXTRA_EMAIL, address);
email.putExtra(Intent.EXTRA_SUBJECT, getPackageName());
email.putExtra(Intent.EXTRA_TEXT, "text");
startActivity(email);
});
SwipeRefreshLayout refreshLayout = findViewById(R.id.refresh_grid);
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
getImages();
refreshLayout.setRefreshing(false);
}
});
getImages();
}
private void getImages() {
Call<List<String>> imagesResponse = NetworkUtils.getInterface().loadImages();
imagesResponse.enqueue(new Callback<List<String>>() {
#Override
public void onResponse(Call<List<String>> call, Response<List<String>> response) {
if (response.isSuccessful()) {
mImagesLinks = response.body();
ImagesAdapter imagesAdapter = new ImagesAdapter(MainActivity.this, mImagesLinks);
mGridView.setAdapter(imagesAdapter);
imagesAdapter.notifyDataSetChanged();
} else {
Toast.makeText(MainActivity.this, R.string.error_response, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<List<String>> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
});
}
#Override
public void onBackPressed() {
//종료팝업 전면광고 추가
nativeTedAdmobDialog = new TedAdmobDialog.Builder(MainActivity.this, TedAdmobDialog.AdType.NATIVE, getString(R.string.banner_ad_unit_id_native))
.setOnBackPressListener(new OnBackPressListener() {
#Override
public void onReviewClick() {
}
#Override
public void onFinish() {
finish();
}
#Override
public void onAdShow() {
log("onAdShow");
nativeTedAdmobDialog.loadNative();
}
})
.create();
nativeTedAdmobDialog.show();
}
//종료팝업 전면광고 추가
private void log(String text) {
Log.d(TAG, text);
}
private void checkPermission() {
PermissionListener permissionlistener = new PermissionListener() {
#Override
public void onPermissionGranted() {
}
#Override
public void onPermissionDenied(List<String> deniedPermissions) {
}
};
TedPermission.with(this)
.setPermissionListener(permissionlistener)
.setPermissions(
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.SET_WALLPAPER,
Manifest.permission.READ_CONTACTS)
.check();
}
}
Just use Collections.shuffle(list); in your getImages() function.
Refer this for more information : https://www.geeksforgeeks.org/shuffle-or-randomize-a-list-in-java/

I Want To Itemonclicklister in Fragment on Spinner

This Is Main Fragment
Fragment:
private void getStock() {
dialog.show();
Retrofit retrofit = RetrofitClient.getRetrofitInstance();
apiInterface api = retrofit.create(apiInterface.class);
Call<List<Blocks>>call = api.getVaccineBlocks();
call.enqueue(new Callback<List<Blocks>>() {
#Override
public void onResponse(Call<List<Blocks>>call, Response<List<Blocks>> response) {
if (response.code() == 200) {
block = response.body();
spinnerada();
dialog.cancel();
}else{
dialog.cancel();
}
}
#Override
public void onFailure(Call<List<Blocks>> call, Throwable t) {
dialog.cancel();
}
});
}
private void spinnerada() {
String[] s = new String[block.size()];
for (int i = 0; i < block.size(); i++) {
s[i] = block.get(i).getBlockName();
final ArrayAdapter a = new ArrayAdapter(getContext(), android.R.layout.simple_spinner_item, s);
a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//Setting the ArrayAdapter data on the Spinner
spinner.setAdapter(a);
}
}
This Is Blocks Model
model:
package com.smmtn.book.models;
import java.io.Serializable;
public class Blocks implements Serializable {
public String id;
public String blockName;
public String blockSlug;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBlockName() {
return blockName;
}
public void setBlockName(String blockName) {
this.blockName = blockName;
}
public String getBlockSlug() {
return blockSlug;
}
public void setBlockSlug(String blockSlug) {
this.blockSlug = blockSlug;
}
}
here i need onitemclick with blockslug please any one can help, am new to android so i need some example.when on click i want take blockslug and load another method with that blockslug,like will get data from u "http://example.com/block/"+blockslug
i want to get blockslug from selected block
i hope guys i will get help
and sorry for my bad English,
First of all, you need to implement setOnItemSelectedListener. Refer to this https://stackoverflow.com/a/20151596/9346054
Once you selected the item, you can call them by making a new method. Example like below
public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
Toast.makeText(parent.getContext(),
"OnItemSelectedListener : " + parent.getItemAtPosition(pos).toString(),
Toast.LENGTH_SHORT).show();
final String itemSelected = parent.getItemAtPosition(pos).toString();
showBlockSlug(itemSelected);
}
And then, at the method showBlockSlug() , you can call Retrofit.
private void showBlockSlug(final String blockslug){
final String url = "http://example.com/block/"+ blockslug;
//Do your stuff...
}

Adapter does not update

When switching to Detail, the RecyclerView list is not updated, but rather, I get a blank screen when returning as in the picture. I know that when using NavigationUI, Fragment is recreated. In the code below, returning results in ruleAdapter! = Null. There is an idea when you click on the list item and go to Detail to make ruleAdapter = null, but I think this is not true.
public class RuleListFragment extends Fragment {
private RecyclerView recyclerView;
private RuleAdapter ruleAdapter;
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recycler, container, false);
recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
updateRule();
return view;
}
public void updateRule() {
RuleLab ruleLab = RuleLab.get(getActivity());
List<Rule> rules = ruleLab.getRules();
if (ruleAdapter == null) {
ruleAdapter = new RuleAdapter(rules);
recyclerView.setAdapter(ruleAdapter);
} else {
ruleAdapter.setRules(rules);
ruleAdapter.notifyDataSetChanged();
}
}
private class RuleHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private Rule rule;
private ImageView ruleIcon;
private TextView ruleTitle;
private ImageButton ruleElect;
private RuleHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
ruleIcon = itemView.findViewById(R.id.ruleIcon);
ruleTitle = itemView.findViewById(R.id.ruleTitle);
ruleElect = itemView.findViewById(R.id.ruleElect);
ruleElect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
boolean elect = !rule.isElect();
rule.setElect(elect);
RuleLab.get(getActivity()).updateRule(rule);
if (elect) {
ruleElect.setImageResource(R.drawable.ic_elect_on);
} else {
ruleElect.setImageResource(R.drawable.ic_elect_off);
}
updateRule();
}
});
}
private void bind (Rule rule) {
this.rule = rule;
int iconId = getResources().getIdentifier(rule.getIcon(), "drawable", getActivity().getPackageName());
ruleIcon.setImageResource(iconId);
ruleTitle.setText(rule.getTitle());
ruleElect.setImageResource(rule.isElect() ? R.drawable.ic_elect_on : R.drawable.ic_elect_off);
}
#Override
public void onClick(View view) {
Bundle args = new Bundle();
args.putSerializable("ruleId", rule.getId());
Navigation.findNavController(view).navigate(R.id.ruleFragment, args);
}
}
private class RuleAdapter extends RecyclerView.Adapter<RuleHolder> {
private List<Rule> rules;
private RuleAdapter (List<Rule> rules) {
this.rules = rules;
}
#NonNull
#Override
public RuleHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View view = layoutInflater.inflate(R.layout.item_recycler_rule, parent, false);
return new RuleHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RuleHolder holder, int position) {
Rule rule = rules.get(position);
holder.bind(rule);
}
#Override
public int getItemCount() {
return rules.size();
}
public void setRules(List<Rule> rules) {
this.rules = rules;
}
}
}
public class RuleLab {
private static RuleLab ruleLab;
private Context context;
private SQLiteDatabase database;
public static RuleLab get(Context context) {
if (ruleLab == null) {
ruleLab = new RuleLab(context);
}
return ruleLab;
}
private RuleLab (Context context) {
context = context.getApplicationContext();
database = new RuleBaseHelper(context).getWritableDatabase();
}
public List<Rule> getRules() {
List<Rule> rules = new ArrayList<>();
RuleCursorWrapper cursor = queryRules(null, null);
try {
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
rules.add(cursor.getRule());
cursor.moveToNext();
}
} finally {
cursor.close();
}
return rules;
}
public Rule getRule(int id) {
RuleCursorWrapper cursor = queryRules("_id = ?", new String[] {Integer.toString(id)});
try {
if (cursor.getCount() == 0) {
return null;
}
cursor.moveToFirst();
return cursor.getRule();
} finally {
cursor.close();
}
}
private static ContentValues getContentValues(Rule rule) {
ContentValues values = new ContentValues();
values.put("elect", rule.isElect() ? 1 : 0);
return values;
}
public void updateRule (Rule rule) {
String idString = Integer.toString(rule.getId());
ContentValues values = getContentValues(rule);
database.update("rules", values,
"_id" + " = ?",
new String[] {idString});
}
private RuleCursorWrapper queryRules (String whereClause, String[] whereArgs) {
Cursor cursor = database.query(
"rules",
null,
whereClause,
whereArgs,
null,
null,
"elect DESC"
);
return new RuleCursorWrapper(cursor);
}
}

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

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