Display a ArrayList with in a JList (Swing) - java

I'm having an issue when I try to display a JList with an ArrayList. I'm using Action Listeners to execute all this:
ContactArray contactObject = new ContactArray();
addContactBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String firstName = firstNameField.getText();
String lastName = lastNameField.getText();
contactObject.addName(firstName + " " + lastName);
// contactObject.getNames().forEach(System.out::println);
}
});
viewContactButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String[] contacts = contactObject.getNames().toArray(new String[0]);
contactList = new JList(contacts);
contactList.setVisibleRowCount(5);
contactList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
add(new JScrollPane(contactList));
}
});
ContactArray class:
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class ContactArray {
private List<String> names;
public ContactArray() {
this.names = new ArrayList<>();
}
//add a name to list
public void addName(String name) {
if (!Objects.nonNull(names)) {
this.names = new ArrayList<>();
}
this.names.add(name);
}
//get the name attribute
public List<String> getNames() {
if (!Objects.nonNull(names)) {
this.names = new ArrayList<>();
}
return this.names;
}
}
I have managed to print the full names to the console with contactObject.getNames().forEach(System.out::println);which I put in comments, but can't seem to add them to JList. Normally, when I press on viewContactButton, it should display it.
Also, I'm using the Swing GUI form from IntelliJ IDEA.
Thanks for any help :)

I have managed to print the full names to the console
Well, you placed that code in the wrong place. The code should be placed when you actually use the List to create the JList. (ie. Maybe you have code somewhere that accidentally deletes the List sometime after it is created and before it is used)
I'm having an issue when I try to display a JList with an ArrayList
Well is the problem the ArrayList or did you also try to hardcode data in the JList? In order to solve a problem you need to know what the real problem is. Always first try to display hard coded data instead of dynamic data.
add(new JScrollPane(contactList));
I would guess the real problem is the above statement.
Whenever you add components to a visible frame the basic code should be:
add(...);
revalidate();
repaint();
You need to invoke the layout manager of the panel. Otherwise the component has a size of 0, so there is nothing to paint.

Related

javafx - .IndexOutOfBoundsException for table view

