ComboBox z ItemListenerem, IndexOfBoundsExceptions

0

Witam ponownie

w dalszym ciągu próbując poznać nieco lepiej Javę, napotkałem kolejny problem którego chyba sam nie rozwiążę.
Otóż, prosty program, który parsuje plik .xml , wyciąga z niego jakieś informacje i wyrzuca na TextArea.
Konkretnie powinien po wciścnięciu przycisku "wczytaj" otworzyć plik i wyciągnąć z niego co trzeba przy okazji tworząc listę Itemów do ComboBoxa.
I teraz gwóźdź programu: Chciałbym żeby po wczytaniu pliku , i stworzeniu listy , program automatycznie wyświetlał dane osoby wybranej w ComboBox , w polu TextArea.
Niestety po uruchomieniu , przy pierwszym wczytaniu rzuca mi wyjątkiem "IndexOfBoundsException, Index 0, Size 0".
Tak jakby ArrayList, z którego ma być pobrany obiekt był pusty ( tak ja to rozumiem ).
Ale jeśli instrukcje wypisania do TextArea obejmę przez try/catch(IndexOfBoundsException ex) to całość pójdzie dalej , i działa jak należy, przy wczytaniu tego samego pliku jeszcze raz, działa poprawnie już bez rzucania wyjątkiem.
bez try/catch wczyta do ComboBox tylko pierwszy Item i tyle.

