JList uzupelnianie

0

Witam

Mam mały problem z uzupełnianiem JList.

W swoim programie tworze nowy JDialog który ma listę z elementami, która z kolei jest pobierana z servera.
Aby okno dialogu od razu się otwierało zamiast czekać na ściągnięcie elementów z servera wstawiłem wypełnianie do SwingWorkera.

Problem w tym, że raz na 10-15 razy lista jest pusta(na pewno się ładuje, widać mrugnięcie z danymi).
Repaint nie pomaga.

Może znacie najczęstsze tego przyczyny? Na co zwrócić uwagę?

0

Podejrzewam, że zmiany listy robisz w którejś funkcji, która nie jest w EDT. Stąd taki efekt, zależny jak się wątki będą realizować. Pokaż kod tego SwingWorker'a.

0

Troche śmieci jest bo próbuje i próbuje


    private class FillList extends SwingWorker<Integer, Integer> 
    {

        private JLabel loadLabel = null;
        private JDialog dialog = null;
        private JTabbedPane pane = null;

          public FillList(JLabel loadLabel, JDialog dialog, JTabbedPane pane) 
          {
              this.loadLabel = loadLabel;
              this.dialog = dialog;
              this.pane = pane;
          }

          @Override
          protected Integer doInBackground() throws Exception {
            System.out.println( "GuiWorker.doInBackground" );

            //this.loadLabel.setVisible(true);
            this.loadLabel.setIcon(load);
            fillDeviceList();
            return 0;
          }

          @Override
          protected void done() {
            System.out.println("done");
            this.loadLabel.setIcon(null);
            this.pane.repaint();
            //this.pane.revalidate();
            this.dialog.invalidate();

          }

        }

i wywoluje tak z jdialog:

EventQueue.invokeLater( new Runnable() {
            @Override
            public void run() {

               new FillList(loadLabel, thisDialog, tabbedPane).execute();

            }
          } );
1

Nie musi być invokeLater, może być samo new...execute(); (a o ile się nie mylę, to powinno być bez invokeLater)
Widzę, że w doInBackground robisz setIcon, a tak nie powinno być. Nie wiem co robi fillDeviceList, ale przypuszczam, że pisze do modelu listy, a to też nie powinno mieć miejsca. Jeżeli cała lista pobiera się od razu, todo modelu wpisz ją w done(), a jeżeli po kawałku (po itemie), to użyj metod publish -> process.

0

Poniżej kod metody fillDeviceList.
Listę mam od razu całą,ale przetwarzam, dodaje do modelu pokolei to co odczytam. Czy w takim wypadku powinno być w done czy uzywając process?

Próbowałem rzucić do done ale wtedy program przytnie aż metoda fillDeviceList się wykona.
W moim kodzie najpierw musi pobrać z servera więc przycinka troche trwa. Podzielić to na metody pobierające z servera i wypelniajace model? umieścić do doInBackground pobranie z servera, a to co ściągnie wrzucić do wypełnienia modelu w done() - wtedy powinno być chyba szybciej?

I jescze takie pytanie gdzie umiescic to setIcon lub jesli lepiej setVisible? Chce wyswietlac gif od ladowania.

private boolean fillDeviceList()
    {
        Document d = httpConnections.getDeviceList(this.login, this.password);

        if(d == null)
            return false;

        return this.fillDeviceList(d);
    }

private boolean fillDeviceList(Document d)
    {
        XPathFactory xpfactory = null;
        XPath path = null;
        String id = null;

        try
        {
            xpfactory = XPathFactory.newInstance();
            path = xpfactory.newXPath();

            int attrCount = ((Number)path.evaluate("count(devices/id)" , d, XPathConstants.NUMBER)).intValue();

            for(int i = 1; i <= attrCount; i++) // indeksy w XPath zaczynaja sie od 1
            {
                id = path.evaluate("devices/id["+ i +"]", d);
                this.deviceListModel.add(i-1, id); // indeksy w XPath zaczynaja sie od 1 w modelu od 0  
            }

            return true;
        }
        catch(XPathExpressionException e)
        {
            e.printStackTrace();
            return false;
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }
1

Zrób taki SwingWorker
SwingWorker<Document, String> worker = new SwingWorker<Document, String>() {...
W metodzie Document doInBackground wywołaj Document d = httpConnections.getDeviceList(this.login, this.password);
i daj return d;
W metodzie done napisz Document d=get();
this.fillDeviceList(d);

W ten sposób pobieranie, które trwa długo jest w osobnym wątku, a wypełnianie listy jest w EDT.
Co do ustawiania ikonki to pierwszą zmianę daj przed wywołaniem execute, a drugą w done. Jest też opcja użycia addPropertyChangeListener, ale może nie jest tutaj konieczna.

0

Dzięki : ) Po poprawkach działa, przynajmniej koło 30 otwarć dobrze zadziałało jak na razie : )

Gdyby jednak okazało się, że wypełnienie modelu w done będzie czasochłonne z powodu ilości elementów to trzeba będzie przejść na publish process ?

0
Swr napisał(a):

Dzięki : ) Po poprawkach działa, przynajmniej koło 30 otwarć dobrze zadziałało jak na razie : )

Gdyby jednak okazało się, że wypełnienie modelu w done będzie czasochłonne z powodu ilości elementów to trzeba będzie przejść na publish process ?

Zasadniczo tak by trzeba zrobić.
Skoro działa, to dobrze. Teraz, żeby to wszystko miało sens, to powinieneś przemyśleć dorobienie możliwości przerwania tego wątku przez użytkownika, albo jakiś timeout na połączenie dać. No ale to już inna bajka, tu właściwie chodziło o to, że się czasem lista nie pokazywała i mam nadzieję, że to był powód i jest to rozwiązane.

0

w klasie od pobrania listy z servera HttpConnections mam shutdown który przerywa połączenie http, wiec wtedy kończy się chyba tez wątek bo tam nie ma żadnej pętli, mam to dorobione przy przycisku anuluj, chyba powinno wystarczyć. Niby nie jest to przerwanie SwingWorkera, ale chyba tak też może być?

0

Nie wiem, nie chcę cię wprowadzić w błąd, bo kwestii przerywania wątku nie testowałem. Najlepiej sprawdź, ale mam pewne obawy. Przycisk działa w innym wątku niż pobieranie więc może być tak, jak się zaczęło: 10 razy zadziała, a raz nie. Ale popróbuj. W takiej sytuacji wywoła się metoda done, więc tam trzeba zabezpieczyć na wypadek jak nie dostanie dokumentu.

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