I would to ask why does IndexOutOfBoundsException appear when I try to delete the first row from the table view of supplement which is index 0. I am using a button to delete the row
Update: update the code to have a minimal reproducible example
SupplementTest.java
public class SupplementTest extends Application {
WindowController windowGUI = new WindowController();
Stage stageGUI;
Scene sceneGUI;
#Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader assignment2 = new FXMLLoader(getClass().getResource("SupplementFXML.fxml"));
Parent fxmlFile = assignment2.load();
try {
stageGUI = primaryStage;
windowGUI.initialize();
sceneGUI = new Scene(fxmlFile, 250, 350);
stageGUI.setScene(sceneGUI);
stageGUI.setTitle("Supplement");
stageGUI.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
WindowController.java
public class WindowController {
Stage newWindow = new Stage();
boolean deleteSupplement;
#FXML
private GridPane primaryGrid = new GridPane();
#FXML
private Label supplementLabel = new Label();
#FXML
private Button deleteBtn = new Button(), addBtn = new Button();
public TableView<Supplement> supplementView = new TableView<>();
int suppIndex;
ArrayList<Supplement> supplementList = new ArrayList<>();
// initialize Method
public void initialize() {
newWindow.initModality(Modality.APPLICATION_MODAL);
newWindow.setOnCloseRequest(e -> e.consume());
initializeWindow();
updateSupplementList();
}
public void initializeWindow() {
deleteSupplement = false;
TableColumn<Supplement, String> suppNameColumn = new TableColumn<>("Name");
suppNameColumn.setCellValueFactory(new PropertyValueFactory<>("supplementName"));
TableColumn<Supplement, Double> suppCostColumn = new TableColumn<>("Weekly Cost");
suppCostColumn.setCellValueFactory(new PropertyValueFactory<>("weeklyCost"));
supplementView.getColumns().addAll(suppNameColumn, suppCostColumn);
supplementView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
suppIndex = supplementView.getSelectionModel().getSelectedIndex();
addBtn.setOnAction(e -> {
supplementList.add(new Supplement("Test1", 10));
supplementList.add(new Supplement("Test2", 20));
supplementList.add(new Supplement("Test3", 15));
updateSupplementList();
});
// remove button
deleteBtn.setOnAction(e -> {
deleteSupplement = true;
deleteSupplement();
});
}
public void updateSupplementList() {
supplementView.getItems().clear();
if (supplementList.size() > 0) {
for(int i = 0; i < supplementList.size(); i++) {
Supplement supplement = new Supplement(supplementList.get(i).getSupplementName(),
supplementList.get(i).getWeeklyCost());
supplementView.getItems().add(supplement);
}
}
}
public void deleteSupplement() {
try {
ObservableList<Supplement> supplementSelected, allSupplement;
allSupplement = supplementView.getItems();
supplementSelected = supplementView.getSelectionModel().getSelectedItems();
supplementSelected.forEach(allSupplement::remove);
supplementList.remove(suppIndex);
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
Supplement.java
public class Supplement implements Serializable {
private String supplementName;
private double weeklyCost;
public Supplement() {
this.supplementName = "";
this.weeklyCost = 0.00;
}
public Supplement(String suppName, double weeklyCost) {
this.supplementName = suppName;
this.weeklyCost = weeklyCost;
}
public String getSupplementName() {
return supplementName;
}
public double getWeeklyCost() {
return weeklyCost;
}
public void setSupplementName(String supplementName) {
this.supplementName = supplementName;
}
public void setWeeklyCost(double weeklyCost) {
this.weeklyCost = weeklyCost;
}
}
How do I fix it so that when I delete any index in the table view the IndexOutOfBoundsException does not appear?
It's difficult to know for certain what is causing the exception, because your code is both incomplete (so no-one here can copy, paste, and run it to reproduce the error), and very confusing (it is full of seemingly-unnecessary code). However:
You seem to be doing two different things to delete the selected item(s) from the table:
supplementSelected = supplementView.getSelectionModel().getSelectedItems();
supplementSelected.forEach(allSupplement::remove);
which is an attempt to delete all selected items (though I don't believe it will work if more than one item is selected)
and
supplementList.remove(suppIndex);
which will delete the selected item, as defined by the selected index property in the selection model. (It is the currently selected item in a single selection model, or the last selected item in a multiple selection model, or -1 if nothing is selected.)
The latter will not work, because you only ever set suppIndex in your initialization code:
public void initializeWindow() {
// ...
suppIndex = supplementView.getSelectionModel().getSelectedIndex();
// ...
}
Of course, when this code is executed, the user has not had a chance to selected anything (the table isn't even displayed at this point), so nothing is selected, and so suppIndex is assigned -1. Since you never change it, it is always -1, and so when you call
supplementList.remove(suppIndex);
you get the obvious exception.
If you are only supporting single selection, and want to delete the currently selected item (or the last selected item in multiple selection), just get the selection at the time. You probably still want to check something is selected:
public void deleteSupplement() {
int selectedIndex = supplementView.getSelectionModel().getSelectedIndex();
if (selectedIndex >= 0) {
supplementView.getItems().remove(selectedIndex);
}
}
A slight variation on this, which I think is preferable, is to work with the actual object instead of its index:
public void deleteSupplement() {
Supplement selection = supplementView.getSelectionModel().getSelectedItem();
if (selection != null) {
supplementView.getItems().remove(selection);
}
}
Now, of course (in a theme that is common to a lot of your code), you can remove suppIndex entirely; it is completely redundant.
If you want to support multiple selection, and delete all selected items, then the code you currently have for that will cause an issue if more than one item is selected. The problem is that if a selected item is removed from the table's items list, it will also be removed from the selection model's selected items list. Thus, the selected items list (supplementSelected) in your code changes while you are iterating over it with forEach(...), which will throw a ConcurrentModificationException.
To avoid this, you should copy the list of selected items into another list, and remove those items:
public void deleteSupplement() {
List<Supplement> selectedItems
= new ArrayList<>(supplementView.getSelectionModel().getSelectedItems());
supplementView.getItems().removeAll(selectedItems);
}
Of course, this code also works with single selection (when the list is always either length 0 or length 1).
To address a couple of other issues: there is really no point in keeping a separate list of Supplement items. The table already keeps that list, and you can reference it at any time with supplementView.getItems(). (If you wanted to reference the list elsewhere, e.g. in a model in a MVC design, you should make sure that there is just a second reference to the existing list; don't create a new list.)
In particular, you should not rebuild the table entirely from scratch every time you add a new item to the list. Get rid of the redundant supplementList entirely from your code. Get rid of updateSupplementList() entirely; it is firstly doing way too much work, and secondly (and more importantly) will replace all the existing items just because you add a new one. This will lost important information (for example it will reset the selection).
To add new items, all you need is
addBtn.setOnAction(e -> {
supplementView.getItems().add(new Supplement("Test1", 10));
supplementView.getItems().add(new Supplement("Test2", 20));
supplementView.getItems().add(new Supplement("Test3", 15));
});
There are various other parts of your code that don't make any sense, such as:
The deleteSupplement variable. This seems to have no purpose.
The try-catch in the deleteSupplement method. The only exceptions that can be thrown here are unchecked exceptions caused by programming logic errors (such as the one you see). There is no point in catching those; you need to fix the errors so the exceptions are not thrown.
The #FXML annotations. You should never initialize fields that are annotated #FXML. This annotation means that the FXMLLoader will initialize these fields. In this case (as far as I can tell) these are not even associated with an FXML file at all, so the annotation should be removed.

How to fill in ComboBox from an API call?

I need to call an API, get a response, add items to ComboBox and update the view in the plugin.
Attached is the image of the combobox
I need to update the thread Ids as they load from an API. My custom Combobox for this is as shown below. I am not sure how to update the custom component from outside the class. Any help?
public class MyComboBox extends AnAction implements CustomComponentAction {
#Override
public void actionPerformed(#NotNull AnActionEvent e) {
}
#Override
public #NotNull JComponent createCustomComponent(#NotNull Presentation presentation, #NotNull String place) {
ComboBox<String> jComboBox = new ComboBox<>();
jComboBox.setMinLength(100);
jComboBox.addItem("Thread Id: " + UUID.randomUUID().toString());
jComboBox.addItem("Thread Id: " + UUID.randomUUID().toString());
jComboBox.setEnabled(true);
return jComboBox;
}
}
I needed a reference to the already instantiated combobox.
I got it with
MyComboBox myComboBox = (MyComboBox) ActionManager.getInstance().getAction("searchThread")
I added another method in MyComboBox:
public void updateUI(List<String> ids) {
this.ids = ids;
String[] array = this.ids.toArray(new String[0]);
jComboBox.setModel(new DefaultComboBoxModel<>(array));
jComboBox.setSelectedIndex(0);
jComboBox.updateUI();
}
and used:
myComboBox.updateUI(newList);
That solved my problem.

Wicket CheckGroup Ajax duplicities in check group model

I have a simple panel (the panel itself is part of bigger form) with CheckGroup. The checkboxes in the check group are generated in the list view component. I need to dynamicaly change this panel and upon every change I need to retrieve the selected items. The code of the panel basically looks like this:
CheckGroup<MyObject> group = new CheckGroup<MyObject>(ID, selectedObjects);
ListView<MyObject> objectList = new ListView<MyObject>(ID, values) {
#Override
protected void populateItem(ListItem<MyObject> item) {
Check<MyObject> check = new Check<MyObject>(TIME_CHECK, item.getModel());
Label l = new Label(TIME_LABEL, item.getModel());
item.add(check);
item.add(l);
}
}
group.add(objectList);
group.add(new AjaxFormChoiceComponentUpdatingBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget target) {
System.out.println("Selected objects: "+selectedObjects.size());
}
});
add(group);
Now, the problem is, whenever I click on the check box, the two identical objects are added to the selectedObjects list. And if I remove the AjaxFormChoiceComponentUpdatingBehavior, no objects are added to the list (which make sense, because I'm not submiting the form at this point).
I'm not exactly sure how to solve this problem and the best solution I came up with was getting the list and the going through it, removing duplicities.
Also, sorry for the title, but I have no idea how to name this problem.
Here's a little example to clarify the problem:
Lets say the check group is displaying these objects:
object 1
object 2
object 3
object 4
object 5
Then when I select object 1 the model of check group (=selectedObjects) will look like this:
object 1
object 1
This was a bug on wicket. I used version 7.1 then changed on version 7.10 and the problem solved!
Try
target.add(form);`
or
target.add(group);
or something similar, depending on your code.
You can try the following construction, recreate the checkgroup so that it is up to date. Maybe a bit overkill, but it should do the trick.
private CheckGroup<MyObject> group;
private IModel<MyObject> selectedObjects;
public MyCurrentPanel() {
selectedObjects = new CompoundPropertyModel<MyObject>(new MyObject());
group = createCheckGroup();
group.setOutputMarkupId(true);
add(group);
}
public CheckGroup<MyObject> createCheckGroup() {
CheckGroup<MyObject> newGroup = new CheckGroup<MyObject>(ID, MyCurrentPanel.this.selectedObjects);
ListView<MyObject> objectList = new ListView<MyObject>(ID, values) {
#Override
protected void populateItem(ListItem<MyObject> item) {
Check<MyObject> check = new Check<MyObject>(TIME_CHECK, item.getModel());
Label l = new Label(TIME_LABEL, item.getModel());
item.add(check);
item.add(l);
}
}
newGroup.add(objectList);
newGroup.add(new AjaxFormChoiceComponentUpdatingBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget target) {
System.out.println("Selected objects: "+selectedObjects.size());
CheckGroup<MyObject> updateGroup = createCheckGroup();
updateGroup.setOutpurMarkupId(true);
MyCurrentPanel.this.group.replaceWith(updateGroup);
MyCurrentPanel.this.group = updateGroup;
target.add(MyCurrentPanel.this.group);
}
});
}

Filtering JList based on JTextField

I have a JTextField and a JList in my program. The JList contains the user's contacts. I'd like to filter the JList based on the text on the JTextField. For example, if I type in "Mike" it will only show contacts including "Mike". When the user clears the JTextField it would reset the filter.
I know I could do this manually by having two arrays. One for the original contacts and one for the filtered ones. When the user changes the value of the JTextField I would go trought the original list, update the temporary list and update the JList. I just wonder if there is some built in feature to avoid manual labour.
The best way to do things like that is to have a ListModel implementation that filters its contents.
I don't know of any default filtering ListModel implementations, but it should not be too hard to do.
Here's a quick and dirty solution just to give you an idea. You might want to add more bells and whistles to it.
package test;
import java.util.ArrayList;
import javax.swing.AbstractListModel;
import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
public class FilteredListModel extends AbstractListModel {
public static interface Filter {
boolean accept(Object element);
}
private final ListModel _source;
private Filter _filter;
private final ArrayList<Integer> _indices = new ArrayList<Integer>();
public FilteredListModel(ListModel source) {
if (source == null)
throw new IllegalArgumentException("Source is null");
_source = source;
_source.addListDataListener(new ListDataListener() {
public void intervalRemoved(ListDataEvent e) {
doFilter();
}
public void intervalAdded(ListDataEvent e) {
doFilter();
}
public void contentsChanged(ListDataEvent e) {
doFilter();
}
});
}
public void setFilter(Filter f) {
_filter = f;
doFilter();
}
private void doFilter() {
_indices.clear();
Filter f = _filter;
if (f != null) {
int count = _source.getSize();
for (int i = 0; i < count; i++) {
Object element = _source.getElementAt(i);
if (f.accept(element)) {
_indices.add(i);
}
}
fireContentsChanged(this, 0, getSize() - 1);
}
}
public int getSize() {
return (_filter != null) ? _indices.size() : _source.getSize();
}
public Object getElementAt(int index) {
return (_filter != null) ? _source.getElementAt(_indices.get(index)) : _source.getElementAt(index);
}
}
In order to use it you need to set it to your JList and then call setFilter() as you need.
Here's an example:
ListModel source = new DefaultListModel(); // use a model of your choice here;
FilteredListModel filteredListModel = new FilteredListModel(source);
JList list = new JList(filteredListModel);
filteredListModel.setFilter(new FilteredListModel.Filter() {
public boolean accept(Object element) {
return false; // put your filtering logic here.
}
});
Once method setFilter() is invoked your JList on the screen is expected to change its contents accordingly.
Alternatively, you may want to implement an observer/observable pattern for your Filter, so you can re-filter the list without calling method setFilter(). You can experiment with that later. For the first iteration it's good enough as long as you call method setFilter every time user types something in your JTextField.
A simpler solution might be to use JTable, which does have a built-in ability to filter and sort (RowSorter). A single-column table is not too different from a list.
If you're okay with external libs, I would recommend Jide's QuickListFilterField/QuickTreeFilterField. With few lines of code, you could get a visually filterable JList/JTree, case sensitive/insensitive search, wildcard/regex matching etc ... Amazingly easy to use !

Writing something in JList

hey i have another problem. I created JList in my main window and now i want to add something to it. I do it this way...
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt)
{
Dodaj_Przedmiot dodaj_przedmiot = new Dodaj_Przedmiot(null, true);
dodaj_przedmiot.setVisible(true);
SterowanieBazy instance = SterowanieBazy.getInstance();
Zmienne_pomocnicze zp = new Zmienne_pomocnicze();
String przedmiot = zp.getPrzechowaj();
instance.dodajPrzedmiot(przedmiot);
String przedm[] = instance.zwrocPrzedmioty();
jList1.setListData(przedm);
}
what i want to write in that list is what i collect from my jDialogForm: dodaj_przedmiot
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
String sciezka = jTextField1.getText();
if (sciezka.length() > 0)
{
Zmienne_pomocnicze zp = new Zmienne_pomocnicze();
zp.setPrzechowaj(sciezka);
}
this.setVisible(false);
}
and i collect try to copy that date using this class
public class Zmienne_pomocnicze {
public String n;
public int a;
public void setPrzechowaj (String neew)
{
n = neew;
}
public String getPrzechowaj ()
{
return n;
}
}
i would be grateful for any ideas how to make it work.
This is somewhat difficult to follow, but from what I gather, you are using your Zmienne_pomocnicze class in two places, and both of them seem to do nothing.
First, in jButton2ActionPerformed you instantiate a new Zmienne_pomocnicze and try to get the data from it using the getPrzechowaj method. This will return n, but as you have just instantiated the instance, n is null. As I cant infer from the method names of the following code, I cant figure out what you want to do with that data, but this action is most certainly not what you want to do.
In the second case, jButton1ActionPerformed takes the value from the text field and then test for validity (legnth is greater than 0). If the validation passes, you then create a new Zmienne_pomocnicze, call setPrezechowaj with the text field value and then let the new object fall out of scope. Again, this is certainly not the desired effect.
It would be interesting to see what the flow of your program is supposed to be, ie what button triggers which jButton[12]ActionPerformed methods and how you expect them to interact.
Here's a simple example of adding entries to a JList.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.*;
public class JListTest {
private static final Random random = new Random();
public static final void main(String args[]) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
final JFrame frame = new JFrame("Test");
final DefaultListModel dlm = new DefaultListModel();
final JList list = new JList(dlm);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new JScrollPane(list));
frame.add(new JButton("Add") {
{
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dlm.addElement("A" + (random.nextInt(9000) + 1000));
}
});
}
}, BorderLayout.SOUTH);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
}
I always recommend reading the API for basic information.
If you read the JList API you will find a link to the Swing tutorial on "How to Use Lists". The example there shows how to dynamically add and remove entries from the ListModel.
Tutorials are a good place to start because you find working examples as well as explanations as to how the code works. Then, if required you can ask a specific question about a specific piece of code.
Not only that you now have a reference that might come in handy for other problems.

Categories

Resources