Poniżej kod do obsługi ComboBoxa i Buttona, w mainie nie ma nic poza wywołaniem jednej funkcji.
Jeśli potrzeba to wkleję cały kod.

        combo.addItemListener(new ItemListener(){

            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange()==(ItemEvent.SELECTED)){
                    try {
                        osoba o=(osoba)listaOsob.get(combo.getSelectedIndex()); //obiekt klasy osoba , która przechowuje dane wczytane z XMLa
                        txtArea.setText(o.zwrocString());                       //listaOsob , to ArrayList stworzony z obiektów osoba
                    }catch (NullPointerException npex){
                        txtArea.setText("null pointer wylazł ");}
                    catch (IndexOutOfBoundsException ioob){
                        txtArea.setText("Out of bounds error \n"+ioob.getMessage());
                        
                    }
                };
            }
            
        });
        
        bZapisz.addActionListener(new ActionListener(){ //button wczytaj
            @Override
            public void actionPerformed(ActionEvent arg0) {
                Object e=arg0.getSource();
                //File plik;
                
                if (e==bZapisz){
                    combo.removeAllItems();
                    txtArea.setText(null);
                    JFileChooser wybierz = new JFileChooser();
                    int returnV=wybierz.showOpenDialog(null);
                    if (returnV==JFileChooser.APPROVE_OPTION){
                        plik=new wczytaj().wczytaj(wybierz.getSelectedFile());
                    }else {
                        System.out.println("nie wybrano pliku");
                    }
                    if (plik.exists()){
                        //txtArea.setText(plik.getAbsolutePath());
                        try {
                            doc=new wczytaj().ParseXML(plik);
                            XPathFactory xpf=XPathFactory.newInstance();
                            XPath path=xpf.newXPath();
                            Element root=doc.getDocumentElement();
                            NodeList children=root.getElementsByTagName("nazwisko");
                            for (int i=1;i<=children.getLength();i++){
                                String sI,sN,sT;
                                String XPn="/pracownicy/osoba["+i+"]/nazwisko";
                                String XPi="/pracownicy/osoba["+i+"]/imie";
                                String XPt="/pracownicy/osoba["+i+"]/telefon";
                                
                                sI=path.evaluate(XPi, doc);
                                sN=path.evaluate(XPn, doc);
                                sT=path.evaluate(XPt, doc);
                                
                                int j=i-1;
                                nOsoba=new osoba(sN,sI,sT);
                                combo.addItem(sI+" "+sN);
                                listaOsob.add(j, nOsoba);
                            }
                            
                        } catch (ParserConfigurationException ex) {
                            Logger.getLogger(plikerShort.class.getName()).log(Level.SEVERE, null, ex);
                        } catch (XPathExpressionException ex) {
                            Logger.getLogger(plikerShort.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                    else txtArea.setText("brak pliku");
                    }
                }
        });

0

Czytam Twój post i zastanawiam się jakie jest pytanie.
Z zamieszczonego kodu nie można wywnioskować kiedy ArrayList zawierająca osoby jest wypełniana. A dokładniej, czy wpierw dodajesz ItemListenera, czy wpierw wypełniasz ArrayList. Taka kolejność jest poprawna:

        for(int i=0;i<=9;i++)
        {
            model.addElement(new Integer(i));
            opisy.add(""+i);            
        }
        cb.addItemListener(new ItemListener()
        {
            public void itemStateChanged(ItemEvent ie)
            {
                System.out.println(opisy.get(cb.getSelectedIndex()));
            }
        }); 

a taka, generuje IndexOutOfBoundException

        cb.addItemListener(new ItemListener()
        {
            public void itemStateChanged(ItemEvent ie)
            {
                System.out.println(opisy.get(cb.getSelectedIndex()));
            }
        });
        for(int i=0;i<=9;i++)
        {
            model.addElement(new Integer(i));
            opisy.add(""+i);            
        }

Kiedy do JComboBoksa dodawany jest pierwszy element, to generowane jest zdarzenie ItemEvent, ale ArrayList jest jeszcze pusta.
Nie podobają mi się dwie rzeczy w kodzie metody actionPerformed:

                    if (returnV==JFileChooser.APPROVE_OPTION){
                        plik=new wczytaj().wczytaj(wybierz.getSelectedFile());
                    }else {
                        System.out.println("nie wybrano pliku");
                        //tu należy przerwać wykonywanie metody, np przez return;
                    }

Wielokrotne tworzenie obiektu typu JFileChooser jest bardzo nieprzyjazne dla użytkownika. Musi on wielokrotnie wędrować po katalogach. To powinno być pole w klasie, tworzone raz.

0

Z zamieszczonego kodu nie można wywnioskować kiedy ArrayList zawierająca osoby jest wypełniana. A dokładniej, czy wpierw dodajesz ItemListenera, czy wpierw wypełniasz ArrayList. Taka kolejność jest poprawna:

ArrayList jest wypełniana gdy wczytuję plik, czyli po naciśnięciu buttona.
naciśnięcie buttona jest obsługiwane przez metodę actionPerformed.

                                int j=i-1;
                                nOsoba=new osoba(sN,sI,sT);
                                combo.addItem(sI+" "+sN);
                                listaOsob.add(j, nOsoba);

Ztego co napisałeś wnioskuję, że ItemEvent jest generowany w linijce :

combo.addItem("");

a faktycznie pierwszy do listy pierwszy element jest dodany w następnej :

listaOsob.add(j,nOsoba);

Zaraz to sprawdzę.

Nie podobają mi się dwie rzeczy w kodzie metody actionPerformed:

Wydaje mi się że obiekt JFileChooser jest tworzony tylko raz, a tu:

if (returnV==JFileChooser.APPROVE_OPTION){
                        plik=new wczytaj().wczytaj(wybierz.getSelectedFile());
                    }else {
                        System.out.println("nie wybrano pliku");
                        //tu należy przerwać wykonywanie metody, np przez return;
                    }

jest tylko sprawdzenie czy zaakceptowano wybór.
Tak wygląda całe wczytanie pliku.Faktycznie można to zrobić w klasie, ale ten program jest dość prosty, i żaden plik więcej tu nie będzie wybierany.

JFileChooser wybierz = new JFileChooser();
                    int returnV=wybierz.showOpenDialog(null);
                    if (returnV==JFileChooser.APPROVE_OPTION){
                        plik=new wczytaj().wczytaj(wybierz.getSelectedFile());
                    }else {
                        System.out.println("nie wybrano pliku");
                    }
0

Wydaje mi się że obiekt JFileChooser jest tworzony tylko raz, a tu:

To Ci się źle wydaje, jest tworzony za każdym razem gdy użytkownik kliknie w przycisk.

ale ten program jest dość prosty, i żaden plik więcej tu nie będzie wybierany

Zabronisz użytkownikowi?

                    }else {
                        System.out.println("nie wybrano pliku");
                        //jeśli tu nie przerwiesz funkcji, to dwa wiersze niżej będziesz miał NPE (plik == null).
                    }
                    if (plik.exists()){
0

To Ci się źle wydaje, jest tworzony za każdym razem gdy użytkownik kliknie w przycisk.

Jak zwykle Masz rację, ale dzięki takim być może głupim pytaniom moja świadomość n/t Javy wzrasta.
Wyrzuciłem tworzenie JFileChoosera piętro wyżej:
Więc teraz obiekt jest tworzony razem z JFrame więc tylko raz.

        wybierz = new JFileChooser();        
		.
		.
		.
        bZapisz.addActionListener(new ActionListener(){ //button2
            @Override
            public void actionPerformed(ActionEvent arg0) {
                Object e=arg0.getSource();
                if (e==bZapisz)
				{
                    int returnV=wybierz.showOpenDialog(null);
                    if (returnV==JFileChooser.APPROVE_OPTION){
                        plik=new wczytaj().wczytaj(wybierz.getSelectedFile());
                }else {
                    System.out.println("nie wybrano pliku");
                    return;
					}
				}
			}
		});
 

brak returna to było przeoczenie, którego nie komentowałem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1