I stumbled on (in my eyes) a silly problem. However I don't find a solution for this (maybe because of not using the right search keywords, or by making it too difficult when it can be easy..)
Scenario:
I have a combobox with 500 customers. I have to select a single costumer.
In Swing, when the list was down and you started typing, it automatically jumps to the typed letter. E.g.:
Items:
Adam
Dirk
Freddy
...
Roger
Steven
Z person
When the combobox list is open, I just type 'R' and, in swing, it jumped to the first customer starting with 'R'. In javafx 2 it seems it does not have that behaviour... Is there some option that I have to enable or should I do something like using an editable combobox instead and make a filter() method that is fired on every keypress?
Edit: sollution based on Bhupendra's answer:
public class FilterComboBox<T> extends ComboBox<T> {
private final FilterComboBox<T> fcbo = this;
//private FilterComboBox fcbo = this;
private ObservableList<T> items;
private ObservableList<T> filter;
private String s;
private Object selection;
private class KeyHandler implements EventHandler< KeyEvent> {
private SingleSelectionModel<T> sm;
public KeyHandler() {
sm = getSelectionModel();
s = "";
}
#Override
public void handle(KeyEvent event) {
filter.clear();
// handle non alphanumeric keys like backspace, delete etc
if (event.getCode() == KeyCode.BACK_SPACE && s.length() > 0) {
s = s.substring(0, s.length() - 1);
} else {
s += event.getText();
}
if (s.length() == 0) {
fcbo.setItems(items);
sm.selectFirst();
return;
}
//System.out.println(s);
if (event.getCode().isLetterKey()) {
for (T item : items) {
if (item.toString().toUpperCase().startsWith(s.toUpperCase())) {
filter.add(item);
//System.out.println(item);
fcbo.setItems(filter);
//sm.clearSelection();
//sm.select(item);
}
}
sm.select(0);
}
}
}
public FilterComboBox(final ObservableList<T> items) {
super(items);
this.items = items;
this.filter = FXCollections.observableArrayList();
setOnKeyReleased(new KeyHandler());
this.focusedProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (newValue == false) {
s = "";
fcbo.setItems(items);
fcbo.getSelectionModel().select((T)selection);
}
}
});
this.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (newValue != null) {
selection = (Object) newValue;
}
}
});
}
}
The simplest form of a filter combo box would be as the code below. But it would need more work to refine it.
Also, if the list is huge, as in your case, there might be a performance issues as we are looping thru' the entire collection on each key press.
public class FilterComboBox extends ComboBox< String > {
private ObservableList< String > items;
private class KeyHandler implements EventHandler< KeyEvent > {
private SingleSelectionModel< String > sm;
private String s;
public KeyHandler() {
sm = getSelectionModel();
s = "";
}
#Override
public void handle( KeyEvent event ) {
// handle non alphanumeric keys like backspace, delete etc
if( event.getCode() == KeyCode.BACK_SPACE && s.length()>0)
s = s.substring( 0, s.length() - 1 );
else s += event.getText();
if( s.length() == 0 ) {
sm.selectFirst();
return;
}
System.out.println( s );
for( String item: items ) {
if( item.startsWith( s ) ) sm.select( item );
}
}
}
public FilterComboBox( ObservableList< String > items ) {
super( items );
this.items = items;
setOnKeyReleased( new KeyHandler() );
}
}
Wouldn't code like this be sufficient?
comboBox.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
String s = jumpTo(event.getText(), comboBox.getValue(), comboBox.getItems());
if (s != null) {
comboBox.setValue(s);
}
}
});
...
static String jumpTo(String keyPressed, String currentlySelected, List<String> items) {
String key = keyPressed.toUpperCase();
if (key.matches("^[A-Z]$")) {
// Only act on letters so that navigating with cursor keys does not
// try to jump somewhere.
boolean letterFound = false;
boolean foundCurrent = currentlySelected == null;
for (String s : items) {
if (s.toUpperCase().startsWith(key)) {
letterFound = true;
if (foundCurrent) {
return s;
}
foundCurrent = s.equals(currentlySelected);
}
}
if (letterFound) {
return jumpTo(keyPressed, null, items);
}
}
return null;
}
This will jump to the first item when you press a letter. If you press that letter again, it jumps to the next item starting with that letter, wrapping back to the first if there are no more items starting with that letter.
I could not really get Perneel's solution to suit my needs. Bhupendra's was nice but there was one detail : it selects the last matching item. If you have numbers from 0 to 20 (as String), it would return 19 instead of 1 if "1" is typed...
The code below adds the line requiered to solve this.
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.ComboBox;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
// TODO: Auto-generated Javadoc
/**
* The Class FilterComboBox.
*/
public class FilterComboBox extends ComboBox< String >
{
/** The items. */
private ObservableList< String > items;
/**
* The Class KeyHandler.
*/
private class KeyHandler implements EventHandler< KeyEvent >
{
/** The sm. */
private SingleSelectionModel< String > sm;
/** The s. */
private String s;
/**
* Instantiates a new key handler.
*/
public KeyHandler()
{
sm = getSelectionModel();
s = "";
}
/* (non-Javadoc)
* #see javafx.event.EventHandler#handle(javafx.event.Event)
*/
#Override
public void handle( KeyEvent event )
{
// handle non alphanumeric keys like backspace, delete etc
if( event.getCode() == KeyCode.BACK_SPACE && s.length()>0)
{
s = s.substring( 0, s.length() - 1 );
}
else if(event.getCode() != KeyCode.TAB )
{
s += event.getText();
}
if( s.length() == 0 )
{
sm.selectFirst();
return;
}
System.out.println( s );
for( String item: items )
{
if( item.startsWith( s ) )
{
sm.select( item );
return;
}
}
}
}
/**
* Instantiates a new filter combo box.
*
* #param items the items
*/
public FilterComboBox( ObservableList< String > items )
{
super( items );
this.items = items;
setOnKeyReleased( new KeyHandler() );
}
}
This component is a ComboBox that only takes String as an input and which can be filtered by typing some character. All credit goes to Bhupendra, I only posted this code so as to prevent other people from having to think too much about this common problem.
Last edit : added a test to prevent TAB from being considered as a character (allow to navigate in a form without breaking the component)
Here is another option how to do it.
An example from the site https://tech.chitgoks.com was taken as the basis.
It features an elegant solution, which, if desired, can be used in the previous examples too.
When typing, the list automatically scrolls, it is very convenient.
import com.sun.javafx.scene.control.skin.ComboBoxListViewSkin;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
class SearchComboBox<T> extends ComboBox<T> {
private static final int IDLE_INTERVAL_MILLIS = 1000;
private Instant instant = Instant.now();
private StringBuilder sb = new StringBuilder();
public SearchComboBox(Collection<T> choices) {
this(FXCollections.observableArrayList(choices));
}
public SearchComboBox(final ObservableList<T> items) {
this();
setItems(items);
getSelectionModel().selectFirst();
}
public SearchComboBox() {
super();
this.addEventFilter(KeyEvent.KEY_RELEASED, event -> {
if (event.getCode() == KeyCode.ESCAPE && sb.length() > 0) {
resetSearch();
}
});
this.setOnKeyReleased(event -> {
if (Duration.between(instant, Instant.now()).toMillis() > IDLE_INTERVAL_MILLIS) {
resetSearch();
}
instant = Instant.now();
if (event.getCode() == KeyCode.DOWN || event.getCode() == KeyCode.UP || event.getCode() == KeyCode.TAB) {
return;
} else if (event.getCode() == KeyCode.BACK_SPACE && sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1);
} else {
sb.append(event.getText().toLowerCase());
}
if (sb.length() == 0) {
return;
}
boolean found = false;
for (int i = 0; i < getItems().size(); i++) {
if (event.getCode() != KeyCode.BACK_SPACE && getItems().get(i).toString().toLowerCase().startsWith(sb.toString())) {
ListView listView = getListView();
listView.getSelectionModel().clearAndSelect(i);
scroll();
found = true;
break;
}
}
if (!found && sb.length() > 0)
sb.deleteCharAt(sb.length() - 1);
}
);
// add a focus listener such that if not in focus, reset the search process
this.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
resetSearch();
} else {
scroll();
}
});
}
private void resetSearch() {
sb.setLength(0);
instant = Instant.now();
}
private void scroll() {
ListView listView = getListView();
int selectedIndex = listView.getSelectionModel().getSelectedIndex();
listView.scrollTo(selectedIndex == 0 ? selectedIndex : selectedIndex - 1);
}
private ListView getListView() {
return ((ComboBoxListViewSkin) this.getSkin()).getListView();
}
}
I improved this example in two ways.
All code is encapsulated in a class - nothing needs to be connected from the outside.
If the user doesn't show activity for some time, then the search string is reset. An alternative solution is how to reset the search: press the Backspace key, or make the ComboBox lose focus.
Related
I have a RecyclerView list of CardViews. Each CardView has a CheckBox that the user can select/de-select. The initial selection launches a Contextual Action Bar. An ArrayList of Integers is used to hold the checkbox state (selected or un-selected). Scrolling and the checkbox views appear to be working correctly. However, when I click a checkbox to de-select it, it remains checked and another checkbox on a different CardView is de-selected? What am I missing here?
Please note that I do not want to set up a ClickListener in onBindViewHolder.
MainActivity.java
public class MainActivity extends AppCompatActivity implements
RecyclerItemClickListener {
private ArrayList<ListItem> allList;
boolean isMultiSelect = false; // for the Contextual Action Bar status
private ActionMode mActionMode;
ArrayList<ListItem> multiselect_list = new ArrayList<>();
private ArrayList<Integer> checkedListItems = new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
...
// method from the Adapter, the ItemHolder's onClick()
public void onCheckBoxClick(View view, int position) {
if (!isMultiSelect) {
multiselect_list = new ArrayList<>();
isMultiSelect = true;
if (mActionMode == null) {
mActionMode = startSupportActionMode(actionModeCallback);
}
}
multi_select(position);
}
public void multi_select(int position) {
if (mActionMode != null) {
// If a CardView with a CheckBox already selected is clicked on, then the
// Checkbox is unselected, the position is removed from the multiselect_list
// and the size of the list is decremented by +1.
if (multiselect_list.contains(allList.get(position))) {
multiselect_list.remove(allList.get(position));
}
else {
// If an empty CheckBox on a CardView is clicked on, then the position is added to the
// multiselect_list and the size of the list is incremented by +1.
multiselect_list.add(allList.get(position));
}
if (multiselect_list.size() == 1) {
mActionMode.setTitle("1 selected");
}
else if (multiselect_list.size() >= 2) {
mActionMode.setTitle(multiselect_list.size() + " selected");
}
else if (multiselect_list.size() == 0) {
mActionMode.finish();
}
refreshAdapter();
}
}
public void refreshAdapter() {
adapter.selectedItemsList = multiselect_list;
adapter.mListItems = allList;
adapter.notifyDataSetChanged();
}
private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
Menu context_menu;
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_action_mode, menu);
context_menu = menu;
return true;
}
...
}
Adapter.java
public class MyRecylerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public ArrayList<ListItem> mListItems;
private Context mContext;
private RecyclerItemClickListener recyclerItemClickListener;
public ArrayList<ListItem> selectedItemsList = new ArrayList<>();
public MyRecylerAdapter(Context context, ArrayList<ListItem> listItems, ArrayList<ListItem> selectedList) {
this.mContext = context;
this.mListItems = listItems;
this.selectedItemsList = selectedList;
}
private class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private CheckBox chkSelected;
private ItemHolder(final View itemView) {
super(itemView);
chkSelected = (CheckBox) itemView.findViewById(R.id.chkSelected);
chkSelected.setOnClickListener(this);
}
public void onClick(View v) {
int adapterPos = getAdapterPosition();
// send data to MainActivity() for starting CAB.
if (recyclerItemClickListener !=null) {
recyclerItemClickListener.onCheckBoxClick(v, adapterPos);
}
if (((CheckBox)v).isChecked()) {
checkedListItems.add(adapterPos);
}
else {
checkedListItems.remove(adapterPos);
}
}
void bind(int position) {
if (checkedListItems.contains(position)) {
chkSelected.setChecked(true);
}
else {
chkSelected.setChecked(false);
}
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false);
final ItemHolder itemHolder = new ItemHolder(view);
...
return itemHolder;
}
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
final ListItem listItem = mListItems.get(position);
final ItemHolder itemHolder = (ItemHolder) holder;
itemHolder.bind(position);
...
}
In Adpater declare an ArrayList of integers
ArrayList<Integer> checkedItems = new ArrayList();
And in bind function
void bind(int position) {
if (checkedItems.contains(position)) {
chkSelected.setChecked(true);
}
else {
chkSelected.setChecked(false);
}
}
In OnBindviewholder add below code
CompoundButton.OnCheckedChangeListener onCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int adapterPos = getAdapterPosition();
if(isChecked) {
checkedItems.add(Integer.valueOf(adapterPos));
}else {
checkedItems.remove(Integer.valueOf(adapterPos));
}
}
}
I try to make my comboBox multiple selection
and this my code:
this multiSelectComboBox:
import java.util.List;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.WindowEvent;
import com.extjs.gxt.ui.client.event.WindowListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.CheckBoxListView;
import com.extjs.gxt.ui.client.widget.Dialog;
import com.extjs.gxt.ui.client.widget.form.TriggerField;
import com.extjs.gxt.ui.client.widget.layout.FillLayout;
import com.google.gwt.user.client.Element;
public class MultiSelectComboBox<D extends ModelData> extends TriggerField<String> {
private Dialog checkBoxListHolder;
private CheckBoxListView<D> listView;
private ListStore<D> store;
private String delimiter = ",";
private boolean readOnly;
public MultiSelectComboBox() {
store = new ListStore<D>();
listView = new CheckBoxListView<D>();
}
#Override
protected void onTriggerClick(ComponentEvent ce) {
super.onTriggerClick(ce);
checkBoxListHolder.setSize(getWidth(), 200);
listView.setWidth(getWidth());
checkBoxListHolder.setPosition(getAbsoluteLeft(),
getAbsoluteTop() + getHeight());
if(checkBoxListHolder.isVisible()) {
checkBoxListHolder.hide();
}
else {
checkBoxListHolder.show();
}
}
#Override
protected void onRender(Element target, int index) {
super.onRender(target, index);
checkBoxListHolder = new Dialog();
checkBoxListHolder.setClosable(false);
checkBoxListHolder.setHeaderVisible(false);
checkBoxListHolder.setFooter(false);
checkBoxListHolder.setFrame(false);
checkBoxListHolder.setResizable(false);
checkBoxListHolder.setAutoHide(false);
checkBoxListHolder.getButtonBar().setVisible(false);
checkBoxListHolder.setLayout(new FillLayout());
checkBoxListHolder.add(listView);
listView.setStore(store);
checkBoxListHolder.addWindowListener(new WindowListener(){
#Override
public void windowHide(WindowEvent we) {
setValue(parseCheckedValues(listView));
}
});
}
private String parseCheckedValues(CheckBoxListView<D> checkBoxView) {
StringBuffer buf = new StringBuffer();
if(checkBoxView != null) {
List<D> selected = checkBoxView.getChecked();
int index = 1, len = selected.size();
for(D c : selected) {
buf.append(c.get(listView.getDisplayProperty()));
if(index < len) {
buf.append(delimiter);
}
index++;
}
}
return buf.toString();
}
public CheckBoxListView<D> getListView() {
return listView;
}
public void setListView(CheckBoxListView<D> listView) {
this.listView = listView;
}
public ListStore<D> getStore() {
return store;
}
public void setStore(ListStore<D> store) {
this.store = store;
}
public String getDelimiter() {
return delimiter;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
public boolean isReadOnly() {
return readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
}
then use this class in my project:
// ...
ListStore<UserDTO> employeeList = getUsers();
MultiSelectComboBox<ModelData> multiUsers = new MultiSelectComboBox<ModelData>();
multiUsers.getListView().setDisplayProperty("label");
//multiUsers.setStore(employeeList);
multiUsers.getStore().add(getModelData());
multiUsers.setFieldLabel("Employee");
//multiUsers.setEditable(true);
//multiUsers.setMaxHeight(200);
simpleForm.add(multiUsers, formData);
// ...
private List<ModelData> getModelData() {
List<ModelData> list = new ArrayList<ModelData>();
List<NctrUserDTO> employees= employeeList.getModels();
for (int i=0; i<employeeList.getCount(); i++) {
ModelData data = new BaseModel();
data.set("label", employeeList.getAt(i).getName());
list.add(data);
}
return list;
}
but the comboBox appear empty or have not any values when i pass values from employeeList but when i tried with static string values this works fine, i dont know why this problem occur, any suggestion please ??
It sounds as if your looking for something like the option multiple select boxes, if so you can look up the source code on Github for pointers - or rather than re-inventing the wheel, just use that GwtBootstrap3 component
I created a parser that reads files formatted in the following way:
version="v4.5.32"
name="Test File"
date="2513.04.02"
players=
{
{
first_name="John"
last_name="Smith"
country=12
id=0
}
{
first_name="Mario"
last_name="Rossi"
country=56
id=1
}
}
next_player_id=2
matches=
{
22 47 88 1045 1048 3511
}
settings=
{
match_prefix="game"
match_reward_scalar=1,55
match_sets_points=
{
0,5 0,75 1,0
}
next_event_id=56
next_event_fired=false
next_event_probability=0,33
}
...
Basically, those files contain a list of key/value pairs in which keys are always a string and values can be either a simple value (boolean, date, float, integer, string), a record (a sublist of key/value pairs like settings) or an array (composed by simple values like matches or records like players). In order to parse and handle those values I created 3 simple classes.
1) MyPair
public sealed class MyPair
{
public MyKey Key { get; }
public MyValue Value { get; }
public MyPair(MyKey key, MyValue value) { ... }
public override String ToString()
{
return String.Concat(Key, " = ", Value);
}
}
2) MyKey
public sealed class MyKey
{
public String Name { get; }
... // other properties set by checking the name in the constructor
public Key(String name) { ... }
public override String ToString()
{
return Name;
}
}
3) MyValue
public sealed class MyValue
{
private readonly dynamic m_UnderlyingValue;
private readonly MyValueCategory m_Category;
public dynamic UnderlyingValue
{
get { return m_UnderlyingValue; }
}
public Boolean Container
{
get { return ((m_Category == ValueCategory.Array) || (m_Category == ValueCategory.Record)); }
}
public MyValueCategory Category
{
get { return m_Category; }
}
public MyValue(DateTime underlyingValue)
{
if (underlyingValue == null)
throw new ArgumentNullException("underlyingValue");
m_UnderlyingValue = underlyingValue;
m_Category = MyValueCategory.DateTime;
}
public MyValue(Boolean underlyingValue) { ... }
public MyValue(Double underlyingValue) { ... }
public MyValue(Int64 underlyingValue) { ... }
public MyValue(MyPair[] underlyingValue) { ... }
public MyValue(MyValue[] underlyingValue) { ... }
public MyValue(String underlyingValue) { ... }
public override String ToString()
{
switch (m_Category)
{
case MyValueCategory.Array:
return String.Concat("Array[", m_UnderlyingValue.Length, "]");
case MyValueCategory.Boolean:
return String.Concat("Boolean[", (m_UnderlyingValue ? "true" : "false"), "]");
case MyValueCategory.DateTime:
return String.Concat("DateTime[", m_UnderlyingValue.ToString("yyyy.MM.dd", CultureInfo.InvariantCulture), "]");
case MyValueCategory.Float:
return String.Concat("Float[", m_UnderlyingValue.ToString("F3", CultureInfo.InvariantCulture), "]");
case MyValueCategory.Integer:
return String.Concat("Integer[", m_UnderlyingValue.ToString("F0", CultureInfo.InvariantCulture), "]");
case MyValueCategory.Record:
return String.Concat("Record[", m_UnderlyingValue.Length, "]");
default:
return String.Concat("Text[", m_UnderlyingValue, "]");
}
}
}
public enum MyValueCategory
{
Array,
Boolean,
DateTime,
Float,
Integer,
Record,
Text
}
The parsing process works like a charm and returns me a MyValue instance that works like a container / root node for everything I parsed.
I'm not using WPF forms, just plain Winforms. I would like to populate a TreeView control hierarchically with the parsed data and then make that data responsive to the changes made to the TreeView nodes. I really can't figure out how to bind data to the control itself and allow a mirrored manipulation.
Any suggestion please?
You can populate your TreeView recursively with this code:
protected override void OnLoad( EventArgs e )
{
base.OnLoad( e );
MyValue root = new MyParser().Parse( "MyFilename.own" );
Populate( treeView1.Nodes, root.UnderlyingValue );
}
protected void Populate( TreeNodeCollection nodes, IList list )
{
if( list is MyPair[] )
{
foreach( MyPair pair in list )
{
TreeNode node = new TreeNode();
node.Text = pair.ToString();
node.Tag = pair;
nodes.Add( node );
if( pair.Value.Container )
Populate( node.Nodes, (IList)pair.Value.UnderlyingValue );
}
}
if( list is MyValue[] )
{
foreach( MyValue value in list )
{
TreeNode node = new TreeNode();
node.Text = value.ToString();
node.Tag = value;
nodes.Add( node );
if( value.Container )
Populate( node.Nodes, (IList)value.UnderlyingValue );
}
}
}
Result looks then like that:
As #Reza Aghaei already mentioned it is not possible to do this via data-binding. You have to maintain your lists manually after adding/removing a node. Setting node.Tag to the corresponding pair or value makes it easy for you to find and modify them.
In my programme I've a large array of strings(say 1600) which I want to show as a CheckBox list. The array is actually the location of all the songs in one's PC, and thus can gradually be bigger. I don't wanna use ListView<String> as the CheckBox list is more efficient and above all visually better for my purpose. I'm currently doing the below :
private void listAll() {
songs = MediaManager.getAllSongs();
VBox vb = new VBox();
vb.setSpacing(5);
vb.getStyleClass().add("background");
if (songs != null) {
Service s = new Service() {
#Override
protected Task createTask() {
Task t = new Task() {
#Override
protected Object call() throws Exception {
for (String song : songs) {
addSong(song, vb);
c++;
updateMessage(c+" songs");
}
return null;
}
};
t.messageProperty().addListener((obs,o,n)->{
count.setText(n);
});
return t;
}
};
s.start();
ScrollPane sp = new ScrollPane(vb);
getChildren().add(sp);
}
}
private void addSong(String n, Pane p) {
String toAdd = "";
Media m = new Media(Paths.get(n).toUri().toString());
if (m.getMetadata().get("title") == null || !(m.getMetadata().get("title").equals(""))) {
toAdd = m.getSource().split("/")[m.getSource().split("/").length - 1].replace("%20", " ").replace(".mp3", "");
} else {
toAdd = ((String) m.getMetadata().get("title"));
}
SongBox s = new SongBox(toAdd);
s.setUserData(n);
p.getChildren().add(s);
}
class SongBox extends CheckBox {
public SongBox(String t) {
this();
setText(t);
}
public SongBox() {
super();
setOnAction((ActionEvent evt) -> {
if (isSelected()) {
if (!playNow.isVisible()) {
playNow.setVisible(true);
}
path = (String) getUserData();
selected.add((String) getUserData());
} else {
selected.remove((String) getUserData());
if (selected.size() == 0) {
playNow.setVisible(false);
}
}
});
}
}
First of all, that is not showing the complete array. Whenever I'm going back and returning to it, the number of songs get changed. Secondly, the whole UI is getting sluggish(sometimes also hanging my PC). Moreover, I can't cancel the Service when I've gone to the previous window, as it's always returning false. Anyone have a better approach?
Good Day Developers,
I already implement this fantastic library called "Android-PanesLibrary" by Kenrick Rilee. and what i want to achive is something like this.
But i end up doing like this :
my first problem if in showDetails method i delete the comment symbol, it will showing up an error. but if i make the method empty, it will run just like the second image.
my objective is how can this be done just using string array data?
Any ideas or help would be greatly appreciated.
Environment : Windows 7, Android Studio, Genymotion.
This is MainMenuFragment.java :
public class MainMenuFragment extends android.app.ListFragment {
private static int sExampleNum = 0;
protected final String TAG = "mainmenuFragment" ;
#ViewById(R.id.menu_listview)
protected ListView menuListView ;
private View parentView;
int mCurCheckPosition = 0;
public MainMenuFragment() {
super();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Resources res = getResources();
String [] mainmenulistview = res.getStringArray(R.array.listview_main_menu);
ArrayAdapter<String> connectArrayToListView = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_activated_1,mainmenulistview);
setListAdapter(connectArrayToListView);
if (savedInstanceState != null) {
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
showDetails(mCurCheckPosition);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
// if I un-comment on method bellow, it will result an error.
void showDetails(int index) {
//mCurCheckPosition = index;
//getListView().setItemChecked(index, true);
//PCDesktopFragment_ pcDesktop = (PCDesktopFragment_) getFragmentManager().findFragmentById(R.id.sub_one_fragment);
//if (pcDesktop == null || pcDesktop.getShownIndex() != index) {
// welder_pipe_reg = PCDesktopFragment_.newInstance(index);
// android.app.FragmentTransaction ft = getFragmentManager().beginTransaction();
// ft.replace(R.id.sub_one_fragment, pcDesktop);
// ft.commit();
//}
}
}
and then i already create a class called PCDesktopFragment.java that extends ListFragment (this should be showing up on second fragment using listfragment)
#EFragment(R.layout.sub_one_menu)
public class PCDesktopFragment_ extends ListFragment {
View v;
public static int i;
public static PCDesktopFragment_ newInstance(int index){
PCDesktopFragment_ f = new PCDesktopFragment_();
Bundle args = new Bundle();
args.putInt("index", index);
index = i;
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
inflater.inflate(R.layout.sub_one_menu, container, false);
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (i == 0) {
String [] sub_a = {"Test1","Test2"};
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, sub_a));
}
}
//#ItemClick(R.id.sub_one_listview)
//protected void handleDomainClick(int position) {
// Fragment f = null ;
// if (position == 0) {
// f = new PCDesktopFragment_();
// }
// Activity a = getActivity();
// if (f != null && a != null && a instanceof FragmentLauncher)
// ((FragmentLauncher) a).addFragment(this, f);
//}